diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 00000000000..15f67b986f1 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,73 @@ +FROM mcr.microsoft.com/devcontainers/base:ubuntu-22.04 + +ENV DEBIAN_FRONTEND=noninteractive + +# Install some basics +RUN apt-get update \ + && apt-get install -y \ + wget \ + curl \ + git \ + vim \ + unzip \ + xz-utils \ + software-properties-common \ + && apt-get clean && rm -rf /var/lib/apt/lists/* + +# Add latest cmake +SHELL ["/bin/bash", "-o", "pipefail", "-c"] +RUN wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc | apt-key add - \ + && apt-add-repository "deb https://apt.kitware.com/ubuntu/ $(lsb_release -sc) main" + +# Install required packages for dev +RUN apt-get update \ + && apt-get install -y \ + build-essential \ + libtool autoconf pkg-config \ + ninja-build \ + ruby-full \ + clang-14 \ + llvm-14 \ + libc++-dev libc++abi-dev \ + cmake \ + libboost-all-dev \ + ccache \ + # Swift dependencies + binutils \ + git \ + gnupg2 \ + libc6-dev \ + libcurl4-openssl-dev \ + libedit2 \ + libgcc-9-dev \ + libpython3.8 \ + libsqlite3-0 \ + libstdc++-9-dev \ + libxml2-dev \ + libz3-dev \ + pkg-config \ + tzdata \ + unzip \ + zlib1g-dev \ + && apt-get clean && rm -rf /var/lib/apt/lists/* + +ENV CC=/usr/bin/clang-14 +ENV CXX=/usr/bin/clang++-14 + +# Instal Swift +RUN curl -sSL \ + https://download.swift.org/swift-5.8-release/ubuntu2204/swift-5.8-RELEASE/swift-5.8-RELEASE-ubuntu22.04.tar.gz \ + -o swift-5.8.tar.gz && \ + mkdir -p swift-5.8 && \ + tar -xzf swift-5.8.tar.gz -C swift-5.8 --strip-components=1 && \ + mv swift-5.8 /usr/share/swift + +ENV PATH="/usr/share/swift/usr/bin:${PATH}" + +USER vscode + +# Install rust +RUN curl https://sh.rustup.rs -sSf | sh -s -- --no-modify-path -y +ENV PATH="/home/vscode/.cargo/bin:${PATH}" +RUN cargo install --force cbindgen \ + && rustup target add wasm32-unknown-emscripten diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000000..6bf6d7c88ac --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,31 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/debian +{ + "name": "Debian", + // Use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "build": { + "dockerfile": "Dockerfile" + }, + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Configure tool-specific properties. + "customizations": { + "vscode": { + "extensions": [ + "rust-lang.rust-analyzer", + "sswg.swift-lang", + "ms-vscode.cpptools", + "ms-vscode.cpptools-extension-pack", + "rebornix.Ruby" + ] + } + }, + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + "remoteUser": "vscode" +} diff --git a/.dockerignore b/.dockerignore new file mode 120000 index 00000000000..3e4e48b0b5f --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +.gitignore \ No newline at end of file diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 707fa9c11ea..1724b9a1b7e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -3,4 +3,5 @@ # @global-owner1 and @global-owner2 will be requested for # review when someone opens a pull request. -* @hewigovens @catenocrypt @milerius @miloserdow +* @milerius @satoshiotomakan @ar-g +kotlin/ @ar-g @JaimeToca @rkokhatskyi diff --git a/.github/workflows/android-ci.yml b/.github/workflows/android-ci.yml index 0bb3ed90964..b8d6bb34c8a 100644 --- a/.github/workflows/android-ci.yml +++ b/.github/workflows/android-ci.yml @@ -2,43 +2,82 @@ name: Android CI on: push: - branches: [ master ] + branches: [ dev, master ] pull_request: - branches: [ master ] + branches: [ dev, master ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: build: - - runs-on: macos-12 - + runs-on: macos-latest-large + if: github.event.pull_request.draft == false steps: - - uses: actions/checkout@v2 - - name: Set up JDK 11 - uses: actions/setup-java@v1 + - uses: actions/checkout@v3 + + - name: Set up JDK 17 + uses: actions/setup-java@v3 with: - java-version: 11 + java-version: '17' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 + - name: Install system dependencies - run: brew install boost ninja - - name: Install Android Dependencies run: | - tools/install-android-dependencies + tools/install-sys-dependencies-mac + + - name: Cache Rust + uses: Swatinem/rust-cache@v2 + with: + workspaces: | + rust + + - name: Install Rust dependencies + run: | + tools/install-rust-dependencies + + - name: Install Android Dependencies + run: tools/install-android-dependencies + - name: Cache internal dependencies id: internal_cache - uses: actions/cache@v1.1.2 + uses: actions/cache@v3 with: path: build/local - key: ${{ runner.os }}-internal-${{ hashFiles('tools/install-dependencies') }} + key: ${{ runner.os }}-${{ runner.arch }}-internal-${{ hashFiles('tools/install-dependencies') }} + - name: Install internal dependencies - run: | - tools/install-dependencies + run: tools/install-dependencies if: steps.internal_cache.outputs.cache-hit != 'true' - - name: Run test + + - name: Generate files + run: tools/generate-files android + + - name: Build Kotlin doc + run: tools/kotlin-doc + + - name: Build tests run: | - tools/generate-files - tools/android-test + pushd android + ./gradlew assembleAndroidTest + popd + + - name: Run tests + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: 30 + target: google_apis + arch: x86 + ndk: 23.1.7779620 + cmake: 3.18.1 + script: cd android; ./gradlew connectedAndroidTest + - name: Build sample app - run: | - tools/samples-build android + run: tools/samples-build android env: GITHUB_USER: ${{ github.actor }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/codegen-v2.yml b/.github/workflows/codegen-v2.yml new file mode 100644 index 00000000000..8438d788d56 --- /dev/null +++ b/.github/workflows/codegen-v2.yml @@ -0,0 +1,47 @@ +name: Codegen-v2 Tests + +on: + push: + branches: [ dev, master ] + pull_request: + branches: [ dev, master ] + +env: + SCCACHE_GHA_ENABLED: "true" + RUSTC_WRAPPER: "sccache" + +jobs: + test: + runs-on: ubuntu-24.04 + if: github.event.pull_request.draft == false + steps: + - uses: actions/checkout@v3 + - name: Install system dependencies + run: | + tools/install-sys-dependencies-linux + + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.3 + + - name: Install Rust dependencies + run: | + tools/install-rust-dependencies + + - name: Run codegen-v2 tests + run: | + cargo test --all + working-directory: codegen-v2 + + # Generate files for a blockchain. + # Please note the blockchain should not be implemented in Rust at the moment of running this step, + # otherwise consider either generating files for another blockchain or removing this step at all. + - name: Test codegen-v2 new-blockchain-rust + run: | + cargo run -- new-blockchain-rust iotex + working-directory: codegen-v2 + + # Check if `new-blockchain-rust` command has generated files that do not break project compilation. + - name: Check Rust compiles + run: | + cargo check --tests + working-directory: rust diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 369efae9cbd..336faa4ce81 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -2,29 +2,25 @@ name: Docker CI on: push: - branches: [ master ] - paths: - - Dockerfile - - tools/install-dependencies + branches: [ dev, master ] pull_request: - branches: [ master ] - paths: + branches: [ dev, master ] + paths: - Dockerfile - tools/install-dependencies jobs: build: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v2 - - name: Lint Dockerfile - run: | - curl -L https://github.com/hadolint/hadolint/releases/download/v1.17.6/hadolint-Linux-x86_64 -o hadolint && chmod +x hadolint - ./hadolint Dockerfile - - - name: Build Dockerfile - uses: docker/build-push-action@v1.1.0 - with: - repository: trustwallet/wallet-core - tags: latest - push: false + - uses: actions/checkout@v3 + - name: Lint Dockerfile + run: | + curl -L https://github.com/hadolint/hadolint/releases/download/v1.17.6/hadolint-Linux-x86_64 -o hadolint && chmod +x hadolint + ./hadolint Dockerfile + - name: Build Dockerfile + uses: docker/build-push-action@v1.1.0 + with: + repository: trustwallet/wallet-core + tags: latest + push: false diff --git a/.github/workflows/ios-ci.yml b/.github/workflows/ios-ci.yml index a7078f649e3..649b15e84a2 100644 --- a/.github/workflows/ios-ci.yml +++ b/.github/workflows/ios-ci.yml @@ -2,34 +2,55 @@ name: iOS CI on: push: - branches: [ master ] + branches: [ dev, master ] pull_request: - branches: [ master ] + branches: [ dev, master ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: build: - runs-on: macos-12 + runs-on: macos-latest-xlarge + if: github.event.pull_request.draft == false steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 + - name: Install system dependencies run: | - brew install boost ninja xcodegen xcbeautify + tools/install-sys-dependencies-mac + + - name: Cache Rust + uses: Swatinem/rust-cache@v2 + with: + workspaces: | + rust + + - name: Install Rust dependencies + run: | + tools/install-rust-dependencies + - name: Cache internal dependencies id: internal_cache - uses: actions/cache@v1.1.2 + uses: actions/cache@v3 with: path: build/local key: ${{ runner.os }}-internal-${{ hashFiles('tools/install-dependencies') }} + - name: Install internal dependencies run: | tools/install-dependencies if: steps.internal_cache.outputs.cache-hit != 'true' + - name: Run codegen tests run: tools/codegen-test + - name: Run iOS tests run: | - tools/generate-files + tools/generate-files ios tools/ios-test + - name: Build sample app run: | tools/samples-build ios diff --git a/.github/workflows/kotlin-ci.yml b/.github/workflows/kotlin-ci.yml new file mode 100644 index 00000000000..1198c20ae3c --- /dev/null +++ b/.github/workflows/kotlin-ci.yml @@ -0,0 +1,83 @@ +name: Kotlin CI + +on: + push: + branches: [ dev, master ] + pull_request: + branches: [ dev, master ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + runs-on: macos-latest-xlarge + if: github.event.pull_request.draft == false + steps: + - uses: actions/checkout@v3 + + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'temurin' + + - name: Setup Android SDK + uses: android-actions/setup-android@v3 + + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 + with: + gradle-version: 8.1.1 + + - name: Install system dependencies + run: | + tools/install-sys-dependencies-mac + + - name: Cache Rust + uses: Swatinem/rust-cache@v2 + with: + workspaces: | + rust + + - name: Install Rust dependencies + run: | + tools/install-rust-dependencies + + - name: Install emsdk + run: tools/install-wasm-dependencies + + - name: Install Kotlin Dependencies + run: tools/install-kotlin-dependencies + + - name: Cache internal dependencies + id: internal_cache + uses: actions/cache@v3 + with: + path: build/local + key: ${{ runner.os }}-internal-${{ hashFiles('tools/install-dependencies') }} + + - name: Install internal dependencies + run: tools/install-dependencies + if: steps.internal_cache.outputs.cache-hit != 'true' + + - name: Generate files + run: | + source emsdk/emsdk_env.sh + tools/generate-files + + - name: CMake (Java, Kotlin) + run: | + cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug -DTW_UNITY_BUILD=ON -DTW_COMPILE_JAVA=ON -DTW_COMPILE_KOTLIN=ON -GNinja + + - name: Build JNI + run: | + ninja -Cbuild + mv build/libTrustWalletCore.dylib kotlin/wallet-core-kotlin/src/jvmMain/resources/jni/macos-arm64/ + + - name: Build Kotlin Multiplatform + run: tools/kotlin-build + + - name: Run Kotlin Multiplatform tests + run: tools/kotlin-test diff --git a/.github/workflows/kotlin-sample-ci.yml b/.github/workflows/kotlin-sample-ci.yml new file mode 100644 index 00000000000..f96b2a4b280 --- /dev/null +++ b/.github/workflows/kotlin-sample-ci.yml @@ -0,0 +1,39 @@ +name: Kotlin Multiplatform CI + +on: + push: + branches: [ dev, master ] + pull_request: + branches: [ dev, master ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + runs-on: macos-latest-xlarge + if: github.event.pull_request.draft == false + steps: + - uses: actions/checkout@v3 + + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'temurin' + + - name: Setup Android SDK + uses: android-actions/setup-android@v3 + + - name: Install Kotlin Dependencies + run: tools/install-kotlin-dependencies + + - name: Build KMP Sample + run: | + ./gradlew --version + ./gradlew assemble + working-directory: samples/kmp + env: + GITHUB_USER: ${{ github.actor }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/linux-ci-rust.yml b/.github/workflows/linux-ci-rust.yml new file mode 100644 index 00000000000..7e0889e824a --- /dev/null +++ b/.github/workflows/linux-ci-rust.yml @@ -0,0 +1,161 @@ +name: Linux CI Rust + +on: + push: + branches: [ dev, master ] + pull_request: + branches: [ dev, master ] + +env: + SCCACHE_GHA_ENABLED: "true" + RUSTC_WRAPPER: "sccache" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + # Check formatting, clippy warnings, run tests and check code coverage. + build-and-test: + permissions: + contents: read + checks: write + runs-on: ubuntu-24.04 + if: github.event.pull_request.draft == false + steps: + - uses: actions/checkout@v3 + - name: Install system dependencies + run: | + tools/install-sys-dependencies-linux + + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.3 + + - name: Cache Rust + uses: Swatinem/rust-cache@v2 + with: + workspaces: | + rust + + - name: Install Rust dependencies + run: | + tools/install-rust-dependencies dev + + - name: Check code formatting + run: | + cargo fmt --check + working-directory: rust + + - name: Check Clippy warnings + run: | + cargo clippy -- -D warnings + working-directory: rust + + - name: Run tests + run: | + tools/rust-coverage + + - name: Gather and check Rust code coverage + run: | + tools/check-coverage rust/coverage.stats rust/coverage.info + + # Run Rust tests in WASM. + test-wasm: + runs-on: ubuntu-24.04 + if: github.event.pull_request.draft == false + steps: + - uses: actions/checkout@v3 + - name: Install system dependencies + run: | + tools/install-sys-dependencies-linux + + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.3 + + - name: Cache Rust + uses: Swatinem/rust-cache@v2 + with: + workspaces: | + rust + + - name: Install Rust dependencies + run: | + tools/install-rust-dependencies + + - name: Install emsdk + run: tools/install-wasm-dependencies + + - name: Run tests in WASM + run: tools/rust-test wasm + + check-binary-sizes: + permissions: + contents: read + pull-requests: write + runs-on: macos-latest-xlarge + if: github.event.pull_request.draft == false + steps: + - uses: actions/checkout@v3 + - name: Install system dependencies + run: | + tools/install-sys-dependencies-mac + + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.3 + + - name: Cache Rust + uses: Swatinem/rust-cache@v2 + with: + workspaces: | + rust + + - name: Install Rust dependencies + run: tools/install-rust-dependencies + + - name: Install emsdk + run: tools/install-wasm-dependencies + + - name: Compile release binaries + run: | + mkdir -p build/local/lib + source emsdk/emsdk_env.sh + tools/rust-bindgen + + - name: Generate release report + run: | + ./tools/release-size measure-rust > release-report.json + + - name: Upload release report + uses: actions/upload-artifact@v4 + with: + name: release_report + path: release-report.json + + # Download previous release report, compare the release binary sizes, and post/update a comment at the Pull Request. + - name: Download previous release report + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false + uses: dawidd6/action-download-artifact@v6 + with: + commit: ${{github.event.pull_request.base.sha}} + path: previous + if_no_artifact_found: warn + # Same artifact name as at the "Upload release report" step. + name: release_report + # Ignore status or conclusion in the search. + workflow_conclusion: "" + + - name: Craft Comment Body + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false + run: | + # Please note `previous/release-report.json` may not exist if the previous report was not found. + ./tools/release-size compare --before previous/release-report.json --current release-report.json > report-diff.md + + - name: Create or Update Comment + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false + uses: edumserrano/find-create-or-update-comment@v2 + with: + issue-number: ${{ github.event.pull_request.number }} + body-includes: "Binary size comparison" + comment-author: 'github-actions[bot]' + edit-mode: replace + body-path: 'report-diff.md' diff --git a/.github/workflows/linux-ci-sonarcloud.yml b/.github/workflows/linux-ci-sonarcloud.yml new file mode 100644 index 00000000000..83fa3b4f216 --- /dev/null +++ b/.github/workflows/linux-ci-sonarcloud.yml @@ -0,0 +1,66 @@ +name: Linux CI SonarCloud + +on: + push: + branches: [ dev, master ] + pull_request: + branches: [ dev, master ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + if: github.event.pull_request.draft == false && github.event.pull_request.head.repo.fork == false + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v3 + + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'temurin' + + - name: Install system dependencies + run: | + tools/install-sys-dependencies-linux + tools/install-rust-dependencies + + - name: Cache internal dependencies + id: internal_cache + uses: actions/cache@v3 + with: + path: build/local + key: ${{ runner.os }}-internal-${{ hashFiles('tools/install-dependencies') }} + + - name: Install internal dependencies + run: | + tools/install-dependencies + env: + CC: /usr/bin/clang + CXX: /usr/bin/clang++ + if: steps.internal_cache.outputs.cache-hit != 'true' + + - name: Code generation + run: | + tools/generate-files native + env: + CC: /usr/bin/clang + CXX: /usr/bin/clang++ + + - name: CMake (coverage/clang-tidy/clang-asan) + run: | + cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug -DTW_CODE_COVERAGE=ON -DTW_ENABLE_CLANG_TIDY=ON -DTW_CLANG_ASAN=ON -GNinja + cat build/compile_commands.json + env: + CC: /usr/bin/clang + CXX: /usr/bin/clang++ + + - name: SonarCloud Scan + run: | + ./tools/sonarcloud-analysis + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index bed1b725444..1062e02dacb 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -2,25 +2,30 @@ name: Linux CI on: push: - branches: [ master ] + branches: [ dev, master ] pull_request: - branches: [ master ] + branches: [ dev, master ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 + if: github.event.pull_request.draft == false steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install system dependencies run: | - # build-essential clang-14 libc++-dev libc++abi-dev ruby-full cmake - sudo apt-get update && sudo apt-get install ninja-build lcov llvm-14 clang-tidy-14 libboost-all-dev --fix-missing + tools/install-sys-dependencies-linux + tools/install-rust-dependencies - name: Cache internal dependencies id: internal_cache - uses: actions/cache@v1.1.2 + uses: actions/cache@v3 with: path: build/local - key: ${{ runner.os }}-internal-${{ hashFiles('tools/install-dependencies') }} + key: ${{ runner.os }}-internal-${{ hashFiles('tools/install-sys-dependencies-linux') }}-${{ hashFiles('tools/install-dependencies') }} - name: Install internal dependencies run: | tools/install-dependencies @@ -28,9 +33,16 @@ jobs: CC: /usr/bin/clang CXX: /usr/bin/clang++ if: steps.internal_cache.outputs.cache-hit != 'true' + + - name: Cache Rust + uses: Swatinem/rust-cache@v2 + with: + workspaces: | + rust + - name: Code generation run: | - tools/generate-files + tools/generate-files native env: CC: /usr/bin/clang CXX: /usr/bin/clang++ diff --git a/.github/workflows/linux-sampleapp-ci.yml b/.github/workflows/linux-sampleapp-ci.yml index 3d16471abbd..a8c0dbe15da 100644 --- a/.github/workflows/linux-sampleapp-ci.yml +++ b/.github/workflows/linux-sampleapp-ci.yml @@ -2,24 +2,30 @@ name: Linux SampleApps CI on: push: - branches: [ master ] + branches: [ dev, master ] pull_request: - branches: [ master ] + branches: [ dev, master ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 + if: github.event.pull_request.draft == false steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install system dependencies run: | - sudo apt-get update && sudo apt-get install ninja-build llvm-11 libboost-all-dev clang-11 --fix-missing + tools/install-sys-dependencies-linux + tools/install-rust-dependencies - name: Cache internal dependencies id: internal_cache - uses: actions/cache@v1.1.2 + uses: actions/cache@v3 with: path: build/local - key: ${{ runner.os }}-internal-${{ hashFiles('tools/install-dependencies') }} + key: ${{ runner.os }}-internal-${{ hashFiles('tools/install-sys-dependencies-linux') }}-${{ hashFiles('tools/install-dependencies') }} - name: Install internal dependencies run: | tools/install-dependencies @@ -29,7 +35,7 @@ jobs: if: steps.internal_cache.outputs.cache-hit != 'true' - name: Code generation run: | - tools/generate-files + tools/generate-files native env: CC: /usr/bin/clang CXX: /usr/bin/clang++ @@ -55,13 +61,6 @@ jobs: env: CC: /usr/bin/clang CXX: /usr/bin/clang++ - - name: Build, run, and test devconsole.ts - run: | - cd samples/typescript/devconsole.ts - npm install - npm run build - echo -e "help() \n .exit" | npm run start - npm run test - name: Install Go env: GO_VERSION: 1.19 @@ -88,3 +87,9 @@ jobs: env: CC: /usr/bin/clang CXX: /usr/bin/clang++ + - name: Build and run Rust sample app + run: | + cd samples/rust + rustc --version + cargo build + cargo run diff --git a/.github/workflows/wasm-ci.yml b/.github/workflows/wasm-ci.yml index d383cc49195..d68b0dcb39d 100644 --- a/.github/workflows/wasm-ci.yml +++ b/.github/workflows/wasm-ci.yml @@ -2,27 +2,31 @@ name: Wasm CI on: push: - branches: [ master ] + branches: [ dev, master ] pull_request: - branches: [ master ] + branches: [ dev, master ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 + if: github.event.pull_request.draft == false steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install system dependencies run: | - # build-essential clang-11 libc++-dev libc++abi-dev ruby-full cmake python3 - sudo apt-get update && sudo apt-get install libboost-all-dev --fix-missing - + tools/install-sys-dependencies-linux + tools/install-rust-dependencies - name: Install emsdk run: tools/install-wasm-dependencies - name: Cache internal dependencies id: internal_cache - uses: actions/cache@v1.1.2 + uses: actions/cache@v3 with: path: build/local key: ${{ runner.os }}-internal-${{ hashFiles('tools/install-dependencies') }} @@ -35,7 +39,9 @@ jobs: if: steps.internal_cache.outputs.cache-hit != 'true' - name: Code generation - run: tools/generate-files + run: | + source emsdk/emsdk_env.sh + tools/generate-files wasm env: CC: /usr/bin/clang CXX: /usr/bin/clang++ diff --git a/.gitignore b/.gitignore index 707a2517dee..7b093f9e1a3 100644 --- a/.gitignore +++ b/.gitignore @@ -23,17 +23,21 @@ lib/protobuf .vscode/ .project .history/ +*.xcuserdatad/ # Generated files +jni/android/generated jni/cpp/generated jni/java/wallet/core/jni -jni/java/wallet/core/proto +jni/proto/wallet +jni/dokka-out swift/Sources/Generated swift/wallet-core/ +codegen-v2/bindings/ + src/Generated/*.cpp include/TrustWalletCore/TWHRP.h include/TrustWalletCore/TW*Proto.h -include/TrustWalletCore/TWDerivation.h include/TrustWalletCore/TWEthereumChainID.h # Wasm @@ -62,5 +66,5 @@ samples/cpp/*.cmake # built binary samples/cpp/sample -*.xcuserdatad/ - +# Rust target build +**/target/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 3b061e1c15b..6fec5513326 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,6 @@ -# Copyright © 2017-2022 Trust Wallet. +# SPDX-License-Identifier: Apache-2.0 # -# This file is part of Trust. The full Trust copyright notice, including -# terms governing use, modification, and redistribution, is contained in the -# file LICENSE at the root of the source code distribution tree. +# Copyright © 2017 Trust Wallet. cmake_minimum_required(VERSION 3.18 FATAL_ERROR) @@ -24,14 +22,20 @@ include(cmake/CompilerWarnings.cmake) include(cmake/StaticAnalyzers.cmake) include(cmake/FindHostPackage.cmake) +set(WALLET_CORE_RS_TARGET_DIR ${CMAKE_SOURCE_DIR}/rust/target) add_library(${PROJECT_NAME}_INTERFACE INTERFACE) target_include_directories(${PROJECT_NAME}_INTERFACE INTERFACE ${PREFIX}/include) target_link_directories(${PROJECT_NAME}_INTERFACE INTERFACE ${PREFIX}/lib) +target_link_directories(${PROJECT_NAME}_INTERFACE INTERFACE ${WALLET_CORE_RS_TARGET_DIR}/release) set_project_warnings(${PROJECT_NAME}_INTERFACE) add_subdirectory(trezor-crypto) +set(WALLET_CORE_RS_LIB libwallet_core_rs.a) + +set(WALLET_CORE_BINDGEN ${WALLET_CORE_RS_TARGET_DIR}/release/${WALLET_CORE_RS_LIB}) if (TW_COMPILE_WASM) message(STATUS "Wasm build enabled") + set(WALLET_CORE_BINDGEN ${WALLET_CORE_RS_TARGET_DIR}/wasm32-unknown-emscripten/release/${WALLET_CORE_RS_LIB}) add_subdirectory(wasm) endif () @@ -44,17 +48,54 @@ include(cmake/Protobuf.cmake) # Source files if (${ANDROID}) - message("Configuring for JNI") - file(GLOB_RECURSE sources src/*.c src/*.cc src/*.cpp src/*.h jni/cpp/*.c jni/cpp/*.cpp jni/cpp/*.h jni/cpp/*.c) + message("Configuring for Android JNI") + file(GLOB_RECURSE core_sources src/*.c src/*.cc src/*.cpp src/*.h jni/cpp/*.cpp jni/cpp/*.h) + if (${KOTLIN}) + file(GLOB_RECURSE specific_sources + jni/kotlin/*.h + jni/kotlin/*.c + kotlin/wallet-core-kotlin/src/commonAndroidJvmMain/cpp/generated/*.h + kotlin/wallet-core-kotlin/src/commonAndroidJvmMain/cpp/generated/*.c + ) + else () + file(GLOB_RECURSE specific_sources jni/android/*.h jni/android/*.c) + endif () + set(sources ${core_sources} ${specific_sources}) add_library(TrustWalletCore SHARED ${sources} ${PROTO_SRCS} ${PROTO_HDRS}) find_library(log-lib log) - target_link_libraries(TrustWalletCore PUBLIC ${PROJECT_NAME}_INTERFACE PRIVATE TrezorCrypto protobuf ${log-lib} Boost::boost) + if (${CMAKE_ANDROID_ARCH_ABI} STREQUAL "arm64-v8a") + set(WALLET_CORE_BINDGEN ${WALLET_CORE_RS_TARGET_DIR}/aarch64-linux-android/release/${WALLET_CORE_RS_LIB}) + elseif (${CMAKE_ANDROID_ARCH_ABI} STREQUAL "x86") + set(WALLET_CORE_BINDGEN ${WALLET_CORE_RS_TARGET_DIR}/i686-linux-android/release/${WALLET_CORE_RS_LIB}) + elseif (${CMAKE_ANDROID_ARCH_ABI} STREQUAL "armeabi-v7a") + set(WALLET_CORE_BINDGEN ${WALLET_CORE_RS_TARGET_DIR}/armv7-linux-androideabi/release/${WALLET_CORE_RS_LIB}) + elseif (${CMAKE_ANDROID_ARCH_ABI} STREQUAL "x86_64") + set(WALLET_CORE_BINDGEN ${WALLET_CORE_RS_TARGET_DIR}/x86_64-linux-android/release/${WALLET_CORE_RS_LIB}) + endif () + target_link_libraries(TrustWalletCore PUBLIC ${WALLET_CORE_BINDGEN} ${PROJECT_NAME}_INTERFACE PRIVATE TrezorCrypto protobuf ${log-lib} Boost::boost) +elseif (${TW_COMPILE_JAVA}) + message("Configuring for JNI") + file(GLOB_RECURSE core_sources src/*.c src/*.cc src/*.cpp src/*.h jni/cpp/*.cpp jni/cpp/*.h) + if (${TW_COMPILE_KOTLIN}) + file(GLOB_RECURSE specific_sources + jni/kotlin/*.h + jni/kotlin/*.c + kotlin/wallet-core-kotlin/src/commonAndroidJvmMain/cpp/generated/*.h + kotlin/wallet-core-kotlin/src/commonAndroidJvmMain/cpp/generated/*.c + ) + else () + file(GLOB_RECURSE specific_sources jni/android/*.h jni/android/*.c) + endif () + set(sources ${core_sources} ${specific_sources}) + add_library(TrustWalletCore SHARED ${sources} ${PROTO_SRCS} ${PROTO_HDRS}) + find_package(JNI REQUIRED) + target_include_directories(TrustWalletCore PRIVATE ${JNI_INCLUDE_DIRS}) + target_link_libraries(TrustWalletCore PUBLIC ${WALLET_CORE_BINDGEN} ${PROJECT_NAME}_INTERFACE PRIVATE TrezorCrypto protobuf Boost::boost) else () message("Configuring standalone") file(GLOB_RECURSE sources src/*.c src/*.cc src/*.cpp src/*.h) - add_library(TrustWalletCore ${sources} ${PROTO_SRCS} ${PROTO_HDRS}) - - target_link_libraries(TrustWalletCore PUBLIC ${PROJECT_NAME}_INTERFACE PRIVATE TrezorCrypto protobuf Boost::boost) + add_library(TrustWalletCore STATIC ${sources} ${PROTO_SRCS} ${PROTO_HDRS}) + target_link_libraries(TrustWalletCore PUBLIC ${WALLET_CORE_BINDGEN} ${PROJECT_NAME}_INTERFACE PRIVATE TrezorCrypto protobuf Boost::boost) endif () if (TW_CODE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") @@ -94,15 +135,15 @@ if (TW_ENABLE_CLANG_TIDY) tw_add_clang_tidy_target(TrustWalletCore) endif () -if (NOT ANDROID AND TW_UNITY_BUILD) +if (TW_UNITY_BUILD) set_target_properties(TrustWalletCore PROPERTIES UNITY_BUILD ON) - file(GLOB_RECURSE PROTOBUF_SOURCE_FILES CONFIGURE_DEPENDS src/Cosmos/Protobuf/*.pb.cc src/proto/*.pb.cc) - foreach(file ${PROTOBUF_SOURCE_FILES}) + file(GLOB_RECURSE PROTOBUF_SOURCE_FILES CONFIGURE_DEPENDS src/Cosmos/Protobuf/*.pb.cc src/Hedera/Protobuf/*.pb.cc src/proto/*.pb.cc) + foreach (file ${PROTOBUF_SOURCE_FILES}) set_property(SOURCE ${file} PROPERTY SKIP_UNITY_BUILD_INCLUSION ON) - endforeach() + endforeach () message(STATUS "Unity build activated") -endif() +endif () configure_file(${CMAKE_CURRENT_SOURCE_DIR}/swift/cpp.xcconfig.in ${CMAKE_CURRENT_SOURCE_DIR}/swift/cpp.xcconfig @ONLY) diff --git a/Dockerfile b/Dockerfile index fae3ef89269..082d5fd1969 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,13 +14,8 @@ RUN apt-get update \ software-properties-common \ && apt-get clean && rm -rf /var/lib/apt/lists/* -# Add latest cmake/boost SHELL ["/bin/bash", "-o", "pipefail", "-c"] -RUN wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc | apt-key add - \ - && apt-add-repository 'deb https://apt.kitware.com/ubuntu/ bionic main' - -RUN wget http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.0g-2ubuntu4_amd64.deb && dpkg -i ./libssl1.1_1.1.0g-2ubuntu4_amd64.deb # Install required packages for dev RUN apt-get update \ && apt-get install -y \ @@ -39,34 +34,34 @@ RUN apt-get update \ ENV CC=/usr/bin/clang-14 ENV CXX=/usr/bin/clang++-14 +# Install rust +RUN wget "https://sh.rustup.rs" -O rustup.sh \ + && sh rustup.sh -y +ENV PATH="/root/.cargo/bin:${PATH}" +RUN rustup default nightly-2024-06-13 +RUN cargo install --force cbindgen \ + && rustup target add wasm32-unknown-emscripten + # ↑ Setup build environment # ↓ Build and compile wallet core -RUN git clone https://github.com/trustwallet/wallet-core.git +COPY . /wallet-core WORKDIR /wallet-core # Install dependencies RUN tools/install-dependencies -# Build: generate, cmake, and make lib -RUN tools/generate-files \ - && cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug \ +# Build: generate files and rust lib +RUN tools/generate-files native + +# Build: cmake + make wallet core +RUN cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug \ && make -Cbuild -j12 TrustWalletCore # Build unit tester RUN make -Cbuild -j12 tests -# Download and Install Go -ENV GO_VERSION=1.16.12 -ENV GO_ARCH=amd64 -RUN wget "https://golang.org/dl/go${GO_VERSION}.linux-${GO_ARCH}.tar.gz" \ - && tar -xf "go${GO_VERSION}.linux-${GO_ARCH}.tar.gz" \ - && chown -R root:root ./go \ - && mv -v ./go /usr/local \ - && ls /usr/local/go \ - && /usr/local/go/bin/go version \ - && rm "go${GO_VERSION}.linux-${GO_ARCH}.tar.gz" - -# Building GoLang sample app: cd samples/go && /usr/local/go/bin/go build -o main && ./main +# Download and Install Go: apt install golang-go +# Build Go sample app: cd samples/go && /usr/local/go/bin/go build -o main && ./main CMD ["/bin/bash"] diff --git a/LICENSE b/LICENSE index d7b2f475420..591e7191a60 100644 --- a/LICENSE +++ b/LICENSE @@ -1,19 +1,190 @@ -Copyright (c) 2017-2020 Trust Wallet - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2017 Trust Wallet + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/LICENSE-3RD-PARTY.txt b/LICENSE-3RD-PARTY.txt new file mode 100644 index 00000000000..93b7fb0a22a --- /dev/null +++ b/LICENSE-3RD-PARTY.txt @@ -0,0 +1,850 @@ +3RD PARTY LICENSES + +Note that not all files in the wallet-core repository and in the released +software packages belong to the wallet-core project. For 3rd party files, +the individual licenses apply. + + +############################################################################# +LICENSE TEXTS +############################################################################# + +Copyright 2008, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +############################################################################# + + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + +############################################################################# + +Copyright 2008 Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Code generated by the Protocol Buffer compiler is owned by the owner +of the input file used when generating it. This code is not +standalone and requires a support library to be linked with it. This +support library is itself covered by the above license. + +############################################################################# + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + +## Runtime Library Exception to the Apache 2.0 License: ## + + + As an exception, if you use this Software to compile your source code and + portions of this Software are embedded into the binary product as a result, + you may redistribute such product without providing attribution as would + otherwise be required by Sections 4(a), 4(b) and 4(d) of the License. + +############################################################################# + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +############################################################################# + +The MIT License (MIT) + +Copyright (c) 2013 Tomas Dzetkulic +Copyright (c) 2013 Pavol Rusnak + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Package.swift b/Package.swift index 7da39e00a9d..7e933efe93d 100644 --- a/Package.swift +++ b/Package.swift @@ -12,13 +12,13 @@ let package = Package( targets: [ .binaryTarget( name: "WalletCore", - url: "https://github.com/trustwallet/wallet-core/releases/download/2.9.5/WalletCore.xcframework.zip", - checksum: "bb3bccd29e4f03c58bfa1fd746a0f8d6fc4ffc9ec2183beb4facd7b01974a9a2" + url: "https://github.com/trustwallet/wallet-core/releases/download/4.1.12/WalletCore.xcframework.zip", + checksum: "1632bbbab1c6a588689eec77a24e1468d9a6746968652cf0a7e669e996c3d24d" ), .binaryTarget( name: "SwiftProtobuf", - url: "https://github.com/trustwallet/wallet-core/releases/download/2.9.5/SwiftProtobuf.xcframework.zip", - checksum: "7903f5e9487db4764dc57be000c384a0619a96c275993711f3a5a858d3c865bd" + url: "https://github.com/trustwallet/wallet-core/releases/download/4.1.12/SwiftProtobuf.xcframework.zip", + checksum: "33d80c20428c9db4fcf99d1272ba19655f7c6ee7e5b1809fa8a7e7d4aa1b222b" ) ] ) diff --git a/README.md b/README.md index 36b798cb3cd..7456046acbd 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,19 @@ -Trust Wallet Core is an open source, cross-platform, mobile-focused library +Trust Wallet Core is an open-source, cross-platform, mobile-focused library implementing low-level cryptographic wallet functionality for a high number of blockchains. It is a core part of the popular [Trust Wallet](https://trustwallet.com), and some other projects. Most of the code is C++ with a set of strict C interfaces, and idiomatic interfaces for supported languages: Swift for iOS and Java (Kotlin) for Android. -![iOS CI](https://github.com/trustwallet/wallet-core/workflows/iOS%20CI/badge.svg) -![Android CI](https://github.com/trustwallet/wallet-core/workflows/Android%20CI/badge.svg) -![Linux CI](https://github.com/trustwallet/wallet-core/workflows/Linux%20CI/badge.svg) -![Wasm CI](https://github.com/trustwallet/wallet-core/workflows/Wasm%20CI/badge.svg) -![Docker CI](https://github.com/trustwallet/wallet-core/workflows/Docker%20CI/badge.svg) +[![iOS CI](https://github.com/trustwallet/wallet-core/actions/workflows/ios-ci.yml/badge.svg)](https://github.com/trustwallet/wallet-core/actions/workflows/ios-ci.yml) +[![Android CI](https://github.com/trustwallet/wallet-core/actions/workflows/android-ci.yml/badge.svg)](https://github.com/trustwallet/wallet-core/actions/workflows/android-ci.yml) +[![Linux CI](https://github.com/trustwallet/wallet-core/actions/workflows/linux-ci.yml/badge.svg)](https://github.com/trustwallet/wallet-core/actions/workflows/linux-ci.yml) +[![Rust CI](https://github.com/trustwallet/wallet-core/actions/workflows/linux-ci-rust.yml/badge.svg)](https://github.com/trustwallet/wallet-core/actions/workflows/linux-ci-rust.yml) +[![Wasm CI](https://github.com/trustwallet/wallet-core/actions/workflows/wasm-ci.yml/badge.svg)](https://github.com/trustwallet/wallet-core/actions/workflows/wasm-ci.yml) +[![Kotlin CI](https://github.com/trustwallet/wallet-core/actions/workflows/kotlin-ci.yml/badge.svg)](https://github.com/trustwallet/wallet-core/actions/workflows/kotlin-ci.yml) +[![Docker CI](https://github.com/trustwallet/wallet-core/actions/workflows/docker.yml/badge.svg)](https://github.com/trustwallet/wallet-core/actions/workflows/docker.yml) +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=TrustWallet_wallet-core&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=TrustWallet_wallet-core) [![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/trustwallet/wallet-core) ![GitHub](https://img.shields.io/github/license/TrustWallet/wallet-core.svg) @@ -22,9 +25,13 @@ Swift for iOS and Java (Kotlin) for Android. For comprehensive documentation, see [developer.trustwallet.com](https://developer.trustwallet.com/wallet-core). +# Audit Reports + +Security Audit reports can be found in the [audit](audit) directory. + # Supported Blockchains -Wallet Core supports more than **60** blockchains: Bitcoin, Ethereum, BNB, Cosmos, Solana, and most major blockchain platforms. +Wallet Core supports more than **130** blockchains: Bitcoin, Ethereum, BNB, Cosmos, Solana, and most major blockchain platforms. The full list is [here](docs/registry.md). # Building @@ -38,7 +45,7 @@ If you want to use wallet core in your project follow these instructions. ## Android -Android releases are hosted on [GitHub packages](https://github.com/trustwallet/wallet-core/packages/700258), you need to add GitHub access token to install it. Please checkout [this installation guide](https://developer.trustwallet.com/wallet-core/integration-guide/android-guide#adding-library-dependency) or `build.gradle` from our [android sample](https://github.com/trustwallet/wallet-core/blob/master/samples/android/build.gradle) +Android releases are hosted on [GitHub packages](https://github.com/trustwallet/wallet-core/packages/700258), you need to add GitHub access token to install it. Please check out [this installation guide](https://developer.trustwallet.com/wallet-core/integration-guide/android-guide#adding-library-dependency) or `build.gradle` from our [android sample](https://github.com/trustwallet/wallet-core/blob/master/samples/android/build.gradle) Don't forget replacing the version in the code with latest: ![GitHub release (latest by date)](https://img.shields.io/github/v/release/trustwallet/wallet-core) @@ -62,7 +69,7 @@ Or add remote url + `master` branch, it points to recent (not always latest) bin .package(name: "WalletCore", url: "https://github.com/trustwallet/wallet-core", .branchItem("master")), ``` -Then add libraries to target's `dependencies`: +Then add libraries to target's `dependencies`: ```swift .product(name: "WalletCore", package: "WalletCore"), @@ -87,19 +94,24 @@ npm install @trustwallet/wallet-core Please check out the [Go integration sample](https://github.com/trustwallet/wallet-core/tree/master/samples/go). +## Kotlin Multipleplatform (beta) + +Please check out the [Kotlin Multiplatform sample](https://github.com/trustwallet/wallet-core/tree/master/samples/kmp) # Projects Projects using Trust Wallet Core. Add yours too! -[Trust Wallet](https://trustwallet.com) +[Trust Wallet](https://trustwallet.com) [Coinpaprika](https://coinpaprika.com/) -| [IFWallet](https://www.ifwallet.com/) | [crypto.com](https://crypto.com) -| [Alice](https://www.alicedapp.com/) | [Frontier](https://frontier.xyz/) | [Tokenary](https://tokenary.io/) +| [MemesWallet](https://planetmemes.com/) +| [xPortal](https://xportal.com/) +| [Slingshot](https://slingshot.finance/) +| [ECOIN Wallet](https://play.google.com/store/apps/details?id=org.ecoinwallet&pcampaignid=web_share) # Community @@ -111,13 +123,20 @@ There are a few community-maintained projects that extend Wallet Core to some ad # Contributing -The best way to submit feedback and report bugs is to [open a GitHub issue](https://github.com/trustwallet/wallet-core/issues/new). +The best way to submit feedback and report bugs related to WalletCore is to [open a GitHub issue](https://github.com/trustwallet/wallet-core/issues/new). +If the bug is not related to WalletCore but to the TrustWallet app, please [create a Customer Support ticket](https://support.trustwallet.com/en/support/tickets/new). If you want to contribute code please see [Contributing](https://developer.trustwallet.com/wallet-core/contributing). If you want to add support for a new blockchain also see [Adding Support for a New Blockchain](https://developer.trustwallet.com/wallet-core/newblockchain), make sure you have read the [requirements](https://developer.trustwallet.com/wallet-core/newblockchain#requirements) section. Thanks to all the people who contribute. +# Disclaimer + +The Wallet Core project is led and managed by Trust Wallet with a large contributor community and actively used in several projects. Our goal at Wallet Core is to give other wallets an easy way to add chain support. + +Trust Wallet products leverage wallet core, however, they may or may not leverage all the capabilities, features, and assets available in wallet core due to their own product requirements. + # License -Trust Wallet Core is available under the MIT license. See the [LICENSE](LICENSE) file for more info. +Trust Wallet Core is available under the Apache 2.0 license. See the [LICENSE](LICENSE) file for more info. diff --git a/SECURITY.MD b/SECURITY.MD new file mode 100644 index 00000000000..720baa249ff --- /dev/null +++ b/SECURITY.MD @@ -0,0 +1,29 @@ +# Security Policy + +The security of our users' assets is of the utmost importance to us. We take a number of steps to ensure that our crypto wallet is as secure as possible. + +## Reporting a Security Vulnerability + +If you believe you have found a security vulnerability in our wallet, please contact us immediately at [Bug Bounty Binance](https://bugcrowd.com/binance). We will investigate all reports and do our best to quickly fix any vulnerabilities. + +## Responsible Disclosure + +IMPORTANT: Do not file public issues on GitHub for security vulnerabilities. Do not publicly disclose the vulnerability until we have had a chance to patch it. This gives us time to fix the problem and protect our users’ assets. + +## Encryption + +All private keys are encrypted and stored on the user's device. The encryption uses industry-standard algorithms and is designed to protect against brute-force attacks. + +## Regular Audits + +We regularly conduct security audits of our code to ensure that it is free of vulnerabilities. We also stay up-to-date with the latest security best practices and technologies. + +## Bug Bounty Program + +As a part of Binance security program, TrustWallet also participate in their bug bounty program. For more information on eligible scope, rewards, and how to submit a report, please visit [https://bugcrowd.com/binance](https://bugcrowd.com/binance) + +## Disclaimer + +As with any software, there are always potential security risks. We do our best to minimize these risks and keep our users' assets safe, but we cannot guarantee that our wallet will be completely immune to all security threats. + + diff --git a/android/app/build.gradle b/android/app/build.gradle index f38c9acc235..1e0093c6494 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -2,6 +2,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' android { + namespace 'com.trustwallet.core.app' compileSdkVersion 32 ndkVersion '23.1.7779620' defaultConfig { @@ -27,7 +28,7 @@ android { } dependencies { - implementation project(':trustwalletcore') + implementation project(':wallet-core') implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2-native-mt' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2-native-mt' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" @@ -35,15 +36,10 @@ dependencies { // Tests androidTestImplementation('androidx.test.espresso:espresso-core:3.3.0', { - testImplementation 'junit:junit:4.13.1' + testImplementation 'junit:junit:4.13.1' exclude group: "com.android.support", module: "support-annotations" }) androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.3.0' androidTestImplementation 'androidx.test:runner:1.3.0' androidTestImplementation 'android.arch.core:core-testing:1.1.1' - - implementation 'com.google.protobuf:protobuf-javalite:3.21.2' -} -repositories { - mavenCentral() } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt index 55d6d14dd38..f99db4e987c 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt @@ -34,15 +34,22 @@ class CoinAddressDerivationTests { private fun runDerivationChecks(coin: CoinType, address: String?) = when (coin) { BINANCE -> assertEquals("bnb12vtaxl9952zm6rwf7v8jerq74pvaf77fcmvzhw", address) + TBINANCE -> assertEquals("tbnb12vtaxl9952zm6rwf7v8jerq74pvaf77fkw9xhl", address) BITCOIN -> assertEquals("bc1quvuarfksewfeuevuc6tn0kfyptgjvwsvrprk9d", address) + BITCOINDIAMOND -> assertEquals("1KaRW9xPPtCTZ9FdaTHduCPck4YvSeEWNn", address) BITCOINCASH -> assertEquals("bitcoincash:qpzl3jxkzgvfd9flnd26leud5duv795fnv7vuaha70", address) BITCOINGOLD -> assertEquals("btg1qwz9sed0k4neu6ycrudzkca6cnqe3zweq35hvtg", address) CALLISTO -> assertEquals("0x3E6FFC80745E6669135a76F4A7ce6BCF02436e04", address) DASH -> assertEquals("XqHiz8EXYbTAtBEYs4pWTHh7ipEDQcNQeT", address) DIGIBYTE -> assertEquals("dgb1qtjgmerfqwdffyf8ghcrkgy52cghsqptynmyswu", address) - ETHEREUM, SMARTCHAIN, POLYGON, OPTIMISM, ARBITRUM, ECOCHAIN, AVALANCHECCHAIN, XDAI, + + ETHEREUM, SMARTCHAIN, POLYGON, OPTIMISM, ZKSYNC, ARBITRUM, ARBITRUMNOVA, ECOCHAIN, AVALANCHECCHAIN, XDAI, FANTOM, CELO, CRONOSCHAIN, SMARTBITCOINCASH, KUCOINCOMMUNITYCHAIN, BOBA, METIS, - AURORA, EVMOS, MOONRIVER, MOONBEAM, KAVAEVM, KLAYTN, METER, OKXCHAIN -> assertEquals("0x8f348F300873Fd5DA36950B2aC75a26584584feE", address) + AURORA, EVMOS, MOONRIVER, MOONBEAM, KAVAEVM, KAIA, METER, OKXCHAIN, POLYGONZKEVM, SCROLL, + CONFLUXESPACE, ACALAEVM, OPBNB, NEON, BASE, LINEA, GREENFIELD, MANTLE, ZENEON, MANTAPACIFIC, + ZETAEVM, MERLIN, LIGHTLINK, BLAST, BOUNCEBIT, ZKLINKNOVA, + -> assertEquals("0x8f348F300873Fd5DA36950B2aC75a26584584feE", address) + RONIN -> assertEquals("ronin:8f348F300873Fd5DA36950B2aC75a26584584feE", address) ETHEREUMCLASSIC -> assertEquals("0x078bA3228F3E6C08bEEac9A005de0b7e7089aD1c", address) GOCHAIN -> assertEquals("0x5940ce4A14210d4Ccd0ac206CE92F21828016aC2", address) @@ -53,12 +60,14 @@ class CoinAddressDerivationTests { POANETWORK -> assertEquals("0xe8a3e8bE17E172B6926130eAfB521e9D2849aca9", address) XRP -> assertEquals("rPwE3gChNKtZ1mhH3Ko8YFGqKmGRWLWXV3", address) TEZOS -> assertEquals("tz1acnY9VbMagps26Kj3RfoGRWD9nYG5qaRX", address) - THUNDERTOKEN -> assertEquals("0x4b92b3ED6d8b24575Bf5ce4C6a86ED261DA0C8d7", address) - TOMOCHAIN -> assertEquals("0xC74b6D8897cBa9A4b659d43fEF73C9cA852cE424", address) + THUNDERCORE -> assertEquals("0x4b92b3ED6d8b24575Bf5ce4C6a86ED261DA0C8d7", address) + VICTION -> assertEquals("0xC74b6D8897cBa9A4b659d43fEF73C9cA852cE424", address) TRON -> assertEquals("TQ5NMqJjhpQGK7YJbESKtNCo86PJ89ujio", address) VECHAIN -> assertEquals("0x1a553275dF34195eAf23942CB7328AcF9d48c160", address) WANCHAIN -> assertEquals("0xD5ca90b928279FE5D06144136a25DeD90127aC15", address) + KOMODO -> assertEquals("RCWJLXE5CSXydxdSnwcghzPgkFswERegyb", address) ZCASH -> assertEquals("t1YYnByMzdGhQv3W3rnjHMrJs6HH4Y231gy", address) + ZEN -> assertEquals("znUmzvod1f4P9LYsBhNxjqCDQvNSStAmYEX", address) FIRO -> assertEquals("aEd5XFChyXobvEics2ppAqgK3Bgusjxtik", address) NIMIQ -> assertEquals("NQ76 7AVR EHDA N05U X7SY XB14 XJU7 8ERV GM6H", address) STELLAR -> assertEquals("GA3H6I4C5XUBYGVB66KXR27JV5KS3APSTKRUWOIXZ5MVWZKVTLXWKZ2P", address) @@ -66,16 +75,19 @@ class CoinAddressDerivationTests { NANO -> assertEquals("nano_39gsbcishxn3n7wd17ono4otq5wazwzusqgqigztx73wbrh5jwbdbshfnumc", address) NEBULAS -> assertEquals("n1ZVgEidtdseYv9ogmGz69Cz4mbqmHYSNqJ", address) NEAR -> assertEquals("0c91f6106ff835c0195d5388565a2d69e25038a7e23d26198f85caf6594117ec", address) - THETA -> assertEquals("0x0d1fa20c218Fec2f2C55d52aB267940485fa5DA4", address) + THETA, THETAFUEL -> assertEquals("0x0d1fa20c218Fec2f2C55d52aB267940485fa5DA4", address) COSMOS -> assertEquals("cosmos142j9u5eaduzd7faumygud6ruhdwme98qsy2ekn", address) DECRED -> assertEquals("DsidJiDGceqHTyqiejABy1ZQ3FX4SiWZkYG", address) DOGECOIN -> assertEquals("DJRFZNg8jkUtjcpo2zJd92FUAzwRjitw6f", address) KIN -> assertEquals("GBL3MT2ICHHM5OJ2QJ44CAHGDK6MLPINVXBKOKLHGBWQDVRWTWQ7U2EA", address) VIACOIN -> assertEquals("via1qnmsgjd6cvfprnszdgmyg9kewtjfgqflz67wwhc", address) + VERGE -> assertEquals("DPb3Xz4vjB6QGLKDmrbprrtv4XzNqkADc2", address) QTUM -> assertEquals("QhceuaTdeCZtcxmVc6yyEDEJ7Riu5gWFoF", address) NULS -> assertEquals("NULSd6HgU8MoRnNjBgvJpa9tqvGxYdv5ne4en", address) EOS -> assertEquals("EOS6hs8sRvGSzuQtq223zwJipMzqTJpXUVjyvHPvPwBSZWWrJTJkg", address) + WAX -> assertEquals("EOS6hs8sRvGSzuQtq223zwJipMzqTJpXUVjyvHPvPwBSZWWrJTJkg", address) IOTEX -> assertEquals("io1qw9cccecw09q7p5kzyqtuhfhvah2mhfrc84jfk", address) + IOTEXEVM -> assertEquals("0x038B8C633873Ca0f06961100BE5d37676EADDD23", address) ZILLIQA -> assertEquals("zil1mk6pqphhkmaguhalq6n3cq0h38ltcehg0rfmv6", address) ZELCASH -> assertEquals("t1UKbRPzL4WN8Rs8aZ8RNiWoD2ftCMHKGUf", address) RAVENCOIN -> assertEquals("RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS", address) @@ -87,17 +99,22 @@ class CoinAddressDerivationTests { HARMONY -> assertEquals("one12fk20wmvgypdkn59n4hq8e3aa5899xfx4vsu09", address) SOLANA -> assertEquals("2bUBiBNZyD29gP1oV6de7nxowMLoDBtopMMTGgMvjG5m", address) ALGORAND -> assertEquals("JTJWO524JXIHVPGBDWFLJE7XUIA32ECOZOBLF2QP3V5TQBT3NKZSCG67BQ", address) + ACALA -> assertEquals("25GGezx3LWFQj6HZpYzoWoVzLsHojGtybef3vthC9nd19ms3", address) KUSAMA -> assertEquals("G9xV2EatmrjRC1FLPexc3ddqNRRzCsAdURU8RFiAAJX6ppY", address) POLKADOT -> assertEquals("13nN6BGAoJwd7Nw1XxeBCx5YcBXuYnL94Mh7i3xBprqVSsFk", address) + PIVX -> assertEquals("D81AqC8zKma3Cht4TbVuh4jyVVyLkZULCm", address) KAVA -> assertEquals("kava1drpa0x9ptz0fql3frv562rcrhj2nstuz3pas87", address) CARDANO -> assertEquals("addr1qyr8jjfnypp95eq74aqzn7ss687ehxclgj7mu6gratmg3mul2040vt35dypp042awzsjk5xm3zr3zm5qh7454uwdv08s84ray2", address) NEO -> assertEquals("AT6w7PJvwPcSqHvtbNBY2aHPDv12eW5Uuf", address) FILECOIN -> assertEquals("f1zzykebxldfcakj5wdb5n3n7priul522fnmjzori", address) - ELROND -> assertEquals("erd1jfcy8aeru6vlx4fe6h3pc3vlpe2cnnur5zetxdhp879yagq7vqvs8na4f8", address) + MULTIVERSX -> assertEquals("erd1jfcy8aeru6vlx4fe6h3pc3vlpe2cnnur5zetxdhp879yagq7vqvs8na4f8", address) BANDCHAIN -> assertEquals("band1624hqgend0s3d94z68fyka2y5jak6vd7u0l50r", address) SMARTCHAINLEGACY -> assertEquals("0x49784f90176D8D9d4A3feCDE7C1373dAAb5b13b8", address) OASIS -> assertEquals("oasis1qzcpavvmuw280dk0kd4lxjhtpf0u3ll27yf7sqps", address) THORCHAIN -> assertEquals("thor1c8jd7ad9pcw4k3wkuqlkz4auv95mldr2kyhc65", address) + IOST -> assertEquals("4av8w81EyzUgHonsVWqfs15WM4Vrpgox4BYYQWhNQDVu", address) + SYSCOIN -> assertEquals("sys1qkl640se3mwpt666e3lyywnwh09e9jquvx9x8qj", address) + STRATIS -> assertEquals("strax1q0caanaw4nkf6fzwnzq2p7yum680e57pdg05zkm", address) BLUZELLE -> assertEquals("bluzelle1xccvees6ev4wm2r49rc6ptulsdxa8x8jfpmund", address) CRYPTOORG -> assertEquals("cro16fdf785ejm00jf9a24d23pzqzjh2h05klxjwu8", address) OSMOSIS -> assertEquals("osmo142j9u5eaduzd7faumygud6ruhdwme98qclefqp", address) @@ -105,5 +122,38 @@ class CoinAddressDerivationTests { NATIVEEVMOS -> assertEquals("evmos13u6g7vqgw074mgmf2ze2cadzvkz9snlwstd20d", address) NERVOS -> assertEquals("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdtyq04tvp02wectaumxn0664yw2jd53lqk4mxg3", address) EVERSCALE -> assertEquals("0:0c39661089f86ec5926ea7d4ee4223d634ba4ed6dcc2e80c7b6a8e6d59f79b04", address) + TON -> assertEquals("UQDgEMqToTacHic7SnvnPFmvceG5auFkCcAw0mSCvzvKUaT4", address) + APTOS -> assertEquals("0x7968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", address) + NEBL -> assertEquals("NgDVaXAwNgBwb88xLiFKomfBmPkEh9F2d7", address) + SUI -> assertEquals("0xada112cfb90b44ba889cc5d39ac2bf46281e4a91f7919c693bcd9b8323e81ed2", address) + HEDERA -> assertEquals("0.0.302a300506032b657003210049eba62f64d0d941045595d9433e65d84ecc46bcdb1421de55e05fcf2d8357d5", address) + SECRET -> assertEquals("secret1f69sk5033zcdr2p2yf3xjehn7xvgdeq09d2llh", address) + NATIVEINJECTIVE -> assertEquals("inj13u6g7vqgw074mgmf2ze2cadzvkz9snlwcrtq8a", address) + AGORIC -> assertEquals("agoric18zvvgk6j3eq5wd7mqxccgt20gz2w94cy88aek5", address) + STARGAZE -> assertEquals("stars142j9u5eaduzd7faumygud6ruhdwme98qycayaz", address) + JUNO -> assertEquals("juno142j9u5eaduzd7faumygud6ruhdwme98qxkfz30", address) + STRIDE -> assertEquals("stride142j9u5eaduzd7faumygud6ruhdwme98qn029zl", address) + AXELAR -> assertEquals("axelar142j9u5eaduzd7faumygud6ruhdwme98q52u3aj", address) + CRESCENT -> assertEquals("cre142j9u5eaduzd7faumygud6ruhdwme98q5veur7", address) + KUJIRA -> assertEquals("kujira142j9u5eaduzd7faumygud6ruhdwme98qpvgpme", address) + NATIVECANTO -> assertEquals("canto13u6g7vqgw074mgmf2ze2cadzvkz9snlwqua5pd", address) + COMDEX -> assertEquals("comdex142j9u5eaduzd7faumygud6ruhdwme98qhtgm0y", address) + NEUTRON -> assertEquals("neutron142j9u5eaduzd7faumygud6ruhdwme98q5mrmv5", address) + SOMMELIER -> assertEquals("somm142j9u5eaduzd7faumygud6ruhdwme98quc948e", address) + FETCHAI -> assertEquals("fetch142j9u5eaduzd7faumygud6ruhdwme98qrera5y", address) + MARS -> assertEquals("mars142j9u5eaduzd7faumygud6ruhdwme98qdenqrg", address) + UMEE -> assertEquals("umee142j9u5eaduzd7faumygud6ruhdwme98qzjhxjp", address) + COREUM -> assertEquals("core1rawf376jz2lnchgc4wzf4h9c77neg3zldc7xa8", address) + QUASAR -> assertEquals("quasar142j9u5eaduzd7faumygud6ruhdwme98q78symk", address) + PERSISTENCE -> assertEquals("persistence142j9u5eaduzd7faumygud6ruhdwme98q7gv2ch", address) + AKASH -> assertEquals("akash142j9u5eaduzd7faumygud6ruhdwme98qal870f", address) + NOBLE -> assertEquals("noble142j9u5eaduzd7faumygud6ruhdwme98qc8l3wa", address) + ROOTSTOCK -> assertEquals("0xA2D7065F94F838a3aB9C04D67B312056846424Df", address) + SEI -> assertEquals("sei142j9u5eaduzd7faumygud6ruhdwme98qagm0sj", address) + INTERNETCOMPUTER -> assertEquals("6f8e568160a3c8362789848dc0fa52891964473c045cc25208a305fb35b7c4ab", address) + TIA -> assertEquals("celestia142j9u5eaduzd7faumygud6ruhdwme98qpwmfv7", address) + NATIVEZETACHAIN -> assertEquals("zeta13u6g7vqgw074mgmf2ze2cadzvkz9snlwywj304", address) + DYDX -> assertEquals("dydx142j9u5eaduzd7faumygud6ruhdwme98qeayaky", address) + PACTUS -> assertEquals("pc1r7ys2g5a4xc2qtm0t4q987m4mvs57w5g0v4pvzg", address) } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/TestCoinType.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/TestCoinType.kt index f8fc2f3a5bf..abbc87b7c2f 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/TestCoinType.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/TestCoinType.kt @@ -1,13 +1,15 @@ package com.trustwallet.core.app.blockchains +import com.trustwallet.core.app.utils.toHexByteArray import wallet.core.jni.CoinType import wallet.core.jni.Curve +import wallet.core.jni.PublicKey import wallet.core.jni.Purpose import wallet.core.jni.Derivation import org.junit.Assert.assertEquals import org.junit.Test - +import wallet.core.jni.PublicKeyType class TestCoinType { @@ -21,7 +23,7 @@ class TestCoinType { assertEquals(CoinType.LITECOIN.value(), 2) assertEquals(CoinType.TRON.value(), 195) assertEquals(CoinType.ETHEREUM.value(), 60) - assertEquals(CoinType.THUNDERTOKEN.value(), 1001) + assertEquals(CoinType.THUNDERCORE.value(), 1001) assertEquals(CoinType.WANCHAIN.value(), 5718350) assertEquals(CoinType.CALLISTO.value(), 820) assertEquals(CoinType.ETHEREUMCLASSIC.value(), 61) @@ -30,7 +32,7 @@ class TestCoinType { assertEquals(CoinType.POANETWORK.value(), 178) assertEquals(CoinType.VECHAIN.value(), 818) assertEquals(CoinType.ICON.value(), 74) - assertEquals(CoinType.TOMOCHAIN.value(), 889) + assertEquals(CoinType.VICTION.value(), 889) assertEquals(CoinType.TEZOS.value(), 1729) assertEquals(CoinType.QTUM.value(), 2301) assertEquals(CoinType.NEBULAS.value(), 2718) @@ -52,7 +54,17 @@ class TestCoinType { assertEquals(res, "m/84'/0'/0'/0/0") res = CoinType.createFromValue(CoinType.BITCOIN.value()).derivationPathWithDerivation(Derivation.BITCOINLEGACY).toString() assertEquals(res, "m/44'/0'/0'/0/0") + res = CoinType.createFromValue(CoinType.BITCOIN.value()).derivationPathWithDerivation(Derivation.BITCOINTAPROOT).toString() + assertEquals(res, "m/86'/0'/0'/0/0") res = CoinType.createFromValue(CoinType.SOLANA.value()).derivationPathWithDerivation(Derivation.SOLANASOLANA).toString() assertEquals(res, "m/44'/501'/0'/0'") } + + @Test + fun testDeriveAddressFromPublicKeyAndDerivation() { + val publicKey = PublicKey("0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798".toHexByteArray(), PublicKeyType.SECP256K1) + + val address = CoinType.BITCOIN.deriveAddressFromPublicKeyAndDerivation(publicKey, Derivation.BITCOINSEGWIT) + assertEquals(address, "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4") + } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/acala/TestAcalaAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/acala/TestAcalaAddress.kt new file mode 100644 index 00000000000..5e50f515ab4 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/acala/TestAcalaAddress.kt @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.acala + +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestAcalaAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val key = PrivateKey("0x9066aa168c379a403becb235c15e7129c133c244e56a757ab07bc369288bcab0".toHexByteArray()) + val pubkey = key.publicKeyEd25519 + val address = AnyAddress(pubkey, CoinType.ACALA) + assertEquals(address.description(), "269ZCS3WLGydTN8ynhyhZfzJrXkePUcdhwgLQs6TWFs5wVL5") + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/acala/TestAcalaSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/acala/TestAcalaSigner.kt new file mode 100644 index 00000000000..ad99985b4ec --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/acala/TestAcalaSigner.kt @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.acala + +import com.trustwallet.core.app.utils.Numeric +import com.trustwallet.core.app.utils.toHexBytesInByteString +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.CoinType +import wallet.core.jni.proto.Polkadot + +class TestAcalaSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun AcalaTransactionSigning() { + val transferCallIndices = Polkadot.CallIndices.newBuilder().apply { + custom = Polkadot.CustomCallIndices.newBuilder().apply { + moduleIndex = 0x0a + methodIndex = 0x00 + }.build() + } + + val call = Polkadot.Balance.Transfer.newBuilder().apply { + value = "0xe8d4a51000".toHexBytesInByteString() // 1 ACA + toAddress = "25Qqz3ARAvnZbahGZUzV3xpP1bB3eRrupEprK7f2FNbHbvsz" + callIndices = transferCallIndices.build() + } + + val acalaGenesisHashStr = "0xfc41b9bd8ef8fe53d58c7ea67c794c7ec9a73daf05e6d54b14ff6342c99ba64c".toHexBytesInByteString() + + val input = Polkadot.SigningInput.newBuilder().apply { + genesisHash = acalaGenesisHashStr + blockHash = "0x707ffa05b7dc6cdb6356bd8bd51ff20b2757c3214a76277516080a10f1bc7537".toHexBytesInByteString() + nonce = 0 + specVersion = 2170 + network = CoinType.ACALA.ss58Prefix() + transactionVersion = 2 + privateKey = "9066aa168c379a403becb235c15e7129c133c244e56a757ab07bc369288bcab0".toHexBytesInByteString() + era = Polkadot.Era.newBuilder().apply { + blockNumber = 3893613 + period = 64 + }.build() + balanceCall = Polkadot.Balance.newBuilder().apply { + transfer = call.build() + }.build() + multiAddress = true + } + + val output = AnySigner.sign(input.build(), CoinType.ACALA, Polkadot.SigningOutput.parser()) + val encoded = Numeric.toHexString(output.encoded.toByteArray()) + + // https://acala.subscan.io/extrinsic/3893620-3 + val expected = "0x41028400e9590e4d99264a14a85e21e69537e4a64f66a875d38cb8f76b305f41fabe24a900dd54466dffd1e3c80b76013e9459fbdcd17805bd5fdbca0961a643bad1cbd2b7fe005c62c51c18b67f31eb9e61b187a911952fee172ef18402d07c703eec3100d50200000a0000c8c602ded977c56076ae38d98026fa669ca10d6a2b5a0bfc4086ae7668ed1c60070010a5d4e8" + assertEquals(encoded, expected) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/acalaevm/TestAcalaEVMAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/acalaevm/TestAcalaEVMAddress.kt new file mode 100644 index 00000000000..6845bea3e89 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/acalaevm/TestAcalaEVMAddress.kt @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.acalaevm + +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestAcalaEVMAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val key = PrivateKey("828c4c48c2cef521f0251920891ed79e871faa24f64f43cde83d07bc99f8dbf0".toHexByteArray()) + val pubkey = key.getPublicKeySecp256k1(false) + val address = AnyAddress(pubkey, CoinType.ACALAEVM) + val expected = AnyAddress("0xe32DC46bfBF78D1eada7b0a68C96903e01418D64", CoinType.ACALAEVM) + + assertEquals(address.description(), expected.description()) + } +} \ No newline at end of file diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/agoric/TestAgoricAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/agoric/TestAgoricAddress.kt new file mode 100644 index 00000000000..1164db16e14 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/agoric/TestAgoricAddress.kt @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.agoric + +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestAgoricAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + + val key = PrivateKey("037048190544fa57651452f477c096de4f3073e7835cf3845b04602563a73f73".toHexByteArray()) + val pubkey = key.getPublicKeySecp256k1(true) + val address = AnyAddress(pubkey, CoinType.AGORIC) + val expected = AnyAddress("agoric18zvvgk6j3eq5wd7mqxccgt20gz2w94cy88aek5", CoinType.AGORIC) + + assertEquals(pubkey.data().toHex(), "0x03df9a5e4089f89d45913fb2b856de984c7e8bf1344cc6444cc9705899a48c939d") + assertEquals(address.description(), expected.description()) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/agoric/TestAgoricSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/agoric/TestAgoricSigner.kt new file mode 100644 index 00000000000..ecdf4372f3a --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/agoric/TestAgoricSigner.kt @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.agoric + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.AnyAddress +import wallet.core.jni.CoinType +import wallet.core.jni.PrivateKey +import wallet.core.jni.proto.Cosmos + +class TestAgoricSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun AgoricTransactionSigning() { + val key = PrivateKey("037048190544fa57651452f477c096de4f3073e7835cf3845b04602563a73f73".toHexByteArray()) + val publicKey = key.getPublicKeySecp256k1(true) + val from = AnyAddress(publicKey, CoinType.AGORIC).description() + + val transferAmount = Cosmos.Amount.newBuilder().apply { + amount = "1" + denom = "ubld" + }.build() + + val message = Cosmos.Message.newBuilder().apply { + sendCoinsMessage = Cosmos.Message.Send.newBuilder().apply { + fromAddress = from + toAddress = "agoric1cqvwa8jr6pmt45jndanc8lqmdsxjkhw0yertc0" + addAllAmounts(listOf(transferAmount)) + }.build() + }.build() + + val feeAmount = Cosmos.Amount.newBuilder().apply { + amount = "2000" + denom = "ubld" + }.build() + + val cosmosFee = Cosmos.Fee.newBuilder().apply { + gas = 100000 + addAllAmounts(listOf(feeAmount)) + }.build() + + val signingInput = Cosmos.SigningInput.newBuilder().apply { + signingMode = Cosmos.SigningMode.Protobuf + accountNumber = 62972 + chainId = "agoric-3" + sequence = 1 + fee = cosmosFee + privateKey = ByteString.copyFrom(key.data()) + addAllMessages(listOf(message)) + }.build() + + val output = AnySigner.sign(signingInput, CoinType.AGORIC, Cosmos.SigningOutput.parser()) + + assertEquals(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CowBCokBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmkKLWFnb3JpYzE4enZ2Z2s2ajNlcTV3ZDdtcXhjY2d0MjBnejJ3OTRjeTg4YWVrNRItYWdvcmljMWNxdndhOGpyNnBtdDQ1am5kYW5jOGxxbWRzeGpraHcweWVydGMwGgkKBHVibGQSATESZgpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA9+aXkCJ+J1FkT+yuFbemEx+i/E0TMZETMlwWJmkjJOdEgQKAggBGAESEgoMCgR1YmxkEgQyMDAwEKCNBhpAenbGO4UBK610dwSY6l5pl58qwHW1OujQ/9vF9unQdrA1SE0b/2mZxnevy5y3u6pJfBffWUfCx68PcVEu7D3EYQ==\"}") + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/algorand/TestAlgorandSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/algorand/TestAlgorandSigner.kt index 5047a62880e..e466740212b 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/algorand/TestAlgorandSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/algorand/TestAlgorandSigner.kt @@ -7,6 +7,7 @@ import com.trustwallet.core.app.utils.toHexBytesInByteString import org.junit.Assert.* import org.junit.Test import wallet.core.java.AnySigner +import wallet.core.jni.Base64 import wallet.core.jni.CoinType.ALGORAND import wallet.core.jni.proto.Algorand import wallet.core.jni.proto.Algorand.SigningOutput @@ -17,6 +18,33 @@ class TestAlgorandSigner { System.loadLibrary("TrustWalletCore") } + @Test + fun algorandTransactionSigningNFTTransfer() { + // Successfully broadcasted: https://algoexplorer.io/tx/FFLUH4QKZHG744RIQ2AZNWZUSIIH262KZ4MEWSY4RXMWN5NMOOJA + val transaction = Algorand.AssetTransfer.newBuilder() + .setToAddress("362T7CSXNLIOBX6J3H2SCPS4LPYFNV6DDWE6G64ZEUJ6SY5OJIR6SB5CVE") + .setAmount(1) + .setAssetId(989643841) + .build() + val signingInput = Algorand.SigningInput.newBuilder() + .setGenesisId("mainnet-v1.0") + .setGenesisHash(ByteString.copyFrom(Base64.decode("wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8="))) + .setNote(ByteString.copyFrom(Base64.decode("VFdUIFRPIFRIRSBNT09O"))) + .setPrivateKey("dc6051ffc7b3ec601bde432f6dea34d40fe3855e4181afa0f0524c42194a6da7".toHexBytesInByteString()) + .setFirstRound(27963950) + .setLastRound(27964950) + .setFee(1000) + .setAssetTransfer(transaction) + .build() + + val output = AnySigner.sign(signingInput, ALGORAND, SigningOutput.parser()) + + assertEquals( + output.signature, + "nXQsDH1ilG3DIo2VQm5tdYKXe9o599ygdqikmROpZiNXAvQeK3avJqgjM5o+iByCdq6uOxlbveDyVmL9nZxxBg==" + ) + } + @Test fun AlgorandTransactionSigning() { val transaction = Algorand.Transfer.newBuilder() diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/aptos/TestAptosAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/aptos/TestAptosAddress.kt new file mode 100644 index 00000000000..c8bed69c5d8 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/aptos/TestAptosAddress.kt @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.aptos + +import org.junit.Assert.assertFalse +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestAptosAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val any = AnyAddress("0x6af7d07b8a541913dfa87a9f99628faa255c70241ef9ebd9b82a7e715ee13108", CoinType.APTOS) + assertEquals(any.coin(), CoinType.APTOS) + assertEquals(any.description(), "0x6af7d07b8a541913dfa87a9f99628faa255c70241ef9ebd9b82a7e715ee13108") + + assertFalse(AnyAddress.isValid("0xMQqpqMQgCBuiPkoXfgZZsJvuzCeI1zc00z6vHJj4", CoinType.APTOS)) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/aptos/TestAptosSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/aptos/TestAptosSigner.kt new file mode 100644 index 00000000000..e536821658b --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/aptos/TestAptosSigner.kt @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.aptos + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.Numeric +import com.trustwallet.core.app.utils.toHexByteArray +import com.trustwallet.core.app.utils.toHexBytes +import com.trustwallet.core.app.utils.toHexBytesInByteString +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.CoinType +import wallet.core.jni.proto.Aptos + +class TestAptosSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun AptosTransactionBlindSigning() { + // Successfully broadcasted: https://explorer.aptoslabs.com/txn/0x7efd69e7f9462774b932ce500ab51c0d0dcc004cf272e09f8ffd5804c2a84e33?network=mainnet + val key = + "5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec".toHexBytesInByteString() + + val payloadJson = """ + { + "function": "0x16fe2df00ea7dde4a63409201f7f4e536bde7bb7335526a35d05111e68aa322c::AnimeSwapPoolV1::swap_exact_coins_for_coins_3_pair_entry", + "type_arguments": [ + "0x1::aptos_coin::AptosCoin", + "0x881ac202b1f1e6ad4efcff7a1d0579411533f2502417a19211cfc49751ddb5f4::coin::MOJO", + "0xf22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa::asset::USDT", + "0xf22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa::asset::USDC" + ], + "arguments": [ + "1000000", + "49329" + ], + "type": "entry_function_payload" + } + """.trimIndent() + val signingInput = Aptos.SigningInput.newBuilder() + .setChainId(1) + .setExpirationTimestampSecs(3664390082) + .setGasUnitPrice(100) + .setMaxGasAmount(100011) + .setSender("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30") + .setSequenceNumber(42) + .setAnyEncoded(payloadJson) + .setPrivateKey(key) + .build() + + val result = AnySigner.sign(signingInput, CoinType.APTOS, Aptos.SigningOutput.parser()) + assertEquals( + Numeric.cleanHexPrefix(Numeric.toHexString(result.rawTxn.toByteArray())), + "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f302a000000000000000216fe2df00ea7dde4a63409201f7f4e536bde7bb7335526a35d05111e68aa322c0f416e696d6553776170506f6f6c563127737761705f65786163745f636f696e735f666f725f636f696e735f335f706169725f656e747279040700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e0007881ac202b1f1e6ad4efcff7a1d0579411533f2502417a19211cfc49751ddb5f404636f696e044d4f4a4f0007f22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa05617373657404555344540007f22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa056173736574045553444300020840420f000000000008b1c0000000000000ab860100000000006400000000000000c2276ada0000000001" + ) + assertEquals( + Numeric.cleanHexPrefix(Numeric.toHexString(result.authenticator.signature.toByteArray())), + "42cd67406e85afd1e948e7ad7f5f484fb4c60d82b267c6b6b28a92301e228b983206d2b87cd5487cf9acfb0effbd183ab90123570eb2e047cb152d337152210b" + ) + assertEquals( + Numeric.cleanHexPrefix(Numeric.toHexString(result.encoded.toByteArray())), + "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f302a000000000000000216fe2df00ea7dde4a63409201f7f4e536bde7bb7335526a35d05111e68aa322c0f416e696d6553776170506f6f6c563127737761705f65786163745f636f696e735f666f725f636f696e735f335f706169725f656e747279040700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e0007881ac202b1f1e6ad4efcff7a1d0579411533f2502417a19211cfc49751ddb5f404636f696e044d4f4a4f0007f22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa05617373657404555344540007f22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa056173736574045553444300020840420f000000000008b1c0000000000000ab860100000000006400000000000000c2276ada00000000010020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c4042cd67406e85afd1e948e7ad7f5f484fb4c60d82b267c6b6b28a92301e228b983206d2b87cd5487cf9acfb0effbd183ab90123570eb2e047cb152d337152210b" + ) + } + + @Test + fun AptosTransactionSigning() { + // Successfully broadcasted https://explorer.aptoslabs.com/txn/0xb4d62afd3862116e060dd6ad9848ccb50c2bc177799819f1d29c059ae2042467?network=devnet + val key = + "5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec".toHexBytesInByteString() + + val transfer = Aptos.TransferMessage.newBuilder().setAmount(1000) + .setTo("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30").build() + val signingInput = Aptos.SigningInput.newBuilder().setChainId(33) + .setSender("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30") + .setSequenceNumber(99) + .setGasUnitPrice(100) + .setMaxGasAmount(3296766) + .setExpirationTimestampSecs(3664390082) + .setTransfer(transfer) + .setPrivateKey(key) + .build() + + val result = AnySigner.sign(signingInput, CoinType.APTOS, Aptos.SigningOutput.parser()) + assertEquals( + Numeric.cleanHexPrefix(Numeric.toHexString(result.rawTxn.toByteArray())), + "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3063000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e74087472616e7366657200022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada0000000021" + ) + assertEquals( + Numeric.cleanHexPrefix(Numeric.toHexString(result.authenticator.signature.toByteArray())), + "5707246db31e2335edc4316a7a656a11691d1d1647f6e864d1ab12f43428aaaf806cf02120d0b608cdd89c5c904af7b137432aacdd60cc53f9fad7bd33578e01" + ) + assertEquals( + Numeric.cleanHexPrefix(Numeric.toHexString(result.encoded.toByteArray())), + "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3063000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e74087472616e7366657200022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada00000000210020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c405707246db31e2335edc4316a7a656a11691d1d1647f6e864d1ab12f43428aaaf806cf02120d0b608cdd89c5c904af7b137432aacdd60cc53f9fad7bd33578e01" + ) + } + + @Test + fun AptosTransferTokensCoins() { + // Successfully broadcasted https://explorer.aptoslabs.com/txn/0x197d40ea12e2bfc65a0a913b9f4ca3b0b0208fe0c1514d3d55cef3d5bcf25211?network=mainnet + val key = + "e7f56c77189e03699a75d8ec5c090e41f3d9d4783bc49c33df8a93d915e10de8".toHexBytesInByteString() + + val function = Aptos.StructTag.newBuilder() + .setAccountAddress("0xe9c192ff55cffab3963c695cff6dbf9dad6aff2bb5ac19a6415cad26a81860d9") + .setModule("mee_coin") + .setName("MeeCoin") + .build() + + val transfer = Aptos.TokenTransferCoinsMessage.newBuilder() + .setAmount(10000) + .setTo("0xb7c7d12080209e9dc14498c80200706e760363fb31782247e82cf57d1d6e5d6c") + .setFunction(function) + .build() + val signingInput = Aptos.SigningInput.newBuilder() + .setChainId(1) + .setSender("0x1869b853768f0ba935d67f837a66b172dd39a60ca2315f8d4e0e669bbd35cf25") + .setSequenceNumber(2) + .setGasUnitPrice(100) + .setMaxGasAmount(2000) + .setExpirationTimestampSecs(3664390082) + .setTokenTransferCoins(transfer) + .setPrivateKey(key) + .build() + + val result = AnySigner.sign(signingInput, CoinType.APTOS, Aptos.SigningOutput.parser()) + assertEquals( + Numeric.cleanHexPrefix(Numeric.toHexString(result.rawTxn.toByteArray())), + "1869b853768f0ba935d67f837a66b172dd39a60ca2315f8d4e0e669bbd35cf2502000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e740e7472616e736665725f636f696e730107e9c192ff55cffab3963c695cff6dbf9dad6aff2bb5ac19a6415cad26a81860d9086d65655f636f696e074d6565436f696e000220b7c7d12080209e9dc14498c80200706e760363fb31782247e82cf57d1d6e5d6c081027000000000000d0070000000000006400000000000000c2276ada0000000001" + ) + assertEquals( + Numeric.cleanHexPrefix(Numeric.toHexString(result.authenticator.signature.toByteArray())), + "30ebd7e95cb464677f411868e2cbfcb22bc01cc63cded36c459dff45e6d2f1354ae4e090e7dfbb509851c0368b343e0e5ecaf6b08e7c1b94c186530b0f7dee0d" + ) + assertEquals( + Numeric.cleanHexPrefix(Numeric.toHexString(result.encoded.toByteArray())), + "1869b853768f0ba935d67f837a66b172dd39a60ca2315f8d4e0e669bbd35cf2502000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e740e7472616e736665725f636f696e730107e9c192ff55cffab3963c695cff6dbf9dad6aff2bb5ac19a6415cad26a81860d9086d65655f636f696e074d6565436f696e000220b7c7d12080209e9dc14498c80200706e760363fb31782247e82cf57d1d6e5d6c081027000000000000d0070000000000006400000000000000c2276ada0000000001002062e7a6a486553b56a53e89dfae3f780693e537e5b0a7ed33290780e581ca83694030ebd7e95cb464677f411868e2cbfcb22bc01cc63cded36c459dff45e6d2f1354ae4e090e7dfbb509851c0368b343e0e5ecaf6b08e7c1b94c186530b0f7dee0d" + ) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bandchain/TestBandChainAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bandchain/TestBandChainAddress.kt index d988eed5bb1..ec361735357 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bandchain/TestBandChainAddress.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bandchain/TestBandChainAddress.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.bandchain diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bandchain/TestBandChainSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bandchain/TestBandChainSigner.kt index 662773bba9c..001e9d90631 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bandchain/TestBandChainSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bandchain/TestBandChainSigner.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.bandchain diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/binance/TestBinanceAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/binance/TestBinanceAddress.kt index 13b91a5e527..f2c62428f64 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/binance/TestBinanceAddress.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/binance/TestBinanceAddress.kt @@ -2,6 +2,8 @@ package com.trustwallet.core.app.blockchains.binance import com.trustwallet.core.app.utils.toHexBytes import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue import org.junit.Test import wallet.core.jni.* import com.trustwallet.core.app.utils.toHex @@ -22,6 +24,23 @@ class TestBinanceAddress { assertEquals("bnb1grpf0955h0ykzq3ar5nmum7y6gdfl6lxfn46h2", address.description()) } + @Test + fun testIsValid() { + assertTrue(AnyAddress.isValid("bnb12vtaxl9952zm6rwf7v8jerq74pvaf77fcmvzhw", CoinType.BINANCE)); + + assertFalse(AnyAddress.isValid("bad1devga6q804tx9fqrnx0vtu5r36kxgp9tqx8h9k", CoinType.BINANCE)); + assertFalse(AnyAddress.isValid("tbnb1devga6q804tx9fqrnx0vtu5r36kxgp9t4ruzk2", CoinType.BINANCE)); + } + + @Test + fun testIsValidBech32() { + assertTrue(AnyAddress.isValidBech32("bnb12vtaxl9952zm6rwf7v8jerq74pvaf77fcmvzhw", CoinType.BINANCE, "bnb")); + assertTrue(AnyAddress.isValidBech32("tbnb1devga6q804tx9fqrnx0vtu5r36kxgp9t4ruzk2", CoinType.BINANCE, "tbnb")); + + assertFalse(AnyAddress.isValidBech32("bnb12vtaxl9952zm6rwf7v8jerq74pvaf77fcmvzhw", CoinType.BINANCE, "tbnb")); + assertFalse(AnyAddress.isValidBech32("tbnb1devga6q804tx9fqrnx0vtu5r36kxgp9t4ruzk2", CoinType.BINANCE, "bnb")); + } + @Test fun testBinanceMainnet() { val wallet = HDWallet("rabbit tilt arm protect banner ill produce vendor april bike much identify pond upset front easily glass gallery address hair priority focus forest angle", "") @@ -31,4 +50,15 @@ class TestBinanceAddress { assertEquals("0x727f677b390c151caf9c206fd77f77918f56904b5504243db9b21e51182c4c06", key.data().toHex()) assertEquals("bnb1devga6q804tx9fqrnx0vtu5r36kxgp9tmk4xkm", address) } + + @Test + fun testBinanceTestnet() { + val wallet = HDWallet("rabbit tilt arm protect banner ill produce vendor april bike much identify pond upset front easily glass gallery address hair priority focus forest angle", "") + val privateKey = wallet.getKeyForCoin(CoinType.BINANCE) + val publicKey = privateKey.getPublicKeySecp256k1(true) + val address = AnyAddress(publicKey, CoinType.BINANCE, "tbnb") + + assertEquals("0x727f677b390c151caf9c206fd77f77918f56904b5504243db9b21e51182c4c06", privateKey.data().toHex()) + assertEquals("tbnb1devga6q804tx9fqrnx0vtu5r36kxgp9t4ruzk2", address.description()) + } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/binance/TestBinanceWalletConnectSigning.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/binance/TestBinanceWalletConnectSigning.kt new file mode 100644 index 00000000000..a66c2dc9776 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/binance/TestBinanceWalletConnectSigning.kt @@ -0,0 +1,46 @@ +package com.trustwallet.core.app.blockchains.binance + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.toHexBytes +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.proto.Binance.SigningOutput +import wallet.core.jni.proto.WalletConnect +import wallet.core.jni.* +import wallet.core.jni.CoinType.BINANCE +import wallet.core.java.AnySigner +import wallet.core.jni.proto.Common + +class TestBinanceWalletConnectSigning { + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testSignBinanceTransactionFromWalletConnectRequest() { + // Step 1: Parse a signing request received through WalletConnect. + + val parsingInput = WalletConnect.ParseRequestInput.newBuilder().apply { + method = WalletConnect.Method.CosmosSignAmino + payload = "{\"signerAddress\":\"bnb1grpf0955h0ykzq3ar5nmum7y6gdfl6lxfn46h2\",\"signDoc\":{\"account_number\":\"19\",\"chain_id\":\"chain-bnb\",\"memo\":\"\",\"data\":null,\"msgs\":[{\"inputs\":[{\"address\":\"bnb1grpf0955h0ykzq3ar5nmum7y6gdfl6lxfn46h2\",\"coins\":[{\"amount\":1001000000,\"denom\":\"BNB\"}]}],\"outputs\":[{\"address\":\"bnb13zeh6hs97d5eu2s5qerguhv8ewwue6u4ywa6yf\",\"coins\":[{\"amount\":1001000000,\"denom\":\"BNB\"}]}]}],\"sequence\":\"23\",\"source\":\"1\"}}" + }.build() + + val parsingOutputBytes = WalletConnectRequest.parse(BINANCE, parsingInput.toByteArray()) + val parsingOutput = WalletConnect.ParseRequestOutput.parseFrom(parsingOutputBytes) + + assertEquals(parsingOutput.error, Common.SigningError.OK) + + // Step 2: Set missing fields. + + val signingInput = parsingOutput.binance.toBuilder().apply { + privateKey = ByteString.copyFrom("95949f757db1f57ca94a5dff23314accbe7abee89597bf6a3c7382c84d7eb832".toHexBytes()) + }.build() + + // Step 3: Sign the transaction. + + val output = AnySigner.sign(signingInput, BINANCE, SigningOutput.parser()) + + assertEquals(output.error, Common.SigningError.OK) + assertEquals(output.signatureJson, "{\"pub_key\":{\"type\":\"tendermint/PubKeySecp256k1\",\"value\":\"Amo1kgCI2Yw4iMpoxT38k/RWRgJgbLuH8P5e5TPbOOUC\"},\"signature\":\"PCTHhMa7+Z1U/6uxU+3LbTxKd0k231xypdMolyVvjgYvMg+0dTMC+wqW8IxHWXTSDt/Ronu+7ac1h/WN3JWJdQ==\"}") + } +} \ No newline at end of file diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bitcoin/TestBitcoinPsbt.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bitcoin/TestBitcoinPsbt.kt new file mode 100644 index 00000000000..884120800ca --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bitcoin/TestBitcoinPsbt.kt @@ -0,0 +1,108 @@ +package com.trustwallet.core.app.blockchains.bitcoin + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.Numeric +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexBytes +import com.trustwallet.core.app.utils.toHexBytesInByteString +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.BitcoinScript +import wallet.core.jni.BitcoinSigHashType +import wallet.core.jni.CoinType +import wallet.core.jni.CoinType.BITCOIN +import wallet.core.jni.Hash +import wallet.core.jni.PrivateKey +import wallet.core.jni.PublicKey +import wallet.core.jni.PublicKeyType +import wallet.core.jni.proto.Bitcoin +import wallet.core.jni.proto.BitcoinV2 +import wallet.core.jni.proto.Common.SigningError + +class TestBitcoinPsbt { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testSignThorSwap() { + // Successfully broadcasted tx: https://mempool.space/tx/634a416e82ac710166725f6a4090ac7b5db69687e86b2d2e38dcb3d91c956c32 + + val privateKey = "f00ffbe44c5c2838c13d2778854ac66b75e04eb6054f0241989e223223ad5e55".toHexBytesInByteString() + val psbt = "70736274ff0100bc0200000001147010db5fbcf619067c1090fec65c131443fbc80fb4aaeebe940e44206098c60000000000ffffffff0360ea000000000000160014f22a703617035ef7f490743d50f26ae08c30d0a70000000000000000426a403d3a474149412e41544f4d3a636f736d6f7331737377797a666d743675396a373437773537753438746778646575393573757a666c6d7175753a303a743a35303e12000000000000160014b139199ec796f36fc42e637f42da8e3e6720aa9d000000000001011f6603010000000000160014b139199ec796f36fc42e637f42da8e3e6720aa9d00000000".toHexBytesInByteString() + + val input = BitcoinV2.SigningInput.newBuilder() + .setPsbt(BitcoinV2.Psbt.newBuilder().setPsbt(psbt)) + .addPrivateKeys(privateKey) + .build() + + val legacyInput = Bitcoin.SigningInput.newBuilder() + .setSigningV2(input) + .build() + + val legacyOutput = AnySigner.sign(legacyInput, BITCOIN, Bitcoin.SigningOutput.parser()) + val output = legacyOutput.signingResultV2 + + assertEquals(output.error, SigningError.OK) + assertEquals( + output.psbt.psbt.toByteArray().toHex(), + "0x70736274ff0100bc0200000001147010db5fbcf619067c1090fec65c131443fbc80fb4aaeebe940e44206098c60000000000ffffffff0360ea000000000000160014f22a703617035ef7f490743d50f26ae08c30d0a70000000000000000426a403d3a474149412e41544f4d3a636f736d6f7331737377797a666d743675396a373437773537753438746778646575393573757a666c6d7175753a303a743a35303e12000000000000160014b139199ec796f36fc42e637f42da8e3e6720aa9d000000000001011f6603010000000000160014b139199ec796f36fc42e637f42da8e3e6720aa9d01086c02483045022100b1229a008f20691639767bf925d6b8956ea957ccc633ad6b5de3618733a55e6b02205774d3320489b8a57a6f8de07f561de3e660ff8e587f6ac5422c49020cd4dc9101210306d8c664ea8fd2683eebea1d3114d90e0a5429e5783ba49b80ddabce04ff28f300000000" + ) + assertEquals( + output.encoded.toByteArray().toHex(), + "0x02000000000101147010db5fbcf619067c1090fec65c131443fbc80fb4aaeebe940e44206098c60000000000ffffffff0360ea000000000000160014f22a703617035ef7f490743d50f26ae08c30d0a70000000000000000426a403d3a474149412e41544f4d3a636f736d6f7331737377797a666d743675396a373437773537753438746778646575393573757a666c6d7175753a303a743a35303e12000000000000160014b139199ec796f36fc42e637f42da8e3e6720aa9d02483045022100b1229a008f20691639767bf925d6b8956ea957ccc633ad6b5de3618733a55e6b02205774d3320489b8a57a6f8de07f561de3e660ff8e587f6ac5422c49020cd4dc9101210306d8c664ea8fd2683eebea1d3114d90e0a5429e5783ba49b80ddabce04ff28f300000000" + ) + assertEquals( + output.txid.toByteArray().toHex(), + "0x634a416e82ac710166725f6a4090ac7b5db69687e86b2d2e38dcb3d91c956c32" + ) + } + + @Test + fun testPlanThorSwap() { + // Successfully broadcasted tx: https://mempool.space/tx/634a416e82ac710166725f6a4090ac7b5db69687e86b2d2e38dcb3d91c956c32 + + val privateKey = PrivateKey("f00ffbe44c5c2838c13d2778854ac66b75e04eb6054f0241989e223223ad5e55".toHexBytes()) + val publicKey = privateKey.getPublicKeySecp256k1(true) + val psbt = "70736274ff0100bc0200000001147010db5fbcf619067c1090fec65c131443fbc80fb4aaeebe940e44206098c60000000000ffffffff0360ea000000000000160014f22a703617035ef7f490743d50f26ae08c30d0a70000000000000000426a403d3a474149412e41544f4d3a636f736d6f7331737377797a666d743675396a373437773537753438746778646575393573757a666c6d7175753a303a743a35303e12000000000000160014b139199ec796f36fc42e637f42da8e3e6720aa9d000000000001011f6603010000000000160014b139199ec796f36fc42e637f42da8e3e6720aa9d00000000".toHexBytesInByteString() + + val input = BitcoinV2.SigningInput.newBuilder() + .setPsbt(BitcoinV2.Psbt.newBuilder().setPsbt(psbt)) + .addPublicKeys(ByteString.copyFrom(publicKey.data())) + .build() + + val legacyInput = Bitcoin.SigningInput.newBuilder() + .setSigningV2(input) + .build() + + val legacyPlan = AnySigner.plan(legacyInput, BITCOIN, Bitcoin.TransactionPlan.parser()) + val plan = legacyPlan.planningResultV2 + + assertEquals(plan.error, SigningError.OK) + + assertEquals(plan.getInputs(0).receiverAddress, "bc1qkyu3n8k8jmekl3pwvdl59k5w8enjp25akz2r3z") + assertEquals(plan.getInputs(0).value, 66_406) + + // Vault transfer + assertEquals(plan.getOutputs(0).toAddress, "bc1q7g48qdshqd000aysws74pun2uzxrp598gcfum0") + assertEquals(plan.getOutputs(0).value, 60_000) + + // OP_RETURN + assertEquals( + plan.getOutputs(1).customScriptPubkey.toByteArray().toHex(), + "0x6a403d3a474149412e41544f4d3a636f736d6f7331737377797a666d743675396a373437773537753438746778646575393573757a666c6d7175753a303a743a3530" + ) + assertEquals(plan.getOutputs(1).value, 0) + + // Change output + assertEquals(plan.getOutputs(2).toAddress, "bc1qkyu3n8k8jmekl3pwvdl59k5w8enjp25akz2r3z") + assertEquals(plan.getOutputs(2).value, 4_670) + + assertEquals(plan.feeEstimate, 1736) + // Please note that `change` in PSBT planning is always 0. + // That's because we aren't able to determine which output is an actual change from PSBT. + assertEquals(plan.change, 0) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bitcoin/TestBitcoinSigning.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bitcoin/TestBitcoinSigning.kt index 45d627d8b46..abd187f8150 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bitcoin/TestBitcoinSigning.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bitcoin/TestBitcoinSigning.kt @@ -10,8 +10,13 @@ import wallet.core.jni.BitcoinScript import wallet.core.jni.BitcoinSigHashType import wallet.core.jni.CoinType import wallet.core.jni.CoinType.BITCOIN +import wallet.core.jni.Hash +import wallet.core.jni.PrivateKey +import wallet.core.jni.PublicKey +import wallet.core.jni.PublicKeyType import wallet.core.jni.proto.Bitcoin import wallet.core.jni.proto.Bitcoin.SigningOutput +import wallet.core.jni.proto.BitcoinV2 import wallet.core.jni.proto.Common.SigningError class TestBitcoinSigning { @@ -155,4 +160,203 @@ class TestBitcoinSigning { assertEquals("0x01000000000102fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f00000000494830450221008d49c4d7cc5ab93c01a67ce3f4ed2c45c59d4da6c76c891a9b56e67eda2e8cb4022078849134c697b1c70c1a19b900d94d8cab00ad7bcc8afe7ad1f6b184c13effa601ffffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02d8d60000000000001976a914a6d85a488bb777a540f24bf777d30d1486036f6188acee430000000000001976a9147d77e6cfb05a9cfc123824279f6caf8b66ac267688ac0002473044022074573d7f7828ae193fbea6d72c0fe2df6cee5c02bf455ea3d9312e16d6a9576502203861c5a3b3a83d4fe372034073f60201a8a944fb4536be0ea7544ab177b967600121025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee635700000000", Numeric.toHexString(encoded.toByteArray())); } + + @Test + fun testSignBrc20Commit() { + // Successfully broadcasted: https://www.blockchain.com/explorer/transactions/btc/797d17d47ae66e598341f9dfdea020b04d4017dcf9cc33f0e51f7a6082171fb1 + val privateKeyData = (Numeric.hexStringToByteArray("e253373989199da27c48680e3a3fc0f648d50f9a727ef17a7fe6a4dc3b159129")) + val dustSatoshis = 546.toLong() + val txId = Numeric.hexStringToByteArray("8ec895b4d30adb01e38471ca1019bfc8c3e5fbd1f28d9e7b5653260d89989008").reversedArray() + + val privateKey = PrivateKey(privateKeyData) + val publicKey = ByteString.copyFrom(privateKey.getPublicKeySecp256k1(true).data()) + + val utxo0 = BitcoinV2.Input.newBuilder() + .setOutPoint(BitcoinV2.OutPoint.newBuilder().apply { + hash = ByteString.copyFrom(txId) + vout = 1 + }) + .setValue(26_400) + .setSighashType(BitcoinSigHashType.ALL.value()) + .setScriptBuilder(BitcoinV2.Input.InputBuilder.newBuilder().apply { + p2Wpkh = BitcoinV2.PublicKeyOrHash.newBuilder().setPubkey(publicKey).build() + }) + + val out0 = BitcoinV2.Output.newBuilder() + .setValue(7_000) + .setBuilder(BitcoinV2.Output.OutputBuilder.newBuilder().apply { + brc20Inscribe = BitcoinV2.Output.OutputBrc20Inscription.newBuilder().apply { + inscribeTo = publicKey + ticker = "oadf" + transferAmount = "20" + }.build() + }) + + val changeOutput = BitcoinV2.Output.newBuilder() + .setValue(16_400) + .setBuilder(BitcoinV2.Output.OutputBuilder.newBuilder().apply { + p2Wpkh = BitcoinV2.PublicKeyOrHash.newBuilder().setPubkey(publicKey).build() + }) + + val builder = BitcoinV2.TransactionBuilder.newBuilder() + .setVersion(BitcoinV2.TransactionVersion.V2) + .addInputs(utxo0) + .addOutputs(out0) + .addOutputs(changeOutput) + .setInputSelector(BitcoinV2.InputSelector.UseAll) + .setFixedDustThreshold(dustSatoshis) + val signingInput = BitcoinV2.SigningInput.newBuilder() + .setBuilder(builder) + .addPrivateKeys(ByteString.copyFrom(privateKeyData)) + .setChainInfo(BitcoinV2.ChainInfo.newBuilder().apply { + p2PkhPrefix = 0 + p2ShPrefix = 5 + }) + .setDangerousUseFixedSchnorrRng(true) + .build() + + val legacySigningInput = Bitcoin.SigningInput.newBuilder().apply { + signingV2 = signingInput + } + + val output = AnySigner.sign(legacySigningInput.build(), BITCOIN, SigningOutput.parser()) + + assertEquals(output.error, SigningError.OK) + assertEquals(output.signingResultV2.error, SigningError.OK) + assertEquals(Numeric.toHexString(output.signingResultV2.encoded.toByteArray()), "0x02000000000101089098890d2653567b9e8df2d1fbe5c3c8bf1910ca7184e301db0ad3b495c88e0100000000ffffffff02581b000000000000225120e8b706a97732e705e22ae7710703e7f589ed13c636324461afa443016134cc051040000000000000160014e311b8d6ddff856ce8e9a4e03bc6d4fe5050a83d02483045022100a44aa28446a9a886b378a4a65e32ad9a3108870bd725dc6105160bed4f317097022069e9de36422e4ce2e42b39884aa5f626f8f94194d1013007d5a1ea9220a06dce0121030f209b6ada5edb42c77fd2bc64ad650ae38314c8f451f3e36d80bc8e26f132cb00000000") + assertEquals(Numeric.toHexString(output.signingResultV2.txid.toByteArray()), "0x797d17d47ae66e598341f9dfdea020b04d4017dcf9cc33f0e51f7a6082171fb1") + } + + @Test + fun testSignBrc20Reveal() { + // Successfully broadcasted: https://www.blockchain.com/explorer/transactions/btc/7046dc2689a27e143ea2ad1039710885147e9485ab6453fa7e87464aa7dd3eca + val privateKeyData = (Numeric.hexStringToByteArray("e253373989199da27c48680e3a3fc0f648d50f9a727ef17a7fe6a4dc3b159129")) + val dustSatoshis = 546.toLong() + val txIdCommit = Numeric.hexStringToByteArray("797d17d47ae66e598341f9dfdea020b04d4017dcf9cc33f0e51f7a6082171fb1").reversedArray() + + val privateKey = PrivateKey(privateKeyData) + val publicKey = ByteString.copyFrom(privateKey.getPublicKeySecp256k1(true).data()) + + val utxo0 = BitcoinV2.Input.newBuilder() + .setOutPoint(BitcoinV2.OutPoint.newBuilder().apply { + hash = ByteString.copyFrom(txIdCommit) + vout = 0 + }) + .setValue(7_000) + .setSighashType(BitcoinSigHashType.ALL.value()) + .setScriptBuilder(BitcoinV2.Input.InputBuilder.newBuilder().apply { + brc20Inscribe = BitcoinV2.Input.InputBrc20Inscription.newBuilder().apply { + inscribeTo = publicKey + ticker = "oadf" + transferAmount = "20" + }.build() + }) + + val out0 = BitcoinV2.Output.newBuilder() + .setValue(dustSatoshis) + .setBuilder(BitcoinV2.Output.OutputBuilder.newBuilder().apply { + p2Wpkh = BitcoinV2.PublicKeyOrHash.newBuilder().setPubkey(publicKey).build() + }) + + val builder = BitcoinV2.TransactionBuilder.newBuilder() + .setVersion(BitcoinV2.TransactionVersion.V2) + .addInputs(utxo0) + .addOutputs(out0) + .setInputSelector(BitcoinV2.InputSelector.UseAll) + .setFixedDustThreshold(dustSatoshis) + val signingInput = BitcoinV2.SigningInput.newBuilder() + .setBuilder(builder) + .addPrivateKeys(ByteString.copyFrom(privateKeyData)) + .setChainInfo(BitcoinV2.ChainInfo.newBuilder().apply { + p2PkhPrefix = 0 + p2ShPrefix = 5 + }) + .setDangerousUseFixedSchnorrRng(true) + .build() + + val legacySigningInput = Bitcoin.SigningInput.newBuilder().apply { + signingV2 = signingInput + } + + val output = AnySigner.sign(legacySigningInput.build(), BITCOIN, SigningOutput.parser()) + + assertEquals(output.error, SigningError.OK) + assertEquals(output.signingResultV2.error, SigningError.OK) + assertEquals(Numeric.toHexString(output.signingResultV2.encoded.toByteArray()), "0x02000000000101b11f1782607a1fe5f033ccf9dc17404db020a0dedff94183596ee67ad4177d790000000000ffffffff012202000000000000160014e311b8d6ddff856ce8e9a4e03bc6d4fe5050a83d03406a35548b8fa4620028e021a944c1d3dc6e947243a7bfc901bf63fefae0d2460efa149a6440cab51966aa4f09faef2d1e5efcba23ab4ca6e669da598022dbcfe35b0063036f7264010118746578742f706c61696e3b636861727365743d7574662d3800377b2270223a226272632d3230222c226f70223a227472616e73666572222c227469636b223a226f616466222c22616d74223a223230227d6821c00f209b6ada5edb42c77fd2bc64ad650ae38314c8f451f3e36d80bc8e26f132cb00000000") + assertEquals(Numeric.toHexString(output.signingResultV2.txid.toByteArray()), "0x7046dc2689a27e143ea2ad1039710885147e9485ab6453fa7e87464aa7dd3eca") + } + + @Test + fun testSignBrc20Transfer() { + // Successfully broadcasted: https://www.blockchain.com/explorer/transactions/btc/3e3576eb02667fac284a5ecfcb25768969680cc4c597784602d0a33ba7c654b7 + val privateKeyData = (Numeric.hexStringToByteArray("e253373989199da27c48680e3a3fc0f648d50f9a727ef17a7fe6a4dc3b159129")) + val dustSatoshis = 546.toLong() + val txIdInscription = Numeric.hexStringToByteArray("7046dc2689a27e143ea2ad1039710885147e9485ab6453fa7e87464aa7dd3eca").reversedArray() + val txIdForFees = Numeric.hexStringToByteArray("797d17d47ae66e598341f9dfdea020b04d4017dcf9cc33f0e51f7a6082171fb1").reversedArray() + + val privateKey = PrivateKey(privateKeyData) + val publicKey = ByteString.copyFrom(privateKey.getPublicKeySecp256k1(true).data()) + val bobAddress = "bc1qazgc2zhu2kmy42py0vs8d7yff67l3zgpwfzlpk" + + val utxo0 = BitcoinV2.Input.newBuilder() + .setOutPoint(BitcoinV2.OutPoint.newBuilder().apply { + hash = ByteString.copyFrom(txIdInscription) + vout = 0 + }) + .setValue(dustSatoshis) + .setSighashType(BitcoinSigHashType.ALL.value()) + .setScriptBuilder(BitcoinV2.Input.InputBuilder.newBuilder().apply { + p2Wpkh = BitcoinV2.PublicKeyOrHash.newBuilder().setPubkey(publicKey).build() + }) + + val utxo1 = BitcoinV2.Input.newBuilder() + .setOutPoint(BitcoinV2.OutPoint.newBuilder().apply { + hash = ByteString.copyFrom(txIdForFees) + vout = 1 + }) + .setValue(16_400) + .setSighashType(BitcoinSigHashType.ALL.value()) + .setScriptBuilder(BitcoinV2.Input.InputBuilder.newBuilder().apply { + p2Wpkh = BitcoinV2.PublicKeyOrHash.newBuilder().setPubkey(publicKey).build() + }) + + val out0 = BitcoinV2.Output.newBuilder() + .setValue(dustSatoshis) + .setToAddress(bobAddress) + + val changeOutput = BitcoinV2.Output.newBuilder() + .setValue(13_400) + .setBuilder(BitcoinV2.Output.OutputBuilder.newBuilder().apply { + p2Wpkh = BitcoinV2.PublicKeyOrHash.newBuilder().setPubkey(publicKey).build() + }) + + val builder = BitcoinV2.TransactionBuilder.newBuilder() + .setVersion(BitcoinV2.TransactionVersion.V2) + .addInputs(utxo0) + .addInputs(utxo1) + .addOutputs(out0) + .addOutputs(changeOutput) + .setInputSelector(BitcoinV2.InputSelector.UseAll) + .setFixedDustThreshold(dustSatoshis) + val signingInput = BitcoinV2.SigningInput.newBuilder() + .setBuilder(builder) + .addPrivateKeys(ByteString.copyFrom(privateKeyData)) + .setChainInfo(BitcoinV2.ChainInfo.newBuilder().apply { + p2PkhPrefix = 0 + p2ShPrefix = 5 + }) + .setDangerousUseFixedSchnorrRng(true) + .build() + + val legacySigningInput = Bitcoin.SigningInput.newBuilder().apply { + signingV2 = signingInput + } + + val output = AnySigner.sign(legacySigningInput.build(), BITCOIN, SigningOutput.parser()) + + assertEquals(output.error, SigningError.OK) + assertEquals(output.signingResultV2.error, SigningError.OK) + assertEquals(Numeric.toHexString(output.signingResultV2.encoded.toByteArray()), "0x02000000000102ca3edda74a46877efa5364ab85947e148508713910ada23e147ea28926dc46700000000000ffffffffb11f1782607a1fe5f033ccf9dc17404db020a0dedff94183596ee67ad4177d790100000000ffffffff022202000000000000160014e891850afc55b64aa8247b2076f8894ebdf889015834000000000000160014e311b8d6ddff856ce8e9a4e03bc6d4fe5050a83d024830450221008798393eb0b7390217591a8c33abe18dd2f7ea7009766e0d833edeaec63f2ec302200cf876ff52e68dbaf108a3f6da250713a9b04949a8f1dcd1fb867b24052236950121030f209b6ada5edb42c77fd2bc64ad650ae38314c8f451f3e36d80bc8e26f132cb0248304502210096bbb9d1f0596d69875646689e46f29485e8ceccacde9d0025db87fd96d3066902206d6de2dd69d965d28df3441b94c76e812384ab9297e69afe3480ee4031e1b2060121030f209b6ada5edb42c77fd2bc64ad650ae38314c8f451f3e36d80bc8e26f132cb00000000") + assertEquals(Numeric.toHexString(output.signingResultV2.txid.toByteArray()), "0x3e3576eb02667fac284a5ecfcb25768969680cc4c597784602d0a33ba7c654b7") + } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bitcoincash/TestBitcoinCashSigning.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bitcoincash/TestBitcoinCashSigning.kt new file mode 100644 index 00000000000..2c826c0bd4f --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bitcoincash/TestBitcoinCashSigning.kt @@ -0,0 +1,81 @@ +package com.trustwallet.core.app.blockchains.bitcoincash + +import com.trustwallet.core.app.utils.Numeric +import com.trustwallet.core.app.utils.toHexBytesInByteString +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.BitcoinSigHashType +import wallet.core.jni.CoinType +import wallet.core.jni.proto.Bitcoin +import wallet.core.jni.proto.BitcoinV2 +import wallet.core.jni.proto.Common.SigningError + +class TestBitcoinCashSigning { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testSignV2P2PKH() { + val privateKey = "7fdafb9db5bc501f2096e7d13d331dc7a75d9594af3d251313ba8b6200f4e384".toHexBytesInByteString() + + val utxo1 = BitcoinV2.Input.newBuilder().apply { + outPoint = BitcoinV2.OutPoint.newBuilder().apply { + hash = "e28c2b955293159898e34c6840d99bf4d390e2ee1c6f606939f18ee1e2000d05".toHexBytesInByteString() + vout = 2 + }.build() + value = 5151 + sighashType = BitcoinSigHashType.ALL.value() + BitcoinSigHashType.FORK.value() + receiverAddress = "bitcoincash:qzhlrcrcne07x94h99thved2pgzdtv8ccujjy73xya" + } + + val out1 = BitcoinV2.Output.newBuilder().apply { + value = 600 + // Legacy address + toAddress = "1Bp9U1ogV3A14FMvKbRJms7ctyso4Z4Tcx" + } + val changeOutputExplicit = BitcoinV2.Output.newBuilder().apply { + value = 4325 + // Legacy address + toAddress = "qz0q3xmg38sr94rw8wg45vujah7kzma3cskxymnw06" + } + + val builder = BitcoinV2.TransactionBuilder.newBuilder() + .setVersion(BitcoinV2.TransactionVersion.V1) + .addInputs(utxo1) + .addOutputs(out1) + .addOutputs(changeOutputExplicit) + .setInputSelector(BitcoinV2.InputSelector.UseAll) + .setFixedDustThreshold(546) + .build() + + val input = BitcoinV2.SigningInput.newBuilder() + .addPrivateKeys(privateKey) + .setBuilder(builder) + .setChainInfo(BitcoinV2.ChainInfo.newBuilder().apply { + p2PkhPrefix = 0 + p2ShPrefix = 5 + hrp = "bitcoincash" + }) + .build() + + val legacyInput = Bitcoin.SigningInput.newBuilder() + .setSigningV2(input) + // `CoinType` must be set to be handled correctly. + .setCoinType(CoinType.BITCOINCASH.value()) + .build() + + val outputLegacy = AnySigner.sign(legacyInput, CoinType.BITCOINCASH, Bitcoin.SigningOutput.parser()) + assertEquals(outputLegacy.error, SigningError.OK) + assert(outputLegacy.hasSigningResultV2()) + + val output = outputLegacy.signingResultV2 + assertEquals(output.error, SigningError.OK) + assertEquals( + Numeric.toHexString(output.encoded.toByteArray()), + "0x0100000001e28c2b955293159898e34c6840d99bf4d390e2ee1c6f606939f18ee1e2000d05020000006b483045022100b70d158b43cbcded60e6977e93f9a84966bc0cec6f2dfd1463d1223a90563f0d02207548d081069de570a494d0967ba388ff02641d91cadb060587ead95a98d4e3534121038eab72ec78e639d02758e7860cdec018b49498c307791f785aa3019622f4ea5bffffffff0258020000000000001976a914769bdff96a02f9135a1d19b749db6a78fe07dc9088ace5100000000000001976a9149e089b6889e032d46e3b915a3392edfd616fb1c488ac00000000" + ) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bitcoindiamond/TestBitcoinDiamondAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bitcoindiamond/TestBitcoinDiamondAddress.kt new file mode 100644 index 00000000000..497b2d6dedc --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bitcoindiamond/TestBitcoinDiamondAddress.kt @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.bitcoindiamond + +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestBitcoinDiamondAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val key = PrivateKey("d2b9f2846d3adcead910ee0124a3ba7ae29e8a4729787d27f9bea1f532928eee".toHexByteArray()) + val pubkey = key.getPublicKeySecp256k1(true); + val address = AnyAddress(pubkey, CoinType.BITCOINDIAMOND) + val expected = AnyAddress("1G15VvshDxwFTnahZZECJfFwEkq9fP79o8", CoinType.BITCOINDIAMOND) + + assertEquals(pubkey.data().toHex(), "0x02485a209514cc896f8ed736e205bc4c35bd5299ef3f9e84054475336b964c02a3") + assertEquals(address.description(), expected.description()) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bitcoindiamond/TestBitcoinDiamondSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bitcoindiamond/TestBitcoinDiamondSigner.kt new file mode 100644 index 00000000000..3bbbd9a77fd --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bitcoindiamond/TestBitcoinDiamondSigner.kt @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.bitcoindiamond + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.Numeric +import com.trustwallet.core.app.utils.toHexByteArray +import com.trustwallet.core.app.utils.toHexBytes +import com.trustwallet.core.app.utils.toHexBytesInByteString +import org.junit.Assert.assertEquals +import org.junit.Test + +import wallet.core.java.AnySigner +import wallet.core.jni.BitcoinScript +import wallet.core.jni.BitcoinSigHashType +import wallet.core.jni.CoinType +import wallet.core.jni.proto.Bitcoin +import wallet.core.jni.proto.Common.SigningError + +class TestBitcoinDiamondSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun BitcoinDiamondTransactionSigning() { + val toScript = BitcoinScript.lockScriptForAddress("1HevQVTSEc8cEpDm65UpfCdj5erd4xxBhx", CoinType.BITCOINDIAMOND); + assertEquals(Numeric.toHexString(toScript.data()), "0x76a914b6adfbbf15c8f6fa53f1edb37054dce5c7c145c688ac"); + + // prepare SigningInput + val input = Bitcoin.SigningInput.newBuilder() + .setHashType(BitcoinScript.hashTypeForCoin(CoinType.BITCOINDIAMOND)) + .setAmount(17615) + .setByteFee(1) + .setToAddress("1HevQVTSEc8cEpDm65UpfCdj5erd4xxBhx") + .setChangeAddress("1G15VvshDxwFTnahZZECJfFwEkq9fP79o8") + .setCoinType(CoinType.BITCOINDIAMOND.value()) + + val utxoKey0 = + (Numeric.hexStringToByteArray("d2b9f2846d3adcead910ee0124a3ba7ae29e8a4729787d27f9bea1f532928eee")) + input.addPrivateKey(ByteString.copyFrom(utxoKey0)) + + // build utxo + val txHash0 = (Numeric.hexStringToByteArray("034f4667301711e8a69236a93476ed798f9c11aaae472da5b315191a0453461d")) + val outpoint0 = Bitcoin.OutPoint.newBuilder() + .setHash(ByteString.copyFrom(txHash0)) + .setIndex(0) + .setSequence(Long.MAX_VALUE.toInt()) + .build() + + val utxo0 = Bitcoin.UnspentTransaction.newBuilder() + .setAmount(27615) + .setOutPoint(outpoint0) + .setScript(ByteString.copyFrom("76a914a48da46386ce52cccad178de900c71f06130c31088ac".toHexBytes())) + .build() + + input.addUtxo(utxo0) + + val plan = AnySigner.plan(input.build(), CoinType.BITCOINDIAMOND, Bitcoin.TransactionPlan.parser()) + + input.plan = Bitcoin.TransactionPlan.newBuilder() + .mergeFrom(plan) + .setAmount(17615) + .setFee(10000) + .setChange(0) + .setPreblockhash(ByteString.copyFrom("99668daf7c77c6462f3ba8fab61b4f62abaabd62911e7e59729ee9e1929dfa4b".toHexBytes())) + .build() + + + val output = AnySigner.sign(input.build(), CoinType.BITCOINDIAMOND, Bitcoin.SigningOutput.parser()) + + assertEquals(output.error, SigningError.OK) + val signedTransaction = output.transaction + assert(signedTransaction.isInitialized) + assertEquals(12, signedTransaction.version) + assertEquals(1, signedTransaction.inputsCount) + assertEquals(1, signedTransaction.outputsCount) + + val encoded = output.encoded + assertEquals("0x0c00000099668daf7c77c6462f3ba8fab61b4f62abaabd62911e7e59729ee9e1929dfa4b01034f4667301711e8a69236a93476ed798f9c11aaae472da5b315191a0453461d000000006a473044022078e0d3a9e1eb270ab02c15f8fcf1d3bfc95a324839690b7de4f011a4266132ff02204679e8103c4d3f0bb5192a5f53cc273732fd0e8392ab3b00dc708fd24d0160b3012102485a209514cc896f8ed736e205bc4c35bd5299ef3f9e84054475336b964c02a3ffffffff01cf440000000000001976a914b6adfbbf15c8f6fa53f1edb37054dce5c7c145c688ac00000000", + Numeric.toHexString(encoded.toByteArray())); + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bluzelle/TestBluzelleAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bluzelle/TestBluzelleAddress.kt index 99baa611f71..d8eb3424893 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bluzelle/TestBluzelleAddress.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bluzelle/TestBluzelleAddress.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2021 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.bluzelle diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bluzelle/TestBluzelleSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bluzelle/TestBluzelleSigner.kt index ba4d7e99238..bf40f0dcc67 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bluzelle/TestBluzelleSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/bluzelle/TestBluzelleSigner.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2021 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.bluzelle diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cardano/TestCardanoAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cardano/TestCardanoAddress.kt index 6ac0f1c4d63..a505e201176 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cardano/TestCardanoAddress.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cardano/TestCardanoAddress.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.cardano diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cardano/TestCardanoSigning.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cardano/TestCardanoSigning.kt index e76aa67b785..d9450e9881c 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cardano/TestCardanoSigning.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cardano/TestCardanoSigning.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.cardano @@ -15,11 +13,11 @@ import org.junit.Assert.assertEquals import org.junit.Test import wallet.core.java.AnySigner import wallet.core.jni.* +import wallet.core.jni.Cardano.getByronAddress import wallet.core.jni.Cardano.getStakingAddress +import wallet.core.jni.Cardano.outputMinAdaAmount import wallet.core.jni.CoinType.CARDANO import wallet.core.jni.proto.Cardano -import wallet.core.jni.proto.Cardano.SigningInput -import wallet.core.jni.proto.Cardano.SigningOutput import wallet.core.jni.proto.Common.SigningError @@ -65,7 +63,7 @@ class TestCardanoSigning { .build() input.addUtxos(utxo2) - val output = AnySigner.sign(input.build(), CARDANO, SigningOutput.parser()) + val output = AnySigner.sign(input.build(), CARDANO, Cardano.SigningOutput.parser()) assertEquals(output.error, SigningError.OK) val encoded = output.encoded @@ -76,6 +74,60 @@ class TestCardanoSigning { assertEquals(Numeric.toHexString(txid.toByteArray()), "0x9b5b15e133cd73ccaa85307d2986aebc846505118a2eb4e6111e6b4b67d1f389"); } + /// Successfully broadcasted: + /// https://cardanoscan.io/transaction/0203ce2c91f59f169a26e9ef91254639d2b7911afac9c7c0ae64539f88ba46a5 + @Test + fun testSignTransferFromLegacy() { + val privateKey = PrivateKey("98f266d1aac660179bc2f456033941238ee6b2beb8ed0f9f34c9902816781f5a9903d1d395d6ab887b65ea5e344ef09b449507c21a75f0ce8c59d0ed1c6764eba7f484aa383806735c46fd769c679ee41f8952952036a6e2338ada940b8a91f4e890ca4eb6bec44bf751b5a843174534af64d6ad1f44e0613db78a7018781f5aa151d2997f52059466b715d8eefab30a78b874ae6ef4931fa58bb21ef8ce2423d46f19d0fbf75afb0b9a24e31d533f4fd74cee3b56e162568e8defe37123afc4".toHexByteArray()) + var publicKey = privateKey.publicKeyEd25519Cardano + var byronAddress = wallet.core.jni.Cardano.getByronAddress(publicKey) + + assertEquals(byronAddress, "Ae2tdPwUPEZ6vkqxSjJxaQYmDxHf5DTnxtZ67pFLJGTb9LTnCGkDP6ca3f8") + + val message = Cardano.Transfer.newBuilder() + .setToAddress("addr1q90uh2eawrdc9vaemftgd50l28yrh9lqxtjjh4z6dnn0u7ggasexxdyyk9f05atygnjlccsjsggtc87hhqjna32fpv5qeq96ls") + .setChangeAddress("addr1qx55ymlqemndq8gluv40v58pu76a2tp4mzjnyx8n6zrp2vtzrs43a0057y0edkn8lh9su8vh5lnhs4npv6l9tuvncv8swc7t08") + .setAmount(3_000_000) + .build() + val input = Cardano.SigningInput.newBuilder() + .setTransferMessage(message) + .setTtl(190000000) + + input.addPrivateKey(ByteString.copyFrom(privateKey.data())) + + val outpoint1 = Cardano.OutPoint.newBuilder() + .setTxHash(ByteString.copyFrom(Numeric.hexStringToByteArray("8316e5007d61fb90652cabb41141972a38b5bc60954d602cf843476aa3f67f63"))) + .setOutputIndex(0) + .build() + val utxo1 = Cardano.TxInput.newBuilder() + .setOutPoint(outpoint1) + .setAddress("Ae2tdPwUPEZ6vkqxSjJxaQYmDxHf5DTnxtZ67pFLJGTb9LTnCGkDP6ca3f8") + .setAmount(2_500_000) + .build() + input.addUtxos(utxo1) + + val outpoint2 = Cardano.OutPoint.newBuilder() + .setTxHash(ByteString.copyFrom(Numeric.hexStringToByteArray("e29392c59c903fefb905730587d22cae8bda30bd8d9aeec3eca082ae77675946"))) + .setOutputIndex(0) + .build() + val utxo2 = Cardano.TxInput.newBuilder() + .setOutPoint(outpoint2) + .setAddress("Ae2tdPwUPEZ6vkqxSjJxaQYmDxHf5DTnxtZ67pFLJGTb9LTnCGkDP6ca3f8") + .setAmount(1_700_000) + .build() + input.addUtxos(utxo2) + + val output = AnySigner.sign(input.build(), CARDANO, Cardano.SigningOutput.parser()) + assertEquals(output.error, SigningError.OK) + + val encoded = output.encoded + assertEquals(Numeric.toHexString(encoded.toByteArray()), + "0x83a400828258208316e5007d61fb90652cabb41141972a38b5bc60954d602cf843476aa3f67f6300825820e29392c59c903fefb905730587d22cae8bda30bd8d9aeec3eca082ae77675946000182825839015fcbab3d70db82b3b9da5686d1ff51c83b97e032e52bd45a6ce6fe7908ec32633484b152fa756444e5fc62128210bc1fd7b8253ec5490b281a002dc6c082583901a9426fe0cee6d01d1fe32af650e1e7b5d52c35d8a53218f3d0861531621c2b1ebdf4f11f96da67fdcb0e1d97a7e778566166be55f193c30f1a000f9ec1021a0002b0bf031a0b532b80a20081825820d163c8c4f0be7c22cd3a1152abb013c855ea614b92201497a568c5d93ceeb41e58406a23ab9267867fbf021c1cb2232bc83d2cdd663d651d22d59b6cddbca5cb106d4db99da50672f69a2309ca8a329a3f9576438afe4538b013de4591a6dfcd4d090281845820d163c8c4f0be7c22cd3a1152abb013c855ea614b92201497a568c5d93ceeb41e58406a23ab9267867fbf021c1cb2232bc83d2cdd663d651d22d59b6cddbca5cb106d4db99da50672f69a2309ca8a329a3f9576438afe4538b013de4591a6dfcd4d095820a7f484aa383806735c46fd769c679ee41f8952952036a6e2338ada940b8a91f441a0f6"); + + val txid = output.txId + assertEquals(Numeric.toHexString(txid.toByteArray()), "0x0203ce2c91f59f169a26e9ef91254639d2b7911afac9c7c0ae64539f88ba46a5"); + } + @Test fun testSignTransferToken1() { val toToken = Cardano.TokenAmount.newBuilder() @@ -115,7 +167,7 @@ class TestCardanoSigning { .setAmount(8_051_373) val token3 = Cardano.TokenAmount.newBuilder() .setPolicyId("9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77") - .setAssetName("CUBY") + .setAssetNameHex("43554259") .setAmount(ByteString.copyFrom(Numeric.hexStringToByteArray("2dc6c0"))) // 3000000 .build() utxo1.addTokenAmount(token3) @@ -131,7 +183,7 @@ class TestCardanoSigning { .setAmount(2_000_000) val token1 = Cardano.TokenAmount.newBuilder() .setPolicyId("9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77") - .setAssetName("SUNDAE") + .setAssetNameHex("53554e444145") .setAmount(ByteString.copyFrom(Numeric.hexStringToByteArray("04d3e8d9"))) // 80996569 .build() utxo2.addTokenAmount(token1) @@ -143,7 +195,7 @@ class TestCardanoSigning { utxo2.addTokenAmount(token2) input.addUtxos(utxo2.build()) - val output = AnySigner.sign(input.build(), CARDANO, SigningOutput.parser()) + val output = AnySigner.sign(input.build(), CARDANO, Cardano.SigningOutput.parser()) assertEquals(output.error, SigningError.OK) val encoded = output.encoded @@ -206,7 +258,7 @@ class TestCardanoSigning { .build() input.addUtxos(utxo2) - val output = AnySigner.sign(input.build(), CARDANO, SigningOutput.parser()) + val output = AnySigner.sign(input.build(), CARDANO, Cardano.SigningOutput.parser()) assertEquals(output.error, SigningError.OK) val encoded = output.encoded @@ -251,7 +303,7 @@ class TestCardanoSigning { .build() input.addUtxos(utxo1) - val output = AnySigner.sign(input.build(), CARDANO, SigningOutput.parser()) + val output = AnySigner.sign(input.build(), CARDANO, Cardano.SigningOutput.parser()) assertEquals(output.error, SigningError.OK) val encoded = output.encoded @@ -261,4 +313,86 @@ class TestCardanoSigning { val txid = output.txId assertEquals(Numeric.toHexString(txid.toByteArray()), "0x6dcf3956232953fc25b8355fb1ded1e912b5802090fd21434d789087d6329683"); } + + // Successfully broadcasted: + // https://cardanoscan.io/transaction/87ca43a36b09c0b140f0ef2b71fbdcfcf1fdc88f7aa378b861e8eed3e8974628 + @Test + fun testSignNftTransfer() { + val fromAddress = "addr1qy5eme9r6frr0m6q2qpncg282jtrhq5lg09uxy2j0545hj8rv7v2ntdxuv6p4s3eq4lqzg39lewgvt6fk5kmpa0zppesufzjud" + val toAddress = "addr1qy9wjfn6nd8kak6dd8z53u7t5wt9f4lx0umll40px5hnq05avwcsq5r3ytdp36wttzv4558jaq8lvhgqhe3y8nuf5xrquju7z4" + val coinsPerUtxoByte = "4310" + + val tokenAmount = Cardano.TokenAmount.newBuilder() + .setPolicyId("219820e6cb04316f41a337fea356480f412e7acc147d28f175f21b5e") + .setAssetName("coolcatssociety4567") + .setAmount(ByteString.copyFrom(Numeric.hexStringToByteArray("01"))) // 1 + .build() + + // UTXOs + + val outpoint1 = Cardano.OutPoint.newBuilder() + .setTxHash(ByteString.copyFrom(Numeric.hexStringToByteArray("aba499ec2f23529e70bb256ceaffcc6274a882cf02f29e5670c75ee980d7c2b8"))) + .setOutputIndex(0) + .build() + val utxo1 = Cardano.TxInput.newBuilder() + .setOutPoint(outpoint1) + .setAddress(fromAddress) + .setAmount(1_202_490) + .addTokenAmount(tokenAmount) + + val outpoint2 = Cardano.OutPoint.newBuilder() + .setTxHash(ByteString.copyFrom(Numeric.hexStringToByteArray("ee414d635b3bc67831907354d274a31174664777c57c21ae923b9459e5644840"))) + .setOutputIndex(0) + .build() + val utxo2 = Cardano.TxInput.newBuilder() + .setOutPoint(outpoint2) + .setAddress(fromAddress) + .setAmount(1_000_000) + + val outpoint3 = Cardano.OutPoint.newBuilder() + .setTxHash(ByteString.copyFrom(Numeric.hexStringToByteArray("6a7221dcc28353ed69b733391ffeb984a34c1e72293af111d59f9ddfa8639167"))) + .setOutputIndex(0) + .build() + val utxo3 = Cardano.TxInput.newBuilder() + .setOutPoint(outpoint3) + .setAddress(fromAddress) + .setAmount(2_000_000) + + // Transfer TX + + val privKey = Numeric.hexStringToByteArray("d09831a668db6b36ffb747600cb1cd3e3d34f36e1e6feefc11b5f988719b7557a7029ab80d3e6fe4180ad07a59ddf742ea9730f3c4145df6365fa4ae2ee49c3392e19444caf461567727b7fefec40a3763bdb6ce5e0e8c05f5e340355a8fef4528dfe7502cfbda49e38f5a0021962d52dc3dee82834a23abb6750981799b75577d1ed9af9853707f0ef74264274e71b2f12e86e3c91314b6efa75ef750d9711b84cedd742ab873ef2f9566ad20b3fc702232c6d2f5d83ff425019234037d1e58") + val toTokenBundle = Cardano.TokenBundle.newBuilder() + .addToken(tokenAmount) + .build() + + // Check min ADA amount, set it + val minAmount = outputMinAdaAmount(toAddress, toTokenBundle.toByteArray(), coinsPerUtxoByte).toLong() + assertEquals(minAmount, 1_202_490) + + val transfer = Cardano.Transfer.newBuilder() + .setToAddress(toAddress) + .setChangeAddress(fromAddress) + .setAmount(minAmount) + .setTokenAmount(toTokenBundle) + .build() + val signInput = Cardano.SigningInput.newBuilder() + .setTransferMessage(transfer) + .setTtl(89130965) + .addUtxos(utxo1) + .addUtxos(utxo2) + .addUtxos(utxo3) + .addPrivateKey(ByteString.copyFrom(privKey)) + + // Sign and check + + val output = AnySigner.sign(signInput.build(), CARDANO, Cardano.SigningOutput.parser()) + assertEquals(output.error, SigningError.OK) + + val encoded = output.encoded + assertEquals(Numeric.toHexString(encoded.toByteArray()), + "0x83a400838258206a7221dcc28353ed69b733391ffeb984a34c1e72293af111d59f9ddfa863916700825820aba499ec2f23529e70bb256ceaffcc6274a882cf02f29e5670c75ee980d7c2b800825820ee414d635b3bc67831907354d274a31174664777c57c21ae923b9459e5644840000182825839010ae9267a9b4f6edb4d69c548f3cba39654d7e67f37ffd5e1352f303e9d63b100507122da18e9cb58995a50f2e80ff65d00be6243cf89a186821a0012593aa1581c219820e6cb04316f41a337fea356480f412e7acc147d28f175f21b5ea153636f6f6c63617473736f6369657479343536370182583901299de4a3d24637ef4050033c214754963b829f43cbc311527d2b4bc8e36798a9ada6e3341ac239057e012225fe5c862f49b52db0f5e208731a002b1525021a0002b19b031a055007d5a1008182582088bd26e8656fa7dead846c3373588f0192da5bfb90bf5d3fb877decfb3b3fd085840da8656aca0dacc57d4c2d957fc7dff03908f6dcf60c48f1e40b3006e2fd0cfacfa4c24fa02e35a310572526586d4ce0d30bf660ba274c8efd507848cbe177d09f6"); + + val txid = output.txId + assertEquals(Numeric.toHexString(txid.toByteArray()), "0x87ca43a36b09c0b140f0ef2b71fbdcfcf1fdc88f7aa378b861e8eed3e8974628"); + } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/confluxespace/TestConfluxeSpaceAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/confluxespace/TestConfluxeSpaceAddress.kt new file mode 100644 index 00000000000..25d5ae1c81e --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/confluxespace/TestConfluxeSpaceAddress.kt @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.confluxespace + +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestConfluxeSpaceAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val key = PrivateKey("828c4c48c2cef521f0251920891ed79e871faa24f64f43cde83d07bc99f8dbf0".toHexByteArray()) + val pubkey = key.getPublicKeySecp256k1(false) + val address = AnyAddress(pubkey, CoinType.CONFLUXESPACE) + val expected = AnyAddress("0xe32DC46bfBF78D1eada7b0a68C96903e01418D64", CoinType.CONFLUXESPACE) + + assertEquals(address.description(), expected.description()) + } +} \ No newline at end of file diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cosmos/TestCosmosTransactions.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cosmos/TestCosmosTransactions.kt index 7267138e1da..4de24f9b60f 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cosmos/TestCosmosTransactions.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cosmos/TestCosmosTransactions.kt @@ -67,9 +67,9 @@ class TestCosmosTransactions { assertEquals( output.serialized, - "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CvgBCvUBCh4vY29zbW9zLmF1dGh6LnYxYmV0YTEuTXNnR3JhbnQS0gEKLWNvc21vczEzazBxMGw3bGcya3IzMmt2dDdseTIzNnBwbGR5OHY5ZHp3aDNnZBItY29zbW9zMWZzN2x1MjhoeDVtOWFrbTdycDBjMjQyMmNuOHIyZjdndXJ1amhmGnIKaAoqL2Nvc21vcy5zdGFraW5nLnYxYmV0YTEuU3Rha2VBdXRob3JpemF0aW9uEjoSNgo0Y29zbW9zdmFsb3BlcjFnanR2bHk5bGVsNnpza3Z3dHZsZzV2aHdwdTljOXdhdzdzeHp3eCABEgYI4LD6pgYSZwpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA/fcQw1hCVUx904t+kCXTiiziaLIY8lyssu1ENfzaN1KEgQKAggBGAUSEwoNCgV1YXRvbRIEMjQxOBCp8wUaQIFyfuijGKf87Hz61ZqxasfLI1PZnNge4RDq/tRyB/tZI6p80iGRqHecoV6+84EQkc9GTlNRQOSlApRCsivT9XI=\"}" + "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CvgBCvUBCh4vY29zbW9zLmF1dGh6LnYxYmV0YTEuTXNnR3JhbnQS0gEKLWNvc21vczEzazBxMGw3bGcya3IzMmt2dDdseTIzNnBwbGR5OHY5ZHp3aDNnZBItY29zbW9zMWZzN2x1MjhoeDVtOWFrbTdycDBjMjQyMmNuOHIyZjdndXJ1amhmGnIKaAoqL2Nvc21vcy5zdGFraW5nLnYxYmV0YTEuU3Rha2VBdXRob3JpemF0aW9uEjogARI2CjRjb3Ntb3N2YWxvcGVyMWdqdHZseTlsZWw2enNrdnd0dmxnNXZod3B1OWM5d2F3N3N4end4EgYI4LD6pgYSZwpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA/fcQw1hCVUx904t+kCXTiiziaLIY8lyssu1ENfzaN1KEgQKAggBGAUSEwoNCgV1YXRvbRIEMjQxOBCp8wUaQEAN1nIfDawlHnep2bNEm14w+g7tYybJJT3htcGVS6s9D7va3ed1OUEIk9LZoc3G//VenJ+KLw26SRVBaRukgVI=\"}" ) - assertEquals(output.error, "") + assertEquals(output.errorMessage, "") } @Test @@ -114,7 +114,7 @@ class TestCosmosTransactions { output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CqoBCqcBCh8vY29zbW9zLmF1dGh6LnYxYmV0YTEuTXNnUmV2b2tlEoMBCi1jb3Ntb3MxM2swcTBsN2xnMmtyMzJrdnQ3bHkyMzZwcGxkeTh2OWR6d2gzZ2QSLWNvc21vczFmczdsdTI4aHg1bTlha203cnAwYzI0MjJjbjhyMmY3Z3VydWpoZhojL2Nvc21vcy5zdGFraW5nLnYxYmV0YTEuTXNnRGVsZWdhdGUSZwpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA/fcQw1hCVUx904t+kCXTiiziaLIY8lyssu1ENfzaN1KEgQKAggBGAQSEwoNCgV1YXRvbRIEMjE5NBC3rQUaQI7K+W7MMBoD6FbFZxRBqs9VTjErztjWTy57+fvrLaTCIZ+eBs7CuaKqfUZdSN8otjubSHVTQID3k9DpPAX0yDo=\"}" ) - assertEquals(output.error, "") + assertEquals(output.errorMessage, "") } @Test @@ -166,7 +166,7 @@ class TestCosmosTransactions { output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CowBCokBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmkKLWNvc21vczFoc2s2anJ5eXFqZmhwNWRoYzU1dGM5anRja3lneDBlcGg2ZGQwMhItY29zbW9zMXp0NTBhenVwYW5xbGZhbTVhZmh2M2hleHd5dXRudWtlaDRjNTczGgkKBG11b24SATESZQpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohAlcobsPzfTNVe7uqAAsndErJAjqplnyudaGB0f+R+p3FEgQKAggBGAgSEQoLCgRtdW9uEgMyMDAQwJoMGkD54fQAFlekIAnE62hZYl0uQelh/HLv0oQpCciY5Dn8H1SZFuTsrGdu41PH1Uxa4woptCELi/8Ov9yzdeEFAC9H\"}" ) - assertEquals(output.error, "") + assertEquals(output.errorMessage, "") } @Test diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cryptoorg/TestCryptoorgAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cryptoorg/TestCryptoorgAddress.kt index 52e06a041d8..214c391624d 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cryptoorg/TestCryptoorgAddress.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cryptoorg/TestCryptoorgAddress.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2021 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.cryptoorg diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cryptoorg/TestCryptoorgSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cryptoorg/TestCryptoorgSigner.kt index 98c568d9bef..74090e73a29 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cryptoorg/TestCryptoorgSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cryptoorg/TestCryptoorgSigner.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2021 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.cryptoorg @@ -73,6 +71,6 @@ class TestCryptoorgSigner { // https://crypto.org/explorer/tx/BCB213B0A121F0CF11BECCF52475F1C8328D6070F3CFDA9E14C42E6DB30E847E assertEquals(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CpABCo0BChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEm0KKmNybzFjdHd0Y3dwZ2tza3k5ODhkaHRoNmpzbHh2ZXVtZ3UwZDQ1emdmMBIqY3JvMXhwYWh5NmM3d2xkeGFjdjZsZDk5aDQzNW1odmZuc3VwMjR2Y3VzGhMKB2Jhc2Vjcm8SCDUwMDAwMDAwEmkKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQOIMbBhYj5+i+WdiIxxCEpFyNCJMHy/XsVdxiwde9Vr4xIECgIIARgCEhUKDwoHYmFzZWNybxIENTAwMBDAmgwaQAcxK9xk6r69gmz+1UWaCnYxNuXPXZdp59YcqKPJE5d6fp+IICTBOwd2rs8MiApcf8kNSrbZ6oECxcGQAdxF0SI=\"}") - assertEquals(output.error, "") + assertEquals(output.errorMessage, "") } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/dydx/TestDydxAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/dydx/TestDydxAddress.kt new file mode 100644 index 00000000000..408f8fb4ae3 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/dydx/TestDydxAddress.kt @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.dydx + +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestDydxAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val key = PrivateKey("a498a9ee41af9bab5ef2a8be63d5c970135c3c109e70efc8c56c534e6636b433".toHexByteArray()) + val pubKey = key.getPublicKeySecp256k1(true) + val address = AnyAddress(pubKey, CoinType.DYDX) + val expected = AnyAddress("dydx1mry47pkga5tdswtluy0m8teslpalkdq0hc72uz", CoinType.DYDX) + + assertEquals(address.description(), expected.description()) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondAddress.kt deleted file mode 100644 index e8304e3deeb..00000000000 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondAddress.kt +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright © 2017-2020 Trust Wallet. -// -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. - -package com.trustwallet.core.app.blockchains.elrond - -import com.trustwallet.core.app.utils.toHex -import com.trustwallet.core.app.utils.toHexByteArray -import org.junit.Assert.assertEquals -import org.junit.Test -import wallet.core.jni.* - -class TestElrondAddress { - - init { - System.loadLibrary("TrustWalletCore") - } - - private var aliceBech32 = "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" - private var alicePubKeyHex = "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1" - private var aliceSeedHex = "0x413f42575f7f26fad3317a778771212fdb80245850981e48b58a4f25e344e8f9" - - @Test - fun testAddressFromPrivateKey() { - val key = PrivateKey(aliceSeedHex.toHexByteArray()) - val pubKey = key.publicKeyEd25519 - val address = AnyAddress(pubKey, CoinType.ELROND) - - assertEquals(alicePubKeyHex, pubKey.data().toHex()) - assertEquals(aliceBech32, address.description()) - } - - @Test - fun testAddressFromPublicKey() { - val pubKey = PublicKey(alicePubKeyHex.toHexByteArray(), PublicKeyType.ED25519) - val address = AnyAddress(pubKey, CoinType.ELROND) - - assertEquals(aliceBech32, address.description()) - } - - @Test - fun testAddressFromString() { - val address = AnyAddress(aliceBech32, CoinType.ELROND) - - assertEquals(aliceBech32, address.description()) - } -} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondSigner.kt deleted file mode 100644 index a99a949bdb4..00000000000 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondSigner.kt +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright © 2017-2020 Trust Wallet. -// -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. - -package com.trustwallet.core.app.blockchains.elrond - -import com.google.protobuf.ByteString -import com.trustwallet.core.app.utils.toHexByteArray -import org.junit.Assert.assertEquals -import org.junit.Test -import wallet.core.java.AnySigner -import wallet.core.jni.CoinType -import wallet.core.jni.PrivateKey -import wallet.core.jni.proto.Elrond - -class TestElrondSigner { - - init { - System.loadLibrary("TrustWalletCore") - } - - private var aliceBech32 = "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" - private var aliceSeedHex = "0x413f42575f7f26fad3317a778771212fdb80245850981e48b58a4f25e344e8f9" - private var bobBech32 = "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx" - - @Test - fun signGenericAction() { - val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) - - val accounts = Elrond.Accounts.newBuilder() - .setSenderNonce(7) - .setSender(aliceBech32) - .setReceiver(bobBech32) - .build() - - val genericAction = Elrond.GenericAction.newBuilder() - .setAccounts(accounts) - .setValue("0") - .setData("foo") - .setVersion(1) - .build() - - val signingInput = Elrond.SigningInput.newBuilder() - .setGenericAction(genericAction) - .setGasPrice(1000000000) - .setGasLimit(50000) - .setChainId("1") - .setPrivateKey(privateKey) - .build() - - val output = AnySigner.sign(signingInput, CoinType.ELROND, Elrond.SigningOutput.parser()) - val expectedSignature = "e8647dae8b16e034d518a1a860c6a6c38d16192d0f1362833e62424f424e5da660770dff45f4b951d9cc58bfb9d14559c977d443449bfc4b8783ff9c84065700" - - assertEquals(expectedSignature, output.signature) - assertEquals("""{"nonce":7,"value":"0","receiver":"$bobBech32","sender":"$aliceBech32","gasPrice":1000000000,"gasLimit":50000,"data":"Zm9v","chainID":"1","version":1,"signature":"$expectedSignature"}""", output.encoded) - } - - @Test - fun signEGLDTransfer() { - val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) - - val accounts = Elrond.Accounts.newBuilder() - .setSenderNonce(7) - .setSender(aliceBech32) - .setReceiver(bobBech32) - .build() - - val transfer = Elrond.EGLDTransfer.newBuilder() - .setAccounts(accounts) - .setAmount("1000000000000000000") - .build() - - val signingInput = Elrond.SigningInput.newBuilder() - .setEgldTransfer(transfer) - .setChainId("1") - .setPrivateKey(privateKey) - .build() - - val output = AnySigner.sign(signingInput, CoinType.ELROND, Elrond.SigningOutput.parser()) - val expectedSignature = "7e1c4c63b88ea72dcf7855a54463b1a424eb357ac3feb4345221e512ce07c7a50afb6d7aec6f480b554e32cf2037082f3bc17263d1394af1f3ef240be53c930b" - - assertEquals(expectedSignature, output.signature) - assertEquals("""{"nonce":7,"value":"1000000000000000000","receiver":"$bobBech32","sender":"$aliceBech32","gasPrice":1000000000,"gasLimit":50000,"chainID":"1","version":1,"signature":"$expectedSignature"}""", output.encoded) - } - - @Test - fun signESDTTransfer() { - val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) - - val accounts = Elrond.Accounts.newBuilder() - .setSenderNonce(7) - .setSender(aliceBech32) - .setReceiver(bobBech32) - .build() - - val transfer = Elrond.ESDTTransfer.newBuilder() - .setAccounts(accounts) - .setTokenIdentifier("MYTOKEN-1234") - .setAmount("10000000000000") - .build() - - val signingInput = Elrond.SigningInput.newBuilder() - .setEsdtTransfer(transfer) - .setChainId("1") - .setPrivateKey(privateKey) - .build() - - val output = AnySigner.sign(signingInput, CoinType.ELROND, Elrond.SigningOutput.parser()) - val expectedSignature = "9add6d9ac3f1a1fddb07b934e8a73cad3b8c232bdf29d723c1b38ad619905f03e864299d06eb3fe3bbb48a9f1d9b7f14e21dc5eaffe0c87f5718ad0c4198bb0c" - val expectedData = "RVNEVFRyYW5zZmVyQDRkNTk1NDRmNGI0NTRlMmQzMTMyMzMzNEAwOTE4NGU3MmEwMDA=" - - assertEquals(expectedSignature, output.signature) - assertEquals("""{"nonce":7,"value":"0","receiver":"$bobBech32","sender":"$aliceBech32","gasPrice":1000000000,"gasLimit":425000,"data":"$expectedData","chainID":"1","version":1,"signature":"$expectedSignature"}""", output.encoded) - } - - @Test - fun signESDTNFTTransfer() { - val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) - - val accounts = Elrond.Accounts.newBuilder() - .setSenderNonce(7) - .setSender(aliceBech32) - .setReceiver(bobBech32) - .build() - - val transfer = Elrond.ESDTNFTTransfer.newBuilder() - .setAccounts(accounts) - .setTokenCollection("LKMEX-aab910") - .setTokenNonce(4) - .setAmount("184300000000000000") - .build() - - val signingInput = Elrond.SigningInput.newBuilder() - .setEsdtnftTransfer(transfer) - .setChainId("1") - .setPrivateKey(privateKey) - .build() - - val output = AnySigner.sign(signingInput, CoinType.ELROND, Elrond.SigningOutput.parser()) - val expectedSignature = "cc935685d5b31525e059a16a832cba98dee751983a5a93de4198f6553a2c55f5f1e0b4300fe9077376fa754546da0b0f6697e66462101a209aafd0fc775ab60a" - val expectedData = "RVNEVE5GVFRyYW5zZmVyQDRjNGI0ZDQ1NTgyZDYxNjE2MjM5MzEzMEAwNEAwMjhlYzNkZmEwMWFjMDAwQDgwNDlkNjM5ZTVhNjk4MGQxY2QyMzkyYWJjY2U0MTAyOWNkYTc0YTE1NjM1MjNhMjAyZjA5NjQxY2MyNjE4Zjg=" - - assertEquals(expectedSignature, output.signature) - assertEquals("""{"nonce":7,"value":"0","receiver":"$aliceBech32","sender":"$aliceBech32","gasPrice":1000000000,"gasLimit":937500,"data":"$expectedData","chainID":"1","version":1,"signature":"$expectedSignature"}""", output.encoded) - } -} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/eos/TestEOSSigning.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/eos/TestEOSSigning.kt index 27fb4ce0b11..d5d073b1840 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/eos/TestEOSSigning.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/eos/TestEOSSigning.kt @@ -82,7 +82,7 @@ class TestEOSSigning { val signatureValue: String = signatures.get(0) as String; assertNotNull("Error parsing JSON result", signatureValue) assertEquals( - "SIG_K1_KfCdjsrTnx5cBpbA5cUdHZAsRYsnC9uKzuS1shFeqfMCfdZwX4PBm9pfHwGRT6ffz3eavhtkyNci5GoFozQAx8P8PBnDmj", + "SIG_K1_K9RdLC7DEDWjTfR64GU8BtDHcAjzR1ntcT651JMcfHNTpdsvDrUwfyzF1FkvL9fxEi2UCtGJZ9zYoNbJoMF1fbU64cRiJ7", signatureValue ) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestBarz.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestBarz.kt new file mode 100644 index 00000000000..235cd442b73 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestBarz.kt @@ -0,0 +1,229 @@ +package com.trustwallet.core.app.blockchains.ethereum + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* +import wallet.core.java.AnySigner +import wallet.core.jni.CoinType +import wallet.core.jni.CoinType.ETHEREUM +import wallet.core.jni.proto.Ethereum +import wallet.core.jni.EthereumAbi +import wallet.core.jni.EthereumAbiFunction +import wallet.core.jni.proto.Ethereum.SigningOutput +import wallet.core.jni.proto.Ethereum.TransactionMode +import wallet.core.jni.PrivateKey +import wallet.core.jni.PublicKey +import wallet.core.jni.PublicKeyType +import com.trustwallet.core.app.utils.Numeric +import org.junit.Assert.assertArrayEquals +import wallet.core.jni.proto.Barz +import wallet.core.jni.Barz as WCBarz + +class TestBarz { + + init { + System.loadLibrary("TrustWalletCore") + } + + // https://testnet.bscscan.com/tx/0x6c6e1fe81c722c0abce1856b9b4e078ab2cad06d51f2d1b04945e5ba2286d1b4 + @Test + fun testInitCode() { + val factoryAddress = "0x3fC708630d85A3B5ec217E53100eC2b735d4f800" + val publicKeyData = Numeric.hexStringToByteArray("04e6f4e0351e2f556fd7284a9a033832bae046ac31fd529ad02ab6220870624b79eb760e718fdaed7a037dd1d77a561759cee9f2706eb55a729dc953e0d5719b02") + val publicKey = PublicKey(publicKeyData, PublicKeyType.NIST256P1EXTENDED) + val verificationFacet = "0x6BF22ff186CC97D88ECfbA47d1473a234CEBEFDf" + val result = WCBarz.getInitCode(factoryAddress, publicKey, verificationFacet, 0) + assertEquals(Numeric.toHexString(result), "0x3fc708630d85a3b5ec217e53100ec2b735d4f800296601cd0000000000000000000000006bf22ff186cc97d88ecfba47d1473a234cebefdf00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004104e6f4e0351e2f556fd7284a9a033832bae046ac31fd529ad02ab6220870624b79eb760e718fdaed7a037dd1d77a561759cee9f2706eb55a729dc953e0d5719b0200000000000000000000000000000000000000000000000000000000000000") + } + + @Test + fun testInitCodeNonZeroSalt() { + val factoryAddress = "0x3fC708630d85A3B5ec217E53100eC2b735d4f800" + val publicKeyData = Numeric.hexStringToByteArray("04e6f4e0351e2f556fd7284a9a033832bae046ac31fd529ad02ab6220870624b79eb760e718fdaed7a037dd1d77a561759cee9f2706eb55a729dc953e0d5719b02") + val publicKey = PublicKey(publicKeyData, PublicKeyType.NIST256P1EXTENDED) + val verificationFacet = "0x6BF22ff186CC97D88ECfbA47d1473a234CEBEFDf" + val salt = 1 + val result = WCBarz.getInitCode(factoryAddress, publicKey, verificationFacet, salt) + assertEquals(Numeric.toHexString(result), "0x3fc708630d85a3b5ec217e53100ec2b735d4f800296601cd0000000000000000000000006bf22ff186cc97d88ecfba47d1473a234cebefdf00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004104e6f4e0351e2f556fd7284a9a033832bae046ac31fd529ad02ab6220870624b79eb760e718fdaed7a037dd1d77a561759cee9f2706eb55a729dc953e0d5719b0200000000000000000000000000000000000000000000000000000000000000") + } + + @Test + fun testCounterfactualAddress() { + val input = Barz.ContractAddressInput.newBuilder() + input.apply { + factory = "0x2c97f4a366Dd5D91178ec9E36c5C1fcA393A538C" + accountFacet = "0x3322C04EAe11B9b14c6c289f2668b6f07071b591" + verificationFacet = "0x90A6fE0A938B0d4188e9013C99A0d7D9ca6bFB63" + entryPoint = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + facetRegistry = "0xFd1A8170c12747060324D9079a386BD4290e6f93" + defaultFallback = "0x22eB0720d9Fc4bC90BB812B309e939880B71c20d" + bytecode = "0x608060405260405162003cc638038062003cc68339818101604052810190620000299190620019ad565b60008673ffffffffffffffffffffffffffffffffffffffff16633253960f6040518163ffffffff1660e01b81526004016020604051808303816000875af115801562000079573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009f919062001aec565b9050600060e01b817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603620000fe576040517f5a5b4d3900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600267ffffffffffffffff8111156200011e576200011d6200196b565b5b6040519080825280602002602001820160405280156200015b57816020015b62000147620018ff565b8152602001906001900390816200013d5790505b5090506000600167ffffffffffffffff8111156200017e576200017d6200196b565b5b604051908082528060200260200182016040528015620001ad5781602001602082028036833780820191505090505b5090506000600167ffffffffffffffff811115620001d057620001cf6200196b565b5b604051908082528060200260200182016040528015620001ff5781602001602082028036833780820191505090505b509050631f931c1c60e01b8260008151811062000221576200022062001b21565b5b60200260200101907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152505060405180606001604052808d73ffffffffffffffffffffffffffffffffffffffff16815260200160006002811115620002ab57620002aa62001b37565b5b81526020018381525083600081518110620002cb57620002ca62001b21565b5b60200260200101819052508381600081518110620002ee57620002ed62001b21565b5b60200260200101907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152505060405180606001604052808b73ffffffffffffffffffffffffffffffffffffffff1681526020016000600281111562000378576200037762001b37565b5b8152602001828152508360018151811062000398576200039762001b21565b5b6020026020010181905250620003b9846200047e60201b620001671760201c565b6200046c838c8b8e8e8d8d8d8d604051602401620003de979695949392919062001b8c565b6040516020818303038152906040527f95a21aec000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050620004b060201b620001911760201c565b5050505050505050505050506200211f565b806200048f6200073460201b60201c565b60010160016101000a81548163ffffffff021916908360e01c021790555050565b60005b8351811015620006df576000848281518110620004d557620004d462001b21565b5b602002602001015160200151905060006002811115620004fa57620004f962001b37565b5b81600281111562000510576200050f62001b37565b5b0362000570576200056a85838151811062000530576200052f62001b21565b5b60200260200101516000015186848151811062000552576200055162001b21565b5b6020026020010151604001516200073960201b60201c565b620006c8565b6001600281111562000587576200058662001b37565b5b8160028111156200059d576200059c62001b37565b5b03620005fd57620005f7858381518110620005bd57620005bc62001b21565b5b602002602001015160000151868481518110620005df57620005de62001b21565b5b602002602001015160400151620009db60201b60201c565b620006c7565b60028081111562000613576200061262001b37565b5b81600281111562000629576200062862001b37565b5b0362000689576200068385838151811062000649576200064862001b21565b5b6020026020010151600001518684815181106200066b576200066a62001b21565b5b60200260200101516040015162000c8f60201b60201c565b620006c6565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620006bd9062001be7565b60405180910390fd5b5b5b508080620006d69062001c61565b915050620004b3565b507f8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb673838383604051620007159392919062001c82565b60405180910390a16200072f828262000e3760201b60201c565b505050565b600090565b600081511162000780576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620007779062001d97565b60405180910390fd5b60006200079262000f6b60201b60201c565b9050600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160362000806576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620007fd9062001dfb565b60405180910390fd5b60008160010160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000018054905090506000816bffffffffffffffffffffffff16036200087c576200087b828562000f9860201b60201c565b5b60005b8351811015620009d4576000848281518110620008a157620008a062001b21565b5b602002602001015190506000846000016000837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161462000998576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200098f9062001e5f565b60405180910390fd5b620009ac8583868a6200107c60201b60201c565b8380620009b99062001ec3565b94505050508080620009cb9062001c61565b9150506200087f565b5050505050565b600081511162000a22576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040162000a199062001d97565b60405180910390fd5b600062000a3462000f6b60201b60201c565b9050600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160362000aa8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040162000a9f9062001dfb565b60405180910390fd5b60008160010160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000018054905090506000816bffffffffffffffffffffffff160362000b1e5762000b1d828562000f9860201b60201c565b5b60005b835181101562000c8857600084828151811062000b435762000b4262001b21565b5b602002602001015190506000846000016000837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508673ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160362000c39576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040162000c309062001eef565b60405180910390fd5b62000c4c8582846200122960201b60201c565b62000c608583868a6200107c60201b60201c565b838062000c6d9062001ec3565b9450505050808062000c7f9062001c61565b91505062000b21565b5050505050565b600081511162000cd6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040162000ccd9062001d97565b60405180910390fd5b600062000ce862000f6b60201b60201c565b9050600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161462000d5c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040162000d539062001f53565b60405180910390fd5b60005b825181101562000e3157600083828151811062000d815762000d8062001b21565b5b602002602001015190506000836000016000837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905062000e198482846200122960201b60201c565b5050808062000e289062001c61565b91505062000d5f565b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16031562000f675762000e988260405180606001604052806028815260200162003c7a60289139620018aa60201b60201c565b6000808373ffffffffffffffffffffffffffffffffffffffff168360405162000ec2919062001fb7565b600060405180830381855af49150503d806000811462000eff576040519150601f19603f3d011682016040523d82523d6000602084013e62000f04565b606091505b50915091508162000f645760008151111562000f235780518082602001fd5b83836040517f192105d700000000000000000000000000000000000000000000000000000000815260040162000f5b92919062001fd7565b60405180910390fd5b50505b5050565b6000807f183cde5d4f6bb7b445b8fc2f7f15d0fd1d162275aded24183babbffee7cd491f90508091505090565b62000fc38160405180606001604052806024815260200162003ca260249139620018aa60201b60201c565b81600201805490508260010160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001018190555081600201819080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b81846000016000857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060000160146101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508360010160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000018390806001815401808255809150506001900390600052602060002090600891828204019190066004029091909190916101000a81548163ffffffff021916908360e01c021790555080846000016000857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036200129b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620012929062002003565b60405180910390fd5b3073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036200130c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620013039062002067565b60405180910390fd5b6000836000016000837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060000160149054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff169050600060018560010160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000180549050620013e59190620020cb565b9050808214620015805760008560010160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000182815481106200144a576200144962001b21565b5b90600052602060002090600891828204019190066004029054906101000a900460e01b9050808660010160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000018481548110620014c957620014c862001b21565b5b90600052602060002090600891828204019190066004026101000a81548163ffffffff021916908360e01c021790555082866000016000837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060000160146101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550505b8460010160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001805480620015d757620015d6620020ec565b5b60019003818190600052602060002090600891828204019190066004026101000a81549063ffffffff02191690559055846000016000847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600080820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556000820160146101000a8154906bffffffffffffffffffffffff0219169055505060008103620018a357600060018660020180549050620016c49190620020cb565b905060008660010160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001015490508181146200180c57600087600201838154811062001732576200173162001b21565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508088600201838154811062001779576200177862001b21565b5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550818860010160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010181905550505b86600201805480620018235762001822620020ec565b5b6001900381819060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905590558660010160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001016000905550505b5050505050565b6000823b9050600081118290620018f9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620018f0919062002102565b60405180910390fd5b50505050565b6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600060028111156200193e576200193d62001b37565b5b8152602001606081525090565b60008151905060018060a01b03811681146200196657600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620019a157808201518184015260208101905062001984565b50600083830152505050565b600080600080600080600080610100898b031215620019cb57600080fd5b620019d6896200194b565b9750620019e660208a016200194b565b9650620019f660408a016200194b565b955062001a0660608a016200194b565b945062001a1660808a016200194b565b935062001a2660a08a016200194b565b925062001a3660c08a016200194b565b915060e089015160018060401b038082111562001a5257600080fd5b818b0191508b601f83011262001a6757600080fd5b81518181111562001a7d5762001a7c6200196b565b5b601f1960405181603f83601f860116011681019150808210848311171562001aaa5762001aa96200196b565b5b816040528281528e602084870101111562001ac457600080fd5b62001ad783602083016020880162001981565b80955050505050509295985092959890939650565b60006020828403121562001aff57600080fd5b815163ffffffff60e01b8116811462001b1757600080fd5b8091505092915050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b60018060a01b03811682525050565b6000815180845262001b7681602086016020860162001981565b6020601f19601f83011685010191505092915050565b600060018060a01b03808a168352808916602084015280881660408401528087166060840152808616608084015280851660a08401525060e060c083015262001bd960e083018462001b5c565b905098975050505050505050565b60208152602760208201527f4c69624469616d6f6e644375743a20496e636f7272656374204661636574437560408201527f74416374696f6e0000000000000000000000000000000000000000000000000060608201526000608082019050919050565b634e487b7160e01b600052601160045260246000fd5b60008019820362001c775762001c7662001c4b565b5b600182019050919050565b60006060808301818452808751808352608092508286019150828160051b8701016020808b0160005b8481101562001d6357607f198a8503018652815188850160018060a01b038251168652848201516003811062001cf157634e487b7160e01b600052602160045260246000fd5b80868801525060408083015192508a81880152508082518083528a880191508684019350600092505b8083101562001d465763ffffffff60e01b84511682528682019150868401935060018301925062001d1a565b508096505050508282019150828601955060018101905062001cab565b505062001d738189018b62001b4d565b50868103604088015262001d88818962001b5c565b95505050505050949350505050565b60208152602b60208201527f4c69624469616d6f6e644375743a204e6f2073656c6563746f727320696e206660408201527f6163657420746f2063757400000000000000000000000000000000000000000060608201526000608082019050919050565b60208152602c60208201527f4c69624469616d6f6e644375743a204164642066616365742063616e2774206260408201527f652061646472657373283029000000000000000000000000000000000000000060608201526000608082019050919050565b60208152603560208201527f4c69624469616d6f6e644375743a2043616e2774206164642066756e6374696f60408201527f6e207468617420616c726561647920657869737473000000000000000000000060608201526000608082019050919050565b600060018060601b0380831681810362001ee25762001ee162001c4b565b5b6001810192505050919050565b60208152603860208201527f4c69624469616d6f6e644375743a2043616e2774207265706c6163652066756e60408201527f6374696f6e20776974682073616d652066756e6374696f6e000000000000000060608201526000608082019050919050565b60208152603660208201527f4c69624469616d6f6e644375743a2052656d6f7665206661636574206164647260408201527f657373206d75737420626520616464726573732830290000000000000000000060608201526000608082019050919050565b6000825162001fcb81846020870162001981565b80830191505092915050565b60018060a01b038316815260406020820152600062001ffa604083018462001b5c565b90509392505050565b60208152603760208201527f4c69624469616d6f6e644375743a2043616e27742072656d6f76652066756e6360408201527f74696f6e207468617420646f65736e277420657869737400000000000000000060608201526000608082019050919050565b60208152602e60208201527f4c69624469616d6f6e644375743a2043616e27742072656d6f766520696d6d7560408201527f7461626c652066756e6374696f6e00000000000000000000000000000000000060608201526000608082019050919050565b6000828203905081811115620020e657620020e562001c4b565b5b92915050565b634e487b7160e01b600052603160045260246000fd5b60208152600062002117602083018462001b5c565b905092915050565b611b4b806200212f6000396000f3fe60806040523661000b57005b6000807f183cde5d4f6bb7b445b8fc2f7f15d0fd1d162275aded24183babbffee7cd491f9050809150600082600001600080357fffffffff00000000000000000000000000000000000000000000000000000000167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610141576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610138906114d3565b60405180910390fd5b3660008037600080366000845af43d6000803e8060008114610162573d6000f35b3d6000fd5b806101706103c0565b60010160016101000a81548163ffffffff021916908360e01c021790555050565b60005b83518110156103755760008482815181106101b2576101b1611510565b5b6020026020010151602001519050600060028111156101d4576101d3611526565b5b8160028111156101e7576101e6611526565b5b036102375761023285838151811061020257610201611510565b5b60200260200101516000015186848151811061022157610220611510565b5b6020026020010151604001516103c5565b610361565b6001600281111561024b5761024a611526565b5b81600281111561025e5761025d611526565b5b036102ae576102a985838151811061027957610278611510565b5b60200260200101516000015186848151811061029857610297611510565b5b60200260200101516040015161063c565b610360565b6002808111156102c1576102c0611526565b5b8160028111156102d4576102d3611526565b5b036103245761031f8583815181106102ef576102ee611510565b5b60200260200101516000015186848151811061030e5761030d611510565b5b6020026020010151604001516108bd565b61035f565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103569061153c565b60405180910390fd5b5b5b50808061036d906115b6565b915050610194565b507f8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb6738383836040516103a99392919061163b565b60405180910390a16103bb8282610a48565b505050565b600090565b6000815111610409576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161040090611747565b60405180910390fd5b6000610413610b6a565b9050600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610484576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161047b906117ab565b60405180910390fd5b60008160010160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000018054905090506000816bffffffffffffffffffffffff16036104f1576104f08285610b97565b5b60005b835181101561063557600084828151811061051257610511611510565b5b602002602001015190506000846000016000837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610606576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105fd9061180f565b60405180910390fd5b6106128583868a610c72565b838061061d90611873565b9450505050808061062d906115b6565b9150506104f4565b5050505050565b6000815111610680576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161067790611747565b60405180910390fd5b600061068a610b6a565b9050600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036106fb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106f2906117ab565b60405180910390fd5b60008160010160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000018054905090506000816bffffffffffffffffffffffff1603610768576107678285610b97565b5b60005b83518110156108b657600084828151811061078957610788611510565b5b602002602001015190506000846000016000837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508673ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361087c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610873906118a2565b60405180910390fd5b610887858284610e1f565b6108938583868a610c72565b838061089e90611873565b945050505080806108ae906115b6565b91505061076b565b5050505050565b6000815111610901576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108f890611747565b60405180910390fd5b600061090b610b6a565b9050600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161461097c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161097390611906565b60405180910390fd5b60005b8251811015610a4257600083828151811061099d5761099c611510565b5b602002602001015190506000836000016000837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050610a2d848284610e1f565b50508080610a3a906115b6565b91505061097f565b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160315610b6657610a9f82604051806060016040528060288152602001611aca60289139611481565b6000808373ffffffffffffffffffffffffffffffffffffffff1683604051610ac7919061196a565b600060405180830381855af49150503d8060008114610b02576040519150601f19603f3d011682016040523d82523d6000602084013e610b07565b606091505b509150915081610b6357600081511115610b245780518082602001fd5b83836040517f192105d7000000000000000000000000000000000000000000000000000000008152600401610b5a929190611988565b60405180910390fd5b50505b5050565b6000807f183cde5d4f6bb7b445b8fc2f7f15d0fd1d162275aded24183babbffee7cd491f90508091505090565b610bb981604051806060016040528060248152602001611af260249139611481565b81600201805490508260010160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001018190555081600201819080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b81846000016000857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060000160146101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508360010160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000018390806001815401808255809150506001900390600052602060002090600891828204019190066004029091909190916101000a81548163ffffffff021916908360e01c021790555080846000016000857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610e8e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e85906119b2565b60405180910390fd5b3073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610efc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ef390611a16565b60405180910390fd5b6000836000016000837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060000160149054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff169050600060018560010160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000180549050610fd39190611a7a565b90508082146111675760008560010160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001828154811061103457611033611510565b5b90600052602060002090600891828204019190066004029054906101000a900460e01b9050808660010160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000184815481106110b0576110af611510565b5b90600052602060002090600891828204019190066004026101000a81548163ffffffff021916908360e01c021790555082866000016000837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060000160146101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550505b8460010160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000018054806111bb576111ba611a98565b5b60019003818190600052602060002090600891828204019190066004026101000a81549063ffffffff02191690559055846000016000847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600080820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556000820160146101000a8154906bffffffffffffffffffffffff021916905550506000810361147a576000600186600201805490506112a59190611a7a565b905060008660010160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001015490508181146113e657600087600201838154811061130f5761130e611510565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508088600201838154811061135357611352611510565b5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550818860010160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010181905550505b866002018054806113fa576113f9611a98565b5b6001900381819060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905590558660010160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001016000905550505b5050505050565b6000823b90506000811182906114cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114c49190611aae565b60405180910390fd5b50505050565b602081526020808201527f4469616d6f6e643a2046756e6374696f6e20646f6573206e6f7420657869737460408201526000606082019050919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b60208152602760208201527f4c69624469616d6f6e644375743a20496e636f7272656374204661636574437560408201527f74416374696f6e0000000000000000000000000000000000000000000000000060608201526000608082019050919050565b634e487b7160e01b600052601160045260246000fd5b6000801982036115c9576115c86115a0565b5b600182019050919050565b60018060a01b03811682525050565b60005b838110156116015780820151818401526020810190506115e6565b50600083830152505050565b600081518084526116258160208601602086016115e3565b6020601f19601f83011685010191505092915050565b60006060808301818452808751808352608092508286019150828160051b8701016020808b0160005b8481101561171757607f198a8503018652815188850160018060a01b03825116865284820151600381106116a857634e487b7160e01b600052602160045260246000fd5b80868801525060408083015192508a81880152508082518083528a880191508684019350600092505b808310156116fb5763ffffffff60e01b8451168252868201915086840193506001830192506116d1565b5080965050505082820191508286019550600181019050611664565b50506117258189018b6115d4565b508681036040880152611738818961160d565b95505050505050949350505050565b60208152602b60208201527f4c69624469616d6f6e644375743a204e6f2073656c6563746f727320696e206660408201527f6163657420746f2063757400000000000000000000000000000000000000000060608201526000608082019050919050565b60208152602c60208201527f4c69624469616d6f6e644375743a204164642066616365742063616e2774206260408201527f652061646472657373283029000000000000000000000000000000000000000060608201526000608082019050919050565b60208152603560208201527f4c69624469616d6f6e644375743a2043616e2774206164642066756e6374696f60408201527f6e207468617420616c726561647920657869737473000000000000000000000060608201526000608082019050919050565b60006bffffffffffffffffffffffff808316818103611895576118946115a0565b5b6001810192505050919050565b60208152603860208201527f4c69624469616d6f6e644375743a2043616e2774207265706c6163652066756e60408201527f6374696f6e20776974682073616d652066756e6374696f6e000000000000000060608201526000608082019050919050565b60208152603660208201527f4c69624469616d6f6e644375743a2052656d6f7665206661636574206164647260408201527f657373206d75737420626520616464726573732830290000000000000000000060608201526000608082019050919050565b6000825161197c8184602087016115e3565b80830191505092915050565b60018060a01b03831681526040602082015260006119a9604083018461160d565b90509392505050565b60208152603760208201527f4c69624469616d6f6e644375743a2043616e27742072656d6f76652066756e6360408201527f74696f6e207468617420646f65736e277420657869737400000000000000000060608201526000608082019050919050565b60208152602e60208201527f4c69624469616d6f6e644375743a2043616e27742072656d6f766520696d6d7560408201527f7461626c652066756e6374696f6e00000000000000000000000000000000000060608201526000608082019050919050565b6000828203905081811115611a9257611a916115a0565b5b92915050565b634e487b7160e01b600052603160045260246000fd5b602081526000611ac1602083018461160d565b90509291505056fe4c69624469616d6f6e644375743a205f696e6974206164647265737320686173206e6f20636f64654c69624469616d6f6e644375743a204e657720666163657420686173206e6f20636f6465a264697066735822122045b771fb2128a1a34c5b052e9a86464933844b34929cf0d65bbea6a4e76e3b2764736f6c634300081200334c69624469616d6f6e644375743a205f696e6974206164647265737320686173206e6f20636f64654c69624469616d6f6e644375743a204e657720666163657420686173206e6f20636f6465" + publicKey = "0xB5547FBdC56DCE45e1B8ef75569916D438e09c46" + } + val result = WCBarz.getCounterfactualAddress(input.build().toByteArray()) + assertEquals(result, "0x77F62bb3E43190253D4E198199356CD2b25063cA") + } + + @Test + fun testCounterfactualAddressNonZeroSalt() { + val input = Barz.ContractAddressInput.newBuilder() + input.apply { + factory = "0x96C489979E39F877BDb8637b75A25C1a5B2DE14C" + accountFacet = "0xF6F5e5fC74905e65e3FF53c6BacEba8535dd14d1" + verificationFacet = "0xaB84813cbf26Fd951CB3d7E33Dccb8995027e490" + entryPoint = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + facetRegistry = "0x9a95d201BB8F559771784D12c01F8084278c65E5" + defaultFallback = "0x522cDc7558b5f798dF5D61AB09B6D95Ebd342EF9" + bytecode = "0x60806040526040516104c83803806104c883398101604081905261002291610163565b6000858585858560405160240161003d959493929190610264565b60408051601f198184030181529181526020820180516001600160e01b0316634a93641760e01b1790525190915060009081906001600160a01b038a16906100869085906102c3565b600060405180830381855af49150503d80600081146100c1576040519150601f19603f3d011682016040523d82523d6000602084013e6100c6565b606091505b50915091508115806100e157506100dc816102df565b600114155b156100ff57604051636ff35f8960e01b815260040160405180910390fd5b505050505050505050610306565b80516001600160a01b038116811461012457600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561015a578181015183820152602001610142565b50506000910152565b60008060008060008060c0878903121561017c57600080fd5b6101858761010d565b95506101936020880161010d565b94506101a16040880161010d565b93506101af6060880161010d565b92506101bd6080880161010d565b60a08801519092506001600160401b03808211156101da57600080fd5b818901915089601f8301126101ee57600080fd5b81518181111561020057610200610129565b604051601f8201601f19908116603f0116810190838211818310171561022857610228610129565b816040528281528c602084870101111561024157600080fd5b61025283602083016020880161013f565b80955050505050509295509295509295565b600060018060a01b0380881683528087166020840152808616604084015280851660608401525060a0608083015282518060a08401526102ab8160c085016020870161013f565b601f01601f19169190910160c0019695505050505050565b600082516102d581846020870161013f565b9190910192915050565b80516020808301519190811015610300576000198160200360031b1b821691505b50919050565b6101b3806103156000396000f3fe60806040523661000b57005b600080356001600160e01b03191681527f183cde5d4f6bb7b445b8fc2f7f15d0fd1d162275aded24183babbffee7cd491f6020819052604090912054819060601c806100cf576004838101546040516366ffd66360e11b81526000356001600160e01b031916928101929092526001600160a01b03169063cdffacc690602401602060405180830381865afa1580156100a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100cc919061014d565b90505b6001600160a01b0381166101295760405162461bcd60e51b815260206004820152601d60248201527f4261727a3a2046756e6374696f6e20646f6573206e6f74206578697374000000604482015260640160405180910390fd5b3660008037600080366000845af43d6000803e808015610148573d6000f35b3d6000fd5b60006020828403121561015f57600080fd5b81516001600160a01b038116811461017657600080fd5b939250505056fea2646970667358221220d35db061bb6ecdb7688c3674af669ce44d527cae4ded59214d06722d73da62be64736f6c63430008120033" + publicKey = "0xB5547FBdC56DCE45e1B8ef75569916D438e09c46" + salt = 123456 + } + val result = WCBarz.getCounterfactualAddress(input.build().toByteArray()) + assertEquals(result, "0xB91aaa96B138A1B1D94c9df4628187132c5F2bf1") + } + + @Test + fun testGetFormattedSignature() { + val signature = Numeric.hexStringToByteArray("0x3044022012d89e3b41e253dc9e90bd34dc1750d059b76d0b1d16af2059aa26e90b8960bf0220256d8a05572c654906ce422464693e280e243e6d9dbc5f96a681dba846bca276") + val challenge = Numeric.hexStringToByteArray("0xcf267a78c5adaf96f341a696eb576824284c572f3e61be619694d539db1925f9") + val authenticatorData = Numeric.hexStringToByteArray("0x1a70842af8c1feb7133b81e6a160a6a2be45ee057f0eb6d3f7f5126daa202e071d00000000") + val clientDataJSON = "{\"type\":\"webauthn.get\",\"challenge\":\"zyZ6eMWtr5bzQaaW61doJChMVy8-Yb5hlpTVOdsZJfk\",\"origin\":\"https://trustwallet.com\"}" + val result = WCBarz.getFormattedSignature(signature, challenge, authenticatorData, clientDataJSON) + assertEquals(Numeric.toHexString(result), "0x12d89e3b41e253dc9e90bd34dc1750d059b76d0b1d16af2059aa26e90b8960bf256d8a05572c654906ce422464693e280e243e6d9dbc5f96a681dba846bca27600000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000251a70842af8c1feb7133b81e6a160a6a2be45ee057f0eb6d3f7f5126daa202e071d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000247b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025222c226f726967696e223a2268747470733a2f2f747275737477616c6c65742e636f6d227d000000000000000000000000000000000000000000000000000000") + } + + // https://testnet.bscscan.com/tx/0x43fc13dfdf06bbb09da8ce070953753764f1e43782d0c8b621946d8b45749419 + @Test + fun testSignK1TransferAccountDeployed() { + val signingInput = Ethereum.SigningInput.newBuilder() + signingInput.apply { + privateKey = ByteString.copyFrom(PrivateKey("3c90badc15c4d35733769093d3733501e92e7f16e101df284cee9a310d36c483".toHexByteArray()).data()) + chainId = ByteString.copyFrom("0x61".toHexByteArray()) + nonce = ByteString.copyFrom("0x2".toHexByteArray()) + toAddress = "0x61061fCAE11fD5461535e134EfF67A98CFFF44E9" + txMode = TransactionMode.UserOp + + gasLimit = ByteString.copyFrom("0x0186A0".toHexByteArray()) + maxFeePerGas = ByteString.copyFrom("0x01a339c9e9".toHexByteArray()) + maxInclusionFeePerGas = ByteString.copyFrom("0x01a339c9e9".toHexByteArray()) + + userOperation = Ethereum.UserOperation.newBuilder().apply { + entryPoint = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + sender = "0xb16Db98B365B1f89191996942612B14F1Da4Bd5f" + preVerificationGas = ByteString.copyFrom("0xb708".toHexByteArray()) + verificationGasLimit = ByteString.copyFrom("0x0186a0".toHexByteArray()) + }.build() + + transaction = Ethereum.Transaction.newBuilder().apply { + transfer = Ethereum.Transaction.Transfer.newBuilder().apply { + amount = ByteString.copyFrom("0x2386f26fc10000".toHexByteArray()) + }.build() + }.build() + } + + val output = AnySigner.sign(signingInput.build(), ETHEREUM, SigningOutput.parser()) + + assertEquals(Numeric.toHexString(output.preHash.toByteArray()), "0x2d37191a8688f69090451ed90a0a9ba69d652c2062ee9d023b3ebe964a3ed2ae"); + + assertEquals(output.encoded.toStringUtf8(), "{\"callData\":\"0xb61d27f600000000000000000000000061061fcae11fd5461535e134eff67a98cfff44e9000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"100000\",\"initCode\":\"0x\",\"maxFeePerGas\":\"7033440745\",\"maxPriorityFeePerGas\":\"7033440745\",\"nonce\":\"2\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"46856\",\"sender\":\"0xb16Db98B365B1f89191996942612B14F1Da4Bd5f\",\"signature\":\"0x80e84992ebf8d5f71180231163ed150a7557ed0aa4b4bcee23d463a09847e4642d0fbf112df2e5fa067adf4b2fa17fc4a8ac172134ba5b78e3ec9c044e7f28d71c\",\"verificationGasLimit\":\"100000\"}"); + } + + // https://testnet.bscscan.com/tx/0xea1f5cddc0653e116327cbcb3bc770360a642891176eff2ec69c227e46791c31 + @Test + fun testSignR1TransferAccountNotDeployed() { + val factoryAddress = "0x3fC708630d85A3B5ec217E53100eC2b735d4f800" + val attestationObject = "0xa363666d74646e6f6e656761747453746d74a068617574684461746158981a70842af8c1feb7133b81e6a160a6a2be45ee057f0eb6d3f7f5126daa202e075d00000000000000000000000000000000000000000014c14f8a2dfd8f451581fad6e4e1c11821abcaacd6a5010203262001215820b173a6a812025c40c38bac46343646bd0a8137c807aae6e04aac238cc24d2ad2225820116ca14d23d357588ff2aabd7db29d5976f4ecc8037775db86f67e873a306b1f" + val verificationFacet = "0x5034534Efe9902779eD6eA6983F435c00f3bc510" + val publicKey = WebAuthn.getPublicKey(attestationObject.toHexByteArray()) + + val signingInput = Ethereum.SigningInput.newBuilder() + signingInput.apply { + privateKey = ByteString.copyFrom(PrivateKey("3c90badc15c4d35733769093d3733501e92e7f16e101df284cee9a310d36c483".toHexByteArray()).data()) + chainId = ByteString.copyFrom("0x61".toHexByteArray()) + nonce = ByteString.copyFrom("0x00".toHexByteArray()) + toAddress = "0x61061fCAE11fD5461535e134EfF67A98CFFF44E9" + txMode = TransactionMode.UserOp + + gasLimit = ByteString.copyFrom("0x2625A0".toHexByteArray()) + maxFeePerGas = ByteString.copyFrom("0x01a339c9e9".toHexByteArray()) + maxInclusionFeePerGas = ByteString.copyFrom("0x01a339c9e9".toHexByteArray()) + + userOperation = Ethereum.UserOperation.newBuilder().apply { + entryPoint = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + sender = "0x1392Ae041BfBdBAA0cFF9234a0C8F64df97B7218" + preVerificationGas = ByteString.copyFrom("0xb708".toHexByteArray()) + verificationGasLimit = ByteString.copyFrom("0x2DC6C0".toHexByteArray()) + initCode = ByteString.copyFrom(WCBarz.getInitCode(factoryAddress, publicKey, verificationFacet, 0)) + }.build() + + transaction = Ethereum.Transaction.newBuilder().apply { + transfer = Ethereum.Transaction.Transfer.newBuilder().apply { + amount = ByteString.copyFrom("0x2386f26fc10000".toHexByteArray()) + }.build() + }.build() + } + + val output = AnySigner.sign(signingInput.build(), ETHEREUM, SigningOutput.parser()) + + assertEquals(Numeric.toHexString(output.preHash.toByteArray()), "0x548c13a0bb87981d04a3a24a78ad5e4ba8d0afbf3cfe9311250e07b54cd38937"); + + assertEquals(output.encoded.toStringUtf8(), "{\"callData\":\"0xb61d27f600000000000000000000000061061fcae11fd5461535e134eff67a98cfff44e9000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"2500000\",\"initCode\":\"0x3fc708630d85a3b5ec217e53100ec2b735d4f800296601cd0000000000000000000000005034534efe9902779ed6ea6983f435c00f3bc51000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004104b173a6a812025c40c38bac46343646bd0a8137c807aae6e04aac238cc24d2ad2116ca14d23d357588ff2aabd7db29d5976f4ecc8037775db86f67e873a306b1f00000000000000000000000000000000000000000000000000000000000000\",\"maxFeePerGas\":\"7033440745\",\"maxPriorityFeePerGas\":\"7033440745\",\"nonce\":\"0\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"46856\",\"sender\":\"0x1392Ae041BfBdBAA0cFF9234a0C8F64df97B7218\",\"signature\":\"0xbf1b68323974e71ad9bd6dfdac07dc062599d150615419bb7876740d2bcf3c8909aa7e627bb0e08a2eab930e2e7313247c9b683c884236dd6ea0b6834fb2cb0a1b\",\"verificationGasLimit\":\"3000000\"}") + } + + // https://testnet.bscscan.com/tx/0x872f709815a9f79623a349f2f16d93b52c4d5136967bab53a586f045edbe9203 + @Test + fun testSignR1BatchedTransferAccountDeployed() { + val approveFunc = EthereumAbiFunction("approve") + approveFunc.addParamAddress("0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789".toHexByteArray(), false) + approveFunc.addParamUInt256("0x8AC7230489E80000".toHexByteArray(), false) + val approveCall = EthereumAbi.encode(approveFunc) + + val transferFunc = EthereumAbiFunction("transfer") + transferFunc.addParamAddress("0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789".toHexByteArray(), false) + transferFunc.addParamUInt256("0x8AC7230489E80000".toHexByteArray(), false) + val transferCall = EthereumAbi.encode(transferFunc) + + val signingInput = Ethereum.SigningInput.newBuilder() + signingInput.apply { + privateKey = ByteString.copyFrom(PrivateKey("3c90badc15c4d35733769093d3733501e92e7f16e101df284cee9a310d36c483".toHexByteArray()).data()) + chainId = ByteString.copyFrom("0x61".toHexByteArray()) + nonce = ByteString.copyFrom("0x03".toHexByteArray()) + txMode = TransactionMode.UserOp + + gasLimit = ByteString.copyFrom("0x015A61".toHexByteArray()) + maxFeePerGas = ByteString.copyFrom("0x02540BE400".toHexByteArray()) + maxInclusionFeePerGas = ByteString.copyFrom("0x02540BE400".toHexByteArray()) + + userOperation = Ethereum.UserOperation.newBuilder().apply { + entryPoint = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + sender = "0x1e6c542ebc7c960c6a155a9094db838cef842cf5" + preVerificationGas = ByteString.copyFrom("0xDAFC".toHexByteArray()) + verificationGasLimit = ByteString.copyFrom("0x07F7C4".toHexByteArray()) + }.build() + + transaction = Ethereum.Transaction.newBuilder().apply { + batch = Ethereum.Transaction.Batch.newBuilder().apply { + addAllCalls(listOf( + Ethereum.Transaction.Batch.BatchedCall.newBuilder().apply { + address = "0x03bBb5660B8687C2aa453A0e42dCb6e0732b1266" + amount = ByteString.copyFrom("0x00".toHexByteArray()) + payload = ByteString.copyFrom(approveCall) + }.build(), + Ethereum.Transaction.Batch.BatchedCall.newBuilder().apply { + address = "0x03bBb5660B8687C2aa453A0e42dCb6e0732b1266" + amount = ByteString.copyFrom("0x00".toHexByteArray()) + payload = ByteString.copyFrom(transferCall) + }.build() + )) + }.build() + }.build() + } + + val output = AnySigner.sign(signingInput.build(), ETHEREUM, SigningOutput.parser()) + + assertEquals(Numeric.toHexString(output.preHash.toByteArray()), "0x84d0464f5a2b191e06295443970ecdcd2d18f565d0d52b5a79443192153770ab"); + assertEquals(output.encoded.toStringUtf8(), "{\"callData\":\"0x47e1da2a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000003bbb5660b8687c2aa453a0e42dcb6e0732b126600000000000000000000000003bbb5660b8687c2aa453a0e42dcb6e0732b12660000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000044095ea7b30000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d27890000000000000000000000000000000000000000000000008ac7230489e80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044a9059cbb0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d27890000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"88673\",\"initCode\":\"0x\",\"maxFeePerGas\":\"10000000000\",\"maxPriorityFeePerGas\":\"10000000000\",\"nonce\":\"3\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"56060\",\"sender\":\"0x1E6c542ebC7c960c6A155A9094DB838cEf842cf5\",\"signature\":\"0x0747b665fe9f3a52407f95a35ac3e76de37c9b89483ae440431244e89a77985f47df712c7364c1a299a5ef62d0b79a2cf4ed63d01772275dd61f72bd1ad5afce1c\",\"verificationGasLimit\":\"522180\"}") + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAbi.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAbi.kt index 1edb4127f62..b6ad3654115 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAbi.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAbi.kt @@ -1,10 +1,12 @@ package com.trustwallet.core.app.blockchains.ethereum +import com.google.protobuf.ByteString import com.trustwallet.core.app.utils.toHexByteArray import org.junit.Assert.assertEquals import org.junit.Test import com.trustwallet.core.app.utils.Numeric -import wallet.core.jni.EthereumAbi +import wallet.core.jni.CoinType +import wallet.core.jni.proto.EthereumAbi class TestEthereumAbiDecoder { @@ -35,15 +37,15 @@ class TestEthereumAbiDecoder { } """.trimIndent() - val decoded = EthereumAbi.decodeCall(call, abi) - val expected = """{"function":"approve(address,uint256)","inputs":[{"name":"_spender","type":"address","value":"0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed"},{"name":"_value","type":"uint256","value":"1"}]}""" + val decoded = wallet.core.jni.EthereumAbi.decodeCall(call, abi) + val expected = """{"function":"approve(address,uint256)","inputs":[{"name":"_spender","type":"address","value":"0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"},{"name":"_value","type":"uint256","value":"1"}]}""" assertEquals(decoded, expected) } @Test fun testEthereumAbiEncodeTyped() { - val hash = EthereumAbi.encodeTyped( + val hash = wallet.core.jni.EthereumAbi.encodeTyped( """ { "types": { @@ -94,4 +96,117 @@ class TestEthereumAbiDecoder { """) assertEquals(Numeric.toHexString(hash), "0xa85c2e2b118698e88db68a8105b794a8cc7cec074e89ef991cb4f5f533819cc2") } + + @Test + fun testEthereumAbiEncodeFunction() { + val amountIn = EthereumAbi.NumberNParam.newBuilder().apply { + bits = 256 + value = ByteString.copyFrom(Numeric.hexStringToByteArray("0xde0b6b3a7640000")) // 1000000000000000000 + } + val amountOutMin = EthereumAbi.NumberNParam.newBuilder().apply { + bits = 256 + value = ByteString.copyFrom(Numeric.hexStringToByteArray("0x229f7e501ad62bdb")) // 2494851601099271131 + } + val deadline = EthereumAbi.NumberNParam.newBuilder().apply { + bits = 256 + value = ByteString.copyFrom(Numeric.hexStringToByteArray("0x5f0ed070")) // 1594806384 + } + val addressType = EthereumAbi.AddressType.newBuilder().build() + + val encodingInput = EthereumAbi.FunctionEncodingInput.newBuilder() + .setFunctionName("swapExactTokensForTokens") + .addTokens(EthereumAbi.Token.newBuilder().setNumberUint(amountIn)) + .addTokens(EthereumAbi.Token.newBuilder().setNumberUint(amountOutMin)) + .addTokens(EthereumAbi.Token.newBuilder().apply { + array = EthereumAbi.ArrayParam.newBuilder() + .setElementType(EthereumAbi.ParamType.newBuilder().setAddress(addressType)) + .addElements(EthereumAbi.Token.newBuilder().setAddress("0x6B175474E89094C44Da98b954EedeAC495271d0F")) + .addElements(EthereumAbi.Token.newBuilder().setAddress("0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2")) + .addElements(EthereumAbi.Token.newBuilder().setAddress("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")) + .addElements(EthereumAbi.Token.newBuilder().setAddress("0xE41d2489571d322189246DaFA5ebDe1F4699F498")) + .build() + }) + .addTokens(EthereumAbi.Token.newBuilder().setAddress("0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1")) + .addTokens(EthereumAbi.Token.newBuilder().setNumberUint(deadline)) + .build() + + val encodingOutputData = wallet.core.jni.EthereumAbi.encodeFunction(CoinType.ETHEREUM, encodingInput.toByteArray()) + val encodingOutput = EthereumAbi.FunctionEncodingOutput.parseFrom(encodingOutputData) + + assertEquals(encodingOutput.error, EthereumAbi.AbiError.OK) + assertEquals(encodingOutput.functionType, "swapExactTokensForTokens(uint256,uint256,address[],address,uint256)") + + val expectedEncoded = ByteString.copyFrom(Numeric.hexStringToByteArray("0x38ed17390000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000229f7e501ad62bdb00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000007d8bf18c7ce84b3e175b339c4ca93aed1dd166f1000000000000000000000000000000000000000000000000000000005f0ed07000000000000000000000000000000000000000000000000000000000000000040000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000009f8f72aa9304c8b593d555f12ef6589cc3a579a2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498")) + assertEquals(encodingOutput.encoded, expectedEncoded) + } + + @Test + fun testEthereumAbiDecodeParams() { + val encoded = ByteString.copyFrom(Numeric.hexStringToByteArray("00000000000000000000000088341d1a8f672d2780c8dc725902aae72f143b0c0000000000000000000000000000000000000000000000000000000000000001")) + + val addressType = EthereumAbi.AddressType.newBuilder().build() + val boolType = EthereumAbi.BoolType.newBuilder().build() + + val params = EthereumAbi.AbiParams.newBuilder() + .addParams(EthereumAbi.Param.newBuilder().apply { + name = "to" + param = EthereumAbi.ParamType.newBuilder().setAddress(addressType).build() + }) + .addParams(EthereumAbi.Param.newBuilder().apply { + name = "approved" + param = EthereumAbi.ParamType.newBuilder().setBoolean(boolType).build() + }) + val decodingInput = EthereumAbi.ParamsDecodingInput.newBuilder() + .setEncoded(encoded) + .setAbiParams(params) + .build() + + val decodingOutputData = wallet.core.jni.EthereumAbi.decodeParams(CoinType.ETHEREUM, decodingInput.toByteArray()) + val decodingOutput = EthereumAbi.ParamsDecodingOutput.parseFrom(decodingOutputData) + + assertEquals(decodingOutput.error, EthereumAbi.AbiError.OK) + + assertEquals(decodingOutput.getTokens(0).name, "to") + assertEquals(decodingOutput.getTokens(0).address, "0x88341d1a8F672D2780C8dC725902AAe72F143B0c") + + assertEquals(decodingOutput.getTokens(1).name, "approved") + assertEquals(decodingOutput.getTokens(1).boolean, true) + } + + @Test + fun testEthereumAbiDecodeValue() { + val encoded = ByteString.copyFrom(Numeric.hexStringToByteArray("000000000000000000000000000000000000000000000000000000000000002c48656c6c6f20576f726c64212020202048656c6c6f20576f726c64212020202048656c6c6f20576f726c64210000000000000000000000000000000000000000")) + + val decodingInput = EthereumAbi.ValueDecodingInput.newBuilder() + .setEncoded(encoded) + .setParamType("string") + .build() + + val decodingOutputData = wallet.core.jni.EthereumAbi.decodeValue(CoinType.ETHEREUM, decodingInput.toByteArray()) + val decodingOutput = EthereumAbi.ValueDecodingOutput.parseFrom(decodingOutputData) + + assertEquals(decodingOutput.error, EthereumAbi.AbiError.OK) + assertEquals(decodingOutput.token.stringValue, "Hello World! Hello World! Hello World!") + } + + @Test + fun testEthereumAbiDecodeContractCall() { + val encoded = ByteString.copyFrom(Numeric.hexStringToByteArray("c47f0027000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000086465616462656566000000000000000000000000000000000000000000000000")) + val abi = """{"c47f0027":{"constant":false,"inputs":[{"name":"name","type":"string"}],"name":"setName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}}""" + val decodingInput = EthereumAbi.ContractCallDecodingInput.newBuilder() + .setEncoded(encoded) + .setSmartContractAbiJson(abi) + .build() + + val decodingOutputData = wallet.core.jni.EthereumAbi.decodeContractCall(CoinType.ETHEREUM, decodingInput.toByteArray()) + val decodingOutput = EthereumAbi.ContractCallDecodingOutput.parseFrom(decodingOutputData) + + assertEquals(decodingOutput.error, EthereumAbi.AbiError.OK) + + val expectedJson = """{"function":"setName(string)","inputs":[{"name":"name","type":"string","value":"deadbeef"}]}""" + assertEquals(decodingOutput.decodedJson, expectedJson) + + assertEquals(decodingOutput.getTokens(0).name, "name") + assertEquals(decodingOutput.getTokens(0).stringValue, "deadbeef") + } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAbiValue.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAbiValue.kt index 02a2680b3e5..5afd77932f9 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAbiValue.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAbiValue.kt @@ -87,7 +87,7 @@ class TestEthereumAbiValue { fun testValueDecoderValue() { assertEquals("42", EthereumAbiValue.decodeValue(Numeric.hexStringToByteArray("000000000000000000000000000000000000000000000000000000000000002a"), "uint")) assertEquals("24", EthereumAbiValue.decodeValue(Numeric.hexStringToByteArray("0000000000000000000000000000000000000000000000000000000000000018"), "uint8")) - assertEquals("0xf784682c82526e245f50975190ef0fff4e4fc077", EthereumAbiValue.decodeValue(Numeric.hexStringToByteArray("000000000000000000000000f784682c82526e245f50975190ef0fff4e4fc077"), "address")) + assertEquals("0xF784682C82526e245F50975190EF0fff4E4fC077", EthereumAbiValue.decodeValue(Numeric.hexStringToByteArray("000000000000000000000000f784682c82526e245f50975190ef0fff4e4fc077"), "address")) assertEquals("Hello World! Hello World! Hello World!", EthereumAbiValue.decodeValue( Numeric.hexStringToByteArray("000000000000000000000000000000000000000000000000000000000000002c48656c6c6f20576f726c64212020202048656c6c6f20576f726c64212020202048656c6c6f20576f726c64210000000000000000000000000000000000000000"), "string")) @@ -103,7 +103,7 @@ class TestEthereumAbiValue { @Test fun testValueDecoderArray_address() { val input = Numeric.hexStringToByteArray("0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000f784682c82526e245f50975190ef0fff4e4fc0770000000000000000000000002e00cd222cb42b616d86d037cc494e8ab7f5c9a3") - assertEquals("[\"0xf784682c82526e245f50975190ef0fff4e4fc077\",\"0x2e00cd222cb42b616d86d037cc494e8ab7f5c9a3\"]", EthereumAbiValue.decodeArray(input, "address[]")) + assertEquals("[\"0xF784682C82526e245F50975190EF0fff4E4fC077\",\"0x2e00CD222Cb42B616D86D037Cc494e8ab7F5c9a3\"]", EthereumAbiValue.decodeArray(input, "address[]")) } @Test diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAddress.kt index f4b29c5db5d..86f725fdd2e 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAddress.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAddress.kt @@ -1,10 +1,13 @@ package com.trustwallet.core.app.blockchains.ethereum +import com.trustwallet.core.app.utils.Numeric import org.junit.Assert.assertEquals import org.junit.Test import wallet.core.jni.AnyAddress import wallet.core.jni.CoinType import org.junit.Assert.assertFalse +import wallet.core.jni.Ethereum +import wallet.core.jni.Hash class TestEthereumAddress { diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumMessageSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumMessageSigner.kt new file mode 100644 index 00000000000..6245751d124 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumMessageSigner.kt @@ -0,0 +1,134 @@ +package com.trustwallet.core.app.blockchains.ethereum + +import com.trustwallet.core.app.utils.Numeric +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test +import wallet.core.jni.CoinType +import wallet.core.jni.EthereumMessageSigner +import wallet.core.jni.PrivateKey + +class TestEthereumMessageSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testEthereumSignAndVerifyMessageImmutableX() { + val data = Numeric.hexStringToByteArray("3b0a61f46fdae924007146eacb6db6642de7a5603ad843ec58e10331d89d4b84") + val privateKey = PrivateKey(data) + val publicKey = privateKey.getPublicKey(CoinType.ETHEREUM) + val msg = "Only sign this request if you’ve initiated an action with Immutable X.\n\nFor internal use:\nbd717ba31dca6e0f3f136f7c4197babce5f09a9f25176044c0b3112b1b6017a3" + val signature = EthereumMessageSigner.signMessageImmutableX(privateKey, msg) + assertEquals(signature, "32cd5a58f3419fc5db672e3d57f76199b853eda0856d491b38f557b629b0a0814ace689412bf354a1af81126d2749207dffae8ae8845160f33948a6b787e17ee01"); + assertTrue(EthereumMessageSigner.verifyMessage(publicKey, msg, signature)) + } + + @Test + fun testEthereumSignAndVerifyMessageLegacy() { + val data = Numeric.hexStringToByteArray("03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d") + val privateKey = PrivateKey(data) + val publicKey = privateKey.getPublicKey(CoinType.ETHEREUM) + val msg = "Foo" + val signature = EthereumMessageSigner.signMessage(privateKey, msg) + assertEquals(signature, "21a779d499957e7fd39392d49a079679009e60e492d9654a148829be43d2490736ec72bc4a5644047d979c3cf4ebe2c1c514044cf436b063cb89fc6676be71101b"); + assertTrue(EthereumMessageSigner.verifyMessage(publicKey, msg, signature)) + } + + @Test + fun testEthereumSignAndVerifyMessageLegacyHex() { + val data = Numeric.hexStringToByteArray("9066aa168c379a403becb235c15e7129c133c244e56a757ab07bc369288bcab0") + val privateKey = PrivateKey(data) + val publicKey = privateKey.getPublicKey(CoinType.ETHEREUM) + val msg = "0xc0a96273d5c3fbe4d4000491f08daef9c17f88df846c1d6f57eb5f33c1fbd035" + val signature = EthereumMessageSigner.signMessage(privateKey, msg) + assertEquals(signature, "b18a666ad08bf9bfcd39920b26b5a5d1486b67b45119810b3c7bda22e41e5c4c1bfbe0c932f6c14df4947a18ba310831a37b7307d724a3ac2a4935b99d7075141b"); + assertTrue(EthereumMessageSigner.verifyMessage(publicKey, msg, signature)) + } + + @Test + fun testEthereumSignAndVerifyMessage712Legacy() { + val data = Numeric.hexStringToByteArray("03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d") + val privateKey = PrivateKey(data) + val publicKey = privateKey.getPublicKey(CoinType.ETHEREUM) + val msg = """ + { + "types": { + "EIP712Domain": [ + {"name": "name", "type": "string"}, + {"name": "version", "type": "string"}, + {"name": "chainId", "type": "uint256"}, + {"name": "verifyingContract", "type": "address"} + ], + "Person": [ + {"name": "name", "type": "string"}, + {"name": "wallet", "type": "address"} + ] + }, + "primaryType": "Person", + "domain": { + "name": "Ether Person", + "version": "1", + "chainId": 0, + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "name": "Cow", + "wallet": "CD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + } + } + """.trimIndent() + val signature = EthereumMessageSigner.signTypedMessage(privateKey, msg) + assertEquals(signature, "446434e4c34d6b7456e5f07a1b994b88bf85c057234c68d1e10c936b1c85706c4e19147c0ac3a983bc2d56ebfd7146f8b62bcea6114900fe8e7d7351f44bf3761c"); + assertTrue(EthereumMessageSigner.verifyMessage(publicKey, msg, signature)) + } + + @Test + fun testEthereumSignAndVerifyMessage712Eip155() { + val data = Numeric.hexStringToByteArray("03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d") + val privateKey = PrivateKey(data) + val publicKey = privateKey.getPublicKey(CoinType.ETHEREUM) + val msg = """ + { + "types": { + "EIP712Domain": [ + {"name": "name", "type": "string"}, + {"name": "version", "type": "string"}, + {"name": "chainId", "type": "uint256"}, + {"name": "verifyingContract", "type": "address"} + ], + "Person": [ + {"name": "name", "type": "string"}, + {"name": "wallet", "type": "address"} + ] + }, + "primaryType": "Person", + "domain": { + "name": "Ether Person", + "version": "1", + "chainId": 0, + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "name": "Cow", + "wallet": "CD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + } + } + """.trimIndent() + val signature = EthereumMessageSigner.signTypedMessageEip155(privateKey, msg, 0) + assertEquals(signature, "446434e4c34d6b7456e5f07a1b994b88bf85c057234c68d1e10c936b1c85706c4e19147c0ac3a983bc2d56ebfd7146f8b62bcea6114900fe8e7d7351f44bf37624"); + assertTrue(EthereumMessageSigner.verifyMessage(publicKey, msg, signature)) + } + + @Test + fun testEthereumSignAndVerifyMessageEip155() { + val data = Numeric.hexStringToByteArray("03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d") + val privateKey = PrivateKey(data) + val publicKey = privateKey.getPublicKey(CoinType.ETHEREUM) + val msg = "Foo" + val signature = EthereumMessageSigner.signMessageEip155(privateKey, msg, 0) + assertEquals(signature, "21a779d499957e7fd39392d49a079679009e60e492d9654a148829be43d2490736ec72bc4a5644047d979c3cf4ebe2c1c514044cf436b063cb89fc6676be711023"); + assertTrue(EthereumMessageSigner.verifyMessage(publicKey, msg, signature)) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumRlp.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumRlp.kt new file mode 100644 index 00000000000..80abb39ff7f --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumRlp.kt @@ -0,0 +1,57 @@ +package com.trustwallet.core.app.blockchains.ethereum + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import com.trustwallet.core.app.utils.Numeric +import wallet.core.jni.CoinType +import wallet.core.jni.proto.Common +import wallet.core.jni.proto.EthereumRlp + +class TestEthereumRlp { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testEthereumRlpEncodeEip1559() { + val chainId = ByteString.copyFrom("0x0a".toHexByteArray()) + val nonce = ByteString.copyFrom("0x06".toHexByteArray()) + val maxInclusionFeePerGas = ByteString.copyFrom("0x77359400".toHexByteArray()) // 2000000000 + val maxFeePerGas = ByteString.copyFrom("0xb2d05e00".toHexByteArray()) // 3000000000 + val gasLimit = ByteString.copyFrom("0x526c".toHexByteArray()) // 21100 + val to = "0x6b175474e89094c44da98b954eedeac495271d0f" + val amount = 0.toLong() + val payload = ByteString.copyFrom("a9059cbb0000000000000000000000005322b34c88ed0691971bf52a7047448f0f4efc840000000000000000000000000000000000000000000000000001ee0c29f50cb1".toHexByteArray()) + // An empty `accessList`. + val accessList = EthereumRlp.RlpList.newBuilder().build() + + val rlpList = EthereumRlp.RlpList.newBuilder() + .addItems(EthereumRlp.RlpItem.newBuilder().setNumberU256(chainId)) + .addItems(EthereumRlp.RlpItem.newBuilder().setNumberU256(nonce)) + .addItems(EthereumRlp.RlpItem.newBuilder().setNumberU256(maxInclusionFeePerGas)) + .addItems(EthereumRlp.RlpItem.newBuilder().setNumberU256(maxFeePerGas)) + .addItems(EthereumRlp.RlpItem.newBuilder().setNumberU256(gasLimit)) + .addItems(EthereumRlp.RlpItem.newBuilder().setAddress(to)) + .addItems(EthereumRlp.RlpItem.newBuilder().setNumberU64(amount)) + .addItems(EthereumRlp.RlpItem.newBuilder().setData(payload)) + .addItems(EthereumRlp.RlpItem.newBuilder().setList(accessList)) + .build() + + val encodingInput = EthereumRlp.EncodingInput.newBuilder().apply { + item = EthereumRlp.RlpItem.newBuilder().setList(rlpList).build() + }.build() + + val outputData = wallet.core.jni.EthereumRlp.encode(CoinType.ETHEREUM, encodingInput.toByteArray()) + val output = EthereumRlp.EncodingOutput.parseFrom(outputData) + + assertEquals(output.error, Common.SigningError.OK) + assert(output.errorMessage.isEmpty()) + assertEquals( + Numeric.toHexString(output.encoded.toByteArray()), + "0xf86c0a06847735940084b2d05e0082526c946b175474e89094c44da98b954eedeac495271d0f80b844a9059cbb0000000000000000000000005322b34c88ed0691971bf52a7047448f0f4efc840000000000000000000000000000000000000000000000000001ee0c29f50cb1c0" + ) + } +} \ No newline at end of file diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumTransactionSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumTransactionSigner.kt index ab3b38bf229..61a6b9a42df 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumTransactionSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumTransactionSigner.kt @@ -9,6 +9,8 @@ import wallet.core.java.AnySigner import wallet.core.jni.CoinType import wallet.core.jni.CoinType.ETHEREUM import wallet.core.jni.proto.Ethereum +import wallet.core.jni.EthereumAbi +import wallet.core.jni.EthereumAbiFunction import wallet.core.jni.proto.Ethereum.SigningOutput import wallet.core.jni.proto.Ethereum.TransactionMode import com.trustwallet.core.app.utils.Numeric @@ -147,6 +149,66 @@ class TestEthereumTransactionSigner { assertEquals(Numeric.toHexString(output.data.toByteArray()), "0xf242432a000000000000000000000000718046867b5b1782379a14ea4fc0c9b724da94fc0000000000000000000000005322b34c88ed0691971bf52a7047448f0f4efc840000000000000000000000000000000000000000000000000000000023c47ee50000000000000000000000000000000000000000000000001bc16d674ec8000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000") } + @Test + fun testEthereumStakeRocketPool() { + val function = EthereumAbiFunction("deposit") + val signingInput = Ethereum.SigningInput.newBuilder() + signingInput.apply { + chainId = ByteString.copyFrom("01".toHexByteArray()) + nonce = ByteString.copyFrom("01".toHexByteArray()) + txMode = TransactionMode.Enveloped + gasPrice = ByteString.copyFrom("77541880".toHexByteArray()) // 2002000000 + gasLimit = ByteString.copyFrom("0320c8".toHexByteArray()) // 205000 + maxFeePerGas = ByteString.copyFrom("067ef83700".toHexByteArray()) // 27900000000 + maxInclusionFeePerGas = ByteString.copyFrom("3b9aca00".toHexByteArray()) // 1000000000 + toAddress = "0x2cac916b2a963bf162f076c0a8a4a8200bcfbfb4" // contract + privateKey = ByteString.copyFrom(PrivateKey("9f56448d33de406db1561aae15fce64bdf0e9706ff15c45d4409e8fcbfd1a498".toHexByteArray()).data()) + transaction = Ethereum.Transaction.newBuilder().apply { + transfer = Ethereum.Transaction.Transfer.newBuilder().apply { + amount = ByteString.copyFrom("2386f26fc10000".toHexByteArray()) // 0.01 ETH + data = ByteString.copyFrom(EthereumAbi.encode(function)) + }.build() + }.build() + } + + val output = AnySigner.sign(signingInput.build(), ETHEREUM, SigningOutput.parser()) + + // https://etherscan.io/tx/0xfeba0c579f3e964fbc4eafa500e86891b9f4113735b1364edd4433d765506f1e + assertEquals(Numeric.toHexString(output.r.toByteArray()), "0xfb39e5079d7a0598ec45785d73a06b91fe1db707b9c6a150c87ffce2492c66d6") + assertEquals(Numeric.toHexString(output.s.toByteArray()), "0x7fbd43a6f4733b2b4f98ad1bc4678ea2615f5edf56ad91408337adec2f07c0ac") + } + + @Test + fun testEthereumUnstakeRocketPool() { + val function = EthereumAbiFunction("burn") + function.addParamUInt256("0x21faa32ab2502b".toHexByteArray(), false) + + val signingInput = Ethereum.SigningInput.newBuilder() + signingInput.apply { + chainId = ByteString.copyFrom("01".toHexByteArray()) + nonce = ByteString.copyFrom("03".toHexByteArray()) + txMode = TransactionMode.Enveloped + gasPrice = ByteString.copyFrom("77541880".toHexByteArray()) // 2002000000 + gasLimit = ByteString.copyFrom("055730".toHexByteArray()) // 350000 + maxFeePerGas = ByteString.copyFrom("067ef83700".toHexByteArray()) // 27900000000 + maxInclusionFeePerGas = ByteString.copyFrom("3b9aca00".toHexByteArray()) // 1000000000 + toAddress = "0xae78736Cd615f374D3085123A210448E74Fc6393" // contract + privateKey = ByteString.copyFrom(PrivateKey("9f56448d33de406db1561aae15fce64bdf0e9706ff15c45d4409e8fcbfd1a498".toHexByteArray()).data()) + transaction = Ethereum.Transaction.newBuilder().apply { + contractGeneric = Ethereum.Transaction.ContractGeneric.newBuilder().apply { + amount = ByteString.copyFrom("00".toHexByteArray()) + data = ByteString.copyFrom(EthereumAbi.encode(function)) + }.build() + }.build() + } + + val output = AnySigner.sign(signingInput.build(), ETHEREUM, SigningOutput.parser()) + + // https://etherscan.io/tx/0x7fd3c0e9b8b309b4258baa7677c60f5e00e8db7b647fbe3a52adda25058a4b37 + assertEquals(Numeric.toHexString(output.r.toByteArray()), "0x1fc6e94908107584357799e952b4e3fb87f088aeb66d7930a7015643f19c9e7f") + assertEquals(Numeric.toHexString(output.s.toByteArray()), "0x2c56a0b70ff2e52bf374a3dcd404bc42317d5ca15d319f5e33665352eb48f06f") + } + @Test fun testSignJSON() { val json = """ diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/everscale/TestEverscaleAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/everscale/TestEverscaleAddress.kt index b09cfaff057..5922fa9f191 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/everscale/TestEverscaleAddress.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/everscale/TestEverscaleAddress.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.everscale diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/everscale/TestEverscaleSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/everscale/TestEverscaleSigner.kt index cb1d7266f92..a07ba7c46b4 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/everscale/TestEverscaleSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/everscale/TestEverscaleSigner.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.everscale diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/filecoin/TestFilecoin.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/filecoin/TestFilecoin.kt index a2d739e65c2..82f292da61d 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/filecoin/TestFilecoin.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/filecoin/TestFilecoin.kt @@ -6,10 +6,7 @@ import com.trustwallet.core.app.utils.toHexBytesInByteString import org.junit.Assert.assertEquals import org.junit.Test import wallet.core.java.AnySigner -import wallet.core.jni.AnyAddress -import wallet.core.jni.CoinType -import wallet.core.jni.CoinType.FILECOIN -import wallet.core.jni.PrivateKey +import wallet.core.jni.* import wallet.core.jni.proto.Filecoin import wallet.core.jni.proto.Filecoin.SigningOutput @@ -20,13 +17,32 @@ class TestFilecoin { } @Test - fun testAddress() { + fun testCreateAddress() { val privateKey = PrivateKey("1d969865e189957b9824bd34f26d5cbf357fda1a6d844cbf0c9ab1ed93fa7dbe".toHexByteArray()) val publicKey = privateKey.getPublicKeySecp256k1(false) val address = AnyAddress(publicKey, CoinType.FILECOIN) assertEquals("f1z4a36sc7mfbv4z3qwutblp2flycdui3baffytbq", address.description()) } + @Test + fun testCreateDelegatedAddress() { + val privateKey = PrivateKey("825d2bb32965764a98338139412c7591ed54c951dd65504cd8ddaeaa0fea7b2a".toHexByteArray()) + val publicKey = privateKey.getPublicKeySecp256k1(false) + val address = AnyAddress(publicKey, FilecoinAddressType.DELEGATED) + assertEquals("f410fvak24cyg3saddajborn6idt7rrtfj2ptauk5pbq", address.description()) + } + + @Test + fun testAddressConverter() { + val ethereumAddress = FilecoinAddressConverter.convertToEthereum("f410frw6wy7w6sbsguyn3yzeygg34fgf72n5ao5sxyky") + assertEquals(ethereumAddress, "0x8dbD6c7Ede90646a61Bbc649831b7c298BFd37A0") + assert(AnyAddress.isValid(ethereumAddress, CoinType.ETHEREUM)) + + val filecoinAddress = FilecoinAddressConverter.convertFromEthereum("0x8dbD6c7Ede90646a61Bbc649831b7c298BFd37A0") + assertEquals(filecoinAddress, "f410frw6wy7w6sbsguyn3yzeygg34fgf72n5ao5sxyky") + assert(AnyAddress.isValid(filecoinAddress, CoinType.FILECOIN)) + } + @Test fun testSigner() { val input = Filecoin.SigningInput.newBuilder() @@ -41,7 +57,7 @@ class TestFilecoin { .build() val output = AnySigner.sign(input, CoinType.FILECOIN, SigningOutput.parser()) - val expted = """{"Message":{"From":"f1z4a36sc7mfbv4z3qwutblp2flycdui3baffytbq","GasFeeCap":"700000000000000000000","GasLimit":1000,"GasPremium":"800000000000000000000","Nonce":2,"To":"f3um6uo3qt5of54xjbx3hsxbw5mbsc6auxzrvfxekn5bv3duewqyn2tg5rhrlx73qahzzpkhuj7a34iq7oifsq","Value":"600000000000000000000"},"Signature":{"Data":"jMRu+OZ/lfppgmqSfGsntFrRLWZnUg3ZYmJTTRLsVt4V1310vR3VKGJpaE6S4sNvDOE6sEgmN9YmfTkPVK2qMgE=","Type":1}}""" - assertEquals(expted, output.json) + val expected = """{"Message":{"From":"f1z4a36sc7mfbv4z3qwutblp2flycdui3baffytbq","GasFeeCap":"700000000000000000000","GasLimit":1000,"GasPremium":"800000000000000000000","Method":0,"Nonce":2,"To":"f3um6uo3qt5of54xjbx3hsxbw5mbsc6auxzrvfxekn5bv3duewqyn2tg5rhrlx73qahzzpkhuj7a34iq7oifsq","Value":"600000000000000000000"},"Signature":{"Data":"jMRu+OZ/lfppgmqSfGsntFrRLWZnUg3ZYmJTTRLsVt4V1310vR3VKGJpaE6S4sNvDOE6sEgmN9YmfTkPVK2qMgE=","Type":1}}""" + assertEquals(expected, output.json) } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/fio/TestFIOAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/fio/TestFIOAddress.kt index 6b6461e78d1..4a9bef5fedb 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/fio/TestFIOAddress.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/fio/TestFIOAddress.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.fio diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/fio/TestFIOSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/fio/TestFIOSigner.kt index 7037706254b..6992aa0b9f8 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/fio/TestFIOSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/fio/TestFIOSigner.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.fio diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/greenfield/TestGreenfieldSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/greenfield/TestGreenfieldSigner.kt new file mode 100644 index 00000000000..cd7caf5e2ac --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/greenfield/TestGreenfieldSigner.kt @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.greenfield + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.CoinType +import wallet.core.jni.PrivateKey +import wallet.core.jni.proto.Greenfield + +class TestGreenfieldSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun GreenfieldTransactionSigningSend() { + // Successfully broadcasted: https://greenfieldscan.com/tx/ED8508F3C174C4430B8EE718A6D6F0B02A8C516357BE72B1336CF74356529D19 + + val key = + PrivateKey("825d2bb32965764a98338139412c7591ed54c951dd65504cd8ddaeaa0fea7b2a".toHexByteArray()) + + val msgSend = Greenfield.Message.Send.newBuilder().apply { + fromAddress = "0xA815ae0b06dC80318121745BE40e7F8c6654e9f3" + toAddress = "0x8dbD6c7Ede90646a61Bbc649831b7c298BFd37A0" + addAmounts(Greenfield.Amount.newBuilder().apply { + amount = "1234500000000000" + denom = "BNB" + }) + }.build() + + val greenfieldFee = Greenfield.Fee.newBuilder().apply { + gas = 1200 + addAmounts(Greenfield.Amount.newBuilder().apply { + amount = "6000000000000" + denom = "BNB" + }) + }.build() + + val signingInput = Greenfield.SigningInput.newBuilder().apply { + signingMode = Greenfield.SigningMode.Eip712 + encodingMode = Greenfield.EncodingMode.Protobuf + accountNumber = 15952 + ethChainId = "5600" + cosmosChainId = "greenfield_5600-1" + memo = "Trust Wallet test memo" + sequence = 0 + fee = greenfieldFee + mode = Greenfield.BroadcastMode.SYNC + privateKey = ByteString.copyFrom(key.data()) + addMessages(Greenfield.Message.newBuilder().apply { + sendCoinsMessage = msgSend + }) + }.build() + + val output = AnySigner.sign(signingInput, CoinType.GREENFIELD, Greenfield.SigningOutput.parser()) + + assertEquals( + output.serialized, + "{\"mode\":\"BROADCAST_MODE_SYNC\",\"tx_bytes\":\"CqwBCpEBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnEKKjB4QTgxNWFlMGIwNmRDODAzMTgxMjE3NDVCRTQwZTdGOGM2NjU0ZTlmMxIqMHg4ZGJENmM3RWRlOTA2NDZhNjFCYmM2NDk4MzFiN2MyOThCRmQzN0EwGhcKA0JOQhIQMTIzNDUwMDAwMDAwMDAwMBIWVHJ1c3QgV2FsbGV0IHRlc3QgbWVtbxJzClYKTQomL2Nvc21vcy5jcnlwdG8uZXRoLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohAhm/mQgs8vzaqBLW66HrqQNv86PYTBgXyElU1OiuKD/sEgUKAwjIBRIZChQKA0JOQhINNjAwMDAwMDAwMDAwMBCwCRpBwbRb1qEAWwaqVfmp1Mn7iMi7wwV/oPi2J2eW9NBIdNoky+ZL+uegS/kY+funCOrqVZ+Kbol9/djAV+bQaNUB0xw=\"}" + ) + assertEquals(output.errorMessage, "") + } + + @Test + fun GreenfieldTransactionSigningTransferOut() { + // Successfully broadcasted Greenfield: https://greenfieldscan.com/tx/38C29C530A74946CFD22EE07DA642F5EF9399BC9AEA59EC56A9B5BE16DE16CE7 + // BSC (parent transaction): https://testnet.bscscan.com/tx/0x7f73c8a362e14e58cb5e0ec17616afc50eff7aa398db472383a6d017c8a5861a + + val key = + PrivateKey("9066aa168c379a403becb235c15e7129c133c244e56a757ab07bc369288bcab0".toHexByteArray()) + + val msgTransferOut = Greenfield.Message.BridgeTransferOut.newBuilder().apply { + fromAddress = "0x9d1d97aDFcd324Bbd603D3872BD78e04098510b1" + toAddress = "0x9d1d97aDFcd324Bbd603D3872BD78e04098510b1" + amount = Greenfield.Amount.newBuilder().apply { + amount = "5670000000000000" + denom = "BNB" + }.build() + }.build() + + val greenfieldFee = Greenfield.Fee.newBuilder().apply { + gas = 1200 + addAmounts(Greenfield.Amount.newBuilder().apply { + amount = "6000000000000" + denom = "BNB" + }) + }.build() + + val signingInput = Greenfield.SigningInput.newBuilder().apply { + signingMode = Greenfield.SigningMode.Eip712 + encodingMode = Greenfield.EncodingMode.Protobuf + accountNumber = 15560 + ethChainId = "5600" + cosmosChainId = "greenfield_5600-1" + sequence = 7 + fee = greenfieldFee + mode = Greenfield.BroadcastMode.SYNC + privateKey = ByteString.copyFrom(key.data()) + addMessages(Greenfield.Message.newBuilder().apply { + bridgeTransferOut = msgTransferOut + }) + }.build() + + val output = AnySigner.sign(signingInput, CoinType.GREENFIELD, Greenfield.SigningOutput.parser()) + + assertEquals( + output.serialized, + "{\"mode\":\"BROADCAST_MODE_SYNC\",\"tx_bytes\":\"CpkBCpYBCiEvZ3JlZW5maWVsZC5icmlkZ2UuTXNnVHJhbnNmZXJPdXQScQoqMHg5ZDFkOTdhREZjZDMyNEJiZDYwM0QzODcyQkQ3OGUwNDA5ODUxMGIxEioweDlkMWQ5N2FERmNkMzI0QmJkNjAzRDM4NzJCRDc4ZTA0MDk4NTEwYjEaFwoDQk5CEhA1NjcwMDAwMDAwMDAwMDAwEnUKWApNCiYvY29zbW9zLmNyeXB0by5ldGguZXRoc2VjcDI1NmsxLlB1YktleRIjCiECee80Bk2hDbBGPHBIBha6AgcD7DpFAm3ve+vSCC9db8gSBQoDCMgFGAcSGQoUCgNCTkISDTYwMDAwMDAwMDAwMDAQsAkaQc4DDByhu80Uy/M3sQePvAmhmbFWZeGq359rugtskEiXKfCzSB86XmBi+l+Q5ETDS2folMxbufHSE8gM4WBCHzgc\"}" + ) + assertEquals(output.errorMessage, "") + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/hedera/TestHederaAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/hedera/TestHederaAddress.kt new file mode 100644 index 00000000000..925c36c7851 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/hedera/TestHederaAddress.kt @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.hedera + +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestHederaAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val any = AnyAddress("0.0.1377988", CoinType.HEDERA) + assertEquals(any.coin(), CoinType.HEDERA) + assertEquals(any.description(), "0.0.1377988") + + Assert.assertFalse( + AnyAddress.isValid( + "0.0.a", + CoinType.HEDERA + ) + ) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/hedera/TestHederaSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/hedera/TestHederaSigner.kt new file mode 100644 index 00000000000..c01f813e2d0 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/hedera/TestHederaSigner.kt @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.hedera + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.Numeric +import com.trustwallet.core.app.utils.toHexByteArray +import com.trustwallet.core.app.utils.toHexBytes +import com.trustwallet.core.app.utils.toHexBytesInByteString +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.* +import wallet.core.jni.proto.Hedera + +class TestHederaSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun HederaTransactionSimpleTransferSigning() { + // Successfully broadcasted: https://hashscan.io/testnet/transaction/0.0.48694347-1667222879-749068449?t=1667222891.440398729&p=1 + val key = + "e87a5584c0173263e138db689fdb2a7389025aaae7cb1a18a1017d76012130e8".toHexBytesInByteString() + + val transfer = Hedera.TransferMessage + .newBuilder() + .setAmount(100000000) + .setFrom("0.0.48694347") + .setTo("0.0.48462050") + .build() + + val timestamp = Hedera.Timestamp + .newBuilder() + .setSeconds(1667222879) + .setNanos(749068449) + .build() + + val transactionID = Hedera.TransactionID + .newBuilder() + .setTransactionValidStart(timestamp) + .setAccountID("0.0.48694347") + .build() + + val body = Hedera.TransactionBody + .newBuilder() + .setMemo("") + .setTransfer(transfer) + .setTransactionID(transactionID) + .setNodeAccountID("0.0.9") + .setTransactionFee(100000000) + .setTransactionValidDuration(120) + .build() + + val signingInput = Hedera.SigningInput + .newBuilder() + .setPrivateKey(key) + .setBody(body).build() + + val result = AnySigner.sign(signingInput, CoinType.HEDERA, Hedera.SigningOutput.parser()) + assertEquals( + Numeric.cleanHexPrefix(Numeric.toHexString(result.encoded.toByteArray())), + "0a440a150a0c08df9aff9a0610a1c197e502120518cb889c17120218091880c2d72f22020878721e0a1c0a0c0a0518e2f18d17108084af5f0a0c0a0518cb889c1710ff83af5f12660a640a205d3a70d08b2beafb72c7a68986b3ff819a306078b8c359d739e4966e82e6d40e1a40612589c3b15f1e3ed6084b5a3a5b1b81751578cac8d6c922f31731b3982a5bac80a22558b2197276f5bae49b62503a4d39448ceddbc5ef3ba9bee4c0f302f70c" + ) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/internetcomputer/TestInternetComputerAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/internetcomputer/TestInternetComputerAddress.kt new file mode 100644 index 00000000000..2861aea3a4a --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/internetcomputer/TestInternetComputerAddress.kt @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.internetcomputer + +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestInternetComputerAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val key = PrivateKey("ee42eaada903e20ef6e5069f0428d552475c1ea7ed940842da6448f6ef9d48e7".toHexByteArray()) + val pubkey = key.getPublicKeySecp256k1(false); + val address = AnyAddress(pubkey, CoinType.INTERNETCOMPUTER) + val expected = AnyAddress("2f25874478d06cf68b9833524a6390d0ba69c566b02f46626979a3d6a4153211", CoinType.INTERNETCOMPUTER) + + assertEquals(pubkey.data().toHex(), "0x048542e6fb4b17d6dfcac3948fe412c00d626728815ee7cc70509603f1bc92128a6e7548f3432d6248bc49ff44a1e50f6389238468d17f7d7024de5be9b181dbc8") + assertEquals(address.description(), expected.description()) + } +} \ No newline at end of file diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/internetcomputer/TestInternetComputerSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/internetcomputer/TestInternetComputerSigner.kt new file mode 100644 index 00000000000..d3e97de972e --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/internetcomputer/TestInternetComputerSigner.kt @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.internetcomputer + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.Numeric +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexByteArray +import com.trustwallet.core.app.utils.toHexBytes +import com.trustwallet.core.app.utils.toHexBytesInByteString +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.* +import wallet.core.jni.proto.InternetComputer +import wallet.core.jni.proto.InternetComputer.SigningOutput + +class TestInternetComputerSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun InternetComputerTransactionSigning() { + val key = PrivateKey("227102911bb99ce7285a55f952800912b7d22ebeeeee59d77fc33a5d7c7080be".toHexByteArray()) + + val input = InternetComputer.SigningInput.newBuilder() + .setTransaction(InternetComputer.Transaction.newBuilder().apply { + transfer = InternetComputer.Transaction.Transfer.newBuilder().apply { + toAccountIdentifier = "943d12e762f43806782f524b8f90297298a6d79e4749b41b585ec427409c826a" + amount = 100000000 + memo = 0 + currentTimestampNanos = 1691709940000000000 + }.build() + }.build()) + .setPrivateKey(ByteString.copyFrom(key.data())) + val output = AnySigner.sign(input.build(), CoinType.INTERNETCOMPUTER, SigningOutput.parser()) + assertEquals(output.signedTransaction.toByteArray().toHex(), "0x81826b5452414e53414354494f4e81a266757064617465a367636f6e74656e74a66c726571756573745f747970656463616c6c6e696e67726573735f6578706972791b177a297215cfe8006673656e646572581d971cd2ddeecd1cf1b28be914d7a5c43441f6296f1f9966a7c8aff68d026b63616e69737465725f69644a000000000000000201016b6d6574686f645f6e616d656773656e645f706263617267583b0a0012070a050880c2d72f2a220a20943d12e762f43806782f524b8f90297298a6d79e4749b41b585ec427409c826a3a0a088090caa5a3a78abd176d73656e6465725f7075626b65799858183018561830100607182a1886184818ce183d02010605182b188104000a0318420004183d18ab183a182118a81838184d184c187e1852188a187e18dc18d8184418ea18cd18c5189518ac188518b518bc181d188515186318bc18e618ab18d2184318d3187c184f18cd18f018de189b18b5181918dd18ef1889187218e71518c40418d4189718881843187218c611182e18cc18e6186b182118630218356a73656e6465725f736967984013186f18b9181c189818b318a8186518b2186118d418971618b1187d18eb185818e01826182f1873183b185018cb185d18ef18d81839186418b3183218da1824182f184e18a01880182718c0189018c918a018fd18c418d9189e189818b318ef1874183b185118e118a51864185918e718ed18c71889186c1822182318ca6a726561645f7374617465a367636f6e74656e74a46c726571756573745f747970656a726561645f73746174656e696e67726573735f6578706972791b177a297215cfe8006673656e646572581d971cd2ddeecd1cf1b28be914d7a5c43441f6296f1f9966a7c8aff68d0265706174687381824e726571756573745f7374617475735820e8fbc2d5b0bf837b3a369249143e50d4476faafb2dd620e4e982586a51ebcf1e6d73656e6465725f7075626b65799858183018561830100607182a1886184818ce183d02010605182b188104000a0318420004183d18ab183a182118a81838184d184c187e1852188a187e18dc18d8184418ea18cd18c5189518ac188518b518bc181d188515186318bc18e618ab18d2184318d3187c184f18cd18f018de189b18b5181918dd18ef1889187218e71518c40418d4189718881843187218c611182e18cc18e6186b182118630218356a73656e6465725f7369679840182d182718201888188618ce187f0c182a187a18d718e818df18fb18d318d41118a5186a184b18341842185318d718e618e8187a1828186c186a183618461418f3183318bd18a618a718bc18d918c818b7189d186e1865188418ff18fd18e418e9187f181b18d705184818b21872187818d6181c161833184318a2") + } + + @Test + fun InternetComputerTransactionSigningWithInvalidToAccountIdentifier() { + val key = PrivateKey("227102911bb99ce7285a55f952800912b7d22ebeeeee59d77fc33a5d7c7080be".toHexByteArray()) + + val input = InternetComputer.SigningInput.newBuilder() + .setTransaction(InternetComputer.Transaction.newBuilder().apply { + transfer = InternetComputer.Transaction.Transfer.newBuilder().apply { + toAccountIdentifier = "643d12e762f43806782f524b8f90297298a6d79e4749b41b585ec427409c826b" + amount = 100000000 + memo = 0 + currentTimestampNanos = 1691709940000000000 + }.build() + }.build()) + .setPrivateKey(ByteString.copyFrom(key.data())) + val output = AnySigner.sign(input.build(), CoinType.INTERNETCOMPUTER, SigningOutput.parser()) + assertEquals(output.error.number, 16) + } + + @Test + fun InternetComputerTransactionSigningWithInvalidAmount() { + val key = PrivateKey("227102911bb99ce7285a55f952800912b7d22ebeeeee59d77fc33a5d7c7080be".toHexByteArray()) + + val input = InternetComputer.SigningInput.newBuilder() + .setTransaction(InternetComputer.Transaction.newBuilder().apply { + transfer = InternetComputer.Transaction.Transfer.newBuilder().apply { + toAccountIdentifier = "943d12e762f43806782f524b8f90297298a6d79e4749b41b585ec427409c826a" + amount = 0 + memo = 0 + currentTimestampNanos = 1691709940000000000 + }.build() + }.build()) + .setPrivateKey(ByteString.copyFrom(key.data())) + val output = AnySigner.sign(input.build(), CoinType.INTERNETCOMPUTER, SigningOutput.parser()) + assertEquals(output.error.number, 23) + } +} \ No newline at end of file diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/juno/TestJunoAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/juno/TestJunoAddress.kt new file mode 100644 index 00000000000..39c7022b743 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/juno/TestJunoAddress.kt @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.juno + +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert +import org.junit.Test +import wallet.core.jni.* + +class TestJunoAddress { + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAnyAddressValidation() { + val addr = "juno1gckvjxau7k56f8wg8c8xj80khyp83y8x8eqc94" + val anyAddr = AnyAddress(addr, CoinType.COSMOS, "juno") + assert(AnyAddress.isValidBech32(anyAddr.description(), CoinType.COSMOS, "juno")) + assert(AnyAddress.isValid(anyAddr.description(), CoinType.JUNO)) + assert(!AnyAddress.isValidBech32(anyAddr.description(), CoinType.BITCOIN, "juno")) + assert(!AnyAddress.isValid(anyAddr.description(), CoinType.BITCOIN)) + assert(!AnyAddress.isValid(anyAddr.description(), CoinType.COSMOS)) + } + + @Test + fun testAnyAddressFromPubkey() { + val pubKey = PublicKey("02753f5c275e1847ba4d2fd3df36ad00af2e165650b35fe3991e9c9c46f68b12bc".toHexByteArray(), PublicKeyType.SECP256K1) + val anyAddr = AnyAddress(pubKey, CoinType.COSMOS, "juno") + Assert.assertEquals(anyAddr.description(), "juno1cj2vfjec3c3luf9fx9vddnglhh9gawmncn4k5n"); + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/kcc/TestKuCoinCommunityChainAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/kcc/TestKuCoinCommunityChainAddress.kt index 0d2fe4a7446..9a2ecfc3811 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/kcc/TestKuCoinCommunityChainAddress.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/kcc/TestKuCoinCommunityChainAddress.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2021 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.kcc diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/kusama/TestKusamaAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/kusama/TestKusamaAddress.kt index 23f6b258315..39fc302d0ff 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/kusama/TestKusamaAddress.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/kusama/TestKusamaAddress.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.kusama diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/kusama/TestKusamaSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/kusama/TestKusamaSigner.kt index 738ff2a4c1f..7bec37b4f0e 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/kusama/TestKusamaSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/kusama/TestKusamaSigner.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.polkadot @@ -36,7 +34,7 @@ class TestKusamaSigner { blockHash = hash nonce = 1 specVersion = 2019 - network = Polkadot.Network.KUSAMA + network = KUSAMA.ss58Prefix() transactionVersion = 2 privateKey = key balanceCall = Polkadot.Balance.newBuilder().apply { diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/multiversx/TestMultiversXAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/multiversx/TestMultiversXAddress.kt new file mode 100644 index 00000000000..ab3b1ec2483 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/multiversx/TestMultiversXAddress.kt @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.multiversx + +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestMultiversXAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + private var aliceBech32 = "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" + private var alicePubKeyHex = "0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1" + private var aliceSeedHex = "0x413f42575f7f26fad3317a778771212fdb80245850981e48b58a4f25e344e8f9" + + @Test + fun testAddressFromPrivateKey() { + val key = PrivateKey(aliceSeedHex.toHexByteArray()) + val pubKey = key.publicKeyEd25519 + val address = AnyAddress(pubKey, CoinType.MULTIVERSX) + + assertEquals(alicePubKeyHex, pubKey.data().toHex()) + assertEquals(aliceBech32, address.description()) + } + + @Test + fun testAddressFromPublicKey() { + val pubKey = PublicKey(alicePubKeyHex.toHexByteArray(), PublicKeyType.ED25519) + val address = AnyAddress(pubKey, CoinType.MULTIVERSX) + + assertEquals(aliceBech32, address.description()) + } + + @Test + fun testAddressFromString() { + val address = AnyAddress(aliceBech32, CoinType.MULTIVERSX) + + assertEquals(aliceBech32, address.description()) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/multiversx/TestMultiversXSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/multiversx/TestMultiversXSigner.kt new file mode 100644 index 00000000000..811c8a6b76f --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/multiversx/TestMultiversXSigner.kt @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.multiversx + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.CoinType +import wallet.core.jni.PrivateKey +import wallet.core.jni.proto.MultiversX + +class TestMultiversXSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + private var aliceBech32 = "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" + private var aliceSeedHex = "0x413f42575f7f26fad3317a778771212fdb80245850981e48b58a4f25e344e8f9" + private var bobBech32 = "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx" + private var carolBech32 = "erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8" + + @Test + fun signGenericAction() { + val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) + + val accounts = MultiversX.Accounts.newBuilder() + .setSenderNonce(7) + .setSender(aliceBech32) + .setReceiver(bobBech32) + .build() + + val genericAction = MultiversX.GenericAction.newBuilder() + .setAccounts(accounts) + .setValue("0") + .setData("foo") + .setVersion(1) + .build() + + val signingInput = MultiversX.SigningInput.newBuilder() + .setGenericAction(genericAction) + .setGasPrice(1000000000) + .setGasLimit(50000) + .setChainId("1") + .setPrivateKey(privateKey) + .build() + + val output = AnySigner.sign(signingInput, CoinType.MULTIVERSX, MultiversX.SigningOutput.parser()) + val expectedSignature = "e8647dae8b16e034d518a1a860c6a6c38d16192d0f1362833e62424f424e5da660770dff45f4b951d9cc58bfb9d14559c977d443449bfc4b8783ff9c84065700" + + assertEquals(expectedSignature, output.signature) + assertEquals("""{"nonce":7,"value":"0","receiver":"$bobBech32","sender":"$aliceBech32","gasPrice":1000000000,"gasLimit":50000,"data":"Zm9v","chainID":"1","version":1,"signature":"$expectedSignature"}""", output.encoded) + } + + @Test + fun signGenericActionWithGuardian() { + val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) + + val accounts = MultiversX.Accounts.newBuilder() + .setSenderNonce(42) + .setSender(aliceBech32) + .setReceiver(bobBech32) + .setGuardian(carolBech32) + .build() + + val genericAction = MultiversX.GenericAction.newBuilder() + .setAccounts(accounts) + .setValue("1000000000000000000") + .setVersion(2) + .setOptions(2) + .build() + + val signingInput = MultiversX.SigningInput.newBuilder() + .setGenericAction(genericAction) + .setGasPrice(1000000000) + .setGasLimit(100000) + .setChainId("1") + .setPrivateKey(privateKey) + .build() + + val output = AnySigner.sign(signingInput, CoinType.MULTIVERSX, MultiversX.SigningOutput.parser()) + val expectedSignature = "dae30e5cddb4a1f050009f939ce2c90843770870f9e6c77366be07e5cd7b3ebfdda38cd45d04e9070037d57761b6a68cee697e6043057f9dc565a4d0e632480d" + + assertEquals(expectedSignature, output.signature) + assertEquals("""{"nonce":42,"value":"1000000000000000000","receiver":"$bobBech32","sender":"$aliceBech32","gasPrice":1000000000,"gasLimit":100000,"chainID":"1","version":2,"signature":"$expectedSignature","options":2,"guardian":"$carolBech32"}""", output.encoded) + } + + @Test + fun signGenericActionUndelegate() { + // Successfully broadcasted https://explorer.multiversx.com/transactions/3301ae5a6a77f0ab9ceb5125258f12539a113b0c6787de76a5c5867f2c515d65 + val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) + + val accounts = MultiversX.Accounts.newBuilder() + .setSenderNonce(6) + .setSender("erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa") + .setReceiver("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r") + .build() + + val genericAction = MultiversX.GenericAction.newBuilder() + .setAccounts(accounts) + .setValue("0") + .setData("unDelegate@0de0b6b3a7640000") + .setVersion(1) + .build() + + val signingInput = MultiversX.SigningInput.newBuilder() + .setGenericAction(genericAction) + .setGasPrice(1000000000) + .setGasLimit(12000000) + .setChainId("1") + .setPrivateKey(privateKey) + .build() + + val output = AnySigner.sign(signingInput, CoinType.MULTIVERSX, MultiversX.SigningOutput.parser()) + val expectedSignature = "89f9683af92f7b835bff4e1d0dbfcff5245b3367df4d23538eb799e0ad0a90be29ac3bd3598ce55b35b35ebef68bfa5738eed39fd01adc33476f65bd1b966e0b" + + assertEquals(expectedSignature, output.signature) + assertEquals("""{"nonce":6,"value":"0","receiver":"erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r","sender":"erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa","gasPrice":1000000000,"gasLimit":12000000,"data":"dW5EZWxlZ2F0ZUAwZGUwYjZiM2E3NjQwMDAw","chainID":"1","version":1,"signature":"$expectedSignature"}""", output.encoded) + } + + @Test + fun signGenericActionDelegate() { + // Successfully broadcasted https://explorer.multiversx.com/transactions/e5007662780f8ed677b37b156007c24bf60b7366000f66ec3525cfa16a4564e7 + val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) + + val accounts = MultiversX.Accounts.newBuilder() + .setSenderNonce(1) + .setSender("erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa") + .setReceiver("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r") + .build() + + val genericAction = MultiversX.GenericAction.newBuilder() + .setAccounts(accounts) + .setValue("1") + .setData("delegate") + .setVersion(1) + .build() + + val signingInput = MultiversX.SigningInput.newBuilder() + .setGenericAction(genericAction) + .setGasPrice(1000000000) + .setGasLimit(12000000) + .setChainId("1") + .setPrivateKey(privateKey) + .build() + + val output = AnySigner.sign(signingInput, CoinType.MULTIVERSX, MultiversX.SigningOutput.parser()) + val expectedSignature = "3b9164d47a4e3c0330ae387cd29ba6391f9295acf5e43a16a4a2611645e66e5fa46bf22294ca68fe1948adf45cec8cb47b8792afcdb248bd9adec7c6e6c27108" + + assertEquals(expectedSignature, output.signature) + assertEquals("""{"nonce":1,"value":"1","receiver":"erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r","sender":"erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa","gasPrice":1000000000,"gasLimit":12000000,"data":"ZGVsZWdhdGU=","chainID":"1","version":1,"signature":"$expectedSignature"}""", output.encoded) + } + + @Test + fun signEGLDTransfer() { + val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) + + val accounts = MultiversX.Accounts.newBuilder() + .setSenderNonce(7) + .setSender(aliceBech32) + .setReceiver(bobBech32) + .build() + + val transfer = MultiversX.EGLDTransfer.newBuilder() + .setAccounts(accounts) + .setAmount("1000000000000000000") + .build() + + val signingInput = MultiversX.SigningInput.newBuilder() + .setEgldTransfer(transfer) + .setChainId("1") + .setPrivateKey(privateKey) + .build() + + val output = AnySigner.sign(signingInput, CoinType.MULTIVERSX, MultiversX.SigningOutput.parser()) + val expectedSignature = "0f40dec9d37bde3c67803fc535088e536344e271807bb7c1aa24af3c69bffa9b705e149ff7bcaf21678f4900c4ee72741fa6ef08bf4c67fc6da1c6b0f337730e" + + assertEquals(expectedSignature, output.signature) + assertEquals("""{"nonce":7,"value":"1000000000000000000","receiver":"$bobBech32","sender":"$aliceBech32","gasPrice":1000000000,"gasLimit":50000,"chainID":"1","version":2,"signature":"$expectedSignature"}""", output.encoded) + } + + @Test + fun signEGLDTransferWithGuardian() { + val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) + + val accounts = MultiversX.Accounts.newBuilder() + .setSenderNonce(7) + .setSender(aliceBech32) + .setReceiver(bobBech32) + .setGuardian(carolBech32) + .build() + + val transfer = MultiversX.EGLDTransfer.newBuilder() + .setAccounts(accounts) + .setAmount("1000000000000000000") + .build() + + val signingInput = MultiversX.SigningInput.newBuilder() + .setEgldTransfer(transfer) + .setChainId("1") + .setPrivateKey(privateKey) + .build() + + val output = AnySigner.sign(signingInput, CoinType.MULTIVERSX, MultiversX.SigningOutput.parser()) + val expectedSignature = "741dd0d24db4df37a050f693f8481b6e51b8dd6dfc2f01a4f90aa1af3e59c89a8b0ef9d710af33103970e353d9f0cb9fd128a2e174731cbc88265d9737ed5604" + + assertEquals(expectedSignature, output.signature) + assertEquals("""{"nonce":7,"value":"1000000000000000000","receiver":"$bobBech32","sender":"$aliceBech32","gasPrice":1000000000,"gasLimit":100000,"chainID":"1","version":2,"signature":"$expectedSignature","options":2,"guardian":"$carolBech32"}""", output.encoded) + } + + @Test + fun signESDTTransfer() { + val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) + + val accounts = MultiversX.Accounts.newBuilder() + .setSenderNonce(7) + .setSender(aliceBech32) + .setReceiver(bobBech32) + .build() + + val transfer = MultiversX.ESDTTransfer.newBuilder() + .setAccounts(accounts) + .setTokenIdentifier("MYTOKEN-1234") + .setAmount("10000000000000") + .build() + + val signingInput = MultiversX.SigningInput.newBuilder() + .setEsdtTransfer(transfer) + .setChainId("1") + .setPrivateKey(privateKey) + .build() + + val output = AnySigner.sign(signingInput, CoinType.MULTIVERSX, MultiversX.SigningOutput.parser()) + val expectedSignature = "dd7cdc90aa09da6034b00a99e3ba0f1a2a38fa788fad018d53bf2e706f99e1a42c80063c28e6b48a5f2574c4054986f34c8eb36b1da63a22d19cf3ea5990b306" + val expectedData = "RVNEVFRyYW5zZmVyQDRkNTk1NDRmNGI0NTRlMmQzMTMyMzMzNEAwOTE4NGU3MmEwMDA=" + + assertEquals(expectedSignature, output.signature) + assertEquals("""{"nonce":7,"value":"0","receiver":"$bobBech32","sender":"$aliceBech32","gasPrice":1000000000,"gasLimit":425000,"data":"$expectedData","chainID":"1","version":2,"signature":"$expectedSignature"}""", output.encoded) + } + + @Test + fun signESDTNFTTransfer() { + val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) + + val accounts = MultiversX.Accounts.newBuilder() + .setSenderNonce(7) + .setSender(aliceBech32) + .setReceiver(bobBech32) + .build() + + val transfer = MultiversX.ESDTNFTTransfer.newBuilder() + .setAccounts(accounts) + .setTokenCollection("LKMEX-aab910") + .setTokenNonce(4) + .setAmount("184300000000000000") + .build() + + val signingInput = MultiversX.SigningInput.newBuilder() + .setEsdtnftTransfer(transfer) + .setChainId("1") + .setPrivateKey(privateKey) + .build() + + val output = AnySigner.sign(signingInput, CoinType.MULTIVERSX, MultiversX.SigningOutput.parser()) + val expectedSignature = "59af89d9a9ece1f35bc34323c42061cae27bb5f9830f5eb26772e680732cbd901a86caa7c3eadacd392fe1024bef4c1f08ce1dfcafec257d6f41444ccea30a0c" + val expectedData = "RVNEVE5GVFRyYW5zZmVyQDRjNGI0ZDQ1NTgyZDYxNjE2MjM5MzEzMEAwNEAwMjhlYzNkZmEwMWFjMDAwQDgwNDlkNjM5ZTVhNjk4MGQxY2QyMzkyYWJjY2U0MTAyOWNkYTc0YTE1NjM1MjNhMjAyZjA5NjQxY2MyNjE4Zjg=" + + assertEquals(expectedSignature, output.signature) + assertEquals("""{"nonce":7,"value":"0","receiver":"$aliceBech32","sender":"$aliceBech32","gasPrice":1000000000,"gasLimit":937500,"data":"$expectedData","chainID":"1","version":2,"signature":"$expectedSignature"}""", output.encoded) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nativeinjective/TestNativeInjectiveAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nativeinjective/TestNativeInjectiveAddress.kt new file mode 100644 index 00000000000..8c70eaf1dfe --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nativeinjective/TestNativeInjectiveAddress.kt @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.nativeinjective + +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestNativeInjectiveAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val key = PrivateKey("9ee18daf8e463877aaf497282abc216852420101430482a28e246c179e2c5ef1".toHexByteArray()) + val pubKey = key.getPublicKeySecp256k1(false) + val address = AnyAddress(pubKey, CoinType.NATIVEINJECTIVE) + val expected = AnyAddress("inj13u6g7vqgw074mgmf2ze2cadzvkz9snlwcrtq8a", CoinType.NATIVEINJECTIVE) + + assertEquals(address.description(), expected.description()) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nativeinjective/TestNativeInjectiveSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nativeinjective/TestNativeInjectiveSigner.kt new file mode 100644 index 00000000000..b1295e2d823 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nativeinjective/TestNativeInjectiveSigner.kt @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.nativeinjective + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.AnyAddress +import wallet.core.jni.CoinType +import wallet.core.jni.PrivateKey +import wallet.core.jni.proto.Cosmos + +class TestNativeInjectiveSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun NativeInjectiveTransactionSigning() { + val key = PrivateKey("9ee18daf8e463877aaf497282abc216852420101430482a28e246c179e2c5ef1".toHexByteArray()) + val publicKey = key.getPublicKeySecp256k1(false) + val from = AnyAddress(publicKey, CoinType.NATIVEINJECTIVE).description() + + val transferAmount = Cosmos.Amount.newBuilder().apply { + amount = "10000000000" + denom = "inj" + }.build() + + val message = Cosmos.Message.newBuilder().apply { + sendCoinsMessage = Cosmos.Message.Send.newBuilder().apply { + fromAddress = from + toAddress = "inj1xmpkmxr4as00em23tc2zgmuyy2gr4h3wgcl6vd" + addAllAmounts(listOf(transferAmount)) + }.build() + }.build() + + val feeAmount = Cosmos.Amount.newBuilder().apply { + amount = "100000000000000" + denom = "inj" + }.build() + + val transferFee = Cosmos.Fee.newBuilder().apply { + gas = 110000 + addAllAmounts(listOf(feeAmount)) + }.build() + + val signingInput = Cosmos.SigningInput.newBuilder().apply { + signingMode = Cosmos.SigningMode.Protobuf + accountNumber = 17396 + chainId = "injective-1" + sequence = 1 + fee = transferFee + privateKey = ByteString.copyFrom(key.data()) + addAllMessages(listOf(message)) + }.build() + + val output = AnySigner.sign(signingInput, CoinType.NATIVEINJECTIVE, Cosmos.SigningOutput.parser()) + + // https://www.mintscan.io/injective/txs/135DD2C4A1910E4334A9C0F15125DA992E724EBF23FEB9638FCB71218BB064A5 + assertEquals(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"Co8BCowBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmwKKmluajEzdTZnN3ZxZ3cwNzRtZ21mMnplMmNhZHp2a3o5c25sd2NydHE4YRIqaW5qMXhtcGtteHI0YXMwMGVtMjN0YzJ6Z211eXkyZ3I0aDN3Z2NsNnZkGhIKA2luahILMTAwMDAwMDAwMDASngEKfgp0Ci0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSQwpBBFoMa4O4vZgn5QcnDK20mbfjqQlSRvaiITKB94PYd8mLJWdCdBsGOfMXdo/k9MJ2JmDCESKDp2hdgVUH3uMikXMSBAoCCAEYARIcChYKA2luahIPMTAwMDAwMDAwMDAwMDAwELDbBhpAx2vkplmzeK7n3puCFGPWhLd0l/ZC/CYkGl+stH+3S3hiCvIe7uwwMpUlNaSwvT8HwF1kNUp+Sx2m0Uo1x5xcFw==\"}") + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nativezetachain/TestNativeZetaChainAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nativezetachain/TestNativeZetaChainAddress.kt new file mode 100644 index 00000000000..93a2fbd2a3a --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nativezetachain/TestNativeZetaChainAddress.kt @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.nativezetachain + +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestNativeZetaChainAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val key = PrivateKey("8d2a3bd62d300a148c89dc8635f87b7a24a951bd1c4e78675fe40e1a640d46ed".toHexByteArray()) + val pubKey = key.getPublicKeySecp256k1(false) + val address = AnyAddress(pubKey, CoinType.NATIVEZETACHAIN) + val expected = AnyAddress("zeta14py36sx57ud82t9yrks9z6hdsrpn5x6kmxs0ne", CoinType.NATIVEZETACHAIN) + + assertEquals(address.description(), expected.description()) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nativezetachain/TestNativeZetaChainSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nativezetachain/TestNativeZetaChainSigner.kt new file mode 100644 index 00000000000..2dd00e4f2f8 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nativezetachain/TestNativeZetaChainSigner.kt @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.nativezetachain + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.AnyAddress +import wallet.core.jni.CoinType +import wallet.core.jni.PrivateKey +import wallet.core.jni.proto.Cosmos + +class TestNativeZetaChainSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun NativeZetaChainTransactionSigning() { + val key = PrivateKey("8d2a3bd62d300a148c89dc8635f87b7a24a951bd1c4e78675fe40e1a640d46ed".toHexByteArray()) + val publicKey = key.getPublicKeySecp256k1(false) + val from = AnyAddress(publicKey, CoinType.NATIVEZETACHAIN).description() + + val transferAmount = Cosmos.Amount.newBuilder().apply { + // 0.3 ZETA + amount = "300000000000000000" + denom = "azeta" + }.build() + + val message = Cosmos.Message.newBuilder().apply { + sendCoinsMessage = Cosmos.Message.Send.newBuilder().apply { + fromAddress = from + toAddress = "zeta1cscf4ldnkkz7f0wpveur6dpd0d6p2zxnsuu70y" + addAllAmounts(listOf(transferAmount)) + }.build() + }.build() + + val transferFee = Cosmos.Fee.newBuilder().apply { + gas = 200000 + }.build() + + val signingInput = Cosmos.SigningInput.newBuilder().apply { + signingMode = Cosmos.SigningMode.Protobuf + accountNumber = 2726346 + chainId = "athens_7001-1" + sequence = 2 + fee = transferFee + privateKey = ByteString.copyFrom(key.data()) + txHasher = Cosmos.TxHasher.Keccak256 + signerInfo = Cosmos.SignerInfo.newBuilder().apply { + // Zetachain requires a compressed public key to sign a transaction, + // however an uncompressed public key is used to generate address. + publicKeyType = Cosmos.SignerPublicKeyType.Secp256k1 + jsonType = "ethermint/PubKeyEthSecp256k1" + protobufType = "/ethermint.crypto.v1.ethsecp256k1.PubKey" + }.build() + addAllMessages(listOf(message)) + }.build() + + val output = AnySigner.sign(signingInput, CoinType.NATIVEZETACHAIN, Cosmos.SigningOutput.parser()) + + // Successfully broadcasted (testnet): + // https://explorer.zetachain.com/cosmos/tx/A2FC8816657856ED274C4418C3CAEAEE645561275F6C63AB5F8B1DCFB37341A0 + assertEquals(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CpoBCpcBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEncKK3pldGExNHB5MzZzeDU3dWQ4MnQ5eXJrczl6Nmhkc3JwbjV4NmtteHMwbmUSK3pldGExY3NjZjRsZG5ra3o3ZjB3cHZldXI2ZHBkMGQ2cDJ6eG5zdXU3MHkaGwoFYXpldGESEjMwMDAwMDAwMDAwMDAwMDAwMBJhClkKTwooL2V0aGVybWludC5jcnlwdG8udjEuZXRoc2VjcDI1NmsxLlB1YktleRIjCiECho5+FjRBfbKt/Z/jggW/oP6gGJin/TBWXRP3BWo3wGUSBAoCCAEYAhIEEMCaDBpAgGvqca0w2N9wnHnnxS9HiVud4aQ9lNCumzgNIW6wOR4kvPScacGS1G3kwCw7wyI2NJL8M1eVYjafFIt2FpKl3w==\"}") + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/neo/TestsNEOAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/neo/TestsNEOAddress.kt index dd1ef2e86dc..8eb3f6ac165 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/neo/TestsNEOAddress.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/neo/TestsNEOAddress.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.neo diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/neo/TestsNEOSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/neo/TestsNEOSigner.kt index d67f8d11559..eb40bbf1892 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/neo/TestsNEOSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/neo/TestsNEOSigner.kt @@ -99,5 +99,10 @@ class TestNEOSigner { assertEquals( "8000001efb50cb3be3e08917b308a1dbdb2408109394560ec67518af43035d8c260815c601000bd791a26120eef181d8162bd6cb7495dee1299aa67bb796dcd4a03769f9b24e00000bea299e6a243c9379c3e8884c9176b1456b3017611772b2fadc55d10901ee3f000026c413526bbd45cca355683db9f39d6864a7e298f481f2cdeefe8b578ccea96e00002b2647616d4f4143700f8e862aa8427efd7fa9998fe040e23ed877d2cbd35af700003159b899275e2f0e0b1314acddc7e1ec5948598fca40a9733e2b448fe9344705000036509c8a487005aa8e16663613d2d767461ee2f8dc4f678cc22f9148d4420c8b0000385bfb24fe7f6f5dd28e9836e8220c8ac766efcc4e04082bd9d982ccd6738f040000385bfb24fe7f6f5dd28e9836e8220c8ac766efcc4e04082bd9d982ccd6738f040100385bfb24fe7f6f5dd28e9836e8220c8ac766efcc4e04082bd9d982ccd6738f040200385bfb24fe7f6f5dd28e9836e8220c8ac766efcc4e04082bd9d982ccd6738f040300385bfb24fe7f6f5dd28e9836e8220c8ac766efcc4e04082bd9d982ccd6738f040400385bfb24fe7f6f5dd28e9836e8220c8ac766efcc4e04082bd9d982ccd6738f040500385bfb24fe7f6f5dd28e9836e8220c8ac766efcc4e04082bd9d982ccd6738f040600385bfb24fe7f6f5dd28e9836e8220c8ac766efcc4e04082bd9d982ccd6738f040700385bfb24fe7f6f5dd28e9836e8220c8ac766efcc4e04082bd9d982ccd6738f040800385bfb24fe7f6f5dd28e9836e8220c8ac766efcc4e04082bd9d982ccd6738f04090040ec871088beb680f5b149767dbb0b8ac7ec1a1c5836e177606b6200e6bc83cf00004e393bd89d886ae116ed9e6b49be427b21f7247d896923265e68dfa82b57d79b00005b99bf2caacf20bfc9cd51b3d3472499383c803c2d781d00f1e2dd970325eeb4000062ac42685ef8b856291bb0264fcb767b00706a15243326775f61a159a29c01e100006f011d435ef43c066689d1222f4eada1d4590ebaaa190960ac26a5acf29d37bd00007dea63ea47a6c9e8318f3b19a0df5ccb3a348f54a176736afa7b9b3b843f4c160000925e50254e8056bfd540f3d45f171dbab504f5b191070ee7af1e16764ac7ce4a00009677a6869128961a1a3b17e609e915d2d9a29ceaab5689dccb841ca729665c8900009692e4e512eb2e04b10042bcc28910140b2229ede40291b0e1a0c3c44381825400009dc6c119d0f4bacb1b1e9faffcba33581729c1915a2f1147ce7a6fc8abe4455300009f6b635afee02b5db0c93a5b1bfcace34a18c78d76c73b7bf90d21d4d0193ec80000b11bbb613e36b2bcc6c3a76c888c6c139957a1b7091dab26ce88b65c3fb056340000385bfb24fe7f6f5dd28e9836e8220c8ac766efcc4e04082bd9d982ccd6738f040a00039b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc500ba1dd205000000ea610aa6db39bd8c8556c9569d94b5e5a5d0ad199b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc50083064905000000f2908c7efc0c9e43ffa7e79170ba37e501e1b4ace72d286979ee6cb1b7e65dfddfb2e384100b8d148e7758de42e4168b71792c605013cf0617000000f2908c7efc0c9e43ffa7e79170ba37e501e1b4ac014140dc261ac093a87640441bf0c3ad4a55ec727932b9175f600618bb5275f31aacf122956bc88746dc666759a2d67f120fe3ce1659f916d22a91e0b02421d3bddbd1232102a41c2aea8568864b106553729d32b1317ec463aa23e7a3521455d95992e17a7aac", hex) + + // TODO uncomment when nist256p1 Rust implementation is enabled. + // assertEquals( + // "8000001efb50cb3be3e08917b308a1dbdb2408109394560ec67518af43035d8c260815c601000bd791a26120eef181d8162bd6cb7495dee1299aa67bb796dcd4a03769f9b24e00000bea299e6a243c9379c3e8884c9176b1456b3017611772b2fadc55d10901ee3f000026c413526bbd45cca355683db9f39d6864a7e298f481f2cdeefe8b578ccea96e00002b2647616d4f4143700f8e862aa8427efd7fa9998fe040e23ed877d2cbd35af700003159b899275e2f0e0b1314acddc7e1ec5948598fca40a9733e2b448fe9344705000036509c8a487005aa8e16663613d2d767461ee2f8dc4f678cc22f9148d4420c8b0000385bfb24fe7f6f5dd28e9836e8220c8ac766efcc4e04082bd9d982ccd6738f040000385bfb24fe7f6f5dd28e9836e8220c8ac766efcc4e04082bd9d982ccd6738f040100385bfb24fe7f6f5dd28e9836e8220c8ac766efcc4e04082bd9d982ccd6738f040200385bfb24fe7f6f5dd28e9836e8220c8ac766efcc4e04082bd9d982ccd6738f040300385bfb24fe7f6f5dd28e9836e8220c8ac766efcc4e04082bd9d982ccd6738f040400385bfb24fe7f6f5dd28e9836e8220c8ac766efcc4e04082bd9d982ccd6738f040500385bfb24fe7f6f5dd28e9836e8220c8ac766efcc4e04082bd9d982ccd6738f040600385bfb24fe7f6f5dd28e9836e8220c8ac766efcc4e04082bd9d982ccd6738f040700385bfb24fe7f6f5dd28e9836e8220c8ac766efcc4e04082bd9d982ccd6738f040800385bfb24fe7f6f5dd28e9836e8220c8ac766efcc4e04082bd9d982ccd6738f04090040ec871088beb680f5b149767dbb0b8ac7ec1a1c5836e177606b6200e6bc83cf00004e393bd89d886ae116ed9e6b49be427b21f7247d896923265e68dfa82b57d79b00005b99bf2caacf20bfc9cd51b3d3472499383c803c2d781d00f1e2dd970325eeb4000062ac42685ef8b856291bb0264fcb767b00706a15243326775f61a159a29c01e100006f011d435ef43c066689d1222f4eada1d4590ebaaa190960ac26a5acf29d37bd00007dea63ea47a6c9e8318f3b19a0df5ccb3a348f54a176736afa7b9b3b843f4c160000925e50254e8056bfd540f3d45f171dbab504f5b191070ee7af1e16764ac7ce4a00009677a6869128961a1a3b17e609e915d2d9a29ceaab5689dccb841ca729665c8900009692e4e512eb2e04b10042bcc28910140b2229ede40291b0e1a0c3c44381825400009dc6c119d0f4bacb1b1e9faffcba33581729c1915a2f1147ce7a6fc8abe4455300009f6b635afee02b5db0c93a5b1bfcace34a18c78d76c73b7bf90d21d4d0193ec80000b11bbb613e36b2bcc6c3a76c888c6c139957a1b7091dab26ce88b65c3fb056340000385bfb24fe7f6f5dd28e9836e8220c8ac766efcc4e04082bd9d982ccd6738f040a00039b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc500ba1dd205000000ea610aa6db39bd8c8556c9569d94b5e5a5d0ad199b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc50083064905000000f2908c7efc0c9e43ffa7e79170ba37e501e1b4ace72d286979ee6cb1b7e65dfddfb2e384100b8d148e7758de42e4168b71792c605013cf0617000000f2908c7efc0c9e43ffa7e79170ba37e501e1b4ac014140dc261ac093a87640441bf0c3ad4a55ec727932b9175f600618bb5275f31aacf1dd6a943678b9239a98a65d2980edf01beed0a0b4904573f31309a6a128a54980232102a41c2aea8568864b106553729d32b1317ec463aa23e7a3521455d95992e17a7aac", + // hex) } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nervos/TestNervosAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nervos/TestNervosAddress.kt index 64f1c492ada..f77ce3858cd 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nervos/TestNervosAddress.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nervos/TestNervosAddress.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.nervos diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nervos/TestNervosSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nervos/TestNervosSigner.kt index 3d0a149e5ae..d556f883f17 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nervos/TestNervosSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nervos/TestNervosSigner.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2021 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.nervos diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nuls/TestNULSSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nuls/TestNULSSigner.kt index 44284c35e02..f9399034258 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nuls/TestNULSSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nuls/TestNULSSigner.kt @@ -38,4 +38,84 @@ class TestNULSSigner { "0200f885885d00008c0117010001f7ec6473df12e751d64cf20a8baa7edd50810f8101000100201d9a0000000000000000000000000000000000000000000000000000000000080000000000000000000117010001f05e7878971f3374515eabb6f16d75219d8873120100010080969800000000000000000000000000000000000000000000000000000000000000000000000000692103958b790c331954ed367d37bac901de5c2f06ac8368b37d7bd6cd5ae143c1d7e3463044022028019c0099e2233c7adb84bb03a9a5666ece4a5b65a026a090fa460f3679654702204df0fcb8762b5944b3aba033fa1a287ccb098150035dd8b66f52dc58d3d0843a" ) } + + @Test + fun NULSTokenTransactionSigning() { + val signingInput = NULS.SigningInput.newBuilder() + .setPrivateKey(ByteString.copyFrom(Numeric.hexStringToByteArray("9ce21dad67e0f0af2599b41b515a7f7018059418bab892a7b68f283d489abc4b"))) + .setFrom("NULSd6Hgj7ZoVgsPN9ybB4C1N2TbvkgLc8Z9H") + .setTo("NULSd6Hgied7ym6qMEfVzZanMaa9qeqA6TZSe") + .setAmount(ByteString.copyFrom("0x989680".toHexByteArray())) + .setChainId(9) + .setIdassetsId(1) + .setNonce(ByteString.copyFrom("0000000000000000".toByteArray())) + .setRemark("") + .setBalance(ByteString.copyFrom("0x5F5E100".toHexByteArray())) + .setTimestamp(0x5D8885F8) + .setFeePayer("NULSd6Hgj7ZoVgsPN9ybB4C1N2TbvkgLc8Z9H") + .setFeePayerBalance(ByteString.copyFrom("0xF4240".toHexByteArray())) + .setFeePayerNonce(ByteString.copyFrom("0000000000000000".toByteArray())) + .build() + + val output = AnySigner.sign(signingInput, CoinType.NULS, SigningOutput.parser()) + val encoded = output.encoded.toByteArray() + val hex = Numeric.toHexString(encoded, 0, encoded.size, false) + assertEquals(hex, + "0200f885885d0000d20217010001f7ec6473df12e751d64cf20a8baa7edd50810f810900010080969800000000000000000000000000000000000000000000000000000000000800000000000000000017010001f7ec6473df12e751d64cf20a8baa7edd50810f8101000100a086010000000000000000000000000000000000000000000000000000000000080000000000000000000117010001f05e7878971f3374515eabb6f16d75219d8873120900010080969800000000000000000000000000000000000000000000000000000000000000000000000000692103958b790c331954ed367d37bac901de5c2f06ac8368b37d7bd6cd5ae143c1d7e346304402204629e7e39708468a405f8d8dd208d0133a686beb5d3ae829b7a2f5867c74480902203d0dffac8189b1caa9087e480fd57581e8c382cc4e17034b492dd2178dac851d" + ) + } + + @Test + fun NULSTransactionWithFeePayerSigning() { + val signingInput = NULS.SigningInput.newBuilder() + .setPrivateKey(ByteString.copyFrom(Numeric.hexStringToByteArray("48c91cd24a27a1cdc791022ff39316444229db1c466b3b1841b40c919dee3002"))) + .setFrom("NULSd6HgYx7bdWWv7PxYhYeTRBhD6kZs1o5Ac") + .setTo("NULSd6HgaHjzhMEUjd4T5DFnLz9EvV4TntrdV") + .setAmount(ByteString.copyFrom("0x186A0".toHexByteArray())) + .setChainId(1) + .setIdassetsId(1) + .setNonce(ByteString.copyFrom("0000000000000000".toByteArray())) + .setRemark("") + .setBalance(ByteString.copyFrom("0xF4240".toHexByteArray())) + .setTimestamp(0x62FB3F9F) + .setFeePayer("NULSd6HgYj81NrQBFZYXvyQhHCJCkGYWDTNeA") + .setFeePayerNonce(ByteString.copyFrom("0000000000000000".toByteArray())) + .setFeePayerBalance(ByteString.copyFrom("0xF4240".toHexByteArray())) + .setFeePayerPrivateKey(ByteString.copyFrom(Numeric.hexStringToByteArray("9401fd554cb700777e57b05338f9ff47597add8b23ce9f1c8e041e9b4e2116b6"))) + .build() + + val output = AnySigner.sign(signingInput, CoinType.NULS, SigningOutput.parser()) + val encoded = output.encoded.toByteArray() + val hex = Numeric.toHexString(encoded, 0, encoded.size, false) + assertEquals(hex, + "02009f3ffb620000d202170100014f019a4227bff89d51590fbf53fbd98d994485f801000100a086010000000000000000000000000000000000000000000000000000000000080000000000000000001701000152a6388c8bf54e8fcd73cc824813bfef0912299b01000100a086010000000000000000000000000000000000000000000000000000000000080000000000000000000117010001686a3c9cd2ac45aee0ef825b0443d1eb209368b701000100a0860100000000000000000000000000000000000000000000000000000000000000000000000000d22102764370693450d654d6fc061d1d4dbfbe0c95715fd3cde7e15df073ab0983b8c8463044022040b5820b93fd5e272f2a00518af45a722571834934ba20d9a866de8e6d6409ab022003c610c647648444c1e2193634b2c51817a5a6ac3fe781da1a9ea773506afd8221025910df09ca768909cce9224d182401044c7b5bd44b0adee2ec5f2e64446573ff4630440220140e46b260942a8475f38df39bf54a2eea56c77199fc7ba775aa4b7f147d0d2102206c82705cba509f37ba0e35520a97bccb71a9e35cadcb8d95dd7fde5c8aa9e428" + ) + } + + @Test + fun NULSTokenTransactionWithFeePayerSigning() { + val signingInput = NULS.SigningInput.newBuilder() + .setPrivateKey(ByteString.copyFrom(Numeric.hexStringToByteArray("48c91cd24a27a1cdc791022ff39316444229db1c466b3b1841b40c919dee3002"))) + .setFrom("NULSd6HgYx7bdWWv7PxYhYeTRBhD6kZs1o5Ac") + .setTo("NULSd6HgaHjzhMEUjd4T5DFnLz9EvV4TntrdV") + .setAmount(ByteString.copyFrom("0x186A0".toHexByteArray())) + .setChainId(9) + .setIdassetsId(1) + .setNonce(ByteString.copyFrom("0000000000000000".toByteArray())) + .setRemark("") + .setBalance(ByteString.copyFrom("0xDBBA0".toHexByteArray())) + .setTimestamp(0x62FB4E4C) + .setFeePayer("NULSd6HgYj81NrQBFZYXvyQhHCJCkGYWDTNeA") + .setFeePayerBalance(ByteString.copyFrom("0xF4240".toHexByteArray())) + .setFeePayerNonce(ByteString.copyFrom("e05d03df6ede0e22".toByteArray())) + .setFeePayerPrivateKey(ByteString.copyFrom(Numeric.hexStringToByteArray("9401fd554cb700777e57b05338f9ff47597add8b23ce9f1c8e041e9b4e2116b6"))) + .build() + + val output = AnySigner.sign(signingInput, CoinType.NULS, SigningOutput.parser()) + val encoded = output.encoded.toByteArray() + val hex = Numeric.toHexString(encoded, 0, encoded.size, false) + assertEquals(hex, + "02004c4efb620000d2021701000152a6388c8bf54e8fcd73cc824813bfef0912299b09000100a08601000000000000000000000000000000000000000000000000000000000008000000000000000000170100014f019a4227bff89d51590fbf53fbd98d994485f801000100a08601000000000000000000000000000000000000000000000000000000000008e05d03df6ede0e22000117010001686a3c9cd2ac45aee0ef825b0443d1eb209368b709000100a0860100000000000000000000000000000000000000000000000000000000000000000000000000d32102764370693450d654d6fc061d1d4dbfbe0c95715fd3cde7e15df073ab0983b8c8463044022025cb5b40bda4e6fc0ba719bb0c1a907b2a0faa91316ef2c836310d49f906b6a802207d530a56a6c56d974036c86125da06d6e47f9d8ba1544ac3e620cebd883a707821025910df09ca768909cce9224d182401044c7b5bd44b0adee2ec5f2e64446573ff473045022100ff6f45a1c3856f9ea954baca6b2988295bbb22c958f87f0d3baf9989930549530220426ecb1520513710b99ab50e1f6c7e21b0175adef08aa05070bb9bfca8a001d8" + ) + } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/oasis/TestOasisAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/oasis/TestOasisAddress.kt index 2cdc8dfcd4a..00b315bc40a 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/oasis/TestOasisAddress.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/oasis/TestOasisAddress.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.oasis diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/oasis/TestOasisSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/oasis/TestOasisSigner.kt index f9962ebb13c..ef3ad829694 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/oasis/TestOasisSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/oasis/TestOasisSigner.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.oasis diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ontology/TestOntologySigning.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ontology/TestOntologySigning.kt index abff3b06c6c..2bf777966fb 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ontology/TestOntologySigning.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ontology/TestOntologySigning.kt @@ -76,6 +76,11 @@ class TestOntologySigning { assertEquals( "00d102d45c8bf401000000000000204e00000000000057e9d1a61f9aafa798b6c7fbeae35639681d7df67100c66b14fbacc8214765d457c8e3f2b5a1d3c4981a2e9d2a6a7cc814feec06b79ed299ea06fcb94abac41aaf3ead76586a7cc8516a7cc86c51c1087472616e736665721400000000000000000000000000000000000000010068164f6e746f6c6f67792e4e61746976652e496e766f6b6500024140301766d925382a6ebb2ebeb18d3741954c9370dcf6d9c45b34ce7b18bc42dcdb7cff28ddaf7f1048822c0ca21a0c4926323a2497875b963f3b8cbd3717aa6e7c2321031bec1250aa8f78275f99a6663688f31085848d0ed92f1203e447125f927b7486ac414038466b25ac49a22ba8c301328ef049a61711b257987e85e25d63e0444a14e860305a4cd3bb6ea2fe80fd293abb3c592e679c42c546cbf3baa051a07b28b374a6232103d9fd62df332403d9114f3fa3da0d5aec9dfa42948c2f50738d52470469a1a1eeac", hex) + + // TODO uncomment when nist256p1 Rust implementation is enabled. + // assertEquals( + // "00d102d45c8bf401000000000000204e00000000000057e9d1a61f9aafa798b6c7fbeae35639681d7df67100c66b14fbacc8214765d457c8e3f2b5a1d3c4981a2e9d2a6a7cc814feec06b79ed299ea06fcb94abac41aaf3ead76586a7cc8516a7cc86c51c1087472616e736665721400000000000000000000000000000000000000010068164f6e746f6c6f67792e4e61746976652e496e766f6b6500024140301766d925382a6ebb2ebeb18d3741954c9370dcf6d9c45b34ce7b18bc42dcdb8300d7215080efb87dd3f35de5f3b6d98aacd6161fbc0845b82d0d8be4b8b6d52321031bec1250aa8f78275f99a6663688f31085848d0ed92f1203e447125f927b7486ac414038466b25ac49a22ba8c301328ef049a61711b257987e85e25d63e0444a14e860305a4cd3bb6ea2fe80fd293abb3c592e679c42c546cbf3baa051a07b28b374a6232103d9fd62df332403d9114f3fa3da0d5aec9dfa42948c2f50738d52470469a1a1eeac", + // hex) } @Test @@ -100,6 +105,11 @@ class TestOntologySigning { assertEquals( "00d19d3182a8f401000000000000204e00000000000057e9d1a61f9aafa798b6c7fbeae35639681d7df67100c66b14fbacc8214765d457c8e3f2b5a1d3c4981a2e9d2a6a7cc814feec06b79ed299ea06fcb94abac41aaf3ead76586a7cc8516a7cc86c51c1087472616e736665721400000000000000000000000000000000000000020068164f6e746f6c6f67792e4e61746976652e496e766f6b6500024140e27e935b87855efad62bb76b21c7b591f445f867eff86f888ca6ee1870ecd80f73b8ab199a4d757b4c7b9ed46c4ff8cfa8aefaa90b7fb6485e358034448cba752321031bec1250aa8f78275f99a6663688f31085848d0ed92f1203e447125f927b7486ac4140450047b2efb384129a16ec4c707790e9379b978cc7085170071d8d7c5c037d743b078bd4e21bb4404c0182a32ee05260e22454dffb34dacccf458dfbee6d32db232103d9fd62df332403d9114f3fa3da0d5aec9dfa42948c2f50738d52470469a1a1eeac", hex) + + // TODO uncomment when nist256p1 Rust implementation is enabled. + // assertEquals( + // "00d19d3182a8f401000000000000204e00000000000057e9d1a61f9aafa798b6c7fbeae35639681d7df67100c66b14fbacc8214765d457c8e3f2b5a1d3c4981a2e9d2a6a7cc814feec06b79ed299ea06fcb94abac41aaf3ead76586a7cc8516a7cc86c51c1087472616e736665721400000000000000000000000000000000000000020068164f6e746f6c6f67792e4e61746976652e496e766f6b6500024140e27e935b87855efad62bb76b21c7b591f445f867eff86f888ca6ee1870ecd80f8c4754e565b28a85b384612b93b00730143800049b97e83c95844a8eb7d66adc2321031bec1250aa8f78275f99a6663688f31085848d0ed92f1203e447125f927b7486ac4140450047b2efb384129a16ec4c707790e9379b978cc7085170071d8d7c5c037d74c4f8742a1de44bc0b3fe7d5cd11fad9edac2a5cdabe2c3b824743cc70df5f276232103d9fd62df332403d9114f3fa3da0d5aec9dfa42948c2f50738d52470469a1a1eeac", + // hex) } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/osmosis/TestOsmosisAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/osmosis/TestOsmosisAddress.kt index 1d881bbdef1..88b33d1b9fd 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/osmosis/TestOsmosisAddress.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/osmosis/TestOsmosisAddress.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2021 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.osmosis diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/osmosis/TestOsmosisSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/osmosis/TestOsmosisSigner.kt index 97f075947ba..679583594f7 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/osmosis/TestOsmosisSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/osmosis/TestOsmosisSigner.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2021 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.osmosis @@ -73,6 +71,6 @@ class TestOsmosisSigner { val output = AnySigner.sign(signingInput, OSMOSIS, SigningOutput.parser()) assertEquals(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"Co0BCooBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmoKK29zbW8xbWt5Njljbjhla3R3eTA4NDV2ZWM5dXBzZHBoa3R4dDBlbjk3ZjUSK29zbW8xOHMwaGRuc2xsZ2NjbHdldTlheW13NG5na3RyMmswcmt2bjdqbW4aDgoFdW9zbW8SBTk5ODAwEmQKTgpGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQLs71zkN6MCxn+VRo3ksx826RH0Z9fmpStBweE+HVY2SRIECgIIARISCgwKBXVvc21vEgMyMDAQwJoMGkAMY//Md5GRUR4lVZhk558hFS3kii9QZYoYKfg4+ac/xgNeyoiEweVDhcmEvlH1orVwjLUOnYs4ly2a/yIurYVj\"}") - assertEquals(output.error, "") + assertEquals(output.errorMessage, "") } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/pactus/TestPactusAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/pactus/TestPactusAddress.kt new file mode 100644 index 00000000000..b58b068b859 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/pactus/TestPactusAddress.kt @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.pactus + +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestPactusAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val key = PrivateKey("4e51f1f3721f644ac7a193be7f5e7b8c2abaa3467871daf4eacb5d3af080e5d6".toHexByteArray()) + val pubkey = key.publicKeyEd25519 + val address = AnyAddress(pubkey, CoinType.PACTUS) + val expected = AnyAddress("pc1rwzvr8rstdqypr80ag3t6hqrtnss9nwymcxy3lr", CoinType.PACTUS) + + assertEquals(pubkey.data().toHex(), "0x95794161374b22c696dabb98e93f6ca9300b22f3b904921fbf560bb72145f4fa") + assertEquals(address.description(), expected.description()) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/pactus/TestPactusSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/pactus/TestPactusSigner.kt new file mode 100644 index 00000000000..81bbe9bf532 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/pactus/TestPactusSigner.kt @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.pactus + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.PrivateKey +import wallet.core.java.AnySigner +import wallet.core.jni.CoinType +import wallet.core.jni.CoinType.PACTUS +import wallet.core.jni.proto.Pactus +import wallet.core.jni.proto.Pactus.SigningOutput +import com.trustwallet.core.app.utils.Numeric +import org.junit.Assert.assertArrayEquals + +class TestPactusSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testPactusTransferSigning() { + // Successfully broadcasted transaction: + // https://pacviewer.com/transaction/1b6b7226f7935a15f05371d1a1fefead585a89704ce464b7cc1d453d299d235f + // + val signingInput = Pactus.SigningInput.newBuilder() + signingInput.apply { + privateKey = ByteString.copyFrom( + PrivateKey("4e51f1f3721f644ac7a193be7f5e7b8c2abaa3467871daf4eacb5d3af080e5d6" + .toHexByteArray()).data() + ) + transaction = Pactus.TransactionMessage.newBuilder().apply { + lockTime = 2335524 + fee = 10000000 + memo = "wallet-core" + transfer = Pactus.TransferPayload.newBuilder().apply { + sender = "pc1rwzvr8rstdqypr80ag3t6hqrtnss9nwymcxy3lr" + receiver = "pc1r0g22ufzn8qtw0742dmfglnw73e260hep0k3yra" + amount = 200000000 + }.build() + }.build() + } + + val output = AnySigner.sign(signingInput.build(), PACTUS, SigningOutput.parser()) + + assertEquals( + "0x1b6b7226f7935a15f05371d1a1fefead585a89704ce464b7cc1d453d299d235f", + Numeric.toHexString(output.transactionId.toByteArray()) + ) + + assertEquals( + "0x4ed8fee3d8992e82660dd05bbe8608fc56ceabffdeeee61e3213b9b49d33a0fc8dea6d79ee7ec60f66433f189ed9b3c50b2ad6fa004e26790ee736693eda8506", + Numeric.toHexString(output.signature.toByteArray()) + ) + + assertEquals( + "0x000124a3230080ade2040b77616c6c65742d636f726501037098338e0b6808119dfd4457ab806b9c2059b89b037a14ae24533816e7faaa6ed28fcdde8e55a7df218084af5f4ed8fee3d8992e82660dd05bbe8608fc56ceabffdeeee61e3213b9b49d33a0fc8dea6d79ee7ec60f66433f189ed9b3c50b2ad6fa004e26790ee736693eda850695794161374b22c696dabb98e93f6ca9300b22f3b904921fbf560bb72145f4fa", + Numeric.toHexString(output.signedTransactionData.toByteArray()) + ) + } + + @Test + fun testPactusBondWithPublicKeySigning() { + // Successfully broadcasted transaction: + // https://pacviewer.com/transaction/d194b445642a04ec78ced4448696e50b733f2f0b517a23871882c0eefaf1c28f + // + val signingInput = Pactus.SigningInput.newBuilder() + signingInput.apply { + privateKey = ByteString.copyFrom( + PrivateKey("4e51f1f3721f644ac7a193be7f5e7b8c2abaa3467871daf4eacb5d3af080e5d6" + .toHexByteArray()).data() + ) + transaction = Pactus.TransactionMessage.newBuilder().apply { + lockTime = 2339009 + fee = 10000000 + memo = "wallet-core" + bond = Pactus.BondPayload.newBuilder().apply { + sender = "pc1rwzvr8rstdqypr80ag3t6hqrtnss9nwymcxy3lr" + receiver = "pc1p9y5gmu9l002tt60wak9extgvwm69rq3a9ackrl" + stake = 1000000000 + publicKey = "public1pnz75msstqdrq5eguvcwanug0zauhqjw2cc4flmez3qethnp68y64ehc4k69amapj7x4na2uda0snqz4yxujgx3jsse4f64fgy7jkh0xauvhrc5ts09vfk48g85t0js66hvajm6xruemsvlxqv3xvkyur8v9v0mtn" + }.build() + }.build() + } + + val output = AnySigner.sign(signingInput.build(), PACTUS, SigningOutput.parser()) + + assertEquals( + "0xd194b445642a04ec78ced4448696e50b733f2f0b517a23871882c0eefaf1c28f", + Numeric.toHexString(output.transactionId.toByteArray()) + ) + + assertEquals( + "0x0d7bc6d94927534b89e2f53bcfc9fc849e0e2982438955eda55b4338328adac79d4ee3216d143f0e1629764ab650734f8ba188e716d71f9eff65e39ce7006300", + Numeric.toHexString(output.signature.toByteArray()) + ) + + assertEquals( + "0x0001c1b0230080ade2040b77616c6c65742d636f726502037098338e0b6808119dfd4457ab806b9c2059b89b0129288df0bf7bd4b5e9eeed8b932d0c76f451823d6098bd4dc20b03460a651c661dd9f10f17797049cac62a9fef228832bbcc3a39355cdf15b68bddf432f1ab3eab8debe1300aa43724834650866a9d552827a56bbcdde32e3c517079589b54e83d16f9435abb3b2de8c3e677067cc0644ccb13833b8094ebdc030d7bc6d94927534b89e2f53bcfc9fc849e0e2982438955eda55b4338328adac79d4ee3216d143f0e1629764ab650734f8ba188e716d71f9eff65e39ce700630095794161374b22c696dabb98e93f6ca9300b22f3b904921fbf560bb72145f4fa", + Numeric.toHexString(output.signedTransactionData.toByteArray()) + ) + } + + @Test + fun testPactusBondWithoutPublicKeySigning() { + // Successfully broadcasted transaction: + // https://pacviewer.com/transaction/f83f583a5c40adf93a90ea536a7e4b467d30ca4f308d5da52624d80c42adec80 + // + val signingInput = Pactus.SigningInput.newBuilder() + signingInput.apply { + privateKey = ByteString.copyFrom( + PrivateKey("4e51f1f3721f644ac7a193be7f5e7b8c2abaa3467871daf4eacb5d3af080e5d6" + .toHexByteArray()).data() + ) + transaction = Pactus.TransactionMessage.newBuilder().apply { + lockTime = 2335580 + fee = 10000000 + memo = "wallet-core" + bond = Pactus.BondPayload.newBuilder().apply { + sender = "pc1rwzvr8rstdqypr80ag3t6hqrtnss9nwymcxy3lr" + receiver = "pc1p6taz5l2kq5ppnxv4agnqj48svnvsy797xpe6wd" + stake = 1000000000 + }.build() + }.build() + } + + val output = AnySigner.sign(signingInput.build(), PACTUS, SigningOutput.parser()) + + assertEquals( + "0xf83f583a5c40adf93a90ea536a7e4b467d30ca4f308d5da52624d80c42adec80", + Numeric.toHexString(output.transactionId.toByteArray()) + ) + + assertEquals( + "0x9e6279fb64067c7d7316ac74630bbb8589df268aa4548f1c7d85c087a8748ff0715b9149afbd94c5d8ee6b37c787ec63e963cbb38be513ebc436aa58f9a8f00d", + Numeric.toHexString(output.signature.toByteArray()) + ) + + assertEquals( + "0x00015ca3230080ade2040b77616c6c65742d636f726502037098338e0b6808119dfd4457ab806b9c2059b89b01d2fa2a7d560502199995ea260954f064d90278be008094ebdc039e6279fb64067c7d7316ac74630bbb8589df268aa4548f1c7d85c087a8748ff0715b9149afbd94c5d8ee6b37c787ec63e963cbb38be513ebc436aa58f9a8f00d95794161374b22c696dabb98e93f6ca9300b22f3b904921fbf560bb72145f4fa", + Numeric.toHexString(output.signedTransactionData.toByteArray()) + ) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/polkadot/TestPolkadotAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/polkadot/TestPolkadotAddress.kt index 82477b4bbbe..7ab39ef55f5 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/polkadot/TestPolkadotAddress.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/polkadot/TestPolkadotAddress.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.Polkadot diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/polkadot/TestPolkadotSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/polkadot/TestPolkadotSigner.kt index 2e5a09f2885..da571e5ca1a 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/polkadot/TestPolkadotSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/polkadot/TestPolkadotSigner.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.polkadot @@ -39,7 +37,7 @@ class TestPolkadotSigner { blockHash = genesisHashStr nonce = 0 specVersion = 17 - network = Polkadot.Network.POLKADOT + network = POLKADOT.ss58Prefix() transactionVersion = 3 privateKey = key stakingCall = Polkadot.Staking.newBuilder().apply { @@ -69,7 +67,7 @@ class TestPolkadotSigner { blockHash = genesisHashStr nonce = 4 specVersion = 30 - network = Polkadot.Network.POLKADOT + network = POLKADOT.ss58Prefix() transactionVersion = 7 privateKey = iOSTestKey stakingCall = Polkadot.Staking.newBuilder().apply { @@ -96,7 +94,7 @@ class TestPolkadotSigner { blockHash = "0x35ba668bb19453e8da6334cadcef2a27c8d4141bfc8b49e78e853c3d73e1ecd0".toHexBytesInByteString() nonce = 6 specVersion = 9200 - network = Polkadot.Network.POLKADOT + network = POLKADOT.ss58Prefix() transactionVersion = 12 privateKey = "298fcced2b497ed48367261d8340f647b3fca2d9415d57c2e3c5ef90482a2266".toHexBytesInByteString() era = Polkadot.Era.newBuilder().apply { diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/polygon/TestPolygonAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/polygon/TestPolygonAddress.kt index f6b21b1780c..ab807796d5a 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/polygon/TestPolygonAddress.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/polygon/TestPolygonAddress.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.polygon diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ripple/TestRippleTransactionSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ripple/TestRippleTransactionSigner.kt index d98aab2490d..9ec91772b1b 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ripple/TestRippleTransactionSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ripple/TestRippleTransactionSigner.kt @@ -19,20 +19,25 @@ class TestRippleTransactionSigner { @Test fun testRippleTransactionSigning() { + val operation = Ripple.OperationPayment.newBuilder() + operation.apply { + amount = 10 + destination = "rU893viamSnsfP3zjzM2KPxjqZjXSXK6VF" + } val signingInput = Ripple.SigningInput.newBuilder() signingInput.apply { - account = "rDpysuumkweqeC7XdNgYNtzL5GxbdsmrtF" - amount = 29_000_000 - destination = "rU893viamSnsfP3zjzM2KPxjqZjXSXK6VF" - fee = 200_000 - sequence = 1 - privateKey = ByteString.copyFrom(PrivateKey("ba005cd605d8a02e3d5dfd04234cef3a3ee4f76bfbad2722d1fb5af8e12e6764".toHexByteArray()).data()) + account = "rfxdLwsZnoespnTDDb1Xhvbc8EFNdztaoq" + fee = 10 + sequence = 32268248 + lastLedgerSequence = 32268269 + privateKey = ByteString.copyFrom(PrivateKey("a5576c0f63da10e584568c8d134569ff44017b0a249eb70657127ae04f38cc77".toHexByteArray()).data()) + opPayment = operation.build() } val sign = AnySigner.sign(signingInput.build(), XRP, SigningOutput.parser()) val signBytes = sign.encoded.toByteArray() - assertEquals(signBytes.toHex(), "0x12000022800000002400000001614000000001ba8140684000000000030d407321026cc34b92cefb3a4537b3edb0b6044c04af27c01583c577823ecc69a9a21119b6744630440220067f20b3eebfc7107dd0bcc72337a236ac3be042c0469f2341d76694a17d4bb9022048393d7ee7dcb729783b33f5038939ddce1bb8337e66d752974626854556bbb681148400b6b6d08d5d495653d73eda6804c249a5148883148132e4e20aecf29090ac428a9c43f230a829220d") + assertEquals(signBytes.toHex(), "0x12000022000000002401ec5fd8201b01ec5fed61400000000000000a68400000000000000a732103d13e1152965a51a4a9fd9a8b4ea3dd82a4eba6b25fcad5f460a2342bb650333f74463044022037d32835c9394f39b2cfd4eaf5b0a80e0db397ace06630fa2b099ff73e425dbc02205288f780330b7a88a1980fa83c647b5908502ad7de9a44500c08f0750b0d9e8481144c55f5a78067206507580be7bb2686c8460adff983148132e4e20aecf29090ac428a9c43f230a829220d") } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/scroll/TestScrollAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/scroll/TestScrollAddress.kt new file mode 100644 index 00000000000..23d77ff4ccb --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/scroll/TestScrollAddress.kt @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.scroll + +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestScrollAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val key = PrivateKey("828c4c48c2cef521f0251920891ed79e871faa24f64f43cde83d07bc99f8dbf0".toHexByteArray()) + val pubkey = key.getPublicKeySecp256k1(false) + val address = AnyAddress(pubkey, CoinType.SCROLL) + val expected = AnyAddress("0xe32DC46bfBF78D1eada7b0a68C96903e01418D64", CoinType.SCROLL) + + assertEquals(address.description(), expected.description()) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/secret/TestSecretAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/secret/TestSecretAddress.kt new file mode 100644 index 00000000000..5315c57c9ad --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/secret/TestSecretAddress.kt @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.secret + +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestSecretAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val key = PrivateKey("87201512d132ef7a1e57f9e24905fbc24300bd73f676b5716182be5f3e39dada".toHexByteArray()) + val pubkey = key.getPublicKeySecp256k1(true) + val address = AnyAddress(pubkey, CoinType.SECRET) + val expected = AnyAddress("secret18mdrja40gfuftt5yx6tgj0fn5lurplezyp894y", CoinType.SECRET) + + assertEquals(pubkey.data().toHex(), "0x02466ac5d28cb4fab6c349060c6c1619e8d301e7741fb6b33cc1edac25f45d8646") + assertEquals(address.description(), expected.description()) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/secret/TestSecretSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/secret/TestSecretSigner.kt new file mode 100644 index 00000000000..3f1ef6330a0 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/secret/TestSecretSigner.kt @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.secret + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.Numeric +import com.trustwallet.core.app.utils.toHexByteArray +import com.trustwallet.core.app.utils.toHexBytes +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexBytesInByteString +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.CoinType.SECRET +import wallet.core.jni.proto.Cosmos +import wallet.core.jni.proto.Cosmos.SigningOutput +import wallet.core.jni.proto.Cosmos.SigningMode +import wallet.core.jni.* + +class TestSecretSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun SecretTransactionSigning() { + val key = PrivateKey("87201512d132ef7a1e57f9e24905fbc24300bd73f676b5716182be5f3e39dada".toHexByteArray()) + val publicKey = key.getPublicKeySecp256k1(true) + val from = AnyAddress(publicKey, SECRET).description() + + val txAmount = Cosmos.Amount.newBuilder().apply { + amount = "100000" + denom = "uscrt" + }.build() + + val sendCoinsMsg = Cosmos.Message.Send.newBuilder().apply { + fromAddress = from + toAddress = "secret1rnq6hjfnalxeef87rmdeya3nu9dhpc7k9pujs3" + addAllAmounts(listOf(txAmount)) + }.build() + + val message = Cosmos.Message.newBuilder().apply { + sendCoinsMessage = sendCoinsMsg + }.build() + + val feeAmount = Cosmos.Amount.newBuilder().apply { + amount = "2500" + denom = "uscrt" + }.build() + + val secretFee = Cosmos.Fee.newBuilder().apply { + gas = 25000 + addAllAmounts(listOf(feeAmount)) + }.build() + + val signingInput = Cosmos.SigningInput.newBuilder().apply { + signingMode = SigningMode.Protobuf + accountNumber = 265538 + chainId = "secret-4" + memo = "" + sequence = 1 + fee = secretFee + privateKey = ByteString.copyFrom(key.data()) + addAllMessages(listOf(message)) + }.build() + + val output = AnySigner.sign(signingInput, SECRET, SigningOutput.parser()) + + assertEquals(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CpIBCo8BChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEm8KLXNlY3JldDE4bWRyamE0MGdmdWZ0dDV5eDZ0Z2owZm41bHVycGxlenlwODk0eRItc2VjcmV0MXJucTZoamZuYWx4ZWVmODdybWRleWEzbnU5ZGhwYzdrOXB1anMzGg8KBXVzY3J0EgYxMDAwMDASZwpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohAkZqxdKMtPq2w0kGDGwWGejTAed0H7azPMHtrCX0XYZGEgQKAggBGAESEwoNCgV1c2NydBIEMjUwMBCowwEaQOcHd2gHpa5WKZ/5RRerEtrHlyDlojIEzUGhC9xMFgs7UQMWy+kTTN+NRf7zQ8rx3cPkIKeZhv0u1KRc8uRCc4o=\"}") + assertEquals(output.errorMessage, "") + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/smartbitcoincash/TestSmartBitcoinCashAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/smartbitcoincash/TestSmartBitcoinCashAddress.kt index 852245d5a05..64c33ba9c58 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/smartbitcoincash/TestSmartBitcoinCashAddress.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/smartbitcoincash/TestSmartBitcoinCashAddress.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2021 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.smartbitcoincash @@ -20,12 +18,12 @@ class TestSmartBitcoinCashAddress { @Test fun testAddress() { - val key = PrivateKey("ab4accc9310d90a61fc354d8f353bca4a2b3c0590685d3eb82d0216af3badddc".toHexByteArray()) + val key = PrivateKey("155cbd57319f3d938977b4c18000473eb3c432c4e31b667b63e88559c497d82d".toHexByteArray()) val pubkey = key.getPublicKeySecp256k1(false) val address = AnyAddress(pubkey, CoinType.SMARTBITCOINCASH) - val expected = AnyAddress("0xA3Dcd899C0f3832DFDFed9479a9d828c6A4EB2A7", CoinType.SMARTBITCOINCASH) + val expected = AnyAddress("0x8bFC9477684987dcAf0970b9bce5E3D9267C99C0", CoinType.SMARTBITCOINCASH) - assertEquals(pubkey.data().toHex(), "0x0448a9ffac8022f1c7eb5253746e24d11d9b6b2737c0aecd48335feabb95a179916b1f3a97bed6740a85a2d11c663d38566acfb08af48a47ce0c835c65c9b23d0d") + assertEquals(pubkey.data().toHex(), "0x046439f94100c802691c53ef18523be2c24d301f0e2bd3b425e832378a5405eff4331d5e57303785969073321fc76a8504a3854bdb21e6ab7b268a1737882a29c0") assertEquals(address.description(), expected.description()) } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/smartchain/TestBinanceSmartChainAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/smartchain/TestBinanceSmartChainAddress.kt index 142cbc0babe..a9a83132c36 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/smartchain/TestBinanceSmartChainAddress.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/smartchain/TestBinanceSmartChainAddress.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.binancesmartchain diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/solana/TestSolanaTransaction.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/solana/TestSolanaTransaction.kt new file mode 100644 index 00000000000..a7f1ca53348 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/solana/TestSolanaTransaction.kt @@ -0,0 +1,121 @@ +package com.trustwallet.core.app.blockchains.solana + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.Base64 +import wallet.core.jni.CoinType.SOLANA +import wallet.core.jni.SolanaTransaction +import wallet.core.jni.DataVector +import wallet.core.jni.TransactionDecoder +import wallet.core.jni.proto.Common.SigningError +import wallet.core.jni.proto.Solana +import wallet.core.jni.proto.Solana.DecodingTransactionOutput +import wallet.core.jni.proto.Solana.SigningInput +import wallet.core.jni.proto.Solana.SigningOutput +import wallet.core.jni.proto.Solana.Encoding + +class TestSolanaTransaction { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testUpdateBlockhashAndSign() { + val encodedTx = "AnQTYwZpkm3fs4SdLxnV6gQj3hSLsyacpxDdLMALYWObm722f79IfYFTbZeFK9xHtMumiDOWAM2hHQP4r/GtbARpncaXgOVFv7OgbRLMbuCEJHO1qwcdCbtH72VzyzU8yw9sqqHIAaCUE8xaQTgT6Z5IyZfeyMe2QGJIfOjz65UPAgACBssq8Im1alV3N7wXGODL8jLPWwLhTuCqfGZ1Iz9fb5tXlMOJD6jUvASrKmdtLK/qXNyJns2Vqcvlk+nfJYdZaFpIWiT/tAcEYbttfxyLdYxrLckAKdVRtf1OrNgtZeMCII4SAn6SYaaidrX/AN3s/aVn/zrlEKW0cEUIatHVDKtXO0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqcG3fbh12Whk9nL4UbO63msHLSF7V9bN5E6jPWFfv8Aqe6sdLXiXSDILEtzckCjkjchiSf6zVGpMYiAE5BE2IqHAQUEAgQDAQoMoA8AAAAAAAAG" + val newBlockhash = "CyPYVsYWrsJNfVpi8aazu7WsrswNFuDd385z6GNoBGUg" + + val myPrivateKey = "7f0932159226ddec9e1a4b0b8fe7cdc135049f9e549a867d722aa720dd64f32e".toHexByteArray() + val feePayerPrivateKey = "4b9d6f57d28b06cbfa1d4cc710953e62d653caf853415c56ffd9d150acdeb7f7".toHexByteArray() + + val privateKeys = DataVector() + privateKeys.add(myPrivateKey) + privateKeys.add(feePayerPrivateKey) + + val outputData = SolanaTransaction.updateBlockhashAndSign(encodedTx, newBlockhash, privateKeys) + val output = SigningOutput.parseFrom(outputData) + + assertEquals(output.error, SigningError.OK) + val expectedString = "Ajzc/Tke0CG8Cew5qFa6xZI/7Ya3DN0M8Ige6tKPsGzhg8Bw9DqL18KUrEZZ1F4YqZBo4Rv+FsDT8A7Nss7p4A6BNVZzzGprCJqYQeNg0EVIbmPc6mDitNniHXGeKgPZ6QZbM4FElw9O7IOFTpOBPvQFeqy0vZf/aayncL8EK/UEAgACBssq8Im1alV3N7wXGODL8jLPWwLhTuCqfGZ1Iz9fb5tXlMOJD6jUvASrKmdtLK/qXNyJns2Vqcvlk+nfJYdZaFpIWiT/tAcEYbttfxyLdYxrLckAKdVRtf1OrNgtZeMCII4SAn6SYaaidrX/AN3s/aVn/zrlEKW0cEUIatHVDKtXO0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqcG3fbh12Whk9nL4UbO63msHLSF7V9bN5E6jPWFfv8AqbHiki6ThNH3auuyZPQpJntnN0mA//56nMpK/6HIuu8xAQUEAgQDAQoMoA8AAAAAAAAG" + assertEquals(output.encoded, expectedString) + } + + @Test + fun testDecodeUpdateBlockhashAndSign() { + // https://explorer.solana.com/tx/3KbvREZUat76wgWMtnJfWbJL74Vzh4U2eabVJa3Z3bb2fPtW8AREP5pbmRwUrxZCESbTomWpL41PeKDcPGbojsej?cluster=devnet + val encodedTx = Base64.decode("AnQTYwZpkm3fs4SdLxnV6gQj3hSLsyacpxDdLMALYWObm722f79IfYFTbZeFK9xHtMumiDOWAM2hHQP4r/GtbARpncaXgOVFv7OgbRLMbuCEJHO1qwcdCbtH72VzyzU8yw9sqqHIAaCUE8xaQTgT6Z5IyZfeyMe2QGJIfOjz65UPAgACBssq8Im1alV3N7wXGODL8jLPWwLhTuCqfGZ1Iz9fb5tXlMOJD6jUvASrKmdtLK/qXNyJns2Vqcvlk+nfJYdZaFpIWiT/tAcEYbttfxyLdYxrLckAKdVRtf1OrNgtZeMCII4SAn6SYaaidrX/AN3s/aVn/zrlEKW0cEUIatHVDKtXO0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqcG3fbh12Whk9nL4UbO63msHLSF7V9bN5E6jPWFfv8Aqe6sdLXiXSDILEtzckCjkjchiSf6zVGpMYiAE5BE2IqHAQUEAgQDAQoMoA8AAAAAAAAG") + val newBlockhash = "CyPYVsYWrsJNfVpi8aazu7WsrswNFuDd385z6GNoBGUg" + + val senderPrivateKeyData = "7f0932159226ddec9e1a4b0b8fe7cdc135049f9e549a867d722aa720dd64f32e".toHexByteArray() + val feePayerPrivateKeyData = "4b9d6f57d28b06cbfa1d4cc710953e62d653caf853415c56ffd9d150acdeb7f7".toHexByteArray() + + // Step 1: Decode the transaction. + + val decodedData = TransactionDecoder.decode(SOLANA, encodedTx) + val decodedOutput = DecodingTransactionOutput.parseFrom(decodedData) + + assertEquals(decodedOutput.error, SigningError.OK) + assert(decodedOutput.transaction.hasLegacy()) + + // Step 2: Update recent blockhash. + + val rawTx = decodedOutput.transaction.toBuilder().apply { + legacy = decodedOutput.transaction.legacy.toBuilder().setRecentBlockhash(newBlockhash).build() + }.build() + + // Step 3: Re-sign the updated transaction. + + val signingInput = SigningInput.newBuilder().apply { + rawMessage = rawTx + privateKey = ByteString.copyFrom(senderPrivateKeyData) + feePayerPrivateKey = ByteString.copyFrom(feePayerPrivateKeyData) + txEncoding = Solana.Encoding.Base64 + }.build() + + val output = AnySigner.sign(signingInput, SOLANA, SigningOutput.parser()) + val expectedString = "Ajzc/Tke0CG8Cew5qFa6xZI/7Ya3DN0M8Ige6tKPsGzhg8Bw9DqL18KUrEZZ1F4YqZBo4Rv+FsDT8A7Nss7p4A6BNVZzzGprCJqYQeNg0EVIbmPc6mDitNniHXGeKgPZ6QZbM4FElw9O7IOFTpOBPvQFeqy0vZf/aayncL8EK/UEAgACBssq8Im1alV3N7wXGODL8jLPWwLhTuCqfGZ1Iz9fb5tXlMOJD6jUvASrKmdtLK/qXNyJns2Vqcvlk+nfJYdZaFpIWiT/tAcEYbttfxyLdYxrLckAKdVRtf1OrNgtZeMCII4SAn6SYaaidrX/AN3s/aVn/zrlEKW0cEUIatHVDKtXO0Qss5EhV/E6kz0BNCgtAytf/s0Botvxt3kGCN8ALqcG3fbh12Whk9nL4UbO63msHLSF7V9bN5E6jPWFfv8AqbHiki6ThNH3auuyZPQpJntnN0mA//56nMpK/6HIuu8xAQUEAgQDAQoMoA8AAAAAAAAG" + assertEquals(output.encoded, expectedString) + } + + @Test + fun testSetPriorityFee() { + val privateKey = ByteString.copyFrom("baf2b2dbbbad7ca96c1fa199c686f3d8fbd2c7b352f307e37e04f33df6741f18".toHexByteArray()) + val originalTx = "AX43+Ir2EDqf2zLEvgzFrCZKRjdr3wCdp8CnvYh6N0G/s86IueX9BbiNUl16iLRGvwREDfi2Srb0hmLNBFw1BwABAAEDODI+iWe7g68B9iwCy8bFkJKvsIEj350oSOpcv4gNnv/st+6qmqipl9lwMK6toB9TiL7LrJVfij+pKwr+pUKxfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG6GdPcA92ORzVJe2jfG8KQqqMHr9YTLu30oM4i7MFEoBAgIAAQwCAAAA6AMAAAAAAAA=" + + // Step 1 - Check if there are no price and limit instructions in the original transaction. + assertEquals(SolanaTransaction.getComputeUnitPrice(originalTx), null) + assertEquals(SolanaTransaction.getComputeUnitLimit(originalTx), null) + + // Step 2 - Set price and limit instructions. + val txWithPrice = SolanaTransaction.setComputeUnitPrice(originalTx, "1000") + val updatedTx = SolanaTransaction.setComputeUnitLimit(txWithPrice, "10000") + + assertEquals(updatedTx, "AX43+Ir2EDqf2zLEvgzFrCZKRjdr3wCdp8CnvYh6N0G/s86IueX9BbiNUl16iLRGvwREDfi2Srb0hmLNBFw1BwABAAIEODI+iWe7g68B9iwCy8bFkJKvsIEj350oSOpcv4gNnv/st+6qmqipl9lwMK6toB9TiL7LrJVfij+pKwr+pUKxfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwZGb+UhFzL/7K26csOb57yM5bvF9xJrLEObOkAAAAAboZ09wD3Y5HNUl7aN8bwpCqowev1hMu7fSgziLswUSgMDAAUCECcAAAICAAEMAgAAAOgDAAAAAAAAAwAJA+gDAAAAAAAA") + + // Step 3 - Check if price and limit instructions are set successfully. + assertEquals(SolanaTransaction.getComputeUnitPrice(updatedTx), "1000") + assertEquals(SolanaTransaction.getComputeUnitLimit(updatedTx), "10000") + + // Step 4 - Decode transaction into a `RawMessage` Protobuf. + val updatedTxData = Base64.decode(updatedTx) + val decodedData = TransactionDecoder.decode(SOLANA, updatedTxData) + val decodedOutput = DecodingTransactionOutput.parseFrom(decodedData) + + assertEquals(decodedOutput.error, SigningError.OK) + + // Step 5 - Sign the decoded `RawMessage` transaction. + val signingInput = SigningInput.newBuilder() + .setPrivateKey(privateKey) + .setRawMessage(decodedOutput.transaction) + .setTxEncoding(Encoding.Base64) + .build() + val output = AnySigner.sign(signingInput, SOLANA, SigningOutput.parser()) + // Successfully broadcasted tx: + // https://explorer.solana.com/tx/2ho7wZUXbDNz12xGfsXg2kcNMqkBAQjv7YNXNcVcuCmbC4p9FZe9ELeM2gMjq9MKQPpmE3nBW5pbdgwVCfNLr1h8 + val expectedString = "AVUye82Mv+/aWeU2G+B6Nes365mUU2m8iqcGZn/8kFJvw4wY6AgKGG+vJHaknHlCDwE1yi1SIMVUUtNCOm3kHg8BAAIEODI+iWe7g68B9iwCy8bFkJKvsIEj350oSOpcv4gNnv/st+6qmqipl9lwMK6toB9TiL7LrJVfij+pKwr+pUKxfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwZGb+UhFzL/7K26csOb57yM5bvF9xJrLEObOkAAAAAboZ09wD3Y5HNUl7aN8bwpCqowev1hMu7fSgziLswUSgMDAAUCECcAAAICAAEMAgAAAOgDAAAAAAAAAwAJA+gDAAAAAAAA" + assertEquals(output.encoded, expectedString) + } +} \ No newline at end of file diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/solana/TestSolanaWalletConnectSigning.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/solana/TestSolanaWalletConnectSigning.kt new file mode 100644 index 00000000000..51360e7b5af --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/solana/TestSolanaWalletConnectSigning.kt @@ -0,0 +1,52 @@ +package com.trustwallet.core.app.blockchains.solana + +import com.google.protobuf.ByteString +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.Base58 +import wallet.core.jni.CoinType.SOLANA +import wallet.core.jni.WalletConnectRequest +import wallet.core.jni.proto.Common.SigningError +import wallet.core.jni.proto.Solana.Encoding +import wallet.core.jni.proto.Solana.SigningOutput +import wallet.core.jni.proto.WalletConnect + +class TestSolanaWalletConnectSigning { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testSignSolanaTransactionFromWalletConnectRequest() { + // Step 1: Parse a signing request received through WalletConnect. + + val parsingInput = WalletConnect.ParseRequestInput.newBuilder().apply { + method = WalletConnect.Method.SolanaSignTransaction + payload = "{\"transaction\":\"AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAEDZsL1CMnFVcrMn7JtiOiN1U4hC7WovOVof2DX51xM0H/GizyJTHgrBanCf8bGbrFNTn0x3pCGq30hKbywSTr6AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAgIAAQwCAAAAKgAAAAAAAAA=\"}" + }.build() + + val parsingOutputBytes = WalletConnectRequest.parse(SOLANA, parsingInput.toByteArray()) + val parsingOutput = WalletConnect.ParseRequestOutput.parseFrom(parsingOutputBytes) + + assertEquals(parsingOutput.error, SigningError.OK) + + // Step 2: Set missing fields. + + val signingInput = parsingOutput.solana.toBuilder().apply { + privateKey = ByteString.copyFrom(Base58.decodeNoCheck("A7psj2GW7ZMdY4E5hJq14KMeYg7HFjULSsWSrTXZLvYr")) + txEncoding = Encoding.Base64 + }.build() + + // Step 3: Sign the transaction. + + val output = AnySigner.sign(signingInput, SOLANA, SigningOutput.parser()) + + assertEquals(output.error, SigningError.OK) + assertEquals(output.encoded, "AQPWaOi7dMdmQpXi8HyQQKwiqIftrg1igGQxGtZeT50ksn4wAnyH4DtDrkkuE0fqgx80LTp4LwNN9a440SrmoA8BAAEDZsL1CMnFVcrMn7JtiOiN1U4hC7WovOVof2DX51xM0H/GizyJTHgrBanCf8bGbrFNTn0x3pCGq30hKbywSTr6AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAgIAAQwCAAAAKgAAAAAAAAA=") + + assertEquals(output.getSignatures(0).pubkey, "7v91N7iZ9mNicL8WfG6cgSCKyRXydQjLh6UYBWwm6y1Q") + assertEquals(output.getSignatures(0).signature, "5T6uZBHnHFd8uWErDBTFRVkbKuhbcm94K5MJ2beTYDruzqv4FjS7EMKvC94ZfxNAiWUXZ6bZxS3WXUbhJwYNPWn") + } +} \ No newline at end of file diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/stargaze/TestStargazeAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/stargaze/TestStargazeAddress.kt new file mode 100644 index 00000000000..54577d7971d --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/stargaze/TestStargazeAddress.kt @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.stargaze + +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestStargazeAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val key = PrivateKey("a498a9ee41af9bab5ef2a8be63d5c970135c3c109e70efc8c56c534e6636b433".toHexByteArray()) + val pubkey = key.getPublicKeySecp256k1(true) + val address = AnyAddress(pubkey, CoinType.STARGAZE) + val expected = AnyAddress("stars1mry47pkga5tdswtluy0m8teslpalkdq02a8nhy", CoinType.STARGAZE) + + assertEquals(pubkey.data().toHex(), "0x02cbfdb5e472893322294e60cf0883d43df431e1089d29ecb447a9e6d55045aae5") + assertEquals(address.description(), expected.description()) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/stargaze/TestStargazeSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/stargaze/TestStargazeSigner.kt new file mode 100644 index 00000000000..63a7a166b60 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/stargaze/TestStargazeSigner.kt @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.stargaze + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.AnyAddress +import wallet.core.jni.CoinType +import wallet.core.jni.PrivateKey +import wallet.core.jni.proto.Cosmos + +class TestStargazeSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun stargazeTransactionCW721Signing() { + val key = + PrivateKey("a498a9ee41af9bab5ef2a8be63d5c970135c3c109e70efc8c56c534e6636b433".toHexByteArray()) + + val txMsg = Cosmos.Message.WasmExecuteContractGeneric.newBuilder().apply { + senderAddress = "stars1mry47pkga5tdswtluy0m8teslpalkdq02a8nhy" + contractAddress = "stars14gmjlyfz5mpv5d8zrksn0tjhz2wwvdc4yk06754alfasq9qen7fsknry42" + executeMsg = """{"transfer_nft": {"recipient": "stars1kd5q7qejlqz94kpmd9pvr4v2gzgnca3lvt6xnp","token_id": "1209"}}""" + }.build() + + val message = Cosmos.Message.newBuilder().apply { + wasmExecuteContractGeneric = txMsg + }.build() + + val feeAmount = Cosmos.Amount.newBuilder().apply { + amount = "1000" + denom = "ustars" + }.build() + + val stargazeFee = Cosmos.Fee.newBuilder().apply { + gas = 666666 + addAllAmounts(listOf(feeAmount)) + }.build() + + val signingInput = Cosmos.SigningInput.newBuilder().apply { + signingMode = Cosmos.SigningMode.Protobuf + accountNumber = 188393 + chainId = "stargaze-1" + memo = "" + sequence = 5 + fee = stargazeFee + privateKey = ByteString.copyFrom(key.data()) + addAllMessages(listOf(message)) + }.build() + + val output = AnySigner.sign(signingInput, CoinType.STARGAZE, Cosmos.SigningOutput.parser()) + // Successfully broadcasted: https://www.mintscan.io/stargaze/txs/300836A5BF9002CF38EE34A8C56E8E7E6854FA64F1DEB3AE108F381A48150F7C + val expected = """{"mode":"BROADCAST_MODE_BLOCK","tx_bytes":"CoACCv0BCiQvY29zbXdhc20ud2FzbS52MS5Nc2dFeGVjdXRlQ29udHJhY3QS1AEKLHN0YXJzMW1yeTQ3cGtnYTV0ZHN3dGx1eTBtOHRlc2xwYWxrZHEwMmE4bmh5EkBzdGFyczE0Z21qbHlmejVtcHY1ZDh6cmtzbjB0amh6Mnd3dmRjNHlrMDY3NTRhbGZhc3E5cWVuN2Zza25yeTQyGmJ7InRyYW5zZmVyX25mdCI6IHsicmVjaXBpZW50IjogInN0YXJzMWtkNXE3cWVqbHF6OTRrcG1kOXB2cjR2Mmd6Z25jYTNsdnQ2eG5wIiwidG9rZW5faWQiOiAiMTIwOSJ9fRJoClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiECy/215HKJMyIpTmDPCIPUPfQx4QidKey0R6nm1VBFquUSBAoCCAEYBRIUCg4KBnVzdGFycxIEMTAwMBCq2CgaQMx+l2sdM5DAPbDyY1p173MLnjGyNWIcRmaFiVNphLuTV3tjhwPbsXEA0hyRxyWS3vN0/xUF/JEsO9wRspj2aJ4="}""".trimIndent() + assertEquals( + output.serialized, + expected + ) + assertEquals(output.errorMessage, "") + } + + @Test + fun stargazeTransactionSigning() { + val key = + PrivateKey("a498a9ee41af9bab5ef2a8be63d5c970135c3c109e70efc8c56c534e6636b433".toHexByteArray()) + val publicKey = key.getPublicKeySecp256k1(true) + val from = AnyAddress(publicKey, CoinType.STARGAZE).description() + + val txAmount = Cosmos.Amount.newBuilder().apply { + amount = "10000" + denom = "ustars" + }.build() + + val sendCoinsMsg = Cosmos.Message.Send.newBuilder().apply { + fromAddress = from + toAddress = "stars1mry47pkga5tdswtluy0m8teslpalkdq02a8nhy" + addAllAmounts(listOf(txAmount)) + }.build() + + val message = Cosmos.Message.newBuilder().apply { + sendCoinsMessage = sendCoinsMsg + }.build() + + val feeAmount = Cosmos.Amount.newBuilder().apply { + amount = "1000" + denom = "ustars" + }.build() + + val stargazeFee = Cosmos.Fee.newBuilder().apply { + gas = 80000 + addAllAmounts(listOf(feeAmount)) + }.build() + + val signingInput = Cosmos.SigningInput.newBuilder().apply { + signingMode = Cosmos.SigningMode.Protobuf + accountNumber = 188393 + chainId = "stargaze-1" + memo = "" + sequence = 0 + fee = stargazeFee + privateKey = ByteString.copyFrom(key.data()) + addAllMessages(listOf(message)) + }.build() + + val output = AnySigner.sign(signingInput, CoinType.STARGAZE, Cosmos.SigningOutput.parser()) + // Successfully broadcasted: https://www.mintscan.io/stargaze/txs/98D5E36CA7080DDB286FE924A5A9976ABD4EBE49C92A09D322F29AD30DE4BE4D + val expected = """{"mode":"BROADCAST_MODE_BLOCK","tx_bytes":"CpABCo0BChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEm0KLHN0YXJzMW1yeTQ3cGtnYTV0ZHN3dGx1eTBtOHRlc2xwYWxrZHEwMmE4bmh5EixzdGFyczFtcnk0N3BrZ2E1dGRzd3RsdXkwbTh0ZXNscGFsa2RxMDJhOG5oeRoPCgZ1c3RhcnMSBTEwMDAwEmYKTgpGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQLL/bXkcokzIilOYM8Ig9Q99DHhCJ0p7LRHqebVUEWq5RIECgIIARIUCg4KBnVzdGFycxIEMTAwMBCA8QQaQHAkntxzC1oH7Yde4+KEmnB+K3XbJIYw0q6MqMPEY65YAwBDNDOdaTu/rpehus/20MvBfbAEZiw9+whzXLpkQ5A="}""".trimIndent() + assertEquals( + output.serialized, + expected + ) + assertEquals(output.errorMessage, "") + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/starkex/TestStarkExMessageSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/starkex/TestStarkExMessageSigner.kt new file mode 100644 index 00000000000..d68cd722b80 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/starkex/TestStarkExMessageSigner.kt @@ -0,0 +1,27 @@ +package com.trustwallet.core.app.blockchains.starkex + +import com.trustwallet.core.app.utils.Numeric +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test +import wallet.core.jni.PrivateKey +import wallet.core.jni.PublicKeyType +import wallet.core.jni.StarkExMessageSigner + +class TestStarkExMessageSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testStarkExSignAndVerifyMessage() { + val data = Numeric.hexStringToByteArray("04be51a04e718c202e4dca60c2b72958252024cfc1070c090dd0f170298249de") + val privateKey = PrivateKey(data) + val publicKey = privateKey.getPublicKeyByType(PublicKeyType.STARKEX) + val msg = "463a2240432264a3aa71a5713f2a4e4c1b9e12bbb56083cd56af6d878217cf" + val signature = StarkExMessageSigner.signMessage(privateKey, msg) + assertEquals(signature, "04cf5f21333dd189ada3c0f2a51430d733501a9b1d5e07905273c1938cfb261e05b6013d74adde403e8953743a338c8d414bb96bf69d2ca1a91a85ed2700a528"); + assertTrue(StarkExMessageSigner.verifyMessage(publicKey, msg, signature)) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/sui/TestSuiAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/sui/TestSuiAddress.kt new file mode 100644 index 00000000000..503e6e8c8ad --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/sui/TestSuiAddress.kt @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.sui + +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestSuiAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val any = AnyAddress("0x259ff8074ab425cbb489f236e18e08f03f1a7856bdf7c7a2877bd64f738b5015", CoinType.SUI) + assertEquals(any.coin(), CoinType.SUI) + assertEquals(any.description(), "0x259ff8074ab425cbb489f236e18e08f03f1a7856bdf7c7a2877bd64f738b5015") + + Assert.assertFalse( + AnyAddress.isValid( + "0xMQqpqMQgCBuiPkoXfgZZsJvuzCeI1zc00z6vHJj4", + CoinType.SUI + ) + ) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/sui/TestSuiSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/sui/TestSuiSigner.kt new file mode 100644 index 00000000000..84ab0914391 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/sui/TestSuiSigner.kt @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.sui + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.Numeric +import com.trustwallet.core.app.utils.toHexByteArray +import com.trustwallet.core.app.utils.toHexBytes +import com.trustwallet.core.app.utils.toHexBytesInByteString +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.CoinType +import wallet.core.jni.proto.Sui + +class TestSuiSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testSuiDirectSigning() { + // Successfully broadcasted https://explorer.sui.io/txblock/HkPo6rYPyDY53x1MBszvSZVZyixVN7CHvCJGX381czAh?network=devnet + val txBytes = """ + AAACAAgQJwAAAAAAAAAgJZ/4B0q0Jcu0ifI24Y4I8D8aeFa998eih3vWT3OLUBUCAgABAQAAAQEDAAAAAAEBANV1rX8Y6UhGKlz2mPVk7zlKdSpx/sYkk6+KBVwBLA1QAQbywsjB2JZN8QGdZhbpcFcZvrq9kx2idVy5SM635olk7AIAAAAAAAAgYEVuxmf1zRBGdoDr+VDtMpIFF12s2Ua7I2ru1XyGF8/Vda1/GOlIRipc9pj1ZO85SnUqcf7GJJOvigVcASwNUAEAAAAAAAAA0AcAAAAAAAAA + """.trimIndent() + val key = + "3823dce5288ab55dd1c00d97e91933c613417fdb282a0b8b01a7f5f5a533b266".toHexBytesInByteString() + val signDirect = Sui.SignDirect.newBuilder().setUnsignedTxMsg(txBytes).build() + val signingInput = + Sui.SigningInput.newBuilder().setSignDirectMessage(signDirect).setPrivateKey(key).build() + val result = AnySigner.sign(signingInput, CoinType.SUI, Sui.SigningOutput.parser()) + val expectedSignature = "APxPduNVvHj2CcRcHOtiP2aBR9qP3vO2Cb0g12PI64QofDB6ks33oqe/i/iCTLcop2rBrkczwrayZuJOdi7gvwNqfN7sFqdcD/Z4e8I1YQlGkDMCK7EOgmydRDqfH8C9jg==" + assertEquals(result.unsignedTx, txBytes); + assertEquals(result.signature, expectedSignature) + } + + @Test + fun testSuiTransfer() { + // Successfully broadcasted: https://suiscan.xyz/mainnet/tx/D4Ay9TdBJjXkGmrZSstZakpEWskEQHaWURP6xWPRXbAm + val txBytes = """ + AAAEAAjoAwAAAAAAAAAIUMMAAAAAAAAAIKcXWr3V7ZLr4605DbNmxqcGR4zfUXzebPmGMAZc2jd6ACBU6A1215DCd/WkTzzpL1PSb1iUiSvzld7mN1mIh2vmsgMCAAIBAAABAQABAQMAAAAAAQIAAQEDAAABAAEDAFToDXbXkMJ39aRPPOkvU9JvWJSJK/OV3uY3WYiHa+ayAWNgILOn3HsRw6pvQZsX+KnBLn95ox0b3S3mcLTt1jAFeHEaBQAAAAAgGGuNnxrqusosgjP3gQ3jBjnhapGNBlcU0yTaupXpa0BU6A1215DCd/WkTzzpL1PSb1iUiSvzld7mN1mIh2vmsu4CAAAAAAAAwMYtAAAAAAAA + """.trimIndent() + val key = + "7e6682f7bf479ef0f627823cffd4e1a940a7af33e5fb39d9e0f631d2ecc5daff".toHexBytesInByteString() + + val paySui = Sui.PaySui.newBuilder() + .addInputCoins(Sui.ObjectRef.newBuilder().apply { + objectId = "0x636020b3a7dc7b11c3aa6f419b17f8a9c12e7f79a31d1bdd2de670b4edd63005" + version = 85619064 + objectDigest = "2eKuWbZSVfpFVfg8FXY9wP6W5AFXnTchSoUdp7obyYZ5" + }) + .addRecipients("0xa7175abdd5ed92ebe3ad390db366c6a706478cdf517cde6cf98630065cda377a") + .addRecipients("0x54e80d76d790c277f5a44f3ce92f53d26f5894892bf395dee6375988876be6b2") + .addAmounts(1000) + .addAmounts(50000) + + val signingInput = Sui.SigningInput.newBuilder() + .setPaySui(paySui) + .setPrivateKey(key) + .setGasBudget(3000000) + .setReferenceGasPrice(750) + .build() + + val result = AnySigner.sign(signingInput, CoinType.SUI, Sui.SigningOutput.parser()) + val expectedSignature = "AEh44B7iGArEHF1wOLAQJMLNgGnaIwn3gKPC92vtDJqITDETAM5z9plaxio1xomt6/cZReQ5FZaQsMC6l7E0BwmF69FEH+T5VPvl3GB3vwCOEZpeJpKXxvcIPQAdKsh2/g==" + assertEquals(result.unsignedTx, txBytes); + assertEquals(result.signature, expectedSignature) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/terra/TestTerraClassicTxs.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/terra/TestTerraClassicTxs.kt index 2c67c665dd8..538d0efb76b 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/terra/TestTerraClassicTxs.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/terra/TestTerraClassicTxs.kt @@ -110,7 +110,7 @@ class TestTerraClassicTxs { val output = AnySigner.sign(signingInput, TERRA, SigningOutput.parser()) assertEquals(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CucBCuQBCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBK5AQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMTR6NTZsMGZwMmxzZjg2enkzaHR5Mno0N2V6a2hudGh0cjl5cTc2Glt7InRyYW5zZmVyIjp7ImFtb3VudCI6IjI1MDAwMCIsInJlY2lwaWVudCI6InRlcnJhMWpsZ2FxeTludm4yaGY1dDJzcmE5eWN6OHM3N3duZjlsMGttZ2NwIn19EmcKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQNwZjrHsPmJKW/rXOWfukpQ1+lOHOJW3/IlFFnKLNmsABIECgIIARgDEhMKDQoFdWx1bmESBDMwMDAQwJoMGkAaprIEMLPH2HmFdwFGoaipb2GIyhXt6ombz+WMnG2mORBI6gFt0M+IymYgzZz6w1SW52R922yafDnn7yXfutRw\"}") - assertEquals(output.error, "") + assertEquals(output.errorMessage, "") } @Test @@ -154,7 +154,7 @@ class TestTerraClassicTxs { val output = AnySigner.sign(signingInput, TERRA, SigningOutput.parser()) assertEquals(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"Cu4BCusBCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBLAAQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMTR6NTZsMGZwMmxzZjg2enkzaHR5Mno0N2V6a2hudGh0cjl5cTc2GmJ7InRyYW5zZmVyIjogeyAiYW1vdW50IjogIjI1MDAwMCIsICJyZWNpcGllbnQiOiAidGVycmExZDcwNDhjc2FwNHd6Y3Y1em03ejZ0ZHFlbTJhZ3lwOTY0N3ZkeWoiIH0gfRJnClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDcGY6x7D5iSlv61zln7pKUNfpThziVt/yJRRZyizZrAASBAoCCAEYBxITCg0KBXVsdW5hEgQzMDAwEMCaDBpAkPsS7xlSng2LMc9KiD1soN5NLaDcUh8I9okPmsdJN3le1B7yxRGNB4aQfhaRl/8Z0r5vitRT0AWuxDasd8wcFw==\"}") - assertEquals(output.error, "") + assertEquals(output.errorMessage, "") } @Test @@ -204,6 +204,6 @@ class TestTerraClassicTxs { val output = AnySigner.sign(signingInput, TERRA, SigningOutput.parser()) assertEquals(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CrIBCq8BCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBKEAQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMXNlcGZqN3MwYWVnNTk2N3V4bmZrNHRoemxlcnJza3RrcGVsbTVzGhh7ICJkZXBvc2l0X3N0YWJsZSI6IHt9IH0qDAoEdXVzZBIEMTAwMBJnClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDcGY6x7D5iSlv61zln7pKUNfpThziVt/yJRRZyizZrAASBAoCCAEYCRITCg0KBXVsdW5hEgQ3MDAwEMDPJBpAGyi7f1ioY8XV6pjFq1s86Om4++CIUnd3rLHif2iopCcYvX0mLkTlQ6NUERg8nWTYgXcj6fOTO/ptgPuAtv0NWg==\"}") - assertEquals(output.error, "") + assertEquals(output.errorMessage, "") } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/terra/TestTerraTransactions.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/terra/TestTerraTransactions.kt index 6ee4574001a..e4591ff57e3 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/terra/TestTerraTransactions.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/terra/TestTerraTransactions.kt @@ -64,7 +64,7 @@ class TestTerraTransactions { val jsonPayload = output.json assertEquals(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CpEBCo4BChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEm4KLHRlcnJhMWhzazZqcnl5cWpmaHA1ZGhjNTV0YzlqdGNreWd4MGVwMzdoZGQyEix0ZXJyYTFqbGdhcXk5bnZuMmhmNXQyc3JhOXljejhzNzd3bmY5bDBrbWdjcBoQCgV1bHVuYRIHMTAwMDAwMBJoClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiECVyhuw/N9M1V7u6oACyd0SskCOqmWfK51oYHR/5H6ncUSBAoCCAEYARIUCg4KBXVsdW5hEgUzMDAwMBDAmgwaQPh0C3rjzdixIUiyPx3FlWAxzbKILNAcSRVeQnaTl1vsI5DEfYa2oYlUBLqyilcMCcU/iaJLhex30No2ak0Zn1Q=\"}") - assertEquals(output.error, "") + assertEquals(output.errorMessage, "") } @Test @@ -109,6 +109,6 @@ class TestTerraTransactions { val output = AnySigner.sign(signingInput, TERRAV2, SigningOutput.parser()) assertEquals(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CuUBCuIBCiQvY29zbXdhc20ud2FzbS52MS5Nc2dFeGVjdXRlQ29udHJhY3QSuQEKLHRlcnJhMTh3dWtwODRkcTIyN3d1NG1naDBqbTZuOW5sbmo2cnM4MnBwOXdmEix0ZXJyYTE0ejU2bDBmcDJsc2Y4Nnp5M2h0eTJ6NDdlemtobnRodHI5eXE3NhpbeyJ0cmFuc2ZlciI6eyJhbW91bnQiOiIyNTAwMDAiLCJyZWNpcGllbnQiOiJ0ZXJyYTFqbGdhcXk5bnZuMmhmNXQyc3JhOXljejhzNzd3bmY5bDBrbWdjcCJ9fRJnClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDcGY6x7D5iSlv61zln7pKUNfpThziVt/yJRRZyizZrAASBAoCCAEYAxITCg0KBXVsdW5hEgQzMDAwEMCaDBpAiBGbQaj+jsXE6/FssD3fC77QOxpli9GqsPea+KoNyMIEgVj89Hii+oU1bAEQS4qV0SaE2V6RNy24uCcFTIRbcQ==\"}") - assertEquals(output.error, "") + assertEquals(output.errorMessage, "") } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/tezos/TestTezosMessageSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/tezos/TestTezosMessageSigner.kt new file mode 100644 index 00000000000..57b06f83714 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/tezos/TestTezosMessageSigner.kt @@ -0,0 +1,42 @@ +package com.trustwallet.core.app.blockchains.tezos + +import com.trustwallet.core.app.utils.Numeric +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test +import wallet.core.jni.CoinType +import wallet.core.jni.TezosMessageSigner +import wallet.core.jni.PrivateKey +import java.util.regex.Pattern + +class TestTezosMessageSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testMessageSignerSignAndVerify() { + val data = Numeric.hexStringToByteArray("91b4fb8d7348db2e7de2693f58ce1cceb966fa960739adac1d9dba2cbaa0940a") + val privateKey = PrivateKey(data) + val msg = "05010000004254657a6f73205369676e6564204d6573736167653a207465737455726c20323032332d30322d30385431303a33363a31382e3435345a2048656c6c6f20576f726c64" + val signature = TezosMessageSigner.signMessage(privateKey, msg) + assertEquals("edsigu3se2fcEJUCm1aqxjzbHdf7Wsugr4mLaA9YM2UVZ9Yy5meGv87VqHN3mmDeRwApTj1JKDaYjqmLZifSFdWCqBoghqaowwJ", signature) + val pubKey = privateKey.getPublicKey(CoinType.TEZOS) + assertTrue(TezosMessageSigner.verifyMessage(pubKey, msg, signature)) + } + + @Test + fun testMessageSignerInputToPayload() { + val payload = TezosMessageSigner.inputToPayload("Tezos Signed Message: testUrl 2023-02-08T10:36:18.454Z Hello World") + val expected = "05010000004254657a6f73205369676e6564204d6573736167653a207465737455726c20323032332d30322d30385431303a33363a31382e3435345a2048656c6c6f20576f726c64" + assertEquals(expected, payload) + } + + @Test + fun testMessageSignerFormatMessage() { + val formatedMsg = TezosMessageSigner.formatMessage("Hello World", "testUrl") + val regex = Pattern.compile("Tezos Signed Message: \\S+ \\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z .+") + assertTrue(regex.matcher(formatedMsg).matches()) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkAddress.kt new file mode 100644 index 00000000000..f37d4c7e4e9 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkAddress.kt @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.theopennetwork + +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestTheOpenNetworkAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddressFromPrivateKey() { + val privateKey = PrivateKey("63474e5fe9511f1526a50567ce142befc343e71a49b865ac3908f58667319cb8".toHexByteArray()) + val publicKey = privateKey.getPublicKeyEd25519() + val address = AnyAddress(publicKey, CoinType.TON) + assertEquals(publicKey.data().toHex(), "0xf42c77f931bea20ec5d0150731276bbb2e2860947661245b2319ef8133ee8d41") + assertEquals(address.description(), "UQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts4DV") + } + + @Test + fun testAddressFromPublicKey() { + val publicKey = PublicKey("f42c77f931bea20ec5d0150731276bbb2e2860947661245b2319ef8133ee8d41".toHexByteArray(), PublicKeyType.ED25519) + val address = AnyAddress(publicKey, CoinType.TON) + assertEquals(address.description(), "UQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts4DV") + } + + @Test + fun testAddressFromRawString() { + val addressString = "0:66fbe3c5c03bf5c82792f904c9f8bf28894a6aa3d213d41c20569b654aadedb3" + val address = AnyAddress(addressString, CoinType.TON) + assertEquals(address.description(), "UQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts4DV") + } + + @Test + fun testAddressFromBounceableString() { + val addressString = "EQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts90Q" + val address = AnyAddress(addressString, CoinType.TON) + assertEquals(address.description(), "UQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts4DV") + } + + @Test + fun testAddressFromUserFriendlyString() { + val addressString = "UQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts4DV" + val address = AnyAddress(addressString, CoinType.TON) + assertEquals(address.description(), "UQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts4DV") + } + + @Test + fun testAddressToBounceable() { + val addressString = "UQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts4DV" + val bounceable = true + val testnet = false + val address = TONAddressConverter.toUserFriendly(addressString, bounceable, testnet) + assertEquals(address, "EQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts90Q") + } + + @Test + fun testGenerateJettonAddress() { + val mainAddress = "UQBjKqthWBE6GEcqb_epTRFrQ1niS6Z1Z1MHMwR-mnAYRoYr" + val mainAddressBoc = TONAddressConverter.toBoc(mainAddress) + assertEquals(mainAddressBoc, "te6cckEBAQEAJAAAQ4AMZVVsKwInQwjlTf71KaItaGs8SXTOrOpg5mCP004DCNAptHQU") + + // curl --location 'https://toncenter.com/api/v2/runGetMethod' --header 'Content-Type: application/json' --data \ + // '{"address":"EQAvlWFDxGF2lXm67y4yzC17wYKD9A0guwPkMs1gOsM__NOT","method":"get_wallet_address","method":"get_wallet_address","stack":[["tvm.Slice","te6ccgICAAEAAQAAACQAAABDgAxlVWwrAidDCOVN/vUpoi1oazxJdM6s6mDmYI/TTgMI0A=="]]}' + + // Parse the `get_wallet_address` RPC response. + val jettonAddressBocEncoded = "te6cckEBAQEAJAAAQ4AFvT5rqwxcbKfITqnkwL+go4Zi9bulRHAtLt4cjjFdK7B8L+Cq" + val jettonAddress = TONAddressConverter.fromBoc(jettonAddressBocEncoded) + assertEquals(jettonAddress, "UQAt6fNdWGLjZT5CdU8mBf0FHDMXrd0qI4FpdvDkcYrpXV5H") + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkMessageSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkMessageSigner.kt new file mode 100644 index 00000000000..64c4627cb97 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkMessageSigner.kt @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.theopennetwork + +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.PrivateKey +import wallet.core.jni.TONMessageSigner +import wallet.core.jni.TONWallet + +class TestTheOpenNetworkMessageSigner { + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun TheOpenNetworkMessageSignerSignMessage() { + // The private key has been derived by using [ton-mnemonic](https://www.npmjs.com/package/tonweb-mnemonic/v/0.0.2) + // from the following mnemonic: + // document shield addict crime broom point story depend suit satisfy test chicken valid tail speak fortune sound drill seek cube cheap body music recipe + val privateKey = PrivateKey("112d4e2e700a468f1eae699329202f1ee671d6b665caa2d92dea038cf3868c18".toHexByteArray()) + val message = "Hello world" + val signature = TONMessageSigner.signMessage(privateKey, message) + // The following signature has been computed by calling `window.ton.send("ton_personalSign", { data: "Hello world" });`. + assertEquals(signature, "2490fbaa72aec0b77b19162bbbe0b0e3f7afd42cc9ef469f0494cd4a366a4bf76643300cd5991f66bce6006336742b8d1d435d541d244dcc013d428472e89504") + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkSigner.kt new file mode 100644 index 00000000000..69dd91abada --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkSigner.kt @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.theopennetwork + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.CoinType +import wallet.core.jni.PrivateKey +import wallet.core.jni.proto.TheOpenNetwork +import wallet.core.jni.proto.TheOpenNetwork.SigningOutput + +class TestTheOpenNetworkSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun TheOpenNetworkTransactionSigning() { + val privateKey = PrivateKey("c38f49de2fb13223a9e7d37d5d0ffbdd89a5eb7c8b0ee4d1c299f2cefe7dc4a0".toHexByteArray()) + + val transfer = TheOpenNetwork.Transfer.newBuilder() + .setDest("EQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts90Q") + .setAmount(10) + .setMode(TheOpenNetwork.SendMode.PAY_FEES_SEPARATELY_VALUE or TheOpenNetwork.SendMode.IGNORE_ACTION_PHASE_ERRORS_VALUE) + .setBounceable(true) + .build() + + val input = TheOpenNetwork.SigningInput.newBuilder() + .setPrivateKey(ByteString.copyFrom(privateKey.data())) + .addMessages(transfer) + .setSequenceNumber(6) + .setExpireAt(1671132440) + .setWalletVersion(TheOpenNetwork.WalletVersion.WALLET_V4_R2) + .build() + + val output = AnySigner.sign(input, CoinType.TON, SigningOutput.parser()) + + // tx: https://tonscan.org/tx/3Z4tHpXNLyprecgu5aTQHWtY7dpHXEoo11MAX61Xyg0= + val expectedString = "te6cckEBBAEArQABRYgBsLf6vJOEq42xW0AoyWX0K+uBMUcXFDLFqmkDg6k1Io4MAQGcEUPkil2aZ4s8KKparSep/OKHMC8vuXafFbW2HGp/9AcTRv0J5T4dwyW1G0JpHw+g5Ov6QI3Xo0O9RFr3KidICimpoxdjm3UYAAAABgADAgFiYgAzffHi4B365BPJfIJk/F+URKU1UekJ6g4QK02ypVb22YhQAAAAAAAAAAAAAAAAAQMAAA08Nzs=" + + assertEquals(output.encoded, expectedString) + } + + @Test + fun TheOpenNetworkJettonTransferSigning() { + val privateKey = PrivateKey("c054900a527538c1b4325688a421c0469b171c29f23a62da216e90b0df2412ee".toHexByteArray()) + + val jettonTransfer = TheOpenNetwork.JettonTransfer.newBuilder() + .setJettonAmount(500 * 1000 * 1000) + .setToOwner("EQAFwMs5ha8OgZ9M4hQr80z9NkE7rGxUpE1hCFndiY6JnDx8") + .setResponseAddress("EQBaKIMq5Am2p_rfR1IFTwsNWHxBkOpLTmwUain5Fj4llTXk") + .setForwardAmount(1) + .build() + + val transfer = TheOpenNetwork.Transfer.newBuilder() + .setDest("EQBiaD8PO1NwfbxSkwbcNT9rXDjqhiIvXWymNO-edV0H5lja") + .setAmount(100 * 1000 * 1000) + .setMode(TheOpenNetwork.SendMode.PAY_FEES_SEPARATELY_VALUE or TheOpenNetwork.SendMode.IGNORE_ACTION_PHASE_ERRORS_VALUE) + .setComment("test comment") + .setBounceable(true) + .setJettonTransfer(jettonTransfer) + + val input = TheOpenNetwork.SigningInput.newBuilder() + .setPrivateKey(ByteString.copyFrom(privateKey.data())) + .addMessages(transfer) + .setSequenceNumber(1) + .setExpireAt(1787693046) + .setWalletVersion(TheOpenNetwork.WalletVersion.WALLET_V4_R2) + .build() + + val output = AnySigner.sign(input, CoinType.TON, SigningOutput.parser()) + + // tx: https://testnet.tonscan.org/tx/Er_oT5R3QK7D-qVPBKUGkJAOOq6ayVls-mgEphpI9Ck= + val expectedString = "te6cckECBAEAARUAAUWIALRRBlXIE21P9b6OpAqeFhqw+IMh1Jac2CjUU/IsfEsqDAEBnGiFlaLItV573gJqBvctP5j3jVKlLuxmO+pnW0QGlXjXgzjw5YeTNwRG9upJHOl6GA3pFetKNojqGzfkxku+owUpqaMXao4H9gAAAAEAAwIBaGIAMTQfh52puD7eKUmDbhqfta4cdUMRF662Uxp3zzqug/MgL68IAAAAAAAAAAAAAAAAAAEDAMoPin6lAAAAAAAAAABB3NZQCAALgZZzC14dAz6ZxChX5pn6bIJ3WNipSJrCELO7Ex0TOQAWiiDKuQJtqf630dSBU8LDVh8QZDqS05sFGop+RY+JZUICAAAAAHRlc3QgY29tbWVudG/bd5c=" + + assertEquals(output.encoded, expectedString) + } + + @Test + fun TheOpenNetworkTransferCustomPayload() { + val privateKey = PrivateKey("5525e673087587bc0efd7ab09920ef7d3c1bf6b854a661430244ca59ab19e9d1".toHexByteArray()) + + // Doge chatbot contract payload to be deployed. + // Docs: https://docs.ton.org/develop/dapps/ton-connect/transactions#smart-contract-deployment + val dogeChatbotStateInit = "te6cckEBBAEAUwACATQBAgEU/wD0pBP0vPLICwMAEAAAAZDrkbgQAGrTMAGCCGlJILmRMODQ0wMx+kAwi0ZG9nZYcCCAGMjLBVAEzxaARfoCE8tqEssfAc8WyXP7AO4ioYU=" + // Doge chatbot's address after the contract is deployed. + val dogeChatbotDeployingAddress = "0:3042cd5480da232d5ac1d9cbe324e3c9eb58f167599f6b7c20c6e638aeed0335" + + // The comment has nothing to do with Doge chatbot. + // It's just used to attach the following ASCII comment to the transaction: + // "This transaction deploys Doge Chatbot contract" + val commentPayload = "te6cckEBAQEANAAAZAAAAABUaGlzIHRyYW5zYWN0aW9uIGRlcGxveXMgRG9nZSBDaGF0Ym90IGNvbnRyYWN0v84vSg==" + + val transfer = TheOpenNetwork.Transfer.newBuilder() + .setDest(dogeChatbotDeployingAddress) + // 0.069 TON + .setAmount(69_000_000) + .setMode(TheOpenNetwork.SendMode.PAY_FEES_SEPARATELY_VALUE or TheOpenNetwork.SendMode.IGNORE_ACTION_PHASE_ERRORS_VALUE) + .setBounceable(false) + .setStateInit(dogeChatbotStateInit) + .setCustomPayload(commentPayload) + + val input = TheOpenNetwork.SigningInput.newBuilder() + .setPrivateKey(ByteString.copyFrom(privateKey.data())) + .addMessages(transfer) + .setSequenceNumber(4) + .setExpireAt(1721939714) + .setWalletVersion(TheOpenNetwork.WalletVersion.WALLET_V4_R2) + .build() + + val output = AnySigner.sign(input, CoinType.TON, SigningOutput.parser()) + + // Successfully broadcasted: https://tonviewer.com/transaction/f4b7ed2247b1adf54f33dd2fd99216fbd61beefb281542d0b330ccea9b8d0338 + val expectedString = "te6cckECCAEAATcAAUWIAfq4NsPLegfou/MPhtHE9YuzV3gnI/q6jm3MRJh2PtpaDAEBnPbyCSsWrOZpEjb7ZFxz5yYi+an6M6Lnq7rI7TFWdDS76LEtGBrVVrhMGziwxuy6LCVtsMBikI7RPVQ89FCIAAYpqaMXZqK3AgAAAAQAAwICaUIAGCFmqkBtEZatYOzl8ZJx5PWseLOsz7W+EGNzHFd2gZqgIObaAAAAAAAAAAAAAAAAAAPAAwQCATQFBgBkAAAAAFRoaXMgdHJhbnNhY3Rpb24gZGVwbG95cyBEb2dlIENoYXRib3QgY29udHJhY3QBFP8A9KQT9LzyyAsHABAAAAGQ65G4EABq0zABgghpSSC5kTDg0NMDMfpAMItGRvZ2WHAggBjIywVQBM8WgEX6AhPLahLLHwHPFslz+wAa2r/S" + + assertEquals(output.encoded, expectedString) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkWallet.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkWallet.kt new file mode 100644 index 00000000000..9305072bb75 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkWallet.kt @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.theopennetwork + +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.PublicKey +import wallet.core.jni.PublicKeyType +import wallet.core.jni.TONWallet + +class TestTheOpenNetworkWallet { + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun TheOpenNetworkWalletBuildV4R2StateInit() { + val publicKey = PublicKey("f229a9371fa7c2108b3d90ea22c9be705ff5d0cfeaee9cbb9366ff0171579357".toHexByteArray(), PublicKeyType.ED25519) + val baseWorkchain = 0 + val defaultWalletId = 0x29a9a317 + val stateInit = TONWallet.buildV4R2StateInit(publicKey, baseWorkchain, defaultWalletId) + + val expected = "te6cckECFgEAAwQAAgE0AQIBFP8A9KQT9LzyyAsDAFEAAAAAKamjF/IpqTcfp8IQiz2Q6iLJvnBf9dDP6u6cu5Nm/wFxV5NXQAIBIAQFAgFIBgcE+PKDCNcYINMf0x/THwL4I7vyZO1E0NMf0x/T//QE0VFDuvKhUVG68qIF+QFUEGT5EPKj+AAkpMjLH1JAyx9SMMv/UhD0AMntVPgPAdMHIcAAn2xRkyDXSpbTB9QC+wDoMOAhwAHjACHAAuMAAcADkTDjDQOkyMsfEssfy/8ICQoLAubQAdDTAyFxsJJfBOAi10nBIJJfBOAC0x8hghBwbHVnvSKCEGRzdHK9sJJfBeAD+kAwIPpEAcjKB8v/ydDtRNCBAUDXIfQEMFyBAQj0Cm+hMbOSXwfgBdM/yCWCEHBsdWe6kjgw4w0DghBkc3RyupJfBuMNDA0CASAODwBu0gf6ANTUIvkABcjKBxXL/8nQd3SAGMjLBcsCIs8WUAX6AhTLaxLMzMlz+wDIQBSBAQj0UfKnAgBwgQEI1xj6ANM/yFQgR4EBCPRR8qeCEG5vdGVwdIAYyMsFywJQBs8WUAT6AhTLahLLH8s/yXP7AAIAbIEBCNcY+gDTPzBSJIEBCPRZ8qeCEGRzdHJwdIAYyMsFywJQBc8WUAP6AhPLassfEss/yXP7AAAK9ADJ7VQAeAH6APQEMPgnbyIwUAqhIb7y4FCCEHBsdWeDHrFwgBhQBMsFJs8WWPoCGfQAy2kXyx9SYMs/IMmAQPsABgCKUASBAQj0WTDtRNCBAUDXIMgBzxb0AMntVAFysI4jghBkc3Rygx6xcIAYUAXLBVADzxYj+gITy2rLH8s/yYBA+wCSXwPiAgEgEBEAWb0kK29qJoQICga5D6AhhHDUCAhHpJN9KZEM5pA+n/mDeBKAG3gQFImHFZ8xhAIBWBITABG4yX7UTQ1wsfgAPbKd+1E0IEBQNch9AQwAsjKB8v/ydABgQEI9ApvoTGACASAUFQAZrc52omhAIGuQ64X/wAAZrx32omhAEGuQ64WPwEXtMkg=" + assertEquals(stateInit, expected) + } +} \ No newline at end of file diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thetafuel/TestThetaFuelAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thetafuel/TestThetaFuelAddress.kt new file mode 100644 index 00000000000..17e60b89aeb --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thetafuel/TestThetaFuelAddress.kt @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.thetafuel + +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestThetaFuelAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val key = PrivateKey("4646464646464646464646464646464646464646464646464646464646464646".toHexByteArray()) + val pubkey = key.getPublicKeySecp256k1(false) + val address = AnyAddress(pubkey, CoinType.THETAFUEL) + val expected = AnyAddress("0x9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F", CoinType.THETAFUEL) + + assertEquals(address.description(), expected.description()) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thorchain/TestTHORChainAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thorchain/TestTHORChainAddress.kt index 8a1c5768d90..0974995d3f1 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thorchain/TestTHORChainAddress.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thorchain/TestTHORChainAddress.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2021 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.thorchain diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thorchain/TestTHORChainSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thorchain/TestTHORChainSigner.kt index 2314586d13e..fde6325529f 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thorchain/TestTHORChainSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thorchain/TestTHORChainSigner.kt @@ -1,8 +1,6 @@ -// Copyright © 2017-2021 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.thorchain @@ -74,7 +72,7 @@ class TestTHORChainSigner { val output = AnySigner.sign(signingInput, THORCHAIN, SigningOutput.parser()) assertEquals(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"ClIKUAoOL3R5cGVzLk1zZ1NlbmQSPgoUFSLnZ9tusZcIsAOAKb+9YHvJvQ4SFMqGRZ+wBVHH30JUDF54aRksgzrbGhAKBHJ1bmUSCDM4MDAwMDAwEmYKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQPtmX45bPQpL1/OWkK7pBWZzNXZbjExVKfJ6nBJ3jF8dxIECgIIARgVEhIKCwoEcnVuZRIDMjAwEKDLmAEaQKZtS3ATa26OOGvqdKm14ZbHeNfkPtIajXi5MkZ5XaX2SWOeX+YnCPZ9TxF9Jj5cVIo71m55xq4hVL3yDbRe89g=\"}") - assertEquals(output.error, "") + assertEquals(output.errorMessage, "") assertEquals(output.json, "") } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thorchain/TestTHORSwapSigning.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thorchain/TestTHORSwapSigning.kt index 2d1d3caf77e..68f0f8acc55 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thorchain/TestTHORSwapSigning.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thorchain/TestTHORSwapSigning.kt @@ -20,11 +20,13 @@ class TestTHORChainSwap { } @Test - fun testSwapEthBnb() { + fun testSwapEthBnbWithFee() { // prepare swap input val input = THORChainSwap.SwapInput.newBuilder() input.apply { - fromChain = THORChainSwap.Chain.ETH + fromAsset = THORChainSwap.Asset.newBuilder().apply { + chain = THORChainSwap.Chain.ETH + }.build() fromAddress = "0xb9f5771c27664bf2282d98e09d7f50cec7cb01a7" toAsset = THORChainSwap.Asset.newBuilder().apply { chain = THORChainSwap.Chain.BNB @@ -36,15 +38,17 @@ class TestTHORChainSwap { routerAddress = "0x42A5Ed456650a09Dc10EBc6361A7480fDd61f27B" fromAmount = "50000000000000000" toAmountLimit = "600003" + affiliateFeeAddress = "tthor1ql2tcqyrqsgnql2tcqyj2n8kfdmt9lh0yzql2tcqy" + affiliateFeeRateBp = "10" } // serialize input val inputSerialized = input.build().toByteArray() - assertEquals(Numeric.toHexString(inputSerialized), "0x0802122a3078623966353737316332373636346266323238326439386530396437663530636563376362303161371a0708031203424e42222a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372782a2a307831303931633444653661336346303943644130304162444165443432633763334236394338334543322a3078343241354564343536363530613039446331304542633633363141373438306644643631663237423a1135303030303030303030303030303030304206363030303033") + assertEquals(Numeric.toHexString(inputSerialized), "0x0a020802122a3078623966353737316332373636346266323238326439386530396437663530636563376362303161371a0708031203424e42222a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372782a2a307831303931633444653661336346303943644130304162444165443432633763334236394338334543322a3078343241354564343536363530613039446331304542633633363141373438306644643631663237423a11353030303030303030303030303030303042063630303030334a2f7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c327463717952023130") // invoke swap val outputData = buildSwap(inputSerialized) - assertEquals(outputData.count(), 311) + assertEquals(outputData.count(), 192) // parse result in proto val outputProto = THORChainSwap.SwapOutput.newBuilder().mergeFrom(outputData) @@ -66,6 +70,6 @@ class TestTHORChainSwap { // sign and encode resulting input val output = AnySigner.sign(txInputFull, ETHEREUM, SigningOutput.parser()) - assertEquals(Numeric.toHexString(output.encoded.toByteArray()), "0xf90151038506fc23ac00830138809442a5ed456650a09dc10ebc6361a7480fdd61f27b87b1a2bc2ec50000b8e41fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000003e535741503a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a363030303033000025a06ae104be3201baca38315352f81fac70ca4dd47339981914e64e91149813e780a066a3f0b2c44ddf5a96a38481274f623f552a593d723237d6742185f4885c0064") + assertEquals(Numeric.toHexString(output.encoded.toByteArray()), "0x02f8d90103808083013880941091c4de6a3cf09cda00abdaed42c7c3b69c83ec87b1a2bc2ec50000b86e3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3630303030333a7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c32746371793a3130c001a05c16871b66fd0fa8f658d6f171310bab332d09e0533d6c97329a59ddc93a9a11a05ed2be94e6dbb640e58920c8be4fa597cd5f0a918123245acb899042dd43777f") } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/tron/TestTronMessageSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/tron/TestTronMessageSigner.kt new file mode 100644 index 00000000000..23cfb2302d3 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/tron/TestTronMessageSigner.kt @@ -0,0 +1,27 @@ +package com.trustwallet.core.app.blockchains.tron + +import com.trustwallet.core.app.utils.Numeric +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test +import wallet.core.jni.CoinType +import wallet.core.jni.TronMessageSigner +import wallet.core.jni.PrivateKey + +class TestTronMessageSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testMessageSignerSignAndVerify() { + val data = Numeric.hexStringToByteArray("75065f100e38d3f3b4c5c4235834ba8216de62272a4f03532c44b31a5734360a") + val privateKey = PrivateKey(data) + val msg = "Hello World" + val signature = TronMessageSigner.signMessage(privateKey, msg) + assertEquals("9bb6d11ec8a6a3fb686a8f55b123e7ec4e9746a26157f6f9e854dd72f5683b450397a7b0a9653865658de8f9243f877539882891bad30c7286c3bf5622b900471b", signature) + val pubKey = privateKey.getPublicKey(CoinType.TRON) + assertTrue(TronMessageSigner.verifyMessage(pubKey, msg, signature)) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/tron/TestTronTransactionSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/tron/TestTronTransactionSigner.kt index 254f79bb860..295416c5487 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/tron/TestTronTransactionSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/tron/TestTronTransactionSigner.kt @@ -17,6 +17,18 @@ class TestTronTransactionSigner { System.loadLibrary("TrustWalletCore") } + @Test + fun testSignDirect() { + val signingInput = Tron.SigningInput.newBuilder() + .setTxId("546a3d07164c624809cf4e564a083a7a7974bb3c4eff6bb3e278b0ca21083fcb") + .setPrivateKey(ByteString.copyFrom("2d8f68944bdbfbc0769542fba8fc2d2a3de67393334471624364c7006da2aa54".toHexByteArray())) + + val output = AnySigner.sign(signingInput.build(), TRON, Tron.SigningOutput.parser()) + + assertEquals(Numeric.toHexString(output.id.toByteArray()), "0x546a3d07164c624809cf4e564a083a7a7974bb3c4eff6bb3e278b0ca21083fcb") + assertEquals(Numeric.toHexString(output.signature.toByteArray()), "0x77f5eabde31e739d34a66914540f1756981dc7d782c9656f5e14e53b59a15371603a183aa12124adeee7991bf55acc8e488a6ca04fb393b1a8ac16610eeafdfc00") + } + @Test fun testSignTransferTrc20Contract() { val trc20Contract = Tron.TransferTRC20Contract.newBuilder() diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/zen/TestZenAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/zen/TestZenAddress.kt new file mode 100644 index 00000000000..8398b636928 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/zen/TestZenAddress.kt @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.zen + +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestZenAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val key = PrivateKey("3a8e0a528f62f4ca2c77744c8a571def2845079b50105a9f7ef6b1b823def67a".toHexByteArray()) + val pubkey = key.getPublicKeySecp256k1(true) + val address = AnyAddress(pubkey, CoinType.ZEN) + val expected = AnyAddress("znk19H1wcARcCa7TM6zgmJUbWoWWtZ8k5cg", CoinType.ZEN) + + assertEquals(pubkey.data().toHex(), "0x02b4ac9056d20c52ac11b0d7e83715dd3eac851cfc9cb64b8546d9ea0d4bb3bdfe") + assertEquals(address.description(), expected.description()) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/zen/TestZenSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/zen/TestZenSigner.kt new file mode 100644 index 00000000000..36682ac0293 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/zen/TestZenSigner.kt @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.zen + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.Numeric +import com.trustwallet.core.app.utils.toHexByteArray +import com.trustwallet.core.app.utils.toHexBytes +import com.trustwallet.core.app.utils.toHexBytesInByteString +import org.junit.Assert.assertEquals +import org.junit.Test + +import wallet.core.java.AnySigner +import wallet.core.jni.BitcoinScript +import wallet.core.jni.BitcoinSigHashType +import wallet.core.jni.CoinType +import wallet.core.jni.proto.Bitcoin +import wallet.core.jni.proto.Common.SigningError + +class TestZenSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun ZenTransactionSigning() { + // prepare SigningInput + val input = Bitcoin.SigningInput.newBuilder() + .setHashType(BitcoinScript.hashTypeForCoin(CoinType.ZEN)) + .setAmount(10000) + .setByteFee(1) + .setToAddress("zngBGZGKaaBamofSuFw5WMnvU2HQAtwGeb5") + .setChangeAddress("znk19H1wcARcCa7TM6zgmJUbWoWWtZ8k5cg") + .setCoinType(CoinType.ZEN.value()) + + val utxoKey0 = + (Numeric.hexStringToByteArray("3a8e0a528f62f4ca2c77744c8a571def2845079b50105a9f7ef6b1b823def67a")) + input.addPrivateKey(ByteString.copyFrom(utxoKey0)) + + // build utxo + val txHash0 = (Numeric.hexStringToByteArray("a39e13b5ab406547e31284cd96fb40ed271813939c195ae7a86cd67fb8a4de62")) + val outpoint0 = Bitcoin.OutPoint.newBuilder() + .setHash(ByteString.copyFrom(txHash0)) + .setIndex(0) + .setSequence(Long.MAX_VALUE.toInt()) + .build() + + val utxo0 = Bitcoin.UnspentTransaction.newBuilder() + .setAmount(17600) + .setOutPoint(outpoint0) + .setScript(ByteString.copyFrom("76a914cf83669620de8bbdf2cefcdc5b5113195603c56588ac2081dc725fd33fada1062323802eefb54d3325d924d4297a69221456040000000003e88211b4".toHexBytes())) + .build() + + input.addUtxo(utxo0) + + val plan = AnySigner.plan(input.build(), CoinType.ZEN, Bitcoin.TransactionPlan.parser()) + + input.plan = Bitcoin.TransactionPlan.newBuilder() + .mergeFrom(plan) + .setPreblockhash(ByteString.copyFrom("81dc725fd33fada1062323802eefb54d3325d924d4297a692214560400000000".toHexBytes())) + .setPreblockheight(1147624) + .build() + + + val output = AnySigner.sign(input.build(), CoinType.ZEN, Bitcoin.SigningOutput.parser()) + + assertEquals(output.error, SigningError.OK) + + val encoded = output.encoded + assertEquals("0x0100000001a39e13b5ab406547e31284cd96fb40ed271813939c195ae7a86cd67fb8a4de62000000006a473044022014d687c0bee0b7b584db2eecbbf73b545ee255c42b8edf0944665df3fa882cfe02203bce2412d93c5a56cb4806ddd8297ff05f8fc121306e870bae33377a58a02f05012102b4ac9056d20c52ac11b0d7e83715dd3eac851cfc9cb64b8546d9ea0d4bb3bdfeffffffff0210270000000000003f76a914a58d22659b1082d1fa8698fc51996b43281bfce788ac2081dc725fd33fada1062323802eefb54d3325d924d4297a69221456040000000003e88211b4ce1c0000000000003f76a914cf83669620de8bbdf2cefcdc5b5113195603c56588ac2081dc725fd33fada1062323802eefb54d3325d924d4297a69221456040000000003e88211b400000000", + Numeric.toHexString(encoded.toByteArray())); + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestAnyAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestAnyAddress.kt new file mode 100644 index 00000000000..e440a5f0f32 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestAnyAddress.kt @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.utils + +import com.trustwallet.core.app.utils.Numeric +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexByteArray +import wallet.core.jni.* +import java.security.InvalidParameterException +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Assert.fail +import org.junit.Test + +class TestAnyAddress { + init { + System.loadLibrary("TrustWalletCore"); + } + + val any_address_test_address = "bc1qcj2vfjec3c3luf9fx9vddnglhh9gawmncmgxhz" + val any_address_test_pubkey = "02753f5c275e1847ba4d2fd3df36ad00af2e165650b35fe3991e9c9c46f68b12bc" + + @Test + fun testCreateWithString() { + val coin = CoinType.BITCOIN + val address = AnyAddress(any_address_test_address, coin) + assertEquals(address.coin(), coin) + assertEquals(address.description(), any_address_test_address) + } + + @Test + fun testCreateWithStringBech32() { + val coin = CoinType.BITCOIN + val address1 = AnyAddress(any_address_test_address, coin, "bc") + assertEquals(address1.description(), any_address_test_address) + + val address2 = AnyAddress("tb1qcj2vfjec3c3luf9fx9vddnglhh9gawmnjan4v3", coin, "tb") + assertEquals(address2.description(), "tb1qcj2vfjec3c3luf9fx9vddnglhh9gawmnjan4v3") + } + + @Test + fun testCreateWithPublicKey() { + val coin = CoinType.BITCOIN + val pubkey = PublicKey(any_address_test_pubkey.toHexByteArray(), PublicKeyType.SECP256K1) + val address = AnyAddress(pubkey, coin) + assertEquals(address.description(), any_address_test_address) + } + + @Test + fun testCreateWithPublicKeyDerivation() { + val coin = CoinType.BITCOIN + val pubkey = PublicKey(any_address_test_pubkey.toHexByteArray(), PublicKeyType.SECP256K1) + val address1 = AnyAddress(pubkey, coin, Derivation.BITCOINSEGWIT) + assertEquals(address1.description(), any_address_test_address) + + val address2 = AnyAddress(pubkey, coin, Derivation.BITCOINLEGACY) + assertEquals(address2.description(), "1JvRfEQFv5q5qy9uTSAezH7kVQf4hqnHXx") + + val address3 = AnyAddress(pubkey, coin, Derivation.BITCOINTAPROOT) + assertEquals(address3.description(), "bc1pnncpg8s7gu7t6xmmzxqarcj8ydthmaz8gr4m76eephjfprs53maswgel0w") + } + + @Test + fun testCreateBech32WithPublicKey() { + val coin = CoinType.BITCOIN + val pubkey = PublicKey(any_address_test_pubkey.toHexByteArray(), PublicKeyType.SECP256K1) + val address1 = AnyAddress(pubkey, coin, "bc") + assertEquals(address1.description(), any_address_test_address) + + val address2 = AnyAddress(pubkey, coin, "tb") + assertEquals(address2.description(), "tb1qcj2vfjec3c3luf9fx9vddnglhh9gawmnjan4v3") + } + + @Test + fun testIsValid() { + val coin = CoinType.BITCOIN + assertTrue(AnyAddress.isValid(any_address_test_address, coin)); + assertFalse(AnyAddress.isValid(any_address_test_address, CoinType.ETHEREUM)); + assertFalse(AnyAddress.isValid("__INVALID_ADDRESS__", CoinType.ETHEREUM)); + } + + @Test + fun testIsValidBech32() { + val coin = CoinType.BITCOIN + assertTrue(AnyAddress.isValidBech32(any_address_test_address, coin, "bc")); + assertFalse(AnyAddress.isValidBech32(any_address_test_address, coin, "tb")); + assertTrue(AnyAddress.isValidBech32("tb1qcj2vfjec3c3luf9fx9vddnglhh9gawmnjan4v3", coin, "tb")); + assertFalse(AnyAddress.isValidBech32("tb1qcj2vfjec3c3luf9fx9vddnglhh9gawmnjan4v3", coin, "bc")); + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestAsnParser.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestAsnParser.kt new file mode 100644 index 00000000000..7c896d7860c --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestAsnParser.kt @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.utils + +import wallet.core.jni.AsnParser +import org.junit.Assert.assertEquals +import org.junit.Test + +class TestAsnParser { + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testEcdsaSignatureFromDer() { + val encoded = "3046022100db421231f23d0320dbb8f1284b600cd34b8e9218628139539ff4f1f6c05495da022100ff715aab70d5317dbf8ee224eb18bec3120cfb9db1000dbb31eadaf96c71c1b1" + val expected = "0xdb421231f23d0320dbb8f1284b600cd34b8e9218628139539ff4f1f6c05495daff715aab70d5317dbf8ee224eb18bec3120cfb9db1000dbb31eadaf96c71c1b1" + val actual = AsnParser.ecdsaSignatureFromDer(encoded.toHexBytes()) + assertEquals(actual.toHex(), expected) + } +} \ No newline at end of file diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestBech32.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestBech32.kt new file mode 100644 index 00000000000..64b32728c5c --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestBech32.kt @@ -0,0 +1,49 @@ +package com.trustwallet.core.app.utils + +import org.junit.Assert.* +import org.junit.Test +import wallet.core.jni.Bech32 + +class TestBech32 { + init { + System.loadLibrary("TrustWalletCore"); + } + + @Test + fun testEncode() { + val data = Numeric.hexStringToByteArray("00443214c74254b635cf84653a56d7c675be77df") + assertEquals(Bech32.encode("abcdef", data), "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw") + } + + @Test + fun testDecode() { + val decoded = Bech32.decode("abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw") + assertEquals(Numeric.toHexString(decoded), "0x00443214c74254b635cf84653a56d7c675be77df") + } + + @Test + fun testDecodeWrongChecksumVariant() { + // This is a Bech32m variant, not Bech32 variant. So it should fail using Bech32 decoder. + val decoded = Bech32.decode("abcdef1l7aum6echk45nj3s0wdvt2fg8x9yrzpqzd3ryx") + assertNull(decoded) + } + + @Test + fun testEncodeM() { + val data = Numeric.hexStringToByteArray("ffbbcdeb38bdab49ca307b9ac5a928398a418820") + assertEquals(Bech32.encodeM("abcdef", data), "abcdef1l7aum6echk45nj3s0wdvt2fg8x9yrzpqzd3ryx") + } + + @Test + fun testDecodeM() { + val decoded = Bech32.decodeM("abcdef1l7aum6echk45nj3s0wdvt2fg8x9yrzpqzd3ryx") + assertEquals(Numeric.toHexString(decoded), "0xffbbcdeb38bdab49ca307b9ac5a928398a418820") + } + + @Test + fun testDecodeMWrongChecksumVariant() { + // This is a Bech32 variant, not Bech32m variant. So it should fail using Bech32M decoder. + val decoded = Bech32.decodeM("abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw") + assertNull(decoded) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestCryptoBox.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestCryptoBox.kt new file mode 100644 index 00000000000..4b5bc226ce9 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestCryptoBox.kt @@ -0,0 +1,47 @@ +package com.trustwallet.core.app.utils + +import com.trustwallet.core.app.utils.toHexBytes +import com.trustwallet.core.app.utils.toHex +import org.junit.Assert.* +import org.junit.Test +import wallet.core.jni.* + +class TestCryptoBox { + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testEncryptDecryptEasy() { + val mySecret = CryptoBoxSecretKey() + val myPubkey = mySecret.publicKey + + val otherSecret = CryptoBoxSecretKey() + val otherPubkey = otherSecret.publicKey + + val message = "Well done is better than well said. -Benjamin Franklin" + val encrypted = CryptoBox.encryptEasy(mySecret, otherPubkey, message.toByteArray()) + + // Step 2. Make sure the Box can be decrypted by the other side. + val decrypted = CryptoBox.decryptEasy(otherSecret, myPubkey, encrypted) + assertEquals(decrypted.toString(Charsets.UTF_8), message) + } + + @Test + fun testSecretKeyFromToBytes() { + val secretBytesHex = "0xdd87000d4805d6fbd89ae1352f5e4445648b79d5e901c92aebcb610e9be468e4" + val secretBytes = secretBytesHex.toHexByteArray() + assert(CryptoBoxSecretKey.isValid(secretBytes)) + val secret = CryptoBoxSecretKey(secretBytes) + assertEquals(secret.data().toHex(), secretBytesHex) + } + + @Test + fun testPublicKeyFromToBytes() { + val publicBytesHex = "0xafccabc5b28a8a1fd1cd880516f9c854ae2498d0d1b978b53a59f38e4ae55747" + val publicBytes = publicBytesHex.toHexByteArray() + assert(CryptoBoxPublicKey.isValid(publicBytes)) + val pubkey = CryptoBoxPublicKey(publicBytes) + assertEquals(pubkey.data().toHex(), publicBytesHex) + } +} \ No newline at end of file diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestHDWallet.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestHDWallet.kt index 0d85be821d8..9d165d95142 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestHDWallet.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestHDWallet.kt @@ -1,18 +1,18 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + package com.trustwallet.core.app.utils import com.trustwallet.core.app.utils.Numeric -import wallet.core.jni.CoinType -import wallet.core.jni.Curve -import wallet.core.jni.HDVersion -import wallet.core.jni.HDWallet -import wallet.core.jni.Mnemonic -import wallet.core.jni.Purpose +import com.trustwallet.core.app.utils.toHex import java.security.InvalidParameterException import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Assert.fail import org.junit.Test +import wallet.core.jni.* class TestHDWallet { init { @@ -23,6 +23,39 @@ class TestHDWallet { "ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal" val password = "TREZOR" + @Test + fun testCreateFromMnemonicImmutableXMainnetFromSignature() { + // Successfully register: https://api.x.immutable.com/v1/users/0xd0972E2312518Ca15A2304D56ff9cc0b7ea0Ea37 + val hd = HDWallet("obscure opera favorite shuffle mail tip age debate dirt pact cement loyal", "") + val derivationPath = Ethereum.eip2645GetPath("0xd0972E2312518Ca15A2304D56ff9cc0b7ea0Ea37", "starkex", "immutablex", "1") + assertEquals(derivationPath, "m/2645'/579218131'/211006541'/2124474935'/1609799702'/1") + + // Retrieve eth private key + val ethPrivateKey = hd.getKeyForCoin(CoinType.ETHEREUM) + assertEquals(Numeric.toHexString(ethPrivateKey.data()), "0x03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d") + + // Retrieve StarkKey DerivationPath + val starkDerivationPath = DerivationPath(derivationPath) + + // Retrieve Stark Private key part + val ethMsg = "Only sign this request if you’ve initiated an action with Immutable X." + val ethSignature = EthereumMessageSigner.signMessageImmutableX(ethPrivateKey, ethMsg) + assertEquals(ethSignature, "18b1be8b78807d3326e28bc286d7ee3d068dcd90b1949ce1d25c1f99825f26e70992c5eb7f44f76b202aceded00d74f771ed751f2fe538eec01e338164914fe001") + val starkPrivateKey = StarkWare.getStarkKeyFromSignature(starkDerivationPath, ethSignature) + val starkPublicKey = starkPrivateKey.getPublicKeyByType(PublicKeyType.STARKEX) + assertEquals(Numeric.toHexString(starkPrivateKey.data()), "0x04be51a04e718c202e4dca60c2b72958252024cfc1070c090dd0f170298249de") + assertEquals(Numeric.toHexString(starkPublicKey.data()), "0x00e5b9b11f8372610ef35d647a1dcaba1a4010716588d591189b27bf3c2d5095") + + // Account register + val ethMsgToRegister = "Only sign this key linking request from Immutable X" + val ethSignatureToRegister = EthereumMessageSigner.signMessageImmutableX(ethPrivateKey, ethMsgToRegister) + assertEquals(ethSignatureToRegister, "646da4160f7fc9205e6f502fb7691a0bf63ecbb74bbb653465cd62388dd9f56325ab1e4a9aba99b1661e3e6251b42822855a71e60017b310b9f90e990a12e1dc01") + val starkMsg = "463a2240432264a3aa71a5713f2a4e4c1b9e12bbb56083cd56af6d878217cf" + val starkSignature = StarkExMessageSigner.signMessage(starkPrivateKey, starkMsg) + assertEquals(starkSignature, "04cf5f21333dd189ada3c0f2a51430d733501a9b1d5e07905273c1938cfb261e05b6013d74adde403e8953743a338c8d414bb96bf69d2ca1a91a85ed2700a528") + assertTrue(StarkExMessageSigner.verifyMessage(starkPublicKey, starkMsg, starkSignature)) + } + @Test fun testCreateFromMnemonic() { val hd = HDWallet(words, password) @@ -65,6 +98,61 @@ class TestHDWallet { assertEquals(Numeric.toHexString(hd.entropy()), "0xba5821e8c356c05ba5f025d9532fe0f21f65d594") } + @Test + fun testGetKeyForCoin() { + val coin = CoinType.BITCOIN + val wallet = HDWallet(words, password) + val key = wallet.getKeyForCoin(coin) + + val address = coin.deriveAddress(key) + assertEquals(address, "bc1qumwjg8danv2vm29lp5swdux4r60ezptzz7ce85") + } + + @Test + fun testGetKeyDerivation() { + val coin = CoinType.BITCOIN + val wallet = HDWallet(words, password) + + val key1 = wallet.getKeyDerivation(coin, Derivation.BITCOINSEGWIT) + assertEquals(key1.data().toHex(), "0x1901b5994f075af71397f65bd68a9fff8d3025d65f5a2c731cf90f5e259d6aac") + + val key2 = wallet.getKeyDerivation(coin, Derivation.BITCOINLEGACY) + assertEquals(key2.data().toHex(), "0x28071bf4e2b0340db41b807ed8a5514139e5d6427ff9d58dbd22b7ed187103a4") + + val key3 = wallet.getKeyDerivation(coin, Derivation.BITCOINTESTNET) + assertEquals(key3.data().toHex(), "0xca5845e1b43e3adf577b7f110b60596479425695005a594c88f9901c3afe864f") + + val key4 = wallet.getKeyDerivation(coin, Derivation.BITCOINTAPROOT) + assertEquals(key4.data().toHex(), "0xa2c4d6df786f118f20330affd65d248ffdc0750ae9cbc729d27c640302afd030") + } + + @Test + fun testGetAddressForCoin() { + val coin = CoinType.BITCOIN + val wallet = HDWallet(words, password) + + val address = wallet.getAddressForCoin(coin) + assertEquals(address, "bc1qumwjg8danv2vm29lp5swdux4r60ezptzz7ce85") + } + + @Test + fun testGetAddressDerivation() { + val coin = CoinType.BITCOIN + val wallet = HDWallet(words, password) + + val address1 = wallet.getAddressDerivation(coin, Derivation.BITCOINSEGWIT) + assertEquals(address1, "bc1qumwjg8danv2vm29lp5swdux4r60ezptzz7ce85") + + val address2 = wallet.getAddressDerivation(coin, Derivation.BITCOINLEGACY) + assertEquals(address2, "1PeUvjuxyf31aJKX6kCXuaqxhmG78ZUdL1") + + val address3 = wallet.getAddressDerivation(coin, Derivation.BITCOINTESTNET) + assertEquals(address3, "tb1qwgpxgwn33z3ke9s7q65l976pseh4edrzfmyvl0") + + val address4 = wallet.getAddressDerivation(coin, Derivation.BITCOINTAPROOT) + assertEquals(address4, "bc1pgqks0cynn93ymve4x0jq3u7hne77908nlysp289hc44yc4cmy0hslyckrz") + } + @Test fun testDerive() { val wallet = HDWallet(words, password) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestKeyStore.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestKeyStore.kt index 3832db95139..599d3369216 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestKeyStore.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestKeyStore.kt @@ -4,6 +4,7 @@ import org.junit.Assert.* import org.junit.Test import wallet.core.jni.StoredKey import wallet.core.jni.CoinType +import wallet.core.jni.StoredKeyEncryption class TestKeyStore { @@ -21,6 +22,16 @@ class TestKeyStore { assertNotNull(result2) } + @Test + fun testDecryptMnemonicAes256() { + val keyStore = StoredKey("Test Wallet", "password".toByteArray(), StoredKeyEncryption.AES256CTR) + val result = keyStore.decryptMnemonic("wrong".toByteArray()) + val result2 = keyStore.decryptMnemonic("password".toByteArray()) + + assertNull(result) + assertNotNull(result2) + } + @Test fun testRemoveCoins() { val password = "password".toByteArray() diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestLiquidStaking.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestLiquidStaking.kt new file mode 100644 index 00000000000..44701d5f2b1 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestLiquidStaking.kt @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.utils + +import com.google.protobuf.ByteString +import org.junit.Assert +import wallet.core.jni.* +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.proto.Ethereum +import wallet.core.jni.proto.LiquidStaking +import wallet.core.jni.LiquidStaking as WCLiquidStaking + +class TestLiquidStaking { + init { + System.loadLibrary("TrustWalletCore"); + } + + @Test + fun testStraderStakeMatic() { + val input = LiquidStaking.Input.newBuilder() + input.apply { + blockchain = LiquidStaking.Blockchain.POLYGON + protocol = LiquidStaking.Protocol.Strader + smartContractAddress = "0xfd225c9e6601c9d38d8f98d8731bf59efcf8c0e3" + stake = LiquidStaking.Stake.newBuilder().apply { + amount = "1000000000000000000" + asset = LiquidStaking.Asset.newBuilder().apply { + stakingToken = LiquidStaking.Coin.POL + }.build() + }.build() + } + + + val inputSerialized = input.build().toByteArray() + assertEquals(Numeric.toHexString(inputSerialized), "0x0a170a00121331303030303030303030303030303030303030222a3078666432323563396536363031633964333864386639386438373331626635396566636638633065333001") + val outputData = WCLiquidStaking.buildRequest(inputSerialized) + assertEquals(outputData.count(), 68) + + val outputProto = LiquidStaking.Output.newBuilder().mergeFrom(outputData) + Assert.assertTrue(outputProto.hasEthereum()) + val txInput = outputProto.ethereum + + val txInputFull = txInput.toBuilder().apply { + chainId = ByteString.copyFrom("0x89".toHexByteArray()) + nonce = ByteString.copyFrom("0x01".toHexByteArray()) + maxFeePerGas = ByteString.copyFrom("0x8fbcc8fcd8".toHexByteArray()) + maxInclusionFeePerGas = ByteString.copyFrom("0x085e42c7c0".toHexByteArray()) + gasLimit = ByteString.copyFrom("0x01c520".toHexByteArray()) + privateKey = ByteString.copyFrom(PrivateKey("0x4a160b803c4392ea54865d0c5286846e7ad5e68fbd78880547697472b22ea7ab".toHexByteArray()).data()) + }.build() + + val output = AnySigner.sign(txInputFull, CoinType.ETHEREUM, Ethereum.SigningOutput.parser()) + + assertEquals(Numeric.toHexString(output.encoded.toByteArray()), "0x02f87a81890185085e42c7c0858fbcc8fcd88301c52094fd225c9e6601c9d38d8f98d8731bf59efcf8c0e3880de0b6b3a764000084c78cf1a0c001a04bcf92394d53d4908130cc6d4f7b2491967f9d6c59292b84c1f56adc49f6c458a073e09f45d64078c41a7946ffdb1dee8e604eb76f318088490f8f661bb7ddfc54") + // Successfully broadcasted: https://polygonscan.com/tx/0x0f6c4f7a893c3f08be30d2ea24479d7ed4bdba40875d07cfd607cf97980b7cf0 + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestPrivateKey.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestPrivateKey.kt index abdbc8050ab..d84bccd69c5 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestPrivateKey.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestPrivateKey.kt @@ -3,11 +3,7 @@ package com.trustwallet.core.app.utils import com.trustwallet.core.app.utils.toHexBytes import org.junit.Assert.* import org.junit.Test -import wallet.core.jni.Curve -import wallet.core.jni.Hash -import wallet.core.jni.PrivateKey -import wallet.core.jni.PublicKey -import wallet.core.jni.PublicKeyType +import wallet.core.jni.* class TestPrivateKey { private val validPrivateKeyData = "afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5".toHexBytes() @@ -23,6 +19,24 @@ class TestPrivateKey { assertTrue(data.size == 32); } + @Test + fun testCreateStarkKey() { + val data = Numeric.hexStringToByteArray("06cf0a8bf113352eb863157a45c5e5567abb34f8d32cddafd2c22aa803f4892c") + assertTrue(PrivateKey.isValid(data, Curve.STARKEX)) + var privateKey = PrivateKey(data) + var pubKey = privateKey.getPublicKeyByType(PublicKeyType.STARKEX) + assertEquals(pubKey.data().toHex(), "0x02d2bbdc1adaf887b0027cdde2113cfd81c60493aa6dc15d7887ddf1a82bc831") + } + + @Test + fun testCreateStarkKeySigning() { + val data = Numeric.hexStringToByteArray("0139fe4d6f02e666e86a6f58e65060f115cd3c185bd9e98bd829636931458f79") + var privateKey = PrivateKey(data) + val digest = Numeric.hexStringToByteArray("06fea80189363a786037ed3e7ba546dad0ef7de49fccae0e31eb658b7dd4ea76") + val signature = privateKey.sign(digest, Curve.STARKEX) + assertEquals(signature.toHex(), "0x061ec782f76a66f6984efc3a1b6d152a124c701c00abdd2bf76641b4135c770f04e44e759cea02c23568bb4d8a09929bbca8768ab68270d50c18d214166ccd9a") + } + @Test fun testInvalid() { val bytes = Numeric.hexStringToByteArray("deadbeaf") @@ -67,61 +81,9 @@ class TestPrivateKey { } @Test - fun testGetSharedKey() { - val privateKeyData = "9cd3b16e10bd574fed3743d8e0de0b7b4e6c69f3245ab5a168ef010d22bfefa0".toHexBytes() - val privateKey = PrivateKey(privateKeyData) - - val publicKeyData = "02a18a98316b5f52596e75bfa5ca9fa9912edd0c989b86b73d41bb64c9c6adb992".toHexBytes() - val publicKey = PublicKey(publicKeyData, PublicKeyType.SECP256K1) - - val derivedData = privateKey.getSharedKey(publicKey, Curve.SECP256K1) - assertNotNull(derivedData) - - assertEquals(derivedData?.toHex(), "0xef2cf705af8714b35c0855030f358f2bee356ff3579cea2607b2025d80133c3a") - } - - @Test - fun testGetSharedKeyWycherproof() { - val privateKeyData = "f4b7ff7cccc98813a69fae3df222bfe3f4e28f764bf91b4a10d8096ce446b254".toHexBytes() + fun testGetPublicKeyCoinType() { + val privateKeyData = "afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5".toHexBytes() val privateKey = PrivateKey(privateKeyData) - - val publicKeyData = "02d8096af8a11e0b80037e1ee68246b5dcbb0aeb1cf1244fd767db80f3fa27da2b".toHexBytes() - val publicKey = PublicKey(publicKeyData, PublicKeyType.SECP256K1) - - val derivedData = privateKey.getSharedKey(publicKey, Curve.SECP256K1) - assertNotNull(derivedData) - - assertEquals(derivedData?.toHex(), "0x81165066322732362ca5d3f0991d7f1f7d0aad7ea533276496785d369e35159a") - } - - @Test - fun testGetSharedKeyBidirectional() { - val privateKeyData1 = "9cd3b16e10bd574fed3743d8e0de0b7b4e6c69f3245ab5a168ef010d22bfefa0".toHexBytes() - val privateKey1 = PrivateKey(privateKeyData1) - val publicKey1 = privateKey1.getPublicKeySecp256k1(true) - - val privateKeyData2 = "ef2cf705af8714b35c0855030f358f2bee356ff3579cea2607b2025d80133c3a".toHexBytes() - val privateKey2 = PrivateKey(privateKeyData2) - val publicKey2 = privateKey2.getPublicKeySecp256k1(true) - - val derivedData1 = privateKey1.getSharedKey(publicKey2, Curve.SECP256K1) - assertNotNull(derivedData1) - - val derivedData2 = privateKey2.getSharedKey(publicKey1, Curve.SECP256K1) - assertNotNull(derivedData2) - - assertEquals(derivedData1?.toHex(), derivedData2?.toHex()) + assertEquals(privateKey.getPublicKey(CoinType.ETHEREUM).data().toHex(), "0x0499c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c166b489a4b7c491e7688e6ebea3a71fc3a1a48d60f98d5ce84c93b65e423fde91"); } - - @Test - fun testGetSharedKeyError() { - val privateKeyData = "9cd3b16e10bd574fed3743d8e0de0b7b4e6c69f3245ab5a168ef010d22bfefa0".toHexBytes() - val privateKey = PrivateKey(privateKeyData) - - val publicKeyData = "02a18a98316b5f52596e75bfa5ca9fa9912edd0c989b86b73d41bb64c9c6adb992".toHexBytes() - val publicKey = PublicKey(publicKeyData, PublicKeyType.SECP256K1) - - val derivedData = privateKey.getSharedKey(publicKey, Curve.ED25519) - assertNull(derivedData) - } } \ No newline at end of file diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestPublicKey.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestPublicKey.kt index dbd57dc1425..bfecc51014e 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestPublicKey.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestPublicKey.kt @@ -4,10 +4,7 @@ import com.trustwallet.core.app.utils.toHexBytes import com.trustwallet.core.app.utils.toHex import org.junit.Assert.* import org.junit.Test -import wallet.core.jni.Curve -import wallet.core.jni.Hash -import wallet.core.jni.PrivateKey -import wallet.core.jni.PublicKey +import wallet.core.jni.* class TestPublicKey { @@ -28,6 +25,17 @@ class TestPublicKey { val publicKey = privateKey?.getPublicKeySecp256k1(true) assertEquals("0x0399c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c1", publicKey?.data()?.toHex()) } + + @Test + fun testVerifyStarkey() { + val data = Numeric.hexStringToByteArray("02c5dbad71c92a45cc4b40573ae661f8147869a91d57b8d9b8f48c8af7f83159") + val publicKey = PublicKey(data, PublicKeyType.STARKEX) + var signature = Numeric.hexStringToByteArray("061ec782f76a66f6984efc3a1b6d152a124c701c00abdd2bf76641b4135c770f04e44e759cea02c23568bb4d8a09929bbca8768ab68270d50c18d214166ccd9a") + val hash = Numeric.hexStringToByteArray("06fea80189363a786037ed3e7ba546dad0ef7de49fccae0e31eb658b7dd4ea76") + assertTrue(publicKey.verify(signature, hash)) + signature = Numeric.hexStringToByteArray("061ec782f76a66f6984efc3a1b6d152a124c701c00abdd2bf76641b4135c770f04e44e759cea02c23568bb4d8a09929bbca8768ab68270d50c18d214166ccd9b") + assertFalse(publicKey.verify(signature, hash)) + } @Test fun testSign() { diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestWebAuthn.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestWebAuthn.kt new file mode 100644 index 00000000000..d24ff122dbe --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestWebAuthn.kt @@ -0,0 +1,36 @@ +package com.trustwallet.core.app.utils + +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import com.trustwallet.core.app.utils.Numeric +import wallet.core.jni.* + +class TestWebAuthn { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testGetPublicKey() { + val attestationObject = Numeric.hexStringToByteArray("0xa363666d74646e6f6e656761747453746d74a068617574684461746158a4f95bc73828ee210f9fd3bbe72d97908013b0a3759e9aea3d0ae318766cd2e1ad4500000000adce000235bcc60a648b0b25f1f055030020c720eb493e167ce93183dd91f5661e1004ed8cc1be23d3340d92381da5c0c80ca5010203262001215820a620a8cfc88fd062b11eab31663e56cad95278bef612959be214d98779f645b82258204e7b905b42917570148b0432f99ba21f2e7eebe018cbf837247e38150a89f771") + val result = WebAuthn.getPublicKey(attestationObject).data() + assertEquals(Numeric.toHexString(result), "0x04a620a8cfc88fd062b11eab31663e56cad95278bef612959be214d98779f645b84e7b905b42917570148b0432f99ba21f2e7eebe018cbf837247e38150a89f771") + } + + @Test + fun testGetRSValues() { + val signature = Numeric.hexStringToByteArray("0x30440220766589b461a838748708cdf88444b21b1fa52b57d70671b4f9bf60ad14b372ec022020cc439c9c20661bfa39bbea24a900ec1484b2395eb065ead8ef4e273144a57d") + val result = WebAuthn.getRSValues(signature) + assertEquals(Numeric.toHexString(result), "0x766589b461a838748708cdf88444b21b1fa52b57d70671b4f9bf60ad14b372ec20cc439c9c20661bfa39bbea24a900ec1484b2395eb065ead8ef4e273144a57d") + } + + @Test + fun testReconstructOriginalMessage() { + val authenticatorData = Numeric.hexStringToByteArray("0x1a70842af8c1feb7133b81e6a160a6a2be45ee057f0eb6d3f7f5126daa202e071d00000000") + val clientDataJSON = Numeric.hexStringToByteArray("0x7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a224e5549794f5545774d6b45744e554535517930304d6b5a424c546847516a4174517a52474f4441794d3045304f546b30222c226f726967696e223a2268747470733a2f2f747275737477616c6c65742e636f6d227d") + val result = WebAuthn.reconstructOriginalMessage(authenticatorData, clientDataJSON) + assertEquals(Numeric.toHexString(result), "0x3254cdbd677e6e31e75d2135bad0cf56440d7c6b108c141a3509d76ce45c6731") + } +} \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index ef7f63193fb..1df538f8715 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,21 +1,20 @@ - + + android:allowBackup="true" + android:icon="@mipmap/ic_launcher" + android:label="@string/app_name" + android:roundIcon="@mipmap/ic_launcher_round" + android:supportsRtl="true" + android:theme="@style/AppTheme"> - + - + - \ No newline at end of file + diff --git a/android/build.gradle b/android/build.gradle index b1ca946f2d1..ae4f70d4299 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,18 +1,12 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. - buildscript { ext.kotlin_version = '1.6.10' repositories { google() mavenCentral() - maven { - url = uri("https://plugins.gradle.org/m2/") - } } dependencies { - classpath 'com.android.tools.build:gradle:4.2.2' + classpath 'com.android.tools.build:gradle:8.0.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0' } } @@ -26,7 +20,7 @@ allprojects { subprojects { afterEvaluate { if (getPlugins().hasPlugin('android') || - getPlugins().hasPlugin('android-library')) { + getPlugins().hasPlugin('android-library')) { configure(android.lintOptions) { abortOnError false } diff --git a/android/gradle.properties b/android/gradle.properties index 53c570a2de0..395c1f03275 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -20,6 +20,8 @@ android.useAndroidX=true android.enableJetifier=true # Kotlin code style for this project: "official" or "obsolete": kotlin.code.style=official +android.defaults.buildfeatures.buildconfig=false +android.defaults.buildfeatures.resvalues=false VERSION_NAME=0.12.1 VERSION_CODE=1 diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar index 62d4c053550..c1962a79e29 100644 Binary files a/android/gradle/wrapper/gradle-wrapper.jar and b/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 4cf5f4720c8..a21c6ebe28b 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Jan 19 18:01:57 JST 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.2-bin.zip distributionPath=wrapper/dists -zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-all.zip +networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/android/gradlew b/android/gradlew index fbd7c515832..aeb74cbb43e 100755 --- a/android/gradlew +++ b/android/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,98 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +118,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +129,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +137,109 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/android/gradlew.bat b/android/gradlew.bat index a9f778a7a96..6689b85beec 100644 --- a/android/gradlew.bat +++ b/android/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -54,7 +55,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -64,21 +65,6 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line @@ -86,17 +72,19 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/android/settings.gradle b/android/settings.gradle index 1924f990d04..044d01a9482 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1 +1 @@ -include ':app', ':trustwalletcore' +include ':app', ':wallet-core', ':wallet-core-proto' diff --git a/android/trustwalletcore/build.gradle b/android/trustwalletcore/build.gradle deleted file mode 100644 index bf97bfd2412..00000000000 --- a/android/trustwalletcore/build.gradle +++ /dev/null @@ -1,53 +0,0 @@ -apply plugin: 'com.android.library' -apply plugin: 'maven-publish' -group='com.github.trustwallet' - -android { - compileSdkVersion 32 - ndkVersion '23.1.7779620' - defaultConfig { - minSdkVersion 23 - versionCode 1 - versionName "1.0" - externalNativeBuild { - cmake { - arguments "-DCMAKE_BUILD_TYPE=Release" - } - } - } - - lintOptions { - abortOnError false - disable 'InvalidPackage' - } - - buildTypes { - release { - minifyEnabled false - } - debug { - minifyEnabled false - // limit platforms built for testing - ndk { - abiFilters 'x86', 'arm64-v8a' - } - } - } - - sourceSets { - main.java.srcDirs += '../../jni/java' - } - - externalNativeBuild { - cmake { - version "3.18.1" - path "../../CMakeLists.txt" - } - } -} - -dependencies { - implementation 'com.google.protobuf:protobuf-javalite:3.21.2' -} - -apply from: 'maven-push.gradle' diff --git a/android/trustwalletcore/maven-push.gradle b/android/trustwalletcore/maven-push.gradle deleted file mode 100644 index 12746f09c4a..00000000000 --- a/android/trustwalletcore/maven-push.gradle +++ /dev/null @@ -1,51 +0,0 @@ -apply plugin: 'maven-publish' - -version project.property('version') -group 'com.trustwallet' - -task sourcesJar(type: Jar) { - classifier = 'sources' - from android.sourceSets.main.java.sourceFiles -} - -artifacts { - archives sourcesJar -} - -publishing { - publications { - Production(MavenPublication) { - artifact("$buildDir/outputs/aar/trustwalletcore-release.aar") - artifact sourcesJar { - classifier "sources" - } - groupId this.group - artifactId 'wallet-core' - version this.version - - pom.withXml { - def dependenciesNode = asNode().appendNode('dependencies') - - configurations.implementation.allDependencies.each { - if (it.name != 'unspecified') { - def dependencyNode = dependenciesNode.appendNode('dependency') - dependencyNode.appendNode('groupId', it.group) - dependencyNode.appendNode('artifactId', it.name) - dependencyNode.appendNode('version', it.version) - } - } - } - } - } - - repositories { - maven { - name = "GitHubPackages" - url = uri("https://maven.pkg.github.com/trustwallet/wallet-core") - credentials { - username = System.getenv("WC_GITHUB_USER") - password = System.getenv("WC_GITHUB_TOKEN") - } - } - } -} diff --git a/android/trustwalletcore/src/main/AndroidManifest.xml b/android/trustwalletcore/src/main/AndroidManifest.xml deleted file mode 100644 index 3f53eb1d42b..00000000000 --- a/android/trustwalletcore/src/main/AndroidManifest.xml +++ /dev/null @@ -1,2 +0,0 @@ - diff --git a/android/wallet-core-proto/build.gradle b/android/wallet-core-proto/build.gradle new file mode 100644 index 00000000000..c04e323f48e --- /dev/null +++ b/android/wallet-core-proto/build.gradle @@ -0,0 +1,21 @@ +apply plugin: 'java-library' +apply plugin: 'maven-publish' + +group = 'com.trustwallet' + +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + + withSourcesJar() + + sourceSets { + main.java.srcDirs += '../../jni/proto' + } +} + +dependencies { + api 'com.google.protobuf:protobuf-javalite:3.22.3' +} + +apply from: 'maven-push.gradle' diff --git a/android/wallet-core-proto/maven-push.gradle b/android/wallet-core-proto/maven-push.gradle new file mode 100644 index 00000000000..cb48062952d --- /dev/null +++ b/android/wallet-core-proto/maven-push.gradle @@ -0,0 +1,20 @@ +apply plugin: 'maven-publish' + +publishing { + publications { + release(MavenPublication) { + from components.java + } + } + + repositories { + maven { + name = "GitHubPackages" + url = uri("https://maven.pkg.github.com/trustwallet/wallet-core") + credentials { + username = System.getenv("GITHUB_USER") + password = System.getenv("GITHUB_TOKEN") + } + } + } +} diff --git a/android/trustwalletcore/.gitignore b/android/wallet-core/.gitignore similarity index 100% rename from android/trustwalletcore/.gitignore rename to android/wallet-core/.gitignore diff --git a/android/wallet-core/build.gradle b/android/wallet-core/build.gradle new file mode 100644 index 00000000000..fcdf15afbbc --- /dev/null +++ b/android/wallet-core/build.gradle @@ -0,0 +1,61 @@ +apply plugin: 'com.android.library' +apply plugin: 'maven-publish' + +group = 'com.trustwallet' + +android { + namespace 'wallet.core' + compileSdkVersion 32 + ndkVersion '23.1.7779620' + defaultConfig { + minSdkVersion 23 + versionCode 1 + versionName "1.0" + externalNativeBuild { + cmake { + arguments "-DCMAKE_BUILD_TYPE=Release", "-DTW_UNITY_BUILD=ON" + } + } + } + + lintOptions { + abortOnError false + disable 'InvalidPackage' + } + + buildTypes { + release { + minifyEnabled false + } + debug { + minifyEnabled false + // limit platforms built for testing + ndk { + abiFilters 'x86', 'arm64-v8a' + } + } + } + + sourceSets { + main.java.srcDirs += '../../jni/java' + } + + externalNativeBuild { + cmake { + version "3.18.1" + path "../../CMakeLists.txt" + } + } + + publishing { + singleVariant('release') { + withSourcesJar() + } + } +} + +dependencies { + api project(':wallet-core-proto') +} + +apply from: 'maven-push.gradle' diff --git a/android/trustwalletcore/gradle.properties b/android/wallet-core/gradle.properties similarity index 100% rename from android/trustwalletcore/gradle.properties rename to android/wallet-core/gradle.properties diff --git a/android/wallet-core/maven-push.gradle b/android/wallet-core/maven-push.gradle new file mode 100644 index 00000000000..49dd6eec103 --- /dev/null +++ b/android/wallet-core/maven-push.gradle @@ -0,0 +1,22 @@ +apply plugin: 'maven-publish' + +publishing { + publications { + release(MavenPublication) { + afterEvaluate { + from components.release + } + } + } + + repositories { + maven { + name = "GitHubPackages" + url = uri("https://maven.pkg.github.com/trustwallet/wallet-core") + credentials { + username = System.getenv("GITHUB_USER") + password = System.getenv("GITHUB_TOKEN") + } + } + } +} diff --git a/audit/2023-09-15_TrustWallet_SecureCodeReviewReport_Public_v2.00.pdf b/audit/2023-09-15_TrustWallet_SecureCodeReviewReport_Public_v2.00.pdf new file mode 100644 index 00000000000..d0efac0de8d Binary files /dev/null and b/audit/2023-09-15_TrustWallet_SecureCodeReviewReport_Public_v2.00.pdf differ diff --git a/bootstrap.sh b/bootstrap.sh index 1dba588dd30..1cc2636b987 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -5,8 +5,43 @@ # Fail if any commands fails set -e -echo "#### Initializing workspace with dependencies ... ####" +source tools/parse_args "$@" + +if isHelp; then + echo "usage: bootstrap.sh [-h | --help] [all | wasm | android | ios]" + echo "" + echo "Installs dependencies and prepares WalletCore for building" + exit 0 +fi + +echo "#### Installing system dependencies ... ####" +if [[ $(uname) == "Darwin" ]]; then + tools/install-sys-dependencies-mac +else + tools/install-sys-dependencies-linux +fi + +echo "#### Installing C++ libraries ... ####" tools/install-dependencies -echo "#### Building and running tests ... ####" -tools/build-and-test +echo "#### Installing Rust toolchain and tools ... ####" +tools/install-rust-dependencies dev + +# WASM +if isTargetSpecified "wasm"; then + echo "#### Installing WASM environment ... ####" + tools/install-wasm-dependencies +fi + +# Android +if isTargetSpecified "android"; then + echo "#### Installing Android dependencies ... ####" + tools/install-android-dependencies +fi + +echo "#### Generating files... ####" +tools/generate-files "$@" + +echo "" +echo "WalletCore is ready for development!" +echo "Consider running native C++ tests via './tools/build-and-test'" diff --git a/cmake/Protobuf.cmake b/cmake/Protobuf.cmake index fe59c9ea73a..8e0a93251d2 100644 --- a/cmake/Protobuf.cmake +++ b/cmake/Protobuf.cmake @@ -1,11 +1,9 @@ -# Copyright © 2017-2022 Trust Wallet. +# SPDX-License-Identifier: Apache-2.0 # -# This file is part of Trust. The full Trust copyright notice, including -# terms governing use, modification, and redistribution, is contained in the -# file LICENSE at the root of the source code distribution tree. +# Copyright © 2017 Trust Wallet. -set(protobuf_SOURCE_DIR ${CMAKE_SOURCE_DIR}/build/local/src/protobuf/protobuf-3.19.2) -set(protobuf_source_dir ${CMAKE_SOURCE_DIR}/build/local/src/protobuf/protobuf-3.19.2) +set(protobuf_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/../build/local/src/protobuf/protobuf-3.19.2) +set(protobuf_source_dir ${CMAKE_CURRENT_LIST_DIR}/../build/local/src/protobuf/protobuf-3.19.2) # sort + uniq -u # https://github.com/protocolbuffers/protobuf/blob/master/cmake/libprotobuf.cmake diff --git a/cmake/StandardSettings.cmake b/cmake/StandardSettings.cmake index 752b2285672..bef5a651b52 100644 --- a/cmake/StandardSettings.cmake +++ b/cmake/StandardSettings.cmake @@ -66,7 +66,7 @@ endif () option(TW_UNIT_TESTS "Enable the unit tests of the project" ON) option(TW_BUILD_EXAMPLES "Enable the examples builds of the project" ON) -if (ANDROID OR IOS_PLATFORM OR TW_COMPILE_WASM) +if (ANDROID OR IOS_PLATFORM OR TW_COMPILE_WASM OR TW_COMPILE_JAVA) set(TW_UNIT_TESTS OFF) set(TW_BUILD_EXAMPLES OFF) endif() diff --git a/codegen-v2/Cargo.lock b/codegen-v2/Cargo.lock new file mode 100644 index 00000000000..6ed11b1c48a --- /dev/null +++ b/codegen-v2/Cargo.lock @@ -0,0 +1,385 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "codegen-v2" +version = "0.1.0" +dependencies = [ + "aho-corasick", + "convert_case", + "handlebars", + "heck", + "pathdiff", + "serde", + "serde_json", + "serde_yaml", + "toml_edit", +] + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "handlebars" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faa67bab9ff362228eb3d00bd024a4965d8231bbb7921167f0cfa66c6626b225" +dependencies = [ + "log", + "pest", + "pest_derive", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "indexmap" +version = "2.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + +[[package]] +name = "pest" +version = "2.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f8023d0fb78c8e03784ea1c7f3fa36e68a723138990b8d5a47d916b651e7a8" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0d24f72393fd16ab6ac5738bc33cdb6a9aa73f8b902e8fe29cf4e67d7dd1026" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc17e2a6c7d0a492f0158d7a4bd66cc17280308bbaff78d5bef566dca35ab80" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "934cd7631c050f4674352a6e835d5f6711ffbfb9345c2fc0107155ac495ae293" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd075d994154d4a774f95b51fb96bdc2832b0ea48425c92546073816cda1f2f" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "syn" +version = "2.0.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] diff --git a/codegen-v2/Cargo.toml b/codegen-v2/Cargo.toml new file mode 100644 index 00000000000..43c2afea1c6 --- /dev/null +++ b/codegen-v2/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "codegen-v2" +version = "0.1.0" +edition = "2021" + +[lib] +name = "libparser" +path = "src/lib.rs" + +[[bin]] +name = "parser" +path = "src/main.rs" + +[dependencies] +aho-corasick = "1.1.2" +convert_case = "0.6.0" +pathdiff = "0.2.1" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +serde_yaml = "0.9.21" +toml_edit = "0.21.0" +handlebars = "4.3.6" +heck = "0.4.1" diff --git a/codegen-v2/README.md b/codegen-v2/README.md new file mode 100644 index 00000000000..33e018ac407 --- /dev/null +++ b/codegen-v2/README.md @@ -0,0 +1,14 @@ +# About + +This is a _work-in-progress_ parser meant to deprecate the existing Ruby parser +in `codegen/`. As of now, we only support Swift binding generation. This project +will progress over multiple stages (PRs). + +## Execution + +```bash +$ cd codegen-v2 +$ cargo run -- swift +``` + +The bindings are saved to `bindings/`. diff --git a/codegen-v2/manifest/TWAES.yaml b/codegen-v2/manifest/TWAES.yaml new file mode 100644 index 00000000000..24637e9155b --- /dev/null +++ b/codegen-v2/manifest/TWAES.yaml @@ -0,0 +1,134 @@ +name: TWAES +structs: +- name: TWAES + is_public: true + is_class: false + fields: + - - unused + - variant: u_int8_t + is_constant: false + is_nullable: false + is_pointer: false +functions: +- name: TWAESEncryptCBC + is_public: true + is_static: true + params: + - name: key + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: iv + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: mode + type: + variant: enum + value: TWAESPaddingMode + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true +- name: TWAESDecryptCBC + is_public: true + is_static: true + params: + - name: key + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: iv + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: mode + type: + variant: enum + value: TWAESPaddingMode + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true +- name: TWAESEncryptCTR + is_public: true + is_static: true + params: + - name: key + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: iv + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true +- name: TWAESDecryptCTR + is_public: true + is_static: true + params: + - name: key + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: iv + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true diff --git a/codegen-v2/manifest/TWAESPaddingMode.yaml b/codegen-v2/manifest/TWAESPaddingMode.yaml new file mode 100644 index 00000000000..2776625e45f --- /dev/null +++ b/codegen-v2/manifest/TWAESPaddingMode.yaml @@ -0,0 +1,11 @@ +name: TWAESPaddingMode +enums: +- name: TWAESPaddingMode + is_public: true + value_type: + variant: u_int32_t + variants: + - name: zero + value: 0 + - name: pkcs7 + value: 1 diff --git a/codegen-v2/manifest/TWAccount.yaml b/codegen-v2/manifest/TWAccount.yaml new file mode 100644 index 00000000000..4a2be534e60 --- /dev/null +++ b/codegen-v2/manifest/TWAccount.yaml @@ -0,0 +1,95 @@ +name: TWAccount +structs: +- name: TWAccount + is_public: true + is_class: true +inits: +- name: TWAccountCreate + is_public: true + is_nullable: false + params: + - name: address + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: derivation + type: + variant: enum + value: TWDerivation + is_constant: false + is_nullable: false + is_pointer: false + - name: derivationPath + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: publicKey + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: extendedPublicKey + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +deinits: +- name: TWAccountDelete +properties: +- name: TWAccountAddress + is_public: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWAccountCoin + is_public: true + return_type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false +- name: TWAccountDerivation + is_public: true + return_type: + variant: enum + value: TWDerivation + is_constant: false + is_nullable: false + is_pointer: false +- name: TWAccountDerivationPath + is_public: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWAccountPublicKey + is_public: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWAccountExtendedPublicKey + is_public: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWAeternityProto.yaml b/codegen-v2/manifest/TWAeternityProto.yaml new file mode 100644 index 00000000000..4e2479caffb --- /dev/null +++ b/codegen-v2/manifest/TWAeternityProto.yaml @@ -0,0 +1,4 @@ +name: TWAeternityProto +protos: +- TW_Aeternity_Proto_SigningInput +- TW_Aeternity_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWAionProto.yaml b/codegen-v2/manifest/TWAionProto.yaml new file mode 100644 index 00000000000..f081c9c56dc --- /dev/null +++ b/codegen-v2/manifest/TWAionProto.yaml @@ -0,0 +1,4 @@ +name: TWAionProto +protos: +- TW_Aion_Proto_SigningInput +- TW_Aion_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWAlgorandProto.yaml b/codegen-v2/manifest/TWAlgorandProto.yaml new file mode 100644 index 00000000000..23e6f9e283d --- /dev/null +++ b/codegen-v2/manifest/TWAlgorandProto.yaml @@ -0,0 +1,7 @@ +name: TWAlgorandProto +protos: +- TW_Algorand_Proto_Transfer +- TW_Algorand_Proto_AssetTransfer +- TW_Algorand_Proto_AssetOptIn +- TW_Algorand_Proto_SigningInput +- TW_Algorand_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWAnyAddress.yaml b/codegen-v2/manifest/TWAnyAddress.yaml new file mode 100644 index 00000000000..52ce8860dd7 --- /dev/null +++ b/codegen-v2/manifest/TWAnyAddress.yaml @@ -0,0 +1,308 @@ +name: TWAnyAddress +structs: +- name: TWPublicKey + is_public: false + is_class: false +- name: TWAnyAddress + is_public: true + is_class: true +inits: +- name: TWAnyAddressCreateWithString + is_public: true + is_nullable: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false +- name: TWAnyAddressCreateBech32 + is_public: true + is_nullable: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: hrp + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWAnyAddressCreateSS58 + is_public: true + is_nullable: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: ss58Prefix + type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false +- name: TWAnyAddressCreateWithPublicKey + is_public: true + is_nullable: false + params: + - name: publicKey + type: + variant: struct + value: TWPublicKey + is_constant: false + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false +- name: TWAnyAddressCreateWithPublicKeyDerivation + is_public: true + is_nullable: false + params: + - name: publicKey + type: + variant: struct + value: TWPublicKey + is_constant: false + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: derivation + type: + variant: enum + value: TWDerivation + is_constant: false + is_nullable: false + is_pointer: false +- name: TWAnyAddressCreateBech32WithPublicKey + is_public: true + is_nullable: false + params: + - name: publicKey + type: + variant: struct + value: TWPublicKey + is_constant: false + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: hrp + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWAnyAddressCreateSS58WithPublicKey + is_public: true + is_nullable: false + params: + - name: publicKey + type: + variant: struct + value: TWPublicKey + is_constant: false + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: ss58Prefix + type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false +- name: TWAnyAddressCreateWithPublicKeyFilecoinAddressType + is_public: true + is_nullable: false + params: + - name: publicKey + type: + variant: struct + value: TWPublicKey + is_constant: false + is_nullable: false + is_pointer: true + - name: filecoinAddressType + type: + variant: enum + value: TWFilecoinAddressType + is_constant: false + is_nullable: false + is_pointer: false +deinits: +- name: TWAnyAddressDelete +functions: +- name: TWAnyAddressEqual + is_public: true + is_static: true + params: + - name: lhs + type: + variant: struct + value: TWAnyAddress + is_constant: false + is_nullable: false + is_pointer: true + - name: rhs + type: + variant: struct + value: TWAnyAddress + is_constant: false + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWAnyAddressIsValid + is_public: true + is_static: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWAnyAddressIsValidBech32 + is_public: true + is_static: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: hrp + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWAnyAddressIsValidSS58 + is_public: true + is_static: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: ss58Prefix + type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +properties: +- name: TWAnyAddressDescription + is_public: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWAnyAddressCoin + is_public: true + return_type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false +- name: TWAnyAddressData + is_public: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWAptosProto.yaml b/codegen-v2/manifest/TWAptosProto.yaml new file mode 100644 index 00000000000..f32f51b7632 --- /dev/null +++ b/codegen-v2/manifest/TWAptosProto.yaml @@ -0,0 +1,14 @@ +name: TWAptosProto +protos: +- TW_Aptos_Proto_TransferMessage +- TW_Aptos_Proto_StructTag +- TW_Aptos_Proto_TokenTransferMessage +- TW_Aptos_Proto_ManagedTokensRegisterMessage +- TW_Aptos_Proto_CreateAccountMessage +- TW_Aptos_Proto_OfferNftMessage +- TW_Aptos_Proto_CancelOfferNftMessage +- TW_Aptos_Proto_ClaimNftMessage +- TW_Aptos_Proto_NftMessage +- TW_Aptos_Proto_SigningInput +- TW_Aptos_Proto_TransactionAuthenticator +- TW_Aptos_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWBarz.yaml b/codegen-v2/manifest/TWBarz.yaml new file mode 100644 index 00000000000..8383f1c05cc --- /dev/null +++ b/codegen-v2/manifest/TWBarz.yaml @@ -0,0 +1,21 @@ +name: TWBarz +structs: + - name: TWBarz + is_public: true + is_class: false +functions: + - name: TWBarzGetCounterfactualAddress + is_public: true + is_static: true + params: + - name: input + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true \ No newline at end of file diff --git a/codegen-v2/manifest/TWBase32.yaml b/codegen-v2/manifest/TWBase32.yaml new file mode 100644 index 00000000000..3c1dd778457 --- /dev/null +++ b/codegen-v2/manifest/TWBase32.yaml @@ -0,0 +1,78 @@ +name: TWBase32 +structs: +- name: TWBase32 + is_public: true + is_class: false +functions: +- name: TWBase32DecodeWithAlphabet + is_public: true + is_static: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: alphabet + type: + variant: string + is_constant: true + is_nullable: true + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true +- name: TWBase32Decode + is_public: true + is_static: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true +- name: TWBase32EncodeWithAlphabet + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: alphabet + type: + variant: string + is_constant: true + is_nullable: true + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWBase32Encode + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWBase58.yaml b/codegen-v2/manifest/TWBase58.yaml new file mode 100644 index 00000000000..4806a101d67 --- /dev/null +++ b/codegen-v2/manifest/TWBase58.yaml @@ -0,0 +1,66 @@ +name: TWBase58 +structs: +- name: TWBase58 + is_public: true + is_class: false +functions: +- name: TWBase58Encode + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWBase58EncodeNoCheck + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWBase58Decode + is_public: true + is_static: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true +- name: TWBase58DecodeNoCheck + is_public: true + is_static: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true diff --git a/codegen-v2/manifest/TWBase64.yaml b/codegen-v2/manifest/TWBase64.yaml new file mode 100644 index 00000000000..bcb60202257 --- /dev/null +++ b/codegen-v2/manifest/TWBase64.yaml @@ -0,0 +1,66 @@ +name: TWBase64 +structs: +- name: TWBase64 + is_public: true + is_class: false +functions: +- name: TWBase64Decode + is_public: true + is_static: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true +- name: TWBase64DecodeUrl + is_public: true + is_static: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true +- name: TWBase64Encode + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWBase64EncodeUrl + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWBech32.yaml b/codegen-v2/manifest/TWBech32.yaml new file mode 100644 index 00000000000..1d192712adb --- /dev/null +++ b/codegen-v2/manifest/TWBech32.yaml @@ -0,0 +1,78 @@ +name: TWBech32 +structs: +- name: TWBech32 + is_public: true + is_class: false +functions: +- name: TWBech32Encode + is_public: true + is_static: true + params: + - name: hrp + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWBech32Decode + is_public: true + is_static: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true +- name: TWBech32EncodeM + is_public: true + is_static: true + params: + - name: hrp + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWBech32DecodeM + is_public: true + is_static: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true diff --git a/codegen-v2/manifest/TWBinanceProto.yaml b/codegen-v2/manifest/TWBinanceProto.yaml new file mode 100644 index 00000000000..44483799529 --- /dev/null +++ b/codegen-v2/manifest/TWBinanceProto.yaml @@ -0,0 +1,25 @@ +name: TWBinanceProto +protos: +- TW_Binance_Proto_Transaction +- TW_Binance_Proto_Signature +- TW_Binance_Proto_TradeOrder +- TW_Binance_Proto_CancelTradeOrder +- TW_Binance_Proto_SendOrder +- TW_Binance_Proto_TokenIssueOrder +- TW_Binance_Proto_TokenMintOrder +- TW_Binance_Proto_TokenBurnOrder +- TW_Binance_Proto_TokenFreezeOrder +- TW_Binance_Proto_TokenUnfreezeOrder +- TW_Binance_Proto_HTLTOrder +- TW_Binance_Proto_DepositHTLTOrder +- TW_Binance_Proto_ClaimHTLOrder +- TW_Binance_Proto_RefundHTLTOrder +- TW_Binance_Proto_TransferOut +- TW_Binance_Proto_SideChainDelegate +- TW_Binance_Proto_SideChainRedelegate +- TW_Binance_Proto_SideChainUndelegate +- TW_Binance_Proto_TimeLockOrder +- TW_Binance_Proto_TimeRelockOrder +- TW_Binance_Proto_TimeUnlockOrder +- TW_Binance_Proto_SigningInput +- TW_Binance_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWBitcoinAddress.yaml b/codegen-v2/manifest/TWBitcoinAddress.yaml new file mode 100644 index 00000000000..3e92416eba5 --- /dev/null +++ b/codegen-v2/manifest/TWBitcoinAddress.yaml @@ -0,0 +1,124 @@ +name: TWBitcoinAddress +structs: +- name: TWPublicKey + is_public: false + is_class: false +- name: TWBitcoinAddress + is_public: true + is_class: true +inits: +- name: TWBitcoinAddressCreateWithString + is_public: true + is_nullable: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWBitcoinAddressCreateWithData + is_public: true + is_nullable: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWBitcoinAddressCreateWithPublicKey + is_public: true + is_nullable: true + params: + - name: publicKey + type: + variant: struct + value: TWPublicKey + is_constant: false + is_nullable: false + is_pointer: true + - name: prefix + type: + variant: u_int8_t + is_constant: false + is_nullable: false + is_pointer: false +deinits: +- name: TWBitcoinAddressDelete +functions: +- name: TWBitcoinAddressEqual + is_public: true + is_static: true + params: + - name: lhs + type: + variant: struct + value: TWBitcoinAddress + is_constant: false + is_nullable: false + is_pointer: true + - name: rhs + type: + variant: struct + value: TWBitcoinAddress + is_constant: false + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWBitcoinAddressIsValid + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWBitcoinAddressIsValidString + is_public: true + is_static: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +properties: +- name: TWBitcoinAddressDescription + is_public: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWBitcoinAddressPrefix + is_public: true + return_type: + variant: u_int8_t + is_constant: false + is_nullable: false + is_pointer: false +- name: TWBitcoinAddressKeyhash + is_public: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWBitcoinMessageSigner.yaml b/codegen-v2/manifest/TWBitcoinMessageSigner.yaml new file mode 100644 index 00000000000..e97a4209b14 --- /dev/null +++ b/codegen-v2/manifest/TWBitcoinMessageSigner.yaml @@ -0,0 +1,61 @@ +name: TWBitcoinMessageSigner +structs: +- name: TWBitcoinMessageSigner + is_public: true + is_class: false +functions: +- name: TWBitcoinMessageSignerSignMessage + is_public: true + is_static: true + params: + - name: privateKey + type: + variant: struct + value: TWPrivateKey + is_constant: true + is_nullable: false + is_pointer: true + - name: address + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: message + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWBitcoinMessageSignerVerifyMessage + is_public: true + is_static: true + params: + - name: address + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: message + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: signature + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false diff --git a/codegen-v2/manifest/TWBitcoinProto.yaml b/codegen-v2/manifest/TWBitcoinProto.yaml new file mode 100644 index 00000000000..7bc66e0c655 --- /dev/null +++ b/codegen-v2/manifest/TWBitcoinProto.yaml @@ -0,0 +1,12 @@ +name: TWBitcoinProto +protos: +- TW_Bitcoin_Proto_Transaction +- TW_Bitcoin_Proto_TransactionInput +- TW_Bitcoin_Proto_OutPoint +- TW_Bitcoin_Proto_TransactionOutput +- TW_Bitcoin_Proto_UnspentTransaction +- TW_Bitcoin_Proto_SigningInput +- TW_Bitcoin_Proto_TransactionPlan +- TW_Bitcoin_Proto_SigningOutput +- TW_Bitcoin_Proto_HashPublicKey +- TW_Bitcoin_Proto_PreSigningOutput diff --git a/codegen-v2/manifest/TWBitcoinScript.yaml b/codegen-v2/manifest/TWBitcoinScript.yaml new file mode 100644 index 00000000000..1a06577cd1a --- /dev/null +++ b/codegen-v2/manifest/TWBitcoinScript.yaml @@ -0,0 +1,321 @@ +name: TWBitcoinScript +structs: +- name: TWBitcoinScript + is_public: true + is_class: true +inits: +- name: TWBitcoinScriptCreate + is_public: true + is_nullable: false +- name: TWBitcoinScriptCreateWithData + is_public: true + is_nullable: false + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWBitcoinScriptCreateCopy + is_public: true + is_nullable: false + params: + - name: script + type: + variant: struct + value: TWBitcoinScript + is_constant: true + is_nullable: false + is_pointer: true +deinits: +- name: TWBitcoinScriptDelete +functions: +- name: TWBitcoinScriptEqual + is_public: true + is_static: true + params: + - name: lhs + type: + variant: struct + value: TWBitcoinScript + is_constant: true + is_nullable: false + is_pointer: true + - name: rhs + type: + variant: struct + value: TWBitcoinScript + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWBitcoinScriptMatchPayToPubkey + is_public: true + is_static: false + params: + - name: script + type: + variant: struct + value: TWBitcoinScript + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true +- name: TWBitcoinScriptMatchPayToPubkeyHash + is_public: true + is_static: false + params: + - name: script + type: + variant: struct + value: TWBitcoinScript + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true +- name: TWBitcoinScriptMatchPayToScriptHash + is_public: true + is_static: false + params: + - name: script + type: + variant: struct + value: TWBitcoinScript + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true +- name: TWBitcoinScriptMatchPayToWitnessPublicKeyHash + is_public: true + is_static: false + params: + - name: script + type: + variant: struct + value: TWBitcoinScript + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true +- name: TWBitcoinScriptMatchPayToWitnessScriptHash + is_public: true + is_static: false + params: + - name: script + type: + variant: struct + value: TWBitcoinScript + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true +- name: TWBitcoinScriptEncode + is_public: true + is_static: false + params: + - name: script + type: + variant: struct + value: TWBitcoinScript + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWBitcoinScriptBuildPayToPublicKey + is_public: true + is_static: true + params: + - name: pubkey + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: struct + value: TWBitcoinScript + is_constant: false + is_nullable: false + is_pointer: true +- name: TWBitcoinScriptBuildPayToPublicKeyHash + is_public: true + is_static: true + params: + - name: hash + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: struct + value: TWBitcoinScript + is_constant: false + is_nullable: false + is_pointer: true +- name: TWBitcoinScriptBuildPayToScriptHash + is_public: true + is_static: true + params: + - name: scriptHash + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: struct + value: TWBitcoinScript + is_constant: false + is_nullable: false + is_pointer: true +- name: TWBitcoinScriptBuildPayToWitnessPubkeyHash + is_public: true + is_static: true + params: + - name: hash + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: struct + value: TWBitcoinScript + is_constant: false + is_nullable: false + is_pointer: true +- name: TWBitcoinScriptBuildPayToWitnessScriptHash + is_public: true + is_static: true + params: + - name: scriptHash + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: struct + value: TWBitcoinScript + is_constant: false + is_nullable: false + is_pointer: true +- name: TWBitcoinScriptLockScriptForAddress + is_public: true + is_static: true + params: + - name: address + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: struct + value: TWBitcoinScript + is_constant: false + is_nullable: false + is_pointer: true +- name: TWBitcoinScriptHashTypeForCoin + is_public: true + is_static: true + params: + - name: coinType + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false +properties: +- name: TWBitcoinScriptSize + is_public: true + return_type: + variant: size_t + is_constant: false + is_nullable: false + is_pointer: false +- name: TWBitcoinScriptData + is_public: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWBitcoinScriptScriptHash + is_public: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWBitcoinScriptIsPayToScriptHash + is_public: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWBitcoinScriptIsPayToWitnessScriptHash + is_public: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWBitcoinScriptIsPayToWitnessPublicKeyHash + is_public: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWBitcoinScriptIsWitnessProgram + is_public: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false diff --git a/codegen-v2/manifest/TWBitcoinSigHashType.yaml b/codegen-v2/manifest/TWBitcoinSigHashType.yaml new file mode 100644 index 00000000000..27e2c5f339f --- /dev/null +++ b/codegen-v2/manifest/TWBitcoinSigHashType.yaml @@ -0,0 +1,52 @@ +name: TWBitcoinSigHashType +enums: +- name: TWBitcoinSigHashType + is_public: true + value_type: + variant: u_int32_t + variants: + - name: all + value: 0x01 + - name: none + value: 0x02 + - name: single + value: 0x03 + - name: fork + value: 0x40 + - name: forkBtg + value: 0x4f40 + - name: anyoneCanPay + value: 0x80 +functions: +- name: TWBitcoinSigHashTypeIsSingle + is_public: true + is_static: false + params: + - name: type + type: + variant: enum + value: TWBitcoinSigHashType + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWBitcoinSigHashTypeIsNone + is_public: true + is_static: false + params: + - name: type + type: + variant: enum + value: TWBitcoinSigHashType + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false diff --git a/codegen-v2/manifest/TWBlockchain.yaml b/codegen-v2/manifest/TWBlockchain.yaml new file mode 100644 index 00000000000..545fafee77b --- /dev/null +++ b/codegen-v2/manifest/TWBlockchain.yaml @@ -0,0 +1,97 @@ +name: TWBlockchain +enums: +- name: TWBlockchain + is_public: true + value_type: + variant: u_int32_t + variants: + - name: bitcoin + value: 0 + - name: ethereum + value: 1 + - name: vechain + value: 3 + - name: tron + value: 4 + - name: icon + value: 5 + - name: binance + value: 6 + - name: ripple + value: 7 + - name: tezos + value: 8 + - name: nimiq + value: 9 + - name: stellar + value: 10 + - name: aion + value: 11 + - name: cosmos + value: 12 + - name: theta + value: 13 + - name: ontology + value: 14 + - name: zilliqa + value: 15 + - name: ioTeX + value: 16 + - name: eos + value: 17 + - name: nano + value: 18 + - name: nuls + value: 19 + - name: waves + value: 20 + - name: aeternity + value: 21 + - name: nebulas + value: 22 + - name: fio + value: 23 + - name: solana + value: 24 + - name: harmony + value: 25 + - name: near + value: 26 + - name: algorand + value: 27 + - name: polkadot + value: 29 + - name: cardano + value: 30 + - name: neo + value: 31 + - name: filecoin + value: 32 + - name: multiversX + value: 33 + - name: oasisNetwork + value: 34 + - name: decred + value: 35 + - name: zcash + value: 36 + - name: groestlcoin + value: 37 + - name: thorchain + value: 38 + - name: ronin + value: 39 + - name: kusama + value: 40 + - name: nervos + value: 41 + - name: everscale + value: 42 + - name: aptos + value: 43 + - name: hedera + value: 44 + - name: theOpenNetwork + value: 45 + - name: sui + value: 46 diff --git a/codegen-v2/manifest/TWCardano.yaml b/codegen-v2/manifest/TWCardano.yaml new file mode 100644 index 00000000000..d6489ffa40e --- /dev/null +++ b/codegen-v2/manifest/TWCardano.yaml @@ -0,0 +1,63 @@ +name: TWCardano +structs: +- name: TWCardano + is_public: true + is_class: false +functions: +- name: TWCardanoMinAdaAmount + is_public: true + is_static: true + params: + - name: tokenBundle + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: u_int64_t + is_constant: false + is_nullable: false + is_pointer: false +- name: TWCardanoOutputMinAdaAmount + is_public: true + is_static: true + params: + - name: toAddress + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: tokenBundle + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: coinsPerUtxoByte + type: + variant: u_int64_t + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: u_int64_t + is_constant: false + is_nullable: false + is_pointer: false +- name: TWCardanoGetStakingAddress + is_public: true + is_static: true + params: + - name: baseAddress + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWCardanoProto.yaml b/codegen-v2/manifest/TWCardanoProto.yaml new file mode 100644 index 00000000000..3d01f415f85 --- /dev/null +++ b/codegen-v2/manifest/TWCardanoProto.yaml @@ -0,0 +1,15 @@ +name: TWCardanoProto +protos: +- TW_Cardano_Proto_OutPoint +- TW_Cardano_Proto_TokenAmount +- TW_Cardano_Proto_TxInput +- TW_Cardano_Proto_TxOutput +- TW_Cardano_Proto_TokenBundle +- TW_Cardano_Proto_Transfer +- TW_Cardano_Proto_RegisterStakingKey +- TW_Cardano_Proto_DeregisterStakingKey +- TW_Cardano_Proto_Delegate +- TW_Cardano_Proto_Withdraw +- TW_Cardano_Proto_TransactionPlan +- TW_Cardano_Proto_SigningInput +- TW_Cardano_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWCoinType.yaml b/codegen-v2/manifest/TWCoinType.yaml new file mode 100644 index 00000000000..af01f64569b --- /dev/null +++ b/codegen-v2/manifest/TWCoinType.yaml @@ -0,0 +1,465 @@ +name: TWCoinType +structs: +- name: TWPrivateKey + is_public: false + is_class: false +- name: TWPublicKey + is_public: false + is_class: false +enums: +- name: TWCoinType + is_public: true + value_type: + variant: u_int32_t + variants: + - name: aeternity + value: 457 + - name: aion + value: 425 + - name: binance + value: 714 + - name: bitcoin + value: 0 + - name: bitcoinCash + value: 145 + - name: bitcoinGold + value: 156 + - name: callisto + value: 820 + - name: cardano + value: 1815 + - name: cosmos + value: 118 + - name: dash + value: 5 + - name: decred + value: 42 + - name: digiByte + value: 20 + - name: dogecoin + value: 3 + - name: eos + value: 194 + - name: wax + value: 14001 + - name: ethereum + value: 60 + - name: ethereumClassic + value: 61 + - name: fio + value: 235 + - name: goChain + value: 6060 + - name: groestlcoin + value: 17 + - name: icon + value: 74 + - name: ioTeX + value: 304 + - name: kava + value: 459 + - name: kin + value: 2017 + - name: litecoin + value: 2 + - name: monacoin + value: 22 + - name: nebulas + value: 2718 + - name: nuls + value: 8964 + - name: nano + value: 165 + - name: near + value: 397 + - name: nimiq + value: 242 + - name: ontology + value: 1024 + - name: poanetwork + value: 178 + - name: qtum + value: 2301 + - name: xrp + value: 144 + - name: solana + value: 501 + - name: stellar + value: 148 + - name: tezos + value: 1729 + - name: theta + value: 500 + - name: thunderCore + value: 1001 + - name: neo + value: 888 + - name: tomoChain + value: 889 + - name: tron + value: 195 + - name: veChain + value: 818 + - name: viacoin + value: 14 + - name: wanchain + value: 5718350 + - name: zcash + value: 133 + - name: firo + value: 136 + - name: zilliqa + value: 313 + - name: zelcash + value: 19167 + - name: ravencoin + value: 175 + - name: waves + value: 5741564 + - name: terra + value: 330 + - name: terraV2 + value: 10000330 + - name: harmony + value: 1023 + - name: algorand + value: 283 + - name: kusama + value: 434 + - name: polkadot + value: 354 + - name: filecoin + value: 461 + - name: multiversX + value: 508 + - name: bandChain + value: 494 + - name: smartChainLegacy + value: 10000714 + - name: smartChain + value: 20000714 + - name: oasis + value: 474 + - name: polygon + value: 966 + - name: thorchain + value: 931 + - name: bluzelle + value: 483 + - name: optimism + value: 10000070 + - name: zksync + value: 10000324 + - name: arbitrum + value: 10042221 + - name: ecochain + value: 10000553 + - name: avalancheCChain + value: 10009000 + - name: xdai + value: 10000100 + - name: fantom + value: 10000250 + - name: cryptoOrg + value: 394 + - name: celo + value: 52752 + - name: ronin + value: 10002020 + - name: osmosis + value: 10000118 + - name: ecash + value: 899 + - name: cronosChain + value: 10000025 + - name: smartBitcoinCash + value: 10000145 + - name: kuCoinCommunityChain + value: 10000321 + - name: boba + value: 10000288 + - name: metis + value: 10001088 + - name: aurora + value: 1323161554 + - name: evmos + value: 10009001 + - name: nativeEvmos + value: 20009001 + - name: moonriver + value: 10001285 + - name: moonbeam + value: 10001284 + - name: kavaEvm + value: 10002222 + - name: kaia + value: 10008217 + - name: meter + value: 18000 + - name: okxchain + value: 996 + - name: nervos + value: 309 + - name: everscale + value: 396 + - name: aptos + value: 637 + - name: hedera + value: 3030 + - name: secret + value: 529 + - name: nativeInjective + value: 10000060 + - name: agoric + value: 564 + - name: ton + value: 607 + - name: sui + value: 784 + - name: stargaze + value: 20000118 + - name: polygonzkEVM + value: 10001101 + - name: juno + value: 30000118 + - name: stride + value: 40000118 + - name: axelar + value: 50000118 + - name: crescent + value: 60000118 + - name: kujira + value: 70000118 + - name: ioTeXEVM + value: 10004689 + - name: nativeCanto + value: 10007700 + - name: comdex + value: 80000118 + - name: neutron + value: 90000118 + - name: sommelier + value: 11000118 + - name: fetchAI + value: 12000118 + - name: mars + value: 13000118 + - name: umee + value: 14000118 + - name: coreum + value: 10000990 + - name: quasar + value: 15000118 + - name: persistence + value: 16000118 + - name: akash + value: 17000118 + - name: noble + value: 18000118 +functions: +- name: TWCoinTypeValidate + is_public: true + is_static: false + params: + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: address + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWCoinTypeDerivationPath + is_public: true + is_static: false + params: + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWCoinTypeDerivationPathWithDerivation + is_public: true + is_static: false + params: + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: derivation + type: + variant: enum + value: TWDerivation + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWCoinTypeDeriveAddress + is_public: true + is_static: false + params: + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: privateKey + type: + variant: struct + value: TWPrivateKey + is_constant: false + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWCoinTypeDeriveAddressFromPublicKey + is_public: true + is_static: false + params: + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: publicKey + type: + variant: struct + value: TWPublicKey + is_constant: false + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +properties: +- name: TWCoinTypeBlockchain + is_public: true + return_type: + variant: enum + value: TWBlockchain + is_constant: false + is_nullable: false + is_pointer: false +- name: TWCoinTypePurpose + is_public: true + return_type: + variant: enum + value: TWPurpose + is_constant: false + is_nullable: false + is_pointer: false +- name: TWCoinTypeCurve + is_public: true + return_type: + variant: enum + value: TWCurve + is_constant: false + is_nullable: false + is_pointer: false +- name: TWCoinTypeXpubVersion + is_public: true + return_type: + variant: enum + value: TWHDVersion + is_constant: false + is_nullable: false + is_pointer: false +- name: TWCoinTypeXprvVersion + is_public: true + return_type: + variant: enum + value: TWHDVersion + is_constant: false + is_nullable: false + is_pointer: false +- name: TWCoinTypeHRP + is_public: true + return_type: + variant: enum + value: TWHRP + is_constant: false + is_nullable: false + is_pointer: false +- name: TWCoinTypeP2pkhPrefix + is_public: true + return_type: + variant: u_int8_t + is_constant: false + is_nullable: false + is_pointer: false +- name: TWCoinTypeP2shPrefix + is_public: true + return_type: + variant: u_int8_t + is_constant: false + is_nullable: false + is_pointer: false +- name: TWCoinTypeStaticPrefix + is_public: true + return_type: + variant: u_int8_t + is_constant: false + is_nullable: false + is_pointer: false +- name: TWCoinTypeChainId + is_public: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWCoinTypeSlip44Id + is_public: true + return_type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false +- name: TWCoinTypeSS58Prefix + is_public: true + return_type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false +- name: TWCoinTypePublicKeyType + is_public: true + return_type: + variant: enum + value: TWPublicKeyType + is_constant: false + is_nullable: false + is_pointer: false diff --git a/codegen-v2/manifest/TWCoinTypeConfiguration.yaml b/codegen-v2/manifest/TWCoinTypeConfiguration.yaml new file mode 100644 index 00000000000..aafa2b803cd --- /dev/null +++ b/codegen-v2/manifest/TWCoinTypeConfiguration.yaml @@ -0,0 +1,120 @@ +name: TWCoinTypeConfiguration +structs: +- name: TWCoinTypeConfiguration + is_public: true + is_class: false + fields: + - - unused + - variant: u_int8_t + is_constant: false + is_nullable: false + is_pointer: false +functions: +- name: TWCoinTypeConfigurationGetSymbol + is_public: true + is_static: true + params: + - name: type + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWCoinTypeConfigurationGetDecimals + is_public: true + is_static: true + params: + - name: type + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWCoinTypeConfigurationGetTransactionURL + is_public: true + is_static: true + params: + - name: type + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: transactionID + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWCoinTypeConfigurationGetAccountURL + is_public: true + is_static: true + params: + - name: type + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: accountID + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWCoinTypeConfigurationGetID + is_public: true + is_static: true + params: + - name: type + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWCoinTypeConfigurationGetName + is_public: true + is_static: true + params: + - name: type + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWCommonProto.yaml b/codegen-v2/manifest/TWCommonProto.yaml new file mode 100644 index 00000000000..c5bbdcc1546 --- /dev/null +++ b/codegen-v2/manifest/TWCommonProto.yaml @@ -0,0 +1,3 @@ +name: TWCommonProto +protos: +- TW_Common_Proto_SigningError diff --git a/codegen-v2/manifest/TWCosmosProto.yaml b/codegen-v2/manifest/TWCosmosProto.yaml new file mode 100644 index 00000000000..e9ddb053872 --- /dev/null +++ b/codegen-v2/manifest/TWCosmosProto.yaml @@ -0,0 +1,8 @@ +name: TWCosmosProto +protos: +- TW_Cosmos_Proto_Amount +- TW_Cosmos_Proto_Fee +- TW_Cosmos_Proto_Height +- TW_Cosmos_Proto_Message +- TW_Cosmos_Proto_SigningInput +- TW_Cosmos_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWCurve.yaml b/codegen-v2/manifest/TWCurve.yaml new file mode 100644 index 00000000000..01f14d2dfd5 --- /dev/null +++ b/codegen-v2/manifest/TWCurve.yaml @@ -0,0 +1,28 @@ +name: TWCurve +enums: +- name: TWCurve + is_public: true + value_type: + variant: u_int32_t + variants: + - name: secp256k1 + value: 0 + as_string: secp256k1 + - name: ed25519 + value: 1 + as_string: ed25519 + - name: ed25519Blake2bNano + value: 2 + as_string: ed25519-blake2b-nano + - name: curve25519 + value: 3 + as_string: curve25519 + - name: nist256p1 + value: 4 + as_string: nist256p1 + - name: ed25519ExtendedCardano + value: 5 + as_string: ed25519-cardano-seed + - name: starkex + value: 6 + as_string: starkex diff --git a/codegen-v2/manifest/TWDataVector.yaml b/codegen-v2/manifest/TWDataVector.yaml new file mode 100644 index 00000000000..f9011148096 --- /dev/null +++ b/codegen-v2/manifest/TWDataVector.yaml @@ -0,0 +1,74 @@ +name: TWDataVector +structs: +- name: TWDataVector + is_public: true + is_class: true +inits: +- name: TWDataVectorCreate + is_public: true + is_nullable: false +- name: TWDataVectorCreateWithData + is_public: true + is_nullable: false + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +deinits: +- name: TWDataVectorDelete +functions: +- name: TWDataVectorAdd + is_public: true + is_static: false + params: + - name: dataVector + type: + variant: struct + value: TWDataVector + is_constant: false + is_nullable: false + is_pointer: true + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: void + is_constant: false + is_nullable: false + is_pointer: false +- name: TWDataVectorGet + is_public: true + is_static: false + params: + - name: dataVector + type: + variant: struct + value: TWDataVector + is_constant: true + is_nullable: false + is_pointer: true + - name: index + type: + variant: size_t + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true +properties: +- name: TWDataVectorSize + is_public: true + return_type: + variant: size_t + is_constant: false + is_nullable: false + is_pointer: false diff --git a/codegen-v2/manifest/TWDecredProto.yaml b/codegen-v2/manifest/TWDecredProto.yaml new file mode 100644 index 00000000000..eb8bddcc303 --- /dev/null +++ b/codegen-v2/manifest/TWDecredProto.yaml @@ -0,0 +1,6 @@ +name: TWDecredProto +protos: +- TW_Decred_Proto_Transaction +- TW_Decred_Proto_TransactionInput +- TW_Decred_Proto_TransactionOutput +- TW_Decred_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWDerivation.yaml b/codegen-v2/manifest/TWDerivation.yaml new file mode 100644 index 00000000000..c2143b80431 --- /dev/null +++ b/codegen-v2/manifest/TWDerivation.yaml @@ -0,0 +1,21 @@ +name: TWDerivation +enums: +- name: TWDerivation + is_public: true + value_type: + variant: u_int32_t + variants: + - name: default + value: 0 + - name: custom + value: 1 + - name: bitcoinSegwit + value: 2 + - name: bitcoinLegacy + value: 3 + - name: bitcoinTestnet + value: 4 + - name: litecoinLegacy + value: 5 + - name: solanaSolana + value: 6 diff --git a/codegen-v2/manifest/TWDerivationPath.yaml b/codegen-v2/manifest/TWDerivationPath.yaml new file mode 100644 index 00000000000..8e550ded65e --- /dev/null +++ b/codegen-v2/manifest/TWDerivationPath.yaml @@ -0,0 +1,137 @@ +name: TWDerivationPath +structs: +- name: TWDerivationPath + is_public: true + is_class: true +inits: +- name: TWDerivationPathCreate + is_public: true + is_nullable: false + params: + - name: purpose + type: + variant: enum + value: TWPurpose + is_constant: false + is_nullable: false + is_pointer: false + - name: coin + type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false + - name: account + type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false + - name: change + type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false + - name: address + type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false +- name: TWDerivationPathCreateWithString + is_public: true + is_nullable: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +deinits: +- name: TWDerivationPathDelete +functions: +- name: TWDerivationPathIndexAt + is_public: true + is_static: false + params: + - name: path + type: + variant: struct + value: TWDerivationPath + is_constant: false + is_nullable: false + is_pointer: true + - name: index + type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: struct + value: TWDerivationPathIndex + is_constant: false + is_nullable: true + is_pointer: true +- name: TWDerivationPathIndicesCount + is_public: true + is_static: false + params: + - name: path + type: + variant: struct + value: TWDerivationPath + is_constant: false + is_nullable: false + is_pointer: true + return_type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false +properties: +- name: TWDerivationPathPurpose + is_public: true + return_type: + variant: enum + value: TWPurpose + is_constant: false + is_nullable: false + is_pointer: false +- name: TWDerivationPathCoin + is_public: true + return_type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false +- name: TWDerivationPathAccount + is_public: true + return_type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false +- name: TWDerivationPathChange + is_public: true + return_type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false +- name: TWDerivationPathAddress + is_public: true + return_type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false +- name: TWDerivationPathDescription + is_public: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWDerivationPathIndex.yaml b/codegen-v2/manifest/TWDerivationPathIndex.yaml new file mode 100644 index 00000000000..8106efe6dfe --- /dev/null +++ b/codegen-v2/manifest/TWDerivationPathIndex.yaml @@ -0,0 +1,46 @@ +name: TWDerivationPathIndex +structs: +- name: TWDerivationPathIndex + is_public: true + is_class: true +inits: +- name: TWDerivationPathIndexCreate + is_public: true + is_nullable: false + params: + - name: value + type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false + - name: hardened + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +deinits: +- name: TWDerivationPathIndexDelete +properties: +- name: TWDerivationPathIndexValue + is_public: true + return_type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false +- name: TWDerivationPathIndexHardened + is_public: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWDerivationPathIndexDescription + is_public: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWEOSProto.yaml b/codegen-v2/manifest/TWEOSProto.yaml new file mode 100644 index 00000000000..ea0032abfe9 --- /dev/null +++ b/codegen-v2/manifest/TWEOSProto.yaml @@ -0,0 +1,5 @@ +name: TWEOSProto +protos: +- TW_EOS_Proto_Asset +- TW_EOS_Proto_SigningInput +- TW_EOS_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWEthereum.yaml b/codegen-v2/manifest/TWEthereum.yaml new file mode 100644 index 00000000000..1d4aa9b9d97 --- /dev/null +++ b/codegen-v2/manifest/TWEthereum.yaml @@ -0,0 +1,66 @@ +name: TWEthereum +structs: +- name: TWEthereum + is_public: true + is_class: false +functions: +- name: TWEthereumEip2645GetPath + is_public: true + is_static: true + params: + - name: ethAddress + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: layer + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: application + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: index + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWEthereumEip4337GetDeploymentAddress + is_public: true + is_static: true + params: + - name: factoryAddress + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: logicAddress + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: ownerAddress + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWEthereumAbi.yaml b/codegen-v2/manifest/TWEthereumAbi.yaml new file mode 100644 index 00000000000..fda88c4c4c1 --- /dev/null +++ b/codegen-v2/manifest/TWEthereumAbi.yaml @@ -0,0 +1,83 @@ +name: TWEthereumAbi +structs: +- name: TWEthereumAbiFunction + is_public: false + is_class: false +- name: TWEthereumAbi + is_public: true + is_class: false +functions: +- name: TWEthereumAbiEncode + is_public: true + is_static: true + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWEthereumAbiDecodeOutput + is_public: true + is_static: true + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: encoded + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiDecodeCall + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: abi + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: true + is_pointer: true +- name: TWEthereumAbiEncodeTyped + is_public: true + is_static: true + params: + - name: messageJson + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWEthereumAbiFunction.yaml b/codegen-v2/manifest/TWEthereumAbiFunction.yaml new file mode 100644 index 00000000000..95a54c8338d --- /dev/null +++ b/codegen-v2/manifest/TWEthereumAbiFunction.yaml @@ -0,0 +1,1213 @@ +name: TWEthereumAbiFunction +structs: +- name: TWEthereumAbiFunction + is_public: true + is_class: true +inits: +- name: TWEthereumAbiFunctionCreateWithString + is_public: true + is_nullable: false + params: + - name: name + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +deinits: +- name: TWEthereumAbiFunctionDelete +functions: +- name: TWEthereumAbiFunctionGetType + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWEthereumAbiFunctionAddParamUInt8 + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: val + type: + variant: u_int8_t + is_constant: false + is_nullable: false + is_pointer: false + - name: isOutput + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddParamUInt16 + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: val + type: + variant: u_int16_t + is_constant: false + is_nullable: false + is_pointer: false + - name: isOutput + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddParamUInt32 + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: val + type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false + - name: isOutput + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddParamUInt64 + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: val + type: + variant: u_int64_t + is_constant: false + is_nullable: false + is_pointer: false + - name: isOutput + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddParamUInt256 + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: val + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: isOutput + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddParamUIntN + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: bits + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: val + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: isOutput + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddParamInt8 + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: val + type: + variant: int8_t + is_constant: false + is_nullable: false + is_pointer: false + - name: isOutput + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddParamInt16 + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: val + type: + variant: int16_t + is_constant: false + is_nullable: false + is_pointer: false + - name: isOutput + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddParamInt32 + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: val + type: + variant: int32_t + is_constant: false + is_nullable: false + is_pointer: false + - name: isOutput + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddParamInt64 + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: val + type: + variant: int64_t + is_constant: false + is_nullable: false + is_pointer: false + - name: isOutput + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddParamInt256 + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: val + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: isOutput + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddParamIntN + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: bits + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: val + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: isOutput + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddParamBool + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: val + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + - name: isOutput + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddParamString + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: val + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: isOutput + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddParamAddress + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: val + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: isOutput + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddParamBytes + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: val + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: isOutput + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddParamBytesFix + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: size + type: + variant: size_t + is_constant: false + is_nullable: false + is_pointer: false + - name: val + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: isOutput + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddParamArray + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: isOutput + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionGetParamUInt8 + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: idx + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: isOutput + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: u_int8_t + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionGetParamUInt64 + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: idx + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: isOutput + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: u_int64_t + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionGetParamUInt256 + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: idx + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: isOutput + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWEthereumAbiFunctionGetParamBool + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: idx + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: isOutput + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionGetParamString + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: idx + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: isOutput + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWEthereumAbiFunctionGetParamAddress + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: idx + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: isOutput + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWEthereumAbiFunctionAddInArrayParamUInt8 + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: arrayIdx + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: val + type: + variant: u_int8_t + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddInArrayParamUInt16 + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: arrayIdx + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: val + type: + variant: u_int16_t + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddInArrayParamUInt32 + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: arrayIdx + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: val + type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddInArrayParamUInt64 + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: arrayIdx + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: val + type: + variant: u_int64_t + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddInArrayParamUInt256 + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: arrayIdx + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: val + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddInArrayParamUIntN + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: arrayIdx + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: bits + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: val + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddInArrayParamInt8 + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: arrayIdx + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: val + type: + variant: int8_t + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddInArrayParamInt16 + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: arrayIdx + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: val + type: + variant: int16_t + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddInArrayParamInt32 + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: arrayIdx + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: val + type: + variant: int32_t + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddInArrayParamInt64 + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: arrayIdx + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: val + type: + variant: int64_t + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddInArrayParamInt256 + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: arrayIdx + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: val + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddInArrayParamIntN + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: arrayIdx + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: bits + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: val + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddInArrayParamBool + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: arrayIdx + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: val + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddInArrayParamString + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: arrayIdx + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: val + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddInArrayParamAddress + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: arrayIdx + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: val + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddInArrayParamBytes + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: arrayIdx + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: val + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWEthereumAbiFunctionAddInArrayParamBytesFix + is_public: true + is_static: false + params: + - name: fn + type: + variant: struct + value: TWEthereumAbiFunction + is_constant: false + is_nullable: false + is_pointer: true + - name: arrayIdx + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: size + type: + variant: size_t + is_constant: false + is_nullable: false + is_pointer: false + - name: val + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false diff --git a/codegen-v2/manifest/TWEthereumAbiValue.yaml b/codegen-v2/manifest/TWEthereumAbiValue.yaml new file mode 100644 index 00000000000..31e60cf14f8 --- /dev/null +++ b/codegen-v2/manifest/TWEthereumAbiValue.yaml @@ -0,0 +1,198 @@ +name: TWEthereumAbiValue +structs: +- name: TWEthereumAbiValue + is_public: true + is_class: false +functions: +- name: TWEthereumAbiValueEncodeBool + is_public: true + is_static: true + params: + - name: value + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWEthereumAbiValueEncodeInt32 + is_public: true + is_static: true + params: + - name: value + type: + variant: int32_t + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWEthereumAbiValueEncodeUInt32 + is_public: true + is_static: true + params: + - name: value + type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWEthereumAbiValueEncodeInt256 + is_public: true + is_static: true + params: + - name: value + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWEthereumAbiValueEncodeUInt256 + is_public: true + is_static: true + params: + - name: value + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWEthereumAbiValueEncodeAddress + is_public: true + is_static: true + params: + - name: value + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWEthereumAbiValueEncodeString + is_public: true + is_static: true + params: + - name: value + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWEthereumAbiValueEncodeBytes + is_public: true + is_static: true + params: + - name: value + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWEthereumAbiValueEncodeBytesDyn + is_public: true + is_static: true + params: + - name: value + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWEthereumAbiValueDecodeUInt256 + is_public: true + is_static: true + params: + - name: input + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWEthereumAbiValueDecodeValue + is_public: true + is_static: true + params: + - name: input + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: type + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWEthereumAbiValueDecodeArray + is_public: true + is_static: true + params: + - name: input + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: type + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWEthereumChainID.yaml b/codegen-v2/manifest/TWEthereumChainID.yaml new file mode 100644 index 00000000000..a8c93f297cc --- /dev/null +++ b/codegen-v2/manifest/TWEthereumChainID.yaml @@ -0,0 +1,77 @@ +name: TWEthereumChainID +enums: +- name: TWEthereumChainID + is_public: true + value_type: + variant: u_int32_t + variants: + - name: ethereum + value: 1 + - name: classic + value: 61 + - name: poa + value: 99 + - name: vechain + value: 74 + - name: callisto + value: 820 + - name: tomochain + value: 88 + - name: polygon + value: 137 + - name: okc + value: 66 + - name: thundertoken + value: 108 + - name: gochain + value: 60 + - name: meter + value: 82 + - name: celo + value: 42220 + - name: wanchain + value: 888 + - name: cronos + value: 25 + - name: optimism + value: 10 + - name: xdai + value: 100 + - name: smartbch + value: 10000 + - name: fantom + value: 250 + - name: boba + value: 288 + - name: kcc + value: 321 + - name: zksync + value: 324 + - name: heco + value: 128 + - name: metis + value: 1088 + - name: polygonzkevm + value: 1101 + - name: moonbeam + value: 1284 + - name: moonriver + value: 1285 + - name: ronin + value: 2020 + - name: kavaevm + value: 2222 + - name: iotexevm + value: 4689 + - name: kaia + value: 8217 + - name: avalanchec + value: 43114 + - name: evmos + value: 9001 + - name: arbitrum + value: 42161 + - name: smartchain + value: 56 + - name: aurora + value: 1313161554 diff --git a/codegen-v2/manifest/TWEthereumMessageSigner.yaml b/codegen-v2/manifest/TWEthereumMessageSigner.yaml new file mode 100644 index 00000000000..628ed6cbf76 --- /dev/null +++ b/codegen-v2/manifest/TWEthereumMessageSigner.yaml @@ -0,0 +1,156 @@ +name: TWEthereumMessageSigner +structs: +- name: TWEthereumMessageSigner + is_public: true + is_class: false +functions: +- name: TWEthereumMessageSignerSignTypedMessage + is_public: true + is_static: true + params: + - name: privateKey + type: + variant: struct + value: TWPrivateKey + is_constant: true + is_nullable: false + is_pointer: true + - name: messageJson + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWEthereumMessageSignerSignTypedMessageEip155 + is_public: true + is_static: true + params: + - name: privateKey + type: + variant: struct + value: TWPrivateKey + is_constant: true + is_nullable: false + is_pointer: true + - name: messageJson + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: chainId + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWEthereumMessageSignerSignMessage + is_public: true + is_static: true + params: + - name: privateKey + type: + variant: struct + value: TWPrivateKey + is_constant: true + is_nullable: false + is_pointer: true + - name: message + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWEthereumMessageSignerSignMessageImmutableX + is_public: true + is_static: true + params: + - name: privateKey + type: + variant: struct + value: TWPrivateKey + is_constant: true + is_nullable: false + is_pointer: true + - name: message + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWEthereumMessageSignerSignMessageEip155 + is_public: true + is_static: true + params: + - name: privateKey + type: + variant: struct + value: TWPrivateKey + is_constant: true + is_nullable: false + is_pointer: true + - name: message + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: chainId + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWEthereumMessageSignerVerifyMessage + is_public: true + is_static: true + params: + - name: pubKey + type: + variant: struct + value: TWPublicKey + is_constant: true + is_nullable: false + is_pointer: true + - name: message + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: signature + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false diff --git a/codegen-v2/manifest/TWEthereumProto.yaml b/codegen-v2/manifest/TWEthereumProto.yaml new file mode 100644 index 00000000000..0d7451a69fe --- /dev/null +++ b/codegen-v2/manifest/TWEthereumProto.yaml @@ -0,0 +1,6 @@ +name: TWEthereumProto +protos: +- TW_Ethereum_Proto_Transaction +- TW_Ethereum_Proto_UserOperation +- TW_Ethereum_Proto_SigningInput +- TW_Ethereum_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWEverscaleProto.yaml b/codegen-v2/manifest/TWEverscaleProto.yaml new file mode 100644 index 00000000000..4b932b376aa --- /dev/null +++ b/codegen-v2/manifest/TWEverscaleProto.yaml @@ -0,0 +1,5 @@ +name: TWEverscaleProto +protos: +- TW_Everscale_Proto_Transfer +- TW_Everscale_Proto_SigningInput +- TW_Everscale_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWFIOAccount.yaml b/codegen-v2/manifest/TWFIOAccount.yaml new file mode 100644 index 00000000000..b95d7f7f461 --- /dev/null +++ b/codegen-v2/manifest/TWFIOAccount.yaml @@ -0,0 +1,26 @@ +name: TWFIOAccount +structs: +- name: TWFIOAccount + is_public: true + is_class: true +inits: +- name: TWFIOAccountCreateWithString + is_public: true + is_nullable: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +deinits: +- name: TWFIOAccountDelete +properties: +- name: TWFIOAccountDescription + is_public: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWFIOProto.yaml b/codegen-v2/manifest/TWFIOProto.yaml new file mode 100644 index 00000000000..84e46536c2f --- /dev/null +++ b/codegen-v2/manifest/TWFIOProto.yaml @@ -0,0 +1,8 @@ +name: TWFIOProto +protos: +- TW_FIO_Proto_PublicAddress +- TW_FIO_Proto_NewFundsContent +- TW_FIO_Proto_Action +- TW_FIO_Proto_ChainParams +- TW_FIO_Proto_SigningInput +- TW_FIO_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWFilecoinAddressConverter.yaml b/codegen-v2/manifest/TWFilecoinAddressConverter.yaml new file mode 100644 index 00000000000..1823914ebef --- /dev/null +++ b/codegen-v2/manifest/TWFilecoinAddressConverter.yaml @@ -0,0 +1,36 @@ +name: TWFilecoinAddressConverter +structs: +- name: TWFilecoinAddressConverter + is_public: true + is_class: false +functions: +- name: TWFilecoinAddressConverterConvertToEthereum + is_public: true + is_static: true + params: + - name: filecoinAddress + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWFilecoinAddressConverterConvertFromEthereum + is_public: true + is_static: true + params: + - name: ethAddress + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWFilecoinAddressType.yaml b/codegen-v2/manifest/TWFilecoinAddressType.yaml new file mode 100644 index 00000000000..d7b3e3186d6 --- /dev/null +++ b/codegen-v2/manifest/TWFilecoinAddressType.yaml @@ -0,0 +1,11 @@ +name: TWFilecoinAddressType +enums: +- name: TWFilecoinAddressType + is_public: true + value_type: + variant: u_int32_t + variants: + - name: default + value: 0 + - name: delegated + value: 1 diff --git a/codegen-v2/manifest/TWFilecoinProto.yaml b/codegen-v2/manifest/TWFilecoinProto.yaml new file mode 100644 index 00000000000..34e11a135a5 --- /dev/null +++ b/codegen-v2/manifest/TWFilecoinProto.yaml @@ -0,0 +1,4 @@ +name: TWFilecoinProto +protos: +- TW_Filecoin_Proto_SigningInput +- TW_Filecoin_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWGroestlcoinAddress.yaml b/codegen-v2/manifest/TWGroestlcoinAddress.yaml new file mode 100644 index 00000000000..8f25de34905 --- /dev/null +++ b/codegen-v2/manifest/TWGroestlcoinAddress.yaml @@ -0,0 +1,85 @@ +name: TWGroestlcoinAddress +structs: +- name: TWPublicKey + is_public: false + is_class: false +- name: TWGroestlcoinAddress + is_public: true + is_class: true +inits: +- name: TWGroestlcoinAddressCreateWithString + is_public: true + is_nullable: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWGroestlcoinAddressCreateWithPublicKey + is_public: true + is_nullable: false + params: + - name: publicKey + type: + variant: struct + value: TWPublicKey + is_constant: false + is_nullable: false + is_pointer: true + - name: prefix + type: + variant: u_int8_t + is_constant: false + is_nullable: false + is_pointer: false +deinits: +- name: TWGroestlcoinAddressDelete +functions: +- name: TWGroestlcoinAddressEqual + is_public: true + is_static: true + params: + - name: lhs + type: + variant: struct + value: TWGroestlcoinAddress + is_constant: false + is_nullable: false + is_pointer: true + - name: rhs + type: + variant: struct + value: TWGroestlcoinAddress + is_constant: false + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWGroestlcoinAddressIsValidString + is_public: true + is_static: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +properties: +- name: TWGroestlcoinAddressDescription + is_public: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWHDVersion.yaml b/codegen-v2/manifest/TWHDVersion.yaml new file mode 100644 index 00000000000..72cfb07914a --- /dev/null +++ b/codegen-v2/manifest/TWHDVersion.yaml @@ -0,0 +1,52 @@ +name: TWHDVersion +enums: +- name: TWHDVersion + is_public: true + value_type: + variant: u_int32_t + variants: + - name: none + value: 0 + - name: xpub + value: 0x0488b21e + - name: xprv + value: 0x0488ade4 + - name: ypub + value: 0x049d7cb2 + - name: yprv + value: 0x049d7878 + - name: zpub + value: 0x04b24746 + - name: zprv + value: 0x04b2430c + - name: ltub + value: 0x019da462 + - name: ltpv + value: 0x019d9cfe + - name: mtub + value: 0x01b26ef6 + - name: mtpv + value: 0x01b26792 + - name: dpub + value: 0x2fda926 + - name: dprv + value: 0x2fda4e8 + - name: dgub + value: 0x02facafd + - name: dgpv + value: 0x02fac398 +properties: +- name: TWHDVersionIsPublic + is_public: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWHDVersionIsPrivate + is_public: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false diff --git a/codegen-v2/manifest/TWHDWallet.yaml b/codegen-v2/manifest/TWHDWallet.yaml new file mode 100644 index 00000000000..34dd244a3c9 --- /dev/null +++ b/codegen-v2/manifest/TWHDWallet.yaml @@ -0,0 +1,626 @@ +name: TWHDWallet +structs: +- name: TWHDWallet + is_public: true + is_class: true +inits: +- name: TWHDWalletCreate + is_public: true + is_nullable: true + params: + - name: strength + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false + - name: passphrase + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHDWalletCreateWithMnemonic + is_public: true + is_nullable: true + params: + - name: mnemonic + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: passphrase + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHDWalletCreateWithMnemonicCheck + is_public: true + is_nullable: true + params: + - name: mnemonic + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: passphrase + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: check + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWHDWalletCreateWithEntropy + is_public: true + is_nullable: true + params: + - name: entropy + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: passphrase + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +deinits: +- name: TWHDWalletDelete +functions: +- name: TWHDWalletGetMasterKey + is_public: true + is_static: false + params: + - name: wallet + type: + variant: struct + value: TWHDWallet + is_constant: false + is_nullable: false + is_pointer: true + - name: curve + type: + variant: enum + value: TWCurve + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: struct + value: TWPrivateKey + is_constant: false + is_nullable: false + is_pointer: true +- name: TWHDWalletGetKeyForCoin + is_public: true + is_static: false + params: + - name: wallet + type: + variant: struct + value: TWHDWallet + is_constant: false + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: struct + value: TWPrivateKey + is_constant: false + is_nullable: false + is_pointer: true +- name: TWHDWalletGetAddressForCoin + is_public: true + is_static: false + params: + - name: wallet + type: + variant: struct + value: TWHDWallet + is_constant: false + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHDWalletGetAddressDerivation + is_public: true + is_static: false + params: + - name: wallet + type: + variant: struct + value: TWHDWallet + is_constant: false + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: derivation + type: + variant: enum + value: TWDerivation + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHDWalletGetKey + is_public: true + is_static: false + params: + - name: wallet + type: + variant: struct + value: TWHDWallet + is_constant: false + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: derivationPath + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: struct + value: TWPrivateKey + is_constant: false + is_nullable: false + is_pointer: true +- name: TWHDWalletGetKeyDerivation + is_public: true + is_static: false + params: + - name: wallet + type: + variant: struct + value: TWHDWallet + is_constant: false + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: derivation + type: + variant: enum + value: TWDerivation + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: struct + value: TWPrivateKey + is_constant: false + is_nullable: false + is_pointer: true +- name: TWHDWalletGetKeyByCurve + is_public: true + is_static: false + params: + - name: wallet + type: + variant: struct + value: TWHDWallet + is_constant: false + is_nullable: false + is_pointer: true + - name: curve + type: + variant: enum + value: TWCurve + is_constant: false + is_nullable: false + is_pointer: false + - name: derivationPath + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: struct + value: TWPrivateKey + is_constant: false + is_nullable: false + is_pointer: true +- name: TWHDWalletGetDerivedKey + is_public: true + is_static: false + params: + - name: wallet + type: + variant: struct + value: TWHDWallet + is_constant: false + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: account + type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false + - name: change + type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false + - name: address + type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: struct + value: TWPrivateKey + is_constant: false + is_nullable: false + is_pointer: true +- name: TWHDWalletGetExtendedPrivateKey + is_public: true + is_static: false + params: + - name: wallet + type: + variant: struct + value: TWHDWallet + is_constant: false + is_nullable: false + is_pointer: true + - name: purpose + type: + variant: enum + value: TWPurpose + is_constant: false + is_nullable: false + is_pointer: false + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: version + type: + variant: enum + value: TWHDVersion + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHDWalletGetExtendedPublicKey + is_public: true + is_static: false + params: + - name: wallet + type: + variant: struct + value: TWHDWallet + is_constant: false + is_nullable: false + is_pointer: true + - name: purpose + type: + variant: enum + value: TWPurpose + is_constant: false + is_nullable: false + is_pointer: false + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: version + type: + variant: enum + value: TWHDVersion + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHDWalletGetExtendedPrivateKeyAccount + is_public: true + is_static: false + params: + - name: wallet + type: + variant: struct + value: TWHDWallet + is_constant: false + is_nullable: false + is_pointer: true + - name: purpose + type: + variant: enum + value: TWPurpose + is_constant: false + is_nullable: false + is_pointer: false + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: derivation + type: + variant: enum + value: TWDerivation + is_constant: false + is_nullable: false + is_pointer: false + - name: version + type: + variant: enum + value: TWHDVersion + is_constant: false + is_nullable: false + is_pointer: false + - name: account + type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHDWalletGetExtendedPublicKeyAccount + is_public: true + is_static: false + params: + - name: wallet + type: + variant: struct + value: TWHDWallet + is_constant: false + is_nullable: false + is_pointer: true + - name: purpose + type: + variant: enum + value: TWPurpose + is_constant: false + is_nullable: false + is_pointer: false + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: derivation + type: + variant: enum + value: TWDerivation + is_constant: false + is_nullable: false + is_pointer: false + - name: version + type: + variant: enum + value: TWHDVersion + is_constant: false + is_nullable: false + is_pointer: false + - name: account + type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHDWalletGetExtendedPrivateKeyDerivation + is_public: true + is_static: false + params: + - name: wallet + type: + variant: struct + value: TWHDWallet + is_constant: false + is_nullable: false + is_pointer: true + - name: purpose + type: + variant: enum + value: TWPurpose + is_constant: false + is_nullable: false + is_pointer: false + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: derivation + type: + variant: enum + value: TWDerivation + is_constant: false + is_nullable: false + is_pointer: false + - name: version + type: + variant: enum + value: TWHDVersion + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHDWalletGetExtendedPublicKeyDerivation + is_public: true + is_static: false + params: + - name: wallet + type: + variant: struct + value: TWHDWallet + is_constant: false + is_nullable: false + is_pointer: true + - name: purpose + type: + variant: enum + value: TWPurpose + is_constant: false + is_nullable: false + is_pointer: false + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: derivation + type: + variant: enum + value: TWDerivation + is_constant: false + is_nullable: false + is_pointer: false + - name: version + type: + variant: enum + value: TWHDVersion + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHDWalletGetPublicKeyFromExtended + is_public: true + is_static: true + params: + - name: extended + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: derivationPath + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: struct + value: TWPublicKey + is_constant: false + is_nullable: true + is_pointer: true +properties: +- name: TWHDWalletSeed + is_public: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHDWalletMnemonic + is_public: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHDWalletEntropy + is_public: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWHRP.yaml b/codegen-v2/manifest/TWHRP.yaml new file mode 100644 index 00000000000..3b02a2f6520 --- /dev/null +++ b/codegen-v2/manifest/TWHRP.yaml @@ -0,0 +1,190 @@ +name: TWHRP +enums: +- name: TWHRP + is_public: true + value_type: + variant: u_int32_t + variants: + - name: unknown + value: 0 + as_string: '' + - name: bitcoin + value: 1 + as_string: bc + - name: litecoin + value: 2 + as_string: ltc + - name: viacoin + value: 3 + as_string: via + - name: groestlcoin + value: 4 + as_string: grs + - name: digiByte + value: 5 + as_string: dgb + - name: monacoin + value: 6 + as_string: mona + - name: cosmos + value: 7 + as_string: cosmos + - name: bitcoinCash + value: 8 + as_string: bitcoincash + - name: bitcoinGold + value: 9 + as_string: btg + - name: ioTeX + value: 10 + as_string: io + - name: nervos + value: 11 + as_string: ckb + - name: zilliqa + value: 12 + as_string: zil + - name: terra + value: 13 + as_string: terra + - name: cryptoOrg + value: 14 + as_string: cro + - name: kava + value: 15 + as_string: kava + - name: oasis + value: 16 + as_string: oasis + - name: bluzelle + value: 17 + as_string: bluzelle + - name: bandChain + value: 18 + as_string: band + - name: multiversX + value: 19 + as_string: erd + - name: secret + value: 20 + as_string: secret + - name: agoric + value: 21 + as_string: agoric + - name: binance + value: 22 + as_string: bnb + - name: ecash + value: 23 + as_string: ecash + - name: thorchain + value: 24 + as_string: thor + - name: harmony + value: 25 + as_string: one + - name: cardano + value: 26 + as_string: addr + - name: qtum + value: 27 + as_string: qc + - name: nativeInjective + value: 28 + as_string: inj + - name: osmosis + value: 29 + as_string: osmo + - name: terraV2 + value: 30 + as_string: terra + - name: coreum + value: 31 + as_string: core + - name: nativeCanto + value: 32 + as_string: canto + - name: sommelier + value: 33 + as_string: somm + - name: fetchAI + value: 34 + as_string: fetch + - name: mars + value: 35 + as_string: mars + - name: umee + value: 36 + as_string: umee + - name: quasar + value: 37 + as_string: quasar + - name: persistence + value: 38 + as_string: persistence + - name: akash + value: 39 + as_string: akash + - name: noble + value: 40 + as_string: noble + - name: stargaze + value: 41 + as_string: stars + - name: nativeEvmos + value: 42 + as_string: evmos + - name: juno + value: 43 + as_string: juno + - name: stride + value: 44 + as_string: stride + - name: axelar + value: 45 + as_string: axelar + - name: crescent + value: 46 + as_string: cre + - name: kujira + value: 47 + as_string: kujira + - name: comdex + value: 48 + as_string: comdex + - name: neutron + value: 49 + as_string: neutron +functions: +- name: stringForHRP + is_public: false + is_static: false + params: + - name: hrp + type: + variant: enum + value: TWHRP + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: char + is_constant: true + is_nullable: true + is_pointer: true +- name: hrpForString + is_public: false + is_static: false + params: + - name: string + type: + variant: char + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: enum + value: TWHRP + is_constant: false + is_nullable: false + is_pointer: false diff --git a/codegen-v2/manifest/TWHarmonyProto.yaml b/codegen-v2/manifest/TWHarmonyProto.yaml new file mode 100644 index 00000000000..b11c9c5c6ca --- /dev/null +++ b/codegen-v2/manifest/TWHarmonyProto.yaml @@ -0,0 +1,14 @@ +name: TWHarmonyProto +protos: +- TW_Harmony_Proto_SigningInput +- TW_Harmony_Proto_SigningOutput +- TW_Harmony_Proto_TransactionMessage +- TW_Harmony_Proto_StakingMessage +- TW_Harmony_Proto_Description +- TW_Harmony_Proto_Decimal +- TW_Harmony_Proto_CommissionRate +- TW_Harmony_Proto_DirectiveCreateValidator +- TW_Harmony_Proto_DirectiveEditValidator +- TW_Harmony_Proto_DirectiveDelegate +- TW_Harmony_Proto_DirectiveUndelegate +- TW_Harmony_Proto_DirectiveCollectRewards diff --git a/codegen-v2/manifest/TWHash.yaml b/codegen-v2/manifest/TWHash.yaml new file mode 100644 index 00000000000..6f900c4cb9d --- /dev/null +++ b/codegen-v2/manifest/TWHash.yaml @@ -0,0 +1,288 @@ +name: TWHash +structs: +- name: TWHash + is_public: true + is_class: false + fields: + - - unused + - variant: u_int8_t + is_constant: false + is_nullable: false + is_pointer: false +functions: +- name: TWHashSHA1 + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHashSHA256 + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHashSHA512 + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHashSHA512_256 + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHashKeccak256 + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHashKeccak512 + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHashSHA3_256 + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHashSHA3_512 + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHashRIPEMD + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHashBlake256 + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHashBlake2b + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: size + type: + variant: size_t + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHashGroestl512 + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHashSHA256SHA256 + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHashSHA256RIPEMD + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHashSHA3_256RIPEMD + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHashBlake256Blake256 + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHashBlake256RIPEMD + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWHashGroestl512Groestl512 + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWHederaProto.yaml b/codegen-v2/manifest/TWHederaProto.yaml new file mode 100644 index 00000000000..96074d6e307 --- /dev/null +++ b/codegen-v2/manifest/TWHederaProto.yaml @@ -0,0 +1,8 @@ +name: TWHederaProto +protos: +- TW_Hedera_Proto_Timestamp +- TW_Hedera_Proto_TransactionID +- TW_Hedera_Proto_TransferMessage +- TW_Hedera_Proto_TransactionBody +- TW_Hedera_Proto_SigningInput +- TW_Hedera_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWIconProto.yaml b/codegen-v2/manifest/TWIconProto.yaml new file mode 100644 index 00000000000..86868b8dc30 --- /dev/null +++ b/codegen-v2/manifest/TWIconProto.yaml @@ -0,0 +1,4 @@ +name: TWIconProto +protos: +- TW_Icon_Proto_SigningInput +- TW_Icon_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWIoTeXProto.yaml b/codegen-v2/manifest/TWIoTeXProto.yaml new file mode 100644 index 00000000000..c05c82dcb2b --- /dev/null +++ b/codegen-v2/manifest/TWIoTeXProto.yaml @@ -0,0 +1,9 @@ +name: TWIoTeXProto +protos: +- TW_IoTeX_Proto_Transfer +- TW_IoTeX_Proto_Staking +- TW_IoTeX_Proto_ContractCall +- TW_IoTeX_Proto_SigningInput +- TW_IoTeX_Proto_SigningOutput +- TW_IoTeX_Proto_ActionCore +- TW_IoTeX_Proto_Action diff --git a/codegen-v2/manifest/TWLiquidStaking.yaml b/codegen-v2/manifest/TWLiquidStaking.yaml new file mode 100644 index 00000000000..e5cbae32b2d --- /dev/null +++ b/codegen-v2/manifest/TWLiquidStaking.yaml @@ -0,0 +1,21 @@ +name: TWLiquidStaking +structs: +- name: TWLiquidStaking + is_public: true + is_class: false +functions: +- name: TWLiquidStakingBuildRequest + is_public: true + is_static: true + params: + - name: input + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWLiquidStakingProto.yaml b/codegen-v2/manifest/TWLiquidStakingProto.yaml new file mode 100644 index 00000000000..f678e946b79 --- /dev/null +++ b/codegen-v2/manifest/TWLiquidStakingProto.yaml @@ -0,0 +1,9 @@ +name: TWLiquidStakingProto +protos: +- TW_LiquidStaking_Proto_Status +- TW_LiquidStaking_Proto_Asset +- TW_LiquidStaking_Proto_Stake +- TW_LiquidStaking_Proto_Unstake +- TW_LiquidStaking_Proto_Withdraw +- TW_LiquidStaking_Proto_Input +- TW_LiquidStaking_Proto_Output diff --git a/codegen-v2/manifest/TWMnemonic.yaml b/codegen-v2/manifest/TWMnemonic.yaml new file mode 100644 index 00000000000..f1b426ec636 --- /dev/null +++ b/codegen-v2/manifest/TWMnemonic.yaml @@ -0,0 +1,51 @@ +name: TWMnemonic +structs: +- name: TWMnemonic + is_public: true + is_class: false +functions: +- name: TWMnemonicIsValid + is_public: true + is_static: true + params: + - name: mnemonic + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWMnemonicIsValidWord + is_public: true + is_static: true + params: + - name: word + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWMnemonicSuggest + is_public: true + is_static: true + params: + - name: prefix + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWMultiversXProto.yaml b/codegen-v2/manifest/TWMultiversXProto.yaml new file mode 100644 index 00000000000..71df5e72131 --- /dev/null +++ b/codegen-v2/manifest/TWMultiversXProto.yaml @@ -0,0 +1,9 @@ +name: TWMultiversXProto +protos: +- TW_MultiversX_Proto_GenericAction +- TW_MultiversX_Proto_EGLDTransfer +- TW_MultiversX_Proto_ESDTTransfer +- TW_MultiversX_Proto_ESDTNFTTransfer +- TW_MultiversX_Proto_Accounts +- TW_MultiversX_Proto_SigningInput +- TW_MultiversX_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWNEARAccount.yaml b/codegen-v2/manifest/TWNEARAccount.yaml new file mode 100644 index 00000000000..05b607a0325 --- /dev/null +++ b/codegen-v2/manifest/TWNEARAccount.yaml @@ -0,0 +1,26 @@ +name: TWNEARAccount +structs: +- name: TWNEARAccount + is_public: true + is_class: true +inits: +- name: TWNEARAccountCreateWithString + is_public: true + is_nullable: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +deinits: +- name: TWNEARAccountDelete +properties: +- name: TWNEARAccountDescription + is_public: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWNEARProto.yaml b/codegen-v2/manifest/TWNEARProto.yaml new file mode 100644 index 00000000000..1d983a286c8 --- /dev/null +++ b/codegen-v2/manifest/TWNEARProto.yaml @@ -0,0 +1,17 @@ +name: TWNEARProto +protos: +- TW_NEAR_Proto_PublicKey +- TW_NEAR_Proto_FunctionCallPermission +- TW_NEAR_Proto_FullAccessPermission +- TW_NEAR_Proto_AccessKey +- TW_NEAR_Proto_CreateAccount +- TW_NEAR_Proto_DeployContract +- TW_NEAR_Proto_FunctionCall +- TW_NEAR_Proto_Transfer +- TW_NEAR_Proto_Stake +- TW_NEAR_Proto_AddKey +- TW_NEAR_Proto_DeleteKey +- TW_NEAR_Proto_DeleteAccount +- TW_NEAR_Proto_Action +- TW_NEAR_Proto_SigningInput +- TW_NEAR_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWNEOProto.yaml b/codegen-v2/manifest/TWNEOProto.yaml new file mode 100644 index 00000000000..b4db4f7ef01 --- /dev/null +++ b/codegen-v2/manifest/TWNEOProto.yaml @@ -0,0 +1,8 @@ +name: TWNEOProto +protos: +- TW_NEO_Proto_TransactionInput +- TW_NEO_Proto_TransactionOutput +- TW_NEO_Proto_SigningInput +- TW_NEO_Proto_SigningOutput +- TW_NEO_Proto_TransactionOutputPlan +- TW_NEO_Proto_TransactionPlan diff --git a/codegen-v2/manifest/TWNULSProto.yaml b/codegen-v2/manifest/TWNULSProto.yaml new file mode 100644 index 00000000000..0ecedf0290f --- /dev/null +++ b/codegen-v2/manifest/TWNULSProto.yaml @@ -0,0 +1,8 @@ +name: TWNULSProto +protos: +- TW_NULS_Proto_TransactionCoinFrom +- TW_NULS_Proto_TransactionCoinTo +- TW_NULS_Proto_Signature +- TW_NULS_Proto_Transaction +- TW_NULS_Proto_SigningInput +- TW_NULS_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWNanoProto.yaml b/codegen-v2/manifest/TWNanoProto.yaml new file mode 100644 index 00000000000..b153219bbce --- /dev/null +++ b/codegen-v2/manifest/TWNanoProto.yaml @@ -0,0 +1,4 @@ +name: TWNanoProto +protos: +- TW_Nano_Proto_SigningInput +- TW_Nano_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWNebulasProto.yaml b/codegen-v2/manifest/TWNebulasProto.yaml new file mode 100644 index 00000000000..a53a6975f97 --- /dev/null +++ b/codegen-v2/manifest/TWNebulasProto.yaml @@ -0,0 +1,6 @@ +name: TWNebulasProto +protos: +- TW_Nebulas_Proto_SigningInput +- TW_Nebulas_Proto_SigningOutput +- TW_Nebulas_Proto_Data +- TW_Nebulas_Proto_RawTransaction diff --git a/codegen-v2/manifest/TWNervosAddress.yaml b/codegen-v2/manifest/TWNervosAddress.yaml new file mode 100644 index 00000000000..33a5502426b --- /dev/null +++ b/codegen-v2/manifest/TWNervosAddress.yaml @@ -0,0 +1,86 @@ +name: TWNervosAddress +structs: +- name: TWNervosAddress + is_public: true + is_class: true +inits: +- name: TWNervosAddressCreateWithString + is_public: true + is_nullable: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +deinits: +- name: TWNervosAddressDelete +functions: +- name: TWNervosAddressEqual + is_public: true + is_static: true + params: + - name: lhs + type: + variant: struct + value: TWNervosAddress + is_constant: false + is_nullable: false + is_pointer: true + - name: rhs + type: + variant: struct + value: TWNervosAddress + is_constant: false + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWNervosAddressIsValidString + is_public: true + is_static: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +properties: +- name: TWNervosAddressDescription + is_public: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWNervosAddressCodeHash + is_public: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWNervosAddressHashType + is_public: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWNervosAddressArgs + is_public: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWNervosProto.yaml b/codegen-v2/manifest/TWNervosProto.yaml new file mode 100644 index 00000000000..5c75962a775 --- /dev/null +++ b/codegen-v2/manifest/TWNervosProto.yaml @@ -0,0 +1,15 @@ +name: TWNervosProto +protos: +- TW_Nervos_Proto_TransactionPlan +- TW_Nervos_Proto_CellDep +- TW_Nervos_Proto_OutPoint +- TW_Nervos_Proto_CellOutput +- TW_Nervos_Proto_Script +- TW_Nervos_Proto_NativeTransfer +- TW_Nervos_Proto_SudtTransfer +- TW_Nervos_Proto_DaoDeposit +- TW_Nervos_Proto_DaoWithdrawPhase1 +- TW_Nervos_Proto_DaoWithdrawPhase2 +- TW_Nervos_Proto_SigningInput +- TW_Nervos_Proto_Cell +- TW_Nervos_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWNimiqProto.yaml b/codegen-v2/manifest/TWNimiqProto.yaml new file mode 100644 index 00000000000..874c5688186 --- /dev/null +++ b/codegen-v2/manifest/TWNimiqProto.yaml @@ -0,0 +1,4 @@ +name: TWNimiqProto +protos: +- TW_Nimiq_Proto_SigningInput +- TW_Nimiq_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWOasisProto.yaml b/codegen-v2/manifest/TWOasisProto.yaml new file mode 100644 index 00000000000..d20358b3002 --- /dev/null +++ b/codegen-v2/manifest/TWOasisProto.yaml @@ -0,0 +1,5 @@ +name: TWOasisProto +protos: +- TW_Oasis_Proto_TransferMessage +- TW_Oasis_Proto_SigningInput +- TW_Oasis_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWOntologyProto.yaml b/codegen-v2/manifest/TWOntologyProto.yaml new file mode 100644 index 00000000000..7d9c965172f --- /dev/null +++ b/codegen-v2/manifest/TWOntologyProto.yaml @@ -0,0 +1,4 @@ +name: TWOntologyProto +protos: +- TW_Ontology_Proto_SigningInput +- TW_Ontology_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWPBKDF2.yaml b/codegen-v2/manifest/TWPBKDF2.yaml new file mode 100644 index 00000000000..1e1a36a0b0f --- /dev/null +++ b/codegen-v2/manifest/TWPBKDF2.yaml @@ -0,0 +1,72 @@ +name: TWPBKDF2 +structs: +- name: TWPBKDF2 + is_public: true + is_class: false +functions: +- name: TWPBKDF2HmacSha256 + is_public: true + is_static: true + params: + - name: password + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: salt + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: iterations + type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false + - name: dkLen + type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true +- name: TWPBKDF2HmacSha512 + is_public: true + is_static: true + params: + - name: password + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: salt + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: iterations + type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false + - name: dkLen + type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true diff --git a/codegen-v2/manifest/TWPolkadotProto.yaml b/codegen-v2/manifest/TWPolkadotProto.yaml new file mode 100644 index 00000000000..80eb51c7c9d --- /dev/null +++ b/codegen-v2/manifest/TWPolkadotProto.yaml @@ -0,0 +1,7 @@ +name: TWPolkadotProto +protos: +- TW_Polkadot_Proto_Era +- TW_Polkadot_Proto_Balance +- TW_Polkadot_Proto_Staking +- TW_Polkadot_Proto_SigningInput +- TW_Polkadot_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWPrivateKey.yaml b/codegen-v2/manifest/TWPrivateKey.yaml new file mode 100644 index 00000000000..5ec6bfd486d --- /dev/null +++ b/codegen-v2/manifest/TWPrivateKey.yaml @@ -0,0 +1,322 @@ +name: TWPrivateKey +structs: +- name: TWPrivateKey + is_public: true + is_class: true +inits: +- name: TWPrivateKeyCreate + is_public: true + is_nullable: false +- name: TWPrivateKeyCreateWithData + is_public: true + is_nullable: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWPrivateKeyCreateCopy + is_public: true + is_nullable: true + params: + - name: key + type: + variant: struct + value: TWPrivateKey + is_constant: false + is_nullable: false + is_pointer: true +deinits: +- name: TWPrivateKeyDelete +functions: +- name: TWPrivateKeyIsValid + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: curve + type: + variant: enum + value: TWCurve + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWPrivateKeyGetPublicKey + is_public: true + is_static: false + params: + - name: pk + type: + variant: struct + value: TWPrivateKey + is_constant: false + is_nullable: false + is_pointer: true + - name: coinType + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: struct + value: TWPublicKey + is_constant: false + is_nullable: false + is_pointer: true +- name: TWPrivateKeyGetPublicKeyByType + is_public: true + is_static: false + params: + - name: pk + type: + variant: struct + value: TWPrivateKey + is_constant: false + is_nullable: false + is_pointer: true + - name: pubkeyType + type: + variant: enum + value: TWPublicKeyType + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: struct + value: TWPublicKey + is_constant: false + is_nullable: false + is_pointer: true +- name: TWPrivateKeyGetPublicKeySecp256k1 + is_public: true + is_static: false + params: + - name: pk + type: + variant: struct + value: TWPrivateKey + is_constant: false + is_nullable: false + is_pointer: true + - name: compressed + type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: struct + value: TWPublicKey + is_constant: false + is_nullable: false + is_pointer: true +- name: TWPrivateKeyGetPublicKeyNist256p1 + is_public: true + is_static: false + params: + - name: pk + type: + variant: struct + value: TWPrivateKey + is_constant: false + is_nullable: false + is_pointer: true + return_type: + variant: struct + value: TWPublicKey + is_constant: false + is_nullable: false + is_pointer: true +- name: TWPrivateKeyGetPublicKeyEd25519 + is_public: true + is_static: false + params: + - name: pk + type: + variant: struct + value: TWPrivateKey + is_constant: false + is_nullable: false + is_pointer: true + return_type: + variant: struct + value: TWPublicKey + is_constant: false + is_nullable: false + is_pointer: true +- name: TWPrivateKeyGetPublicKeyEd25519Blake2b + is_public: true + is_static: false + params: + - name: pk + type: + variant: struct + value: TWPrivateKey + is_constant: false + is_nullable: false + is_pointer: true + return_type: + variant: struct + value: TWPublicKey + is_constant: false + is_nullable: false + is_pointer: true +- name: TWPrivateKeyGetPublicKeyEd25519Cardano + is_public: true + is_static: false + params: + - name: pk + type: + variant: struct + value: TWPrivateKey + is_constant: false + is_nullable: false + is_pointer: true + return_type: + variant: struct + value: TWPublicKey + is_constant: false + is_nullable: false + is_pointer: true +- name: TWPrivateKeyGetPublicKeyCurve25519 + is_public: true + is_static: false + params: + - name: pk + type: + variant: struct + value: TWPrivateKey + is_constant: false + is_nullable: false + is_pointer: true + return_type: + variant: struct + value: TWPublicKey + is_constant: false + is_nullable: false + is_pointer: true +- name: TWPrivateKeyGetSharedKey + is_public: true + is_static: false + params: + - name: pk + type: + variant: struct + value: TWPrivateKey + is_constant: true + is_nullable: false + is_pointer: true + - name: publicKey + type: + variant: struct + value: TWPublicKey + is_constant: true + is_nullable: false + is_pointer: true + - name: curve + type: + variant: enum + value: TWCurve + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true +- name: TWPrivateKeySign + is_public: true + is_static: false + params: + - name: pk + type: + variant: struct + value: TWPrivateKey + is_constant: false + is_nullable: false + is_pointer: true + - name: digest + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: curve + type: + variant: enum + value: TWCurve + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true +- name: TWPrivateKeySignAsDER + is_public: true + is_static: false + params: + - name: pk + type: + variant: struct + value: TWPrivateKey + is_constant: false + is_nullable: false + is_pointer: true + - name: digest + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true +- name: TWPrivateKeySignZilliqaSchnorr + is_public: true + is_static: false + params: + - name: pk + type: + variant: struct + value: TWPrivateKey + is_constant: false + is_nullable: false + is_pointer: true + - name: message + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true +properties: +- name: TWPrivateKeyData + is_public: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWPrivateKeyType.yaml b/codegen-v2/manifest/TWPrivateKeyType.yaml new file mode 100644 index 00000000000..c16c8082188 --- /dev/null +++ b/codegen-v2/manifest/TWPrivateKeyType.yaml @@ -0,0 +1,11 @@ +name: TWPrivateKeyType +enums: +- name: TWPrivateKeyType + is_public: true + value_type: + variant: u_int32_t + variants: + - name: default + value: 0 + - name: cardano + value: 1 diff --git a/codegen-v2/manifest/TWPublicKey.yaml b/codegen-v2/manifest/TWPublicKey.yaml new file mode 100644 index 00000000000..bacfe840deb --- /dev/null +++ b/codegen-v2/manifest/TWPublicKey.yaml @@ -0,0 +1,200 @@ +name: TWPublicKey +structs: +- name: TWPublicKey + is_public: true + is_class: true +inits: +- name: TWPublicKeyCreateWithData + is_public: true + is_nullable: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: type + type: + variant: enum + value: TWPublicKeyType + is_constant: false + is_nullable: false + is_pointer: false +deinits: +- name: TWPublicKeyDelete +functions: +- name: TWPublicKeyIsValid + is_public: true + is_static: true + params: + - name: data + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: type + type: + variant: enum + value: TWPublicKeyType + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWPublicKeyVerify + is_public: true + is_static: false + params: + - name: pk + type: + variant: struct + value: TWPublicKey + is_constant: false + is_nullable: false + is_pointer: true + - name: signature + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: message + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWPublicKeyVerifyAsDER + is_public: true + is_static: false + params: + - name: pk + type: + variant: struct + value: TWPublicKey + is_constant: false + is_nullable: false + is_pointer: true + - name: signature + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: message + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWPublicKeyVerifyZilliqaSchnorr + is_public: true + is_static: false + params: + - name: pk + type: + variant: struct + value: TWPublicKey + is_constant: false + is_nullable: false + is_pointer: true + - name: signature + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: message + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWPublicKeyRecover + is_public: true + is_static: true + params: + - name: signature + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: message + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: struct + value: TWPublicKey + is_constant: false + is_nullable: true + is_pointer: true +properties: +- name: TWPublicKeyIsCompressed + is_public: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWPublicKeyCompressed + is_public: true + return_type: + variant: struct + value: TWPublicKey + is_constant: false + is_nullable: false + is_pointer: true +- name: TWPublicKeyUncompressed + is_public: true + return_type: + variant: struct + value: TWPublicKey + is_constant: false + is_nullable: false + is_pointer: true +- name: TWPublicKeyData + is_public: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWPublicKeyKeyType + is_public: true + return_type: + variant: enum + value: TWPublicKeyType + is_constant: false + is_nullable: false + is_pointer: false +- name: TWPublicKeyDescription + is_public: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWPublicKeyType.yaml b/codegen-v2/manifest/TWPublicKeyType.yaml new file mode 100644 index 00000000000..3498161aa65 --- /dev/null +++ b/codegen-v2/manifest/TWPublicKeyType.yaml @@ -0,0 +1,25 @@ +name: TWPublicKeyType +enums: +- name: TWPublicKeyType + is_public: true + value_type: + variant: u_int32_t + variants: + - name: secp256k1 + value: 0 + - name: secp256k1Extended + value: 1 + - name: nist256p1 + value: 2 + - name: nist256p1Extended + value: 3 + - name: ed25519 + value: 4 + - name: ed25519Blake2b + value: 5 + - name: curve25519 + value: 6 + - name: ed25519Cardano + value: 7 + - name: starkex + value: 8 diff --git a/codegen-v2/manifest/TWPurpose.yaml b/codegen-v2/manifest/TWPurpose.yaml new file mode 100644 index 00000000000..8ccf4d8cc0e --- /dev/null +++ b/codegen-v2/manifest/TWPurpose.yaml @@ -0,0 +1,15 @@ +name: TWPurpose +enums: +- name: TWPurpose + is_public: true + value_type: + variant: u_int32_t + variants: + - name: bip44 + value: 44 + - name: bip49 + value: 49 + - name: bip84 + value: 84 + - name: bip1852 + value: 1852 diff --git a/codegen-v2/manifest/TWRippleProto.yaml b/codegen-v2/manifest/TWRippleProto.yaml new file mode 100644 index 00000000000..de3b2af9e88 --- /dev/null +++ b/codegen-v2/manifest/TWRippleProto.yaml @@ -0,0 +1,11 @@ +name: TWRippleProto +protos: +- TW_Ripple_Proto_CurrencyAmount +- TW_Ripple_Proto_OperationTrustSet +- TW_Ripple_Proto_OperationPayment +- TW_Ripple_Proto_OperationNFTokenBurn +- TW_Ripple_Proto_OperationNFTokenCreateOffer +- TW_Ripple_Proto_OperationNFTokenAcceptOffer +- TW_Ripple_Proto_OperationNFTokenCancelOffer +- TW_Ripple_Proto_SigningInput +- TW_Ripple_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWRippleXAddress.yaml b/codegen-v2/manifest/TWRippleXAddress.yaml new file mode 100644 index 00000000000..8793e2ce5f4 --- /dev/null +++ b/codegen-v2/manifest/TWRippleXAddress.yaml @@ -0,0 +1,92 @@ +name: TWRippleXAddress +structs: +- name: TWPublicKey + is_public: false + is_class: false +- name: TWRippleXAddress + is_public: true + is_class: true +inits: +- name: TWRippleXAddressCreateWithString + is_public: true + is_nullable: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWRippleXAddressCreateWithPublicKey + is_public: true + is_nullable: false + params: + - name: publicKey + type: + variant: struct + value: TWPublicKey + is_constant: false + is_nullable: false + is_pointer: true + - name: tag + type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false +deinits: +- name: TWRippleXAddressDelete +functions: +- name: TWRippleXAddressEqual + is_public: true + is_static: true + params: + - name: lhs + type: + variant: struct + value: TWRippleXAddress + is_constant: false + is_nullable: false + is_pointer: true + - name: rhs + type: + variant: struct + value: TWRippleXAddress + is_constant: false + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWRippleXAddressIsValidString + is_public: true + is_static: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +properties: +- name: TWRippleXAddressDescription + is_public: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWRippleXAddressTag + is_public: true + return_type: + variant: u_int32_t + is_constant: false + is_nullable: false + is_pointer: false diff --git a/codegen-v2/manifest/TWSS58AddressType.yaml b/codegen-v2/manifest/TWSS58AddressType.yaml new file mode 100644 index 00000000000..617d5ca49a0 --- /dev/null +++ b/codegen-v2/manifest/TWSS58AddressType.yaml @@ -0,0 +1,11 @@ +name: TWSS58AddressType +enums: +- name: TWSS58AddressType + is_public: true + value_type: + variant: u_int8_t + variants: + - name: polkadot + value: 0 + - name: kusama + value: 2 diff --git a/codegen-v2/manifest/TWSegwitAddress.yaml b/codegen-v2/manifest/TWSegwitAddress.yaml new file mode 100644 index 00000000000..6225484c27d --- /dev/null +++ b/codegen-v2/manifest/TWSegwitAddress.yaml @@ -0,0 +1,108 @@ +name: TWSegwitAddress +structs: +- name: TWPublicKey + is_public: false + is_class: false +- name: TWSegwitAddress + is_public: true + is_class: true +inits: +- name: TWSegwitAddressCreateWithString + is_public: true + is_nullable: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWSegwitAddressCreateWithPublicKey + is_public: true + is_nullable: false + params: + - name: hrp + type: + variant: enum + value: TWHRP + is_constant: false + is_nullable: false + is_pointer: false + - name: publicKey + type: + variant: struct + value: TWPublicKey + is_constant: false + is_nullable: false + is_pointer: true +deinits: +- name: TWSegwitAddressDelete +functions: +- name: TWSegwitAddressEqual + is_public: true + is_static: true + params: + - name: lhs + type: + variant: struct + value: TWSegwitAddress + is_constant: false + is_nullable: false + is_pointer: true + - name: rhs + type: + variant: struct + value: TWSegwitAddress + is_constant: false + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWSegwitAddressIsValidString + is_public: true + is_static: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +properties: +- name: TWSegwitAddressDescription + is_public: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWSegwitAddressHRP + is_public: true + return_type: + variant: enum + value: TWHRP + is_constant: false + is_nullable: false + is_pointer: false +- name: TWSegwitAddressWitnessVersion + is_public: true + return_type: + variant: int + is_constant: false + is_nullable: false + is_pointer: false +- name: TWSegwitAddressWitnessProgram + is_public: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWSolanaAddress.yaml b/codegen-v2/manifest/TWSolanaAddress.yaml new file mode 100644 index 00000000000..28908ef2a9d --- /dev/null +++ b/codegen-v2/manifest/TWSolanaAddress.yaml @@ -0,0 +1,49 @@ +name: TWSolanaAddress +structs: +- name: TWSolanaAddress + is_public: true + is_class: true +inits: +- name: TWSolanaAddressCreateWithString + is_public: true + is_nullable: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +deinits: +- name: TWSolanaAddressDelete +functions: +- name: TWSolanaAddressDefaultTokenAddress + is_public: true + is_static: false + params: + - name: address + type: + variant: struct + value: TWSolanaAddress + is_constant: false + is_nullable: false + is_pointer: true + - name: tokenMintAddress + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: true + is_pointer: true +properties: +- name: TWSolanaAddressDescription + is_public: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWSolanaProto.yaml b/codegen-v2/manifest/TWSolanaProto.yaml new file mode 100644 index 00000000000..4d002e53fad --- /dev/null +++ b/codegen-v2/manifest/TWSolanaProto.yaml @@ -0,0 +1,14 @@ +name: TWSolanaProto +protos: +- TW_Solana_Proto_Transfer +- TW_Solana_Proto_DelegateStake +- TW_Solana_Proto_DeactivateStake +- TW_Solana_Proto_DeactivateAllStake +- TW_Solana_Proto_WithdrawStake +- TW_Solana_Proto_StakeAccountValue +- TW_Solana_Proto_WithdrawAllStake +- TW_Solana_Proto_CreateTokenAccount +- TW_Solana_Proto_TokenTransfer +- TW_Solana_Proto_CreateAndTransferToken +- TW_Solana_Proto_SigningInput +- TW_Solana_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWStarkExMessageSigner.yaml b/codegen-v2/manifest/TWStarkExMessageSigner.yaml new file mode 100644 index 00000000000..2c927399e52 --- /dev/null +++ b/codegen-v2/manifest/TWStarkExMessageSigner.yaml @@ -0,0 +1,56 @@ +name: TWStarkExMessageSigner +structs: +- name: TWStarkExMessageSigner + is_public: true + is_class: false +functions: +- name: TWStarkExMessageSignerSignMessage + is_public: true + is_static: true + params: + - name: privateKey + type: + variant: struct + value: TWPrivateKey + is_constant: true + is_nullable: false + is_pointer: true + - name: message + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWStarkExMessageSignerVerifyMessage + is_public: true + is_static: true + params: + - name: pubKey + type: + variant: struct + value: TWPublicKey + is_constant: true + is_nullable: false + is_pointer: true + - name: message + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: signature + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false diff --git a/codegen-v2/manifest/TWStarkWare.yaml b/codegen-v2/manifest/TWStarkWare.yaml new file mode 100644 index 00000000000..491f36d1826 --- /dev/null +++ b/codegen-v2/manifest/TWStarkWare.yaml @@ -0,0 +1,29 @@ +name: TWStarkWare +structs: +- name: TWStarkWare + is_public: true + is_class: false +functions: +- name: TWStarkWareGetStarkKeyFromSignature + is_public: true + is_static: true + params: + - name: derivationPath + type: + variant: struct + value: TWDerivationPath + is_constant: true + is_nullable: false + is_pointer: true + - name: signature + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: struct + value: TWPrivateKey + is_constant: false + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWStellarMemoType.yaml b/codegen-v2/manifest/TWStellarMemoType.yaml new file mode 100644 index 00000000000..d086e056a0c --- /dev/null +++ b/codegen-v2/manifest/TWStellarMemoType.yaml @@ -0,0 +1,17 @@ +name: TWStellarMemoType +enums: +- name: TWStellarMemoType + is_public: true + value_type: + variant: u_int32_t + variants: + - name: none + value: 0 + - name: text + value: 1 + - name: id + value: 2 + - name: hash + value: 3 + - name: return + value: 4 diff --git a/codegen-v2/manifest/TWStellarPassphrase.yaml b/codegen-v2/manifest/TWStellarPassphrase.yaml new file mode 100644 index 00000000000..4daba41e364 --- /dev/null +++ b/codegen-v2/manifest/TWStellarPassphrase.yaml @@ -0,0 +1,13 @@ +name: TWStellarPassphrase +enums: +- name: TWStellarPassphrase + is_public: true + value_type: + variant: u_int32_t + variants: + - name: stellar + value: 0 + as_string: Public Global Stellar Network ; September 2015 + - name: kin + value: 1 + as_string: Kin Mainnet ; December 2018 diff --git a/codegen-v2/manifest/TWStellarProto.yaml b/codegen-v2/manifest/TWStellarProto.yaml new file mode 100644 index 00000000000..7c016b1627e --- /dev/null +++ b/codegen-v2/manifest/TWStellarProto.yaml @@ -0,0 +1,15 @@ +name: TWStellarProto +protos: +- TW_Stellar_Proto_Asset +- TW_Stellar_Proto_OperationCreateAccount +- TW_Stellar_Proto_OperationPayment +- TW_Stellar_Proto_OperationChangeTrust +- TW_Stellar_Proto_Claimant +- TW_Stellar_Proto_OperationCreateClaimableBalance +- TW_Stellar_Proto_OperationClaimClaimableBalance +- TW_Stellar_Proto_MemoVoid +- TW_Stellar_Proto_MemoText +- TW_Stellar_Proto_MemoId +- TW_Stellar_Proto_MemoHash +- TW_Stellar_Proto_SigningInput +- TW_Stellar_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWStellarVersionByte.yaml b/codegen-v2/manifest/TWStellarVersionByte.yaml new file mode 100644 index 00000000000..7e962ba517c --- /dev/null +++ b/codegen-v2/manifest/TWStellarVersionByte.yaml @@ -0,0 +1,15 @@ +name: TWStellarVersionByte +enums: +- name: TWStellarVersionByte + is_public: true + value_type: + variant: u_int16_t + variants: + - name: accountId + value: 0x30 + - name: seed + value: 0xc0 + - name: preAuthTx + value: 0xc8 + - name: sha256Hash + value: 0x118 diff --git a/codegen-v2/manifest/TWStoredKey.yaml b/codegen-v2/manifest/TWStoredKey.yaml new file mode 100644 index 00000000000..41080bad5c6 --- /dev/null +++ b/codegen-v2/manifest/TWStoredKey.yaml @@ -0,0 +1,755 @@ +name: TWStoredKey +structs: +- name: TWStoredKey + is_public: true + is_class: true +inits: +- name: TWStoredKeyCreateLevel + is_public: true + is_nullable: false + params: + - name: name + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: password + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: encryptionLevel + type: + variant: enum + value: TWStoredKeyEncryptionLevel + is_constant: false + is_nullable: false + is_pointer: false +- name: TWStoredKeyCreateLevelAndEncryption + is_public: true + is_nullable: false + params: + - name: name + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: password + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: encryptionLevel + type: + variant: enum + value: TWStoredKeyEncryptionLevel + is_constant: false + is_nullable: false + is_pointer: false + - name: encryption + type: + variant: enum + value: TWStoredKeyEncryption + is_constant: false + is_nullable: false + is_pointer: false +- name: TWStoredKeyCreate + is_public: true + is_nullable: false + params: + - name: name + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: password + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWStoredKeyCreateEncryption + is_public: true + is_nullable: false + params: + - name: name + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: password + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: encryption + type: + variant: enum + value: TWStoredKeyEncryption + is_constant: false + is_nullable: false + is_pointer: false +deinits: +- name: TWStoredKeyDelete +functions: +- name: TWStoredKeyLoad + is_public: true + is_static: true + params: + - name: path + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: struct + value: TWStoredKey + is_constant: false + is_nullable: true + is_pointer: true +- name: TWStoredKeyImportPrivateKey + is_public: true + is_static: true + params: + - name: privateKey + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: name + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: password + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: struct + value: TWStoredKey + is_constant: false + is_nullable: true + is_pointer: true +- name: TWStoredKeyImportPrivateKeyWithEncryption + is_public: true + is_static: true + params: + - name: privateKey + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: name + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: password + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: encryption + type: + variant: enum + value: TWStoredKeyEncryption + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: struct + value: TWStoredKey + is_constant: false + is_nullable: true + is_pointer: true +- name: TWStoredKeyImportHDWallet + is_public: true + is_static: true + params: + - name: mnemonic + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: name + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: password + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: struct + value: TWStoredKey + is_constant: false + is_nullable: true + is_pointer: true +- name: TWStoredKeyImportHDWalletWithEncryption + is_public: true + is_static: true + params: + - name: mnemonic + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: name + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: password + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: encryption + type: + variant: enum + value: TWStoredKeyEncryption + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: struct + value: TWStoredKey + is_constant: false + is_nullable: true + is_pointer: true +- name: TWStoredKeyImportJSON + is_public: true + is_static: true + params: + - name: json + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: struct + value: TWStoredKey + is_constant: false + is_nullable: true + is_pointer: true +- name: TWStoredKeyAccount + is_public: true + is_static: false + params: + - name: key + type: + variant: struct + value: TWStoredKey + is_constant: false + is_nullable: false + is_pointer: true + - name: index + type: + variant: size_t + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: struct + value: TWAccount + is_constant: false + is_nullable: true + is_pointer: true +- name: TWStoredKeyAccountForCoin + is_public: true + is_static: false + params: + - name: key + type: + variant: struct + value: TWStoredKey + is_constant: false + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: wallet + type: + variant: struct + value: TWHDWallet + is_constant: false + is_nullable: true + is_pointer: true + return_type: + variant: struct + value: TWAccount + is_constant: false + is_nullable: true + is_pointer: true +- name: TWStoredKeyAccountForCoinDerivation + is_public: true + is_static: false + params: + - name: key + type: + variant: struct + value: TWStoredKey + is_constant: false + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: derivation + type: + variant: enum + value: TWDerivation + is_constant: false + is_nullable: false + is_pointer: false + - name: wallet + type: + variant: struct + value: TWHDWallet + is_constant: false + is_nullable: true + is_pointer: true + return_type: + variant: struct + value: TWAccount + is_constant: false + is_nullable: true + is_pointer: true +- name: TWStoredKeyAddAccountDerivation + is_public: true + is_static: false + params: + - name: key + type: + variant: struct + value: TWStoredKey + is_constant: false + is_nullable: false + is_pointer: true + - name: address + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: derivation + type: + variant: enum + value: TWDerivation + is_constant: false + is_nullable: false + is_pointer: false + - name: derivationPath + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: publicKey + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: extendedPublicKey + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: void + is_constant: false + is_nullable: false + is_pointer: false +- name: TWStoredKeyAddAccount + is_public: true + is_static: false + params: + - name: key + type: + variant: struct + value: TWStoredKey + is_constant: false + is_nullable: false + is_pointer: true + - name: address + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: derivationPath + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: publicKey + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: extendedPublicKey + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: void + is_constant: false + is_nullable: false + is_pointer: false +- name: TWStoredKeyRemoveAccountForCoin + is_public: true + is_static: false + params: + - name: key + type: + variant: struct + value: TWStoredKey + is_constant: false + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: void + is_constant: false + is_nullable: false + is_pointer: false +- name: TWStoredKeyRemoveAccountForCoinDerivation + is_public: true + is_static: false + params: + - name: key + type: + variant: struct + value: TWStoredKey + is_constant: false + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: derivation + type: + variant: enum + value: TWDerivation + is_constant: false + is_nullable: false + is_pointer: false + return_type: + variant: void + is_constant: false + is_nullable: false + is_pointer: false +- name: TWStoredKeyRemoveAccountForCoinDerivationPath + is_public: true + is_static: false + params: + - name: key + type: + variant: struct + value: TWStoredKey + is_constant: false + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: derivationPath + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: void + is_constant: false + is_nullable: false + is_pointer: false +- name: TWStoredKeyStore + is_public: true + is_static: false + params: + - name: key + type: + variant: struct + value: TWStoredKey + is_constant: false + is_nullable: false + is_pointer: true + - name: path + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWStoredKeyDecryptPrivateKey + is_public: true + is_static: false + params: + - name: key + type: + variant: struct + value: TWStoredKey + is_constant: false + is_nullable: false + is_pointer: true + - name: password + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true +- name: TWStoredKeyDecryptMnemonic + is_public: true + is_static: false + params: + - name: key + type: + variant: struct + value: TWStoredKey + is_constant: false + is_nullable: false + is_pointer: true + - name: password + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: true + is_pointer: true +- name: TWStoredKeyPrivateKey + is_public: true + is_static: false + params: + - name: key + type: + variant: struct + value: TWStoredKey + is_constant: false + is_nullable: false + is_pointer: true + - name: coin + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: password + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: struct + value: TWPrivateKey + is_constant: false + is_nullable: true + is_pointer: true +- name: TWStoredKeyWallet + is_public: true + is_static: false + params: + - name: key + type: + variant: struct + value: TWStoredKey + is_constant: false + is_nullable: false + is_pointer: true + - name: password + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: struct + value: TWHDWallet + is_constant: false + is_nullable: true + is_pointer: true +- name: TWStoredKeyExportJSON + is_public: true + is_static: false + params: + - name: key + type: + variant: struct + value: TWStoredKey + is_constant: false + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: true + is_pointer: true +- name: TWStoredKeyFixAddresses + is_public: true + is_static: false + params: + - name: key + type: + variant: struct + value: TWStoredKey + is_constant: false + is_nullable: false + is_pointer: true + - name: password + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +properties: +- name: TWStoredKeyIdentifier + is_public: true + return_type: + variant: string + is_constant: true + is_nullable: true + is_pointer: true +- name: TWStoredKeyName + is_public: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWStoredKeyIsMnemonic + is_public: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: TWStoredKeyAccountCount + is_public: true + return_type: + variant: size_t + is_constant: false + is_nullable: false + is_pointer: false +- name: TWStoredKeyEncryptionParameters + is_public: true + return_type: + variant: string + is_constant: true + is_nullable: true + is_pointer: true diff --git a/codegen-v2/manifest/TWStoredKeyEncryption.yaml b/codegen-v2/manifest/TWStoredKeyEncryption.yaml new file mode 100644 index 00000000000..417bea38cb3 --- /dev/null +++ b/codegen-v2/manifest/TWStoredKeyEncryption.yaml @@ -0,0 +1,15 @@ +name: TWStoredKeyEncryption +enums: +- name: TWStoredKeyEncryption + is_public: true + value_type: + variant: u_int32_t + variants: + - name: aes128Ctr + value: 0 + - name: aes128Cbc + value: 1 + - name: aes192Ctr + value: 2 + - name: aes256Ctr + value: 3 diff --git a/codegen-v2/manifest/TWStoredKeyEncryptionLevel.yaml b/codegen-v2/manifest/TWStoredKeyEncryptionLevel.yaml new file mode 100644 index 00000000000..4c0df079d88 --- /dev/null +++ b/codegen-v2/manifest/TWStoredKeyEncryptionLevel.yaml @@ -0,0 +1,15 @@ +name: TWStoredKeyEncryptionLevel +enums: +- name: TWStoredKeyEncryptionLevel + is_public: true + value_type: + variant: u_int32_t + variants: + - name: default + value: 0 + - name: minimal + value: 1 + - name: weak + value: 2 + - name: standard + value: 3 diff --git a/codegen-v2/manifest/TWSuiProto.yaml b/codegen-v2/manifest/TWSuiProto.yaml new file mode 100644 index 00000000000..c84041beac8 --- /dev/null +++ b/codegen-v2/manifest/TWSuiProto.yaml @@ -0,0 +1,5 @@ +name: TWSuiProto +protos: +- TW_Sui_Proto_SignDirect +- TW_Sui_Proto_SigningInput +- TW_Sui_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWTHORChainSwap.yaml b/codegen-v2/manifest/TWTHORChainSwap.yaml new file mode 100644 index 00000000000..f6e42c8966f --- /dev/null +++ b/codegen-v2/manifest/TWTHORChainSwap.yaml @@ -0,0 +1,21 @@ +name: TWTHORChainSwap +structs: +- name: TWTHORChainSwap + is_public: true + is_class: false +functions: +- name: TWTHORChainSwapBuildSwap + is_public: true + is_static: true + params: + - name: input + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWTHORChainSwapProto.yaml b/codegen-v2/manifest/TWTHORChainSwapProto.yaml new file mode 100644 index 00000000000..41a265cae34 --- /dev/null +++ b/codegen-v2/manifest/TWTHORChainSwapProto.yaml @@ -0,0 +1,6 @@ +name: TWTHORChainSwapProto +protos: +- TW_THORChainSwap_Proto_Error +- TW_THORChainSwap_Proto_Asset +- TW_THORChainSwap_Proto_SwapInput +- TW_THORChainSwap_Proto_SwapOutput diff --git a/codegen-v2/manifest/TWTezosMessageSigner.yaml b/codegen-v2/manifest/TWTezosMessageSigner.yaml new file mode 100644 index 00000000000..7019250a8d6 --- /dev/null +++ b/codegen-v2/manifest/TWTezosMessageSigner.yaml @@ -0,0 +1,92 @@ +name: TWTezosMessageSigner +structs: +- name: TWTezosMessageSigner + is_public: true + is_class: false +functions: +- name: TWTezosMessageSignerFormatMessage + is_public: true + is_static: true + params: + - name: message + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: url + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWTezosMessageSignerInputToPayload + is_public: true + is_static: true + params: + - name: message + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWTezosMessageSignerSignMessage + is_public: true + is_static: true + params: + - name: privateKey + type: + variant: struct + value: TWPrivateKey + is_constant: true + is_nullable: false + is_pointer: true + - name: message + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWTezosMessageSignerVerifyMessage + is_public: true + is_static: true + params: + - name: pubKey + type: + variant: struct + value: TWPublicKey + is_constant: true + is_nullable: false + is_pointer: true + - name: message + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: signature + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false diff --git a/codegen-v2/manifest/TWTezosProto.yaml b/codegen-v2/manifest/TWTezosProto.yaml new file mode 100644 index 00000000000..b6a974069bf --- /dev/null +++ b/codegen-v2/manifest/TWTezosProto.yaml @@ -0,0 +1,14 @@ +name: TWTezosProto +protos: +- TW_Tezos_Proto_SigningInput +- TW_Tezos_Proto_SigningOutput +- TW_Tezos_Proto_OperationList +- TW_Tezos_Proto_Operation +- TW_Tezos_Proto_FA12Parameters +- TW_Tezos_Proto_Txs +- TW_Tezos_Proto_TxObject +- TW_Tezos_Proto_FA2Parameters +- TW_Tezos_Proto_OperationParameters +- TW_Tezos_Proto_TransactionOperationData +- TW_Tezos_Proto_RevealOperationData +- TW_Tezos_Proto_DelegationOperationData diff --git a/codegen-v2/manifest/TWTheOpenNetworkProto.yaml b/codegen-v2/manifest/TWTheOpenNetworkProto.yaml new file mode 100644 index 00000000000..bbfb681aa75 --- /dev/null +++ b/codegen-v2/manifest/TWTheOpenNetworkProto.yaml @@ -0,0 +1,5 @@ +name: TWTheOpenNetworkProto +protos: +- TW_TheOpenNetwork_Proto_Transfer +- TW_TheOpenNetwork_Proto_SigningInput +- TW_TheOpenNetwork_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWThetaProto.yaml b/codegen-v2/manifest/TWThetaProto.yaml new file mode 100644 index 00000000000..4097843f588 --- /dev/null +++ b/codegen-v2/manifest/TWThetaProto.yaml @@ -0,0 +1,4 @@ +name: TWThetaProto +protos: +- TW_Theta_Proto_SigningInput +- TW_Theta_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWTransactionCompiler.yaml b/codegen-v2/manifest/TWTransactionCompiler.yaml new file mode 100644 index 00000000000..e31c93bd780 --- /dev/null +++ b/codegen-v2/manifest/TWTransactionCompiler.yaml @@ -0,0 +1,116 @@ +name: TWTransactionCompiler +structs: +- name: TWTransactionCompiler + is_public: true + is_class: false +functions: +- name: TWTransactionCompilerBuildInput + is_public: true + is_static: true + params: + - name: coinType + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: from + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: to + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: amount + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: asset + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: memo + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: chainId + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWTransactionCompilerPreImageHashes + is_public: true + is_static: true + params: + - name: coinType + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: txInputData + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true +- name: TWTransactionCompilerCompileWithSignatures + is_public: true + is_static: true + params: + - name: coinType + type: + variant: enum + value: TWCoinType + is_constant: false + is_nullable: false + is_pointer: false + - name: txInputData + type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true + - name: signatures + type: + variant: struct + value: TWDataVector + is_constant: true + is_nullable: false + is_pointer: true + - name: publicKeys + type: + variant: struct + value: TWDataVector + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: data + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/manifest/TWTransactionCompilerProto.yaml b/codegen-v2/manifest/TWTransactionCompilerProto.yaml new file mode 100644 index 00000000000..46dd9568d6f --- /dev/null +++ b/codegen-v2/manifest/TWTransactionCompilerProto.yaml @@ -0,0 +1,3 @@ +name: TWTransactionCompilerProto +protos: +- TW_TxCompiler_Proto_PreSigningOutput diff --git a/codegen-v2/manifest/TWTronMessageSigner.yaml b/codegen-v2/manifest/TWTronMessageSigner.yaml new file mode 100644 index 00000000000..12d9081737e --- /dev/null +++ b/codegen-v2/manifest/TWTronMessageSigner.yaml @@ -0,0 +1,56 @@ +name: TWTronMessageSigner +structs: +- name: TWTronMessageSigner + is_public: true + is_class: false +functions: +- name: TWTronMessageSignerSignMessage + is_public: true + is_static: true + params: + - name: privateKey + type: + variant: struct + value: TWPrivateKey + is_constant: true + is_nullable: false + is_pointer: true + - name: message + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +- name: TWTronMessageSignerVerifyMessage + is_public: true + is_static: true + params: + - name: pubKey + type: + variant: struct + value: TWPublicKey + is_constant: true + is_nullable: false + is_pointer: true + - name: message + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + - name: signature + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false diff --git a/codegen-v2/manifest/TWTronProto.yaml b/codegen-v2/manifest/TWTronProto.yaml new file mode 100644 index 00000000000..56bd975df44 --- /dev/null +++ b/codegen-v2/manifest/TWTronProto.yaml @@ -0,0 +1,21 @@ +name: TWTronProto +protos: +- TW_Tron_Proto_TransferContract +- TW_Tron_Proto_TransferAssetContract +- TW_Tron_Proto_TransferTRC20Contract +- TW_Tron_Proto_FreezeBalanceContract +- TW_Tron_Proto_FreezeBalanceV2Contract +- TW_Tron_Proto_UnfreezeBalanceV2Contract +- TW_Tron_Proto_WithdrawExpireUnfreezeContract +- TW_Tron_Proto_DelegateResourceContract +- TW_Tron_Proto_UnDelegateResourceContract +- TW_Tron_Proto_UnfreezeBalanceContract +- TW_Tron_Proto_UnfreezeAssetContract +- TW_Tron_Proto_VoteAssetContract +- TW_Tron_Proto_VoteWitnessContract +- TW_Tron_Proto_WithdrawBalanceContract +- TW_Tron_Proto_TriggerSmartContract +- TW_Tron_Proto_BlockHeader +- TW_Tron_Proto_Transaction +- TW_Tron_Proto_SigningInput +- TW_Tron_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWVeChainProto.yaml b/codegen-v2/manifest/TWVeChainProto.yaml new file mode 100644 index 00000000000..21acf417b22 --- /dev/null +++ b/codegen-v2/manifest/TWVeChainProto.yaml @@ -0,0 +1,5 @@ +name: TWVeChainProto +protos: +- TW_VeChain_Proto_Clause +- TW_VeChain_Proto_SigningInput +- TW_VeChain_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWWavesProto.yaml b/codegen-v2/manifest/TWWavesProto.yaml new file mode 100644 index 00000000000..03ff214aff8 --- /dev/null +++ b/codegen-v2/manifest/TWWavesProto.yaml @@ -0,0 +1,7 @@ +name: TWWavesProto +protos: +- TW_Waves_Proto_TransferMessage +- TW_Waves_Proto_LeaseMessage +- TW_Waves_Proto_CancelLeaseMessage +- TW_Waves_Proto_SigningInput +- TW_Waves_Proto_SigningOutput diff --git a/codegen-v2/manifest/TWZilliqaProto.yaml b/codegen-v2/manifest/TWZilliqaProto.yaml new file mode 100644 index 00000000000..671d3a1d432 --- /dev/null +++ b/codegen-v2/manifest/TWZilliqaProto.yaml @@ -0,0 +1,5 @@ +name: TWZilliqaProto +protos: +- TW_Zilliqa_Proto_Transaction +- TW_Zilliqa_Proto_SigningInput +- TW_Zilliqa_Proto_SigningOutput diff --git a/codegen-v2/src/codegen/cpp/blockchain_dispatcher_generator.rs b/codegen-v2/src/codegen/cpp/blockchain_dispatcher_generator.rs new file mode 100644 index 00000000000..0871d545995 --- /dev/null +++ b/codegen-v2/src/codegen/cpp/blockchain_dispatcher_generator.rs @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::codegen::cpp::cpp_source_directory; +use crate::registry::CoinItem; +use crate::utils::FileContent; +use crate::Result; +use std::path::PathBuf; + +const COIN_INCLUDES_END: &str = "end_of_coin_includes_marker_do_not_modify"; +const COIN_DISPATCHER_DECLARATIONS_END: &str = + "end_of_coin_dipatcher_declarations_marker_do_not_modify"; +const COIN_DISPATCHER_SWITCH_END: &str = "end_of_coin_dipatcher_switch_marker_do_not_modify"; + +fn dispatcher_coin_cpp_path() -> PathBuf { + cpp_source_directory().join("Coin.cpp") +} + +/// Represents `Coin.cpp`. +pub struct BlockchainDispatcherGenerator; + +impl BlockchainDispatcherGenerator { + pub fn generate_new_blockchain_type_dispatching(coin: &CoinItem) -> Result<()> { + let dispatcher_path = dispatcher_coin_cpp_path(); + println!("[EDIT] {dispatcher_path:?}"); + let mut file_content = FileContent::read(dispatcher_path)?; + + Self::generate_include_of_blockchain_entry(coin, &mut file_content)?; + Self::generate_blockchain_entry_constant(coin, &mut file_content)?; + Self::generate_blockchain_dispatcher_case(coin, &mut file_content)?; + + file_content.write() + } + + fn generate_include_of_blockchain_entry( + coin: &CoinItem, + file_content: &mut FileContent, + ) -> Result<()> { + let blockchain_type = coin.blockchain_type(); + + let mut line_marker = file_content.rfind_line(|line| line.contains(COIN_INCLUDES_END))?; + line_marker.push_line_before(format!(r#"#include "{blockchain_type}/Entry.h""#)); + + Ok(()) + } + + fn generate_blockchain_entry_constant( + coin: &CoinItem, + file_content: &mut FileContent, + ) -> Result<()> { + let blockchain_type = coin.blockchain_type(); + + let mut entries_region = + file_content.rfind_line(|line| line.contains(COIN_DISPATCHER_DECLARATIONS_END))?; + entries_region.push_line_before(format!("{blockchain_type}::Entry {blockchain_type}DP;")); + + Ok(()) + } + + fn generate_blockchain_dispatcher_case( + coin: &CoinItem, + file_content: &mut FileContent, + ) -> Result<()> { + let blockchain_type = coin.blockchain_type(); + + let mut entries_region = + file_content.rfind_line(|line| line.contains(COIN_DISPATCHER_SWITCH_END))?; + entries_region.push_line_before(format!( + " case TWBlockchain{blockchain_type}: entry = &{blockchain_type}DP; break;" + )); + + Ok(()) + } +} diff --git a/codegen-v2/src/codegen/cpp/entry_generator.rs b/codegen-v2/src/codegen/cpp/entry_generator.rs new file mode 100644 index 00000000000..639ee6c0488 --- /dev/null +++ b/codegen-v2/src/codegen/cpp/entry_generator.rs @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::codegen::cpp::cpp_source_directory; +use crate::codegen::template_generator::TemplateGenerator; +use crate::registry::CoinItem; +use crate::Result; +use std::fs; +use std::path::PathBuf; + +const ENTRY_HEADER_TEMPLATE: &str = include_str!("templates/Entry.h"); + +pub fn coin_source_directory(coin: &CoinItem) -> PathBuf { + cpp_source_directory().join(coin.blockchain_type()) +} + +pub struct EntryGenerator; + +impl EntryGenerator { + pub fn generate(coin: &CoinItem) -> Result { + let blockchain_dir = coin_source_directory(coin); + let entry_header_path = blockchain_dir.join("Entry.h"); + + if blockchain_dir.exists() { + println!("[SKIP] Entry file already exists: {blockchain_dir:?}"); + return Ok(blockchain_dir); + } + + fs::create_dir_all(&blockchain_dir)?; + + println!("[ADD] {entry_header_path:?}"); + TemplateGenerator::new(ENTRY_HEADER_TEMPLATE) + .write_to(entry_header_path.clone()) + .with_default_patterns(coin) + .write()?; + + Ok(entry_header_path) + } +} diff --git a/codegen-v2/src/codegen/cpp/mod.rs b/codegen-v2/src/codegen/cpp/mod.rs new file mode 100644 index 00000000000..1ef7188d86f --- /dev/null +++ b/codegen-v2/src/codegen/cpp/mod.rs @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::registry::CoinItem; +use std::env; +use std::path::PathBuf; + +pub mod blockchain_dispatcher_generator; +pub mod entry_generator; +pub mod new_blockchain; +pub mod new_cosmos_chain; +pub mod new_evmchain; +pub mod tw_any_address_tests_generator; +pub mod tw_any_signer_tests_generator; +pub mod tw_blockchain; +pub mod tw_coin_address_derivation_tests_generator; +pub mod tw_coin_type_generator; +pub mod tw_coin_type_tests_generator; + +pub fn cpp_source_directory() -> PathBuf { + PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()) + .join("..") + .join("src") +} + +pub fn cpp_include_directory() -> PathBuf { + PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()) + .join("..") + .join("include") + .join("TrustWalletCore") +} + +pub fn integration_tests_directory() -> PathBuf { + PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()) + .join("..") + .join("tests") +} + +pub fn coin_integration_tests_directory(coin: &CoinItem) -> PathBuf { + integration_tests_directory() + .join("chains") + .join(coin.coin_type()) +} + +pub fn cosmos_coin_integration_tests_directory(coin: &CoinItem) -> PathBuf { + integration_tests_directory() + .join("chains") + .join("Cosmos") + .join(coin.coin_type()) +} diff --git a/codegen-v2/src/codegen/cpp/new_blockchain.rs b/codegen-v2/src/codegen/cpp/new_blockchain.rs new file mode 100644 index 00000000000..df7c94c62bd --- /dev/null +++ b/codegen-v2/src/codegen/cpp/new_blockchain.rs @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::codegen::cpp::blockchain_dispatcher_generator::BlockchainDispatcherGenerator; +use crate::codegen::cpp::entry_generator::EntryGenerator; +use crate::codegen::cpp::tw_any_address_tests_generator::TWAnyAddressTestsGenerator; +use crate::codegen::cpp::tw_any_signer_tests_generator::TWAnySignerTestsGenerator; +use crate::codegen::cpp::tw_blockchain::TWBlockchainGenerator; +use crate::codegen::cpp::tw_coin_address_derivation_tests_generator::CoinAddressDerivationTestsGenerator; +use crate::codegen::cpp::tw_coin_type_generator::TWCoinTypeGenerator; +use crate::codegen::cpp::tw_coin_type_tests_generator::TWCoinTypeTestsGenerator; +use crate::registry::CoinItem; +use crate::Result; + +pub fn new_blockchain(coin: &CoinItem) -> Result<()> { + // Generate C++ files. + EntryGenerator::generate(coin)?; + + // Add the new coin type to the `TWCoinType` enum. + TWCoinTypeGenerator::generate_coin_type_variant(coin)?; + // Add the new blockchain type to the `TWBlockchain` enum. + TWBlockchainGenerator::generate_blockchain_type_variant(coin)?; + // Add the blockchain entry to the dispatcher `Coin.cpp`. + BlockchainDispatcherGenerator::generate_new_blockchain_type_dispatching(coin)?; + + // Add integration tests. + TWCoinTypeTestsGenerator::generate(coin)?; + TWAnyAddressTestsGenerator::generate(coin)?; + TWAnySignerTestsGenerator::generate(coin)?; + CoinAddressDerivationTestsGenerator::generate_new_coin_type_case(coin)?; + + Ok(()) +} diff --git a/codegen-v2/src/codegen/cpp/new_cosmos_chain.rs b/codegen-v2/src/codegen/cpp/new_cosmos_chain.rs new file mode 100644 index 00000000000..08c4406f994 --- /dev/null +++ b/codegen-v2/src/codegen/cpp/new_cosmos_chain.rs @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::codegen::cpp::tw_coin_address_derivation_tests_generator::CoinAddressDerivationTestsGenerator; +use crate::codegen::cpp::tw_coin_type_generator::TWCoinTypeGenerator; +use crate::codegen::cpp::tw_coin_type_tests_generator::TWCoinTypeTestsGenerator; +use crate::registry::CoinItem; +use crate::Result; + +pub fn new_cosmos_chain(coin: &CoinItem) -> Result<()> { + // Add the new coin type to the `TWCoinType` enum. + TWCoinTypeGenerator::generate_coin_type_variant(coin)?; + + // Add integration tests. + TWCoinTypeTestsGenerator::generate(coin)?; + CoinAddressDerivationTestsGenerator::generate_new_coin_type_case(coin)?; + + Ok(()) +} diff --git a/codegen-v2/src/codegen/cpp/new_evmchain.rs b/codegen-v2/src/codegen/cpp/new_evmchain.rs new file mode 100644 index 00000000000..2368c797ab3 --- /dev/null +++ b/codegen-v2/src/codegen/cpp/new_evmchain.rs @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::codegen::cpp::tw_coin_address_derivation_tests_generator::CoinAddressDerivationTestsGenerator; +use crate::codegen::cpp::tw_coin_type_generator::TWCoinTypeGenerator; +use crate::codegen::cpp::tw_coin_type_tests_generator::TWCoinTypeTestsGenerator; +use crate::registry::CoinItem; +use crate::Result; + +pub fn new_evmchain(coin: &CoinItem) -> Result<()> { + // Add the new coin type to the `TWCoinType` enum. + TWCoinTypeGenerator::generate_coin_type_variant(coin)?; + + // Add integration tests. + TWCoinTypeTestsGenerator::generate(coin)?; + CoinAddressDerivationTestsGenerator::generate_new_evm_coin_type_case(coin)?; + + Ok(()) +} diff --git a/codegen-v2/src/codegen/cpp/templates/Entry.h b/codegen-v2/src/codegen/cpp/templates/Entry.h new file mode 100644 index 00000000000..2c2520f9ccb --- /dev/null +++ b/codegen-v2/src/codegen/cpp/templates/Entry.h @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#pragma once + +#include "rust/RustCoinEntry.h" + +namespace TW::{BLOCKCHAIN} { + +/// Entry point for {BLOCKCHAIN} coin. +/// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file +class Entry : public Rust::RustCoinEntry { +}; + +} // namespace TW::{BLOCKCHAIN} + diff --git a/codegen-v2/src/codegen/cpp/templates/TWAnyAddressTests.cpp b/codegen-v2/src/codegen/cpp/templates/TWAnyAddressTests.cpp new file mode 100644 index 00000000000..139234a20e4 --- /dev/null +++ b/codegen-v2/src/codegen/cpp/templates/TWAnyAddressTests.cpp @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#include +#include "HexCoding.h" + +#include "TestUtilities.h" +#include + +using namespace TW; + +// TODO: Finalize tests + +TEST(TW{COIN_TYPE}, Address) { + // TODO: Finalize test implementation + + auto string = STRING("__ADD_VALID_ADDRESS_HERE__"); + auto addr = WRAP(TWAnyAddress, TWAnyAddressCreateWithString(string.get(), TWCoinType{COIN_TYPE})); + auto string2 = WRAPS(TWAnyAddressDescription(addr.get())); + EXPECT_TRUE(TWStringEqual(string.get(), string2.get())); + auto keyHash = WRAPD(TWAnyAddressData(addr.get())); + assertHexEqual(keyHash, "__CORRESPONDING_ADDRESS_DATA__"); +} diff --git a/codegen-v2/src/codegen/cpp/templates/TWAnySignerTests.cpp b/codegen-v2/src/codegen/cpp/templates/TWAnySignerTests.cpp new file mode 100644 index 00000000000..ce5b56f0467 --- /dev/null +++ b/codegen-v2/src/codegen/cpp/templates/TWAnySignerTests.cpp @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#include +#include "HexCoding.h" + +#include "TestUtilities.h" +#include + +using namespace TW; + +// TODO: Finalize tests + +TEST(TWAnySigner{COIN_TYPE}, Sign) { + // TODO: Finalize test implementation +} diff --git a/codegen-v2/src/codegen/cpp/templates/TWCoinTypeTests.cpp b/codegen-v2/src/codegen/cpp/templates/TWCoinTypeTests.cpp new file mode 100644 index 00000000000..8e917150dd4 --- /dev/null +++ b/codegen-v2/src/codegen/cpp/templates/TWCoinTypeTests.cpp @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#include "TestUtilities.h" +#include +#include + +TEST(TW{COIN_TYPE}CoinType, TWCoinType) { + const auto coin = TWCoinType{COIN_TYPE}; + const auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(coin)); + const auto id = WRAPS(TWCoinTypeConfigurationGetID(coin)); + const auto name = WRAPS(TWCoinTypeConfigurationGetName(coin)); + const auto txId = WRAPS(TWStringCreateWithUTF8Bytes("{EXPLORER_SAMPLE_TX}")); + const auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(coin, txId.get())); + const auto accId = WRAPS(TWStringCreateWithUTF8Bytes("{EXPLORER_SAMPLE_ACCOUNT}")); + const auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(coin, accId.get())); + + assertStringsEqual(id, "{COIN_ID}"); + assertStringsEqual(name, "{COIN_NAME}"); + assertStringsEqual(symbol, "{SYMBOL}"); + ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(coin), {DECIMALS}); + ASSERT_EQ(TWCoinTypeBlockchain(coin), TWBlockchain{BLOCKCHAIN}); + ASSERT_EQ(TWCoinTypeP2pkhPrefix(coin), {P2PKH_PREFIX}); + ASSERT_EQ(TWCoinTypeP2shPrefix(coin), {P2SH_PREFIX}); + ASSERT_EQ(TWCoinTypeStaticPrefix(coin), {STATIC_PREFIX}); + assertStringsEqual(txUrl, "{EXPLORER_URL}{EXPLORER_TX_PATH}{EXPLORER_SAMPLE_TX}"); + assertStringsEqual(accUrl, "{EXPLORER_URL}{EXPLORER_ACCOUNT_PATH}{EXPLORER_SAMPLE_ACCOUNT}"); +} diff --git a/codegen-v2/src/codegen/cpp/tw_any_address_tests_generator.rs b/codegen-v2/src/codegen/cpp/tw_any_address_tests_generator.rs new file mode 100644 index 00000000000..599ea265235 --- /dev/null +++ b/codegen-v2/src/codegen/cpp/tw_any_address_tests_generator.rs @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::codegen::cpp::coin_integration_tests_directory; +use crate::codegen::template_generator::TemplateGenerator; +use crate::registry::CoinItem; +use crate::Result; +use std::fs; +use std::path::PathBuf; + +const TW_ANY_ADDRESS_TESTS_TEMPLATE: &str = include_str!("templates/TWAnyAddressTests.cpp"); + +pub fn tw_any_address_tests_path(coin: &CoinItem) -> PathBuf { + coin_integration_tests_directory(coin).join("TWAnyAddressTests.cpp") +} + +pub struct TWAnyAddressTestsGenerator; + +impl TWAnyAddressTestsGenerator { + pub fn generate(coin: &CoinItem) -> Result<()> { + let coin_tests_dir = coin_integration_tests_directory(coin); + let tw_any_address_tests_path = coin_tests_dir.join("TWAnyAddressTests.cpp"); + + fs::create_dir_all(coin_tests_dir)?; + if tw_any_address_tests_path.exists() { + println!("[SKIP] {tw_any_address_tests_path:?} already exists"); + return Ok(()); + } + + println!("[ADD] {tw_any_address_tests_path:?}"); + TemplateGenerator::new(TW_ANY_ADDRESS_TESTS_TEMPLATE) + .write_to(tw_any_address_tests_path) + .with_default_patterns(coin) + .write()?; + + Ok(()) + } +} diff --git a/codegen-v2/src/codegen/cpp/tw_any_signer_tests_generator.rs b/codegen-v2/src/codegen/cpp/tw_any_signer_tests_generator.rs new file mode 100644 index 00000000000..9ea4337616a --- /dev/null +++ b/codegen-v2/src/codegen/cpp/tw_any_signer_tests_generator.rs @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::codegen::cpp::coin_integration_tests_directory; +use crate::codegen::template_generator::TemplateGenerator; +use crate::registry::CoinItem; +use crate::Result; +use std::fs; +use std::path::PathBuf; + +const TW_ANY_SIGNER_TESTS_TEMPLATE: &str = include_str!("templates/TWAnySignerTests.cpp"); + +pub fn tw_any_signer_tests_path(coin: &CoinItem) -> PathBuf { + coin_integration_tests_directory(coin).join("TWAnySignerTests.cpp") +} + +pub struct TWAnySignerTestsGenerator; + +impl TWAnySignerTestsGenerator { + pub fn generate(coin: &CoinItem) -> Result<()> { + let coin_tests_dir = coin_integration_tests_directory(coin); + let tw_any_signer_tests_path = coin_tests_dir.join("TWAnySignerTests.cpp"); + + fs::create_dir_all(coin_tests_dir)?; + if tw_any_signer_tests_path.exists() { + println!("[SKIP] {tw_any_signer_tests_path:?} already exists"); + return Ok(()); + } + + println!("[ADD] {tw_any_signer_tests_path:?}"); + TemplateGenerator::new(TW_ANY_SIGNER_TESTS_TEMPLATE) + .write_to(tw_any_signer_tests_path) + .with_default_patterns(coin) + .write()?; + + Ok(()) + } +} diff --git a/codegen-v2/src/codegen/cpp/tw_blockchain.rs b/codegen-v2/src/codegen/cpp/tw_blockchain.rs new file mode 100644 index 00000000000..a76a73ab055 --- /dev/null +++ b/codegen-v2/src/codegen/cpp/tw_blockchain.rs @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::codegen::cpp::cpp_include_directory; +use crate::registry::CoinItem; +use crate::utils::FileContent; +use crate::Result; +use std::path::PathBuf; + +/// An offset because of removed blockchain enum types. +const BLOCKCHAIN_TYPE_OFFSET: usize = 2; + +pub fn tw_blockchain_path() -> PathBuf { + cpp_include_directory().join("TWBlockchain.h") +} + +/// Represents `TWBlockchain.h`. +pub struct TWBlockchainGenerator; + +impl TWBlockchainGenerator { + pub fn generate_blockchain_type_variant(coin: &CoinItem) -> Result<()> { + let coin_type = coin.blockchain_type(); + let tw_blockchain_type_path = tw_blockchain_path(); + + println!("[EDIT] {tw_blockchain_type_path:?}"); + let mut tw_blockchain_type_rs = FileContent::read(tw_blockchain_type_path)?; + + { + let mut enum_region = + tw_blockchain_type_rs.find_region_with_prefix(" TWBlockchain")?; + // Add an offset because of removed blockchain enum types. + let new_blockchain_id = enum_region.count_lines() + BLOCKCHAIN_TYPE_OFFSET; + enum_region.push_line(format!( + " TWBlockchain{coin_type} = {new_blockchain_id}," + )); + } + + tw_blockchain_type_rs.write() + } +} diff --git a/codegen-v2/src/codegen/cpp/tw_coin_address_derivation_tests_generator.rs b/codegen-v2/src/codegen/cpp/tw_coin_address_derivation_tests_generator.rs new file mode 100644 index 00000000000..91321dffb05 --- /dev/null +++ b/codegen-v2/src/codegen/cpp/tw_coin_address_derivation_tests_generator.rs @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::codegen::cpp::integration_tests_directory; +use crate::registry::CoinItem; +use crate::utils::FileContent; +use crate::Result; +use std::path::PathBuf; + +const COIN_ADDRESS_DERIVATION_TESTS_END: &str = + "end_of_coin_address_derivation_tests_marker_do_not_modify"; +const EVM_ADDRESS_DERIVATION_TESTS_END: &str = + "end_of_evm_address_derivation_tests_marker_do_not_modify"; + +pub fn coin_address_derivation_tests_path() -> PathBuf { + integration_tests_directory() + .join("common") + .join("CoinAddressDerivationTests.cpp") +} + +/// Represents `CoinAddressDerivationTests.cpp`. +pub struct CoinAddressDerivationTestsGenerator; + +impl CoinAddressDerivationTestsGenerator { + pub fn generate_new_coin_type_case(coin: &CoinItem) -> Result<()> { + let coin_type = coin.coin_type(); + let test_path = coin_address_derivation_tests_path(); + println!("[EDIT] {test_path:?}"); + + let mut coin_address_derivation_test_rs = FileContent::read(test_path)?; + + { + let mut switch_case_region = coin_address_derivation_test_rs + .rfind_line(|line| line.contains(COIN_ADDRESS_DERIVATION_TESTS_END))?; + + #[rustfmt::skip] + let test_case = format!( +r#" case TWCoinType{coin_type}: + EXPECT_EQ(address, "__TODO__"); + break;"# +); + + switch_case_region.push_paragraph_before(test_case); + } + + coin_address_derivation_test_rs.write() + } + + pub fn generate_new_evm_coin_type_case(coin: &CoinItem) -> Result<()> { + let coin_type = coin.coin_type(); + let test_path = coin_address_derivation_tests_path(); + println!("[EDIT] {test_path:?}"); + + let mut evm_address_derivation_test_rs = FileContent::read(test_path)?; + + { + let mut switch_case_region = evm_address_derivation_test_rs + .rfind_line(|line| line.contains(EVM_ADDRESS_DERIVATION_TESTS_END))?; + switch_case_region.push_line_before(format!(" case TWCoinType{coin_type}:")); + } + + evm_address_derivation_test_rs.write() + } +} diff --git a/codegen-v2/src/codegen/cpp/tw_coin_type_generator.rs b/codegen-v2/src/codegen/cpp/tw_coin_type_generator.rs new file mode 100644 index 00000000000..0271838af03 --- /dev/null +++ b/codegen-v2/src/codegen/cpp/tw_coin_type_generator.rs @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::codegen::cpp::cpp_include_directory; +use crate::registry::CoinItem; +use crate::utils::FileContent; +use crate::Result; +use std::path::PathBuf; + +const TW_COIN_TYPE_END: &str = "end_of_tw_coin_type_marker_do_not_modify"; + +pub fn tw_coin_type_path() -> PathBuf { + cpp_include_directory().join("TWCoinType.h") +} + +/// Represents `TWCoinType.h`. +pub struct TWCoinTypeGenerator; + +impl TWCoinTypeGenerator { + pub fn generate_coin_type_variant(coin: &CoinItem) -> Result<()> { + let coin_type = coin.coin_type(); + let coin_id_number = coin.coin_id_number; + let tw_coin_type_file_path = tw_coin_type_path(); + + println!("[EDIT] {tw_coin_type_file_path:?}"); + let mut tw_coin_type_rs = FileContent::read(tw_coin_type_file_path)?; + + { + let mut enum_region = + tw_coin_type_rs.rfind_line(|line| line.contains(TW_COIN_TYPE_END))?; + enum_region.push_line_before(format!(" TWCoinType{coin_type} = {coin_id_number},")); + } + + tw_coin_type_rs.write() + } +} diff --git a/codegen-v2/src/codegen/cpp/tw_coin_type_tests_generator.rs b/codegen-v2/src/codegen/cpp/tw_coin_type_tests_generator.rs new file mode 100644 index 00000000000..a3f9f50c5da --- /dev/null +++ b/codegen-v2/src/codegen/cpp/tw_coin_type_tests_generator.rs @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::codegen::cpp::{ + coin_integration_tests_directory, cosmos_coin_integration_tests_directory, +}; +use crate::codegen::template_generator::TemplateGenerator; +use crate::registry::CoinItem; +use crate::Result; +use std::fs; +use std::path::PathBuf; + +const TW_COIN_TYPE_TESTS_TEMPLATE: &str = include_str!("templates/TWCoinTypeTests.cpp"); + +pub fn tw_coin_type_tests_path(coin: &CoinItem) -> PathBuf { + coin_integration_tests_directory(coin).join("TWCoinTypeTests.cpp") +} + +pub struct TWCoinTypeTestsGenerator; + +impl TWCoinTypeTestsGenerator { + pub fn generate(coin: &CoinItem) -> Result<()> { + let coin_tests_dir = coin_integration_tests_directory(coin); + Self::generate_at(coin, coin_tests_dir) + } + + pub fn generate_cosmos(coin: &CoinItem) -> Result<()> { + let cosmos_coin_tests_dir = cosmos_coin_integration_tests_directory(coin); + Self::generate_at(coin, cosmos_coin_tests_dir) + } + + fn generate_at(coin: &CoinItem, coin_tests_dir: PathBuf) -> Result<()> { + let tw_coin_type_tests_path = coin_tests_dir.join("TWCoinTypeTests.cpp"); + + fs::create_dir(coin_tests_dir)?; + if tw_coin_type_tests_path.exists() { + println!("[SKIP] {tw_coin_type_tests_path:?} already exists"); + return Ok(()); + } + + println!("[ADD] {tw_coin_type_tests_path:?}"); + TemplateGenerator::new(TW_COIN_TYPE_TESTS_TEMPLATE) + .write_to(tw_coin_type_tests_path) + .with_default_patterns(coin) + .write()?; + + Ok(()) + } +} diff --git a/codegen-v2/src/codegen/mod.rs b/codegen-v2/src/codegen/mod.rs new file mode 100644 index 00000000000..1d8522e6b9f --- /dev/null +++ b/codegen-v2/src/codegen/mod.rs @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +pub mod cpp; +pub mod proto; +pub mod rust; +pub mod swift; +pub mod template_generator; diff --git a/codegen-v2/src/codegen/proto/mod.rs b/codegen-v2/src/codegen/proto/mod.rs new file mode 100644 index 00000000000..47d3e1a2dd5 --- /dev/null +++ b/codegen-v2/src/codegen/proto/mod.rs @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use std::env; +use std::path::PathBuf; + +pub mod new_blockchain; +pub mod proto_generator; + +pub fn proto_source_directory() -> PathBuf { + PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()) + .join("..") + .join("src") + .join("proto") +} diff --git a/codegen-v2/src/codegen/proto/new_blockchain.rs b/codegen-v2/src/codegen/proto/new_blockchain.rs new file mode 100644 index 00000000000..9e5f51a5387 --- /dev/null +++ b/codegen-v2/src/codegen/proto/new_blockchain.rs @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::codegen::proto::proto_generator::ProtoGenerator; +use crate::registry::CoinItem; +use crate::Result; + +pub fn new_blockchain(coin: &CoinItem) -> Result<()> { + ProtoGenerator::generate(coin) +} diff --git a/codegen-v2/src/codegen/proto/proto_generator.rs b/codegen-v2/src/codegen/proto/proto_generator.rs new file mode 100644 index 00000000000..f2cdfd94a86 --- /dev/null +++ b/codegen-v2/src/codegen/proto/proto_generator.rs @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::codegen::proto::proto_source_directory; +use crate::codegen::template_generator::TemplateGenerator; +use crate::registry::CoinItem; +use crate::Result; +use std::path::PathBuf; + +const PROTO_TEMPLATE: &str = include_str!("templates/Blockchain.proto"); + +pub fn blockchain_proto_path(coin: &CoinItem) -> PathBuf { + let blockchain_type = coin.blockchain_type(); + proto_source_directory().join(format!("{blockchain_type}.proto")) +} + +pub struct ProtoGenerator; + +impl ProtoGenerator { + pub fn generate(coin: &CoinItem) -> Result<()> { + let proto_path = blockchain_proto_path(coin); + + if proto_path.exists() { + println!("[SKIP] Protobuf interface already exists: {proto_path:?}"); + return Ok(()); + } + + println!("[ADD] {proto_path:?}"); + TemplateGenerator::new(PROTO_TEMPLATE) + .write_to(proto_path) + .with_default_patterns(coin) + .write()?; + + Ok(()) + } +} diff --git a/codegen-v2/src/codegen/proto/templates/Blockchain.proto b/codegen-v2/src/codegen/proto/templates/Blockchain.proto new file mode 100644 index 00000000000..9c4c6e34478 --- /dev/null +++ b/codegen-v2/src/codegen/proto/templates/Blockchain.proto @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +syntax = "proto3"; + +package TW.{BLOCKCHAIN}.Proto; +option java_package = "wallet.core.jni.proto"; + +import "Common.proto"; + +// TODO: typical balance transfer, add more fields needed to sign +message TransferMessage { + int64 amount = 1; + int64 fee = 2; + string to = 3; +} + +// TODO: Input data necessary to create a signed transaction. +message SigningInput { + bytes private_key = 1; + + oneof message_oneof { + TransferMessage transfer = 2; + } +} + +// Transaction signing output. +message SigningOutput { + // Signed and encoded transaction bytes. + bytes encoded = 1; + + // A possible error, `OK` if none. + Common.Proto.SigningError error = 2; + + string error_message = 3; +} diff --git a/codegen-v2/src/codegen/rust/blockchain_dispatcher_generator.rs b/codegen-v2/src/codegen/rust/blockchain_dispatcher_generator.rs new file mode 100644 index 00000000000..92f98bac940 --- /dev/null +++ b/codegen-v2/src/codegen/rust/blockchain_dispatcher_generator.rs @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::codegen::rust::coin_registry_directory; +use crate::registry::CoinItem; +use crate::utils::FileContent; +use crate::Result; +use std::path::PathBuf; + +const BLOCKCHAIN_ENTRIES_START: &str = "start_of_blockchain_entries"; +const BLOCKCHAIN_ENTRIES_END: &str = "end_of_blockchain_entries"; +const BLOCKCHAIN_DISPATCHER_START: &str = "start_of_blockchain_dispatcher"; +const BLOCKCHAIN_DISPATCHER_END: &str = "end_of_blockchain_dispatcher"; + +pub fn dispatcher_path() -> PathBuf { + coin_registry_directory().join("src").join("dispatcher.rs") +} + +pub struct BlockchainDispatcherGenerator; + +impl BlockchainDispatcherGenerator { + pub fn generate_new_blockchain_type_dispatching(coin: &CoinItem) -> Result<()> { + let dispatcher_rs_path = dispatcher_path(); + println!("[EDIT] {dispatcher_rs_path:?}"); + let mut dispatcher_rs = FileContent::read(dispatcher_rs_path)?; + + Self::generate_use_of_blockchain_entry(coin, &mut dispatcher_rs)?; + Self::generate_blockchain_entry_constant(coin, &mut dispatcher_rs)?; + Self::generate_blockchain_dispatch(coin, &mut dispatcher_rs)?; + + dispatcher_rs.write() + } + + fn generate_use_of_blockchain_entry( + coin: &CoinItem, + file_content: &mut FileContent, + ) -> Result<()> { + let import_pattern = "use "; + let blockchain_entry = coin.blockchain_entry(); + let tw_crate_name = coin.id.to_tw_crate_name(); + + let mut last_entry = file_content.rfind_line(|line| line.contains(import_pattern))?; + last_entry.push_line_after(format!("use {tw_crate_name}::entry::{blockchain_entry};")); + + Ok(()) + } + + fn generate_blockchain_entry_constant( + coin: &CoinItem, + file_content: &mut FileContent, + ) -> Result<()> { + let blockchain_entry = coin.blockchain_entry(); + let blockchain_entry_const = coin.blockchain_entry_upper_snake(); + + let mut entries_region = file_content + .find_region_with_comments(BLOCKCHAIN_ENTRIES_START, BLOCKCHAIN_ENTRIES_END)?; + entries_region.push_line(format!( + "const {blockchain_entry_const}: {blockchain_entry} = {blockchain_entry};" + )); + entries_region.sort(); + + Ok(()) + } + + fn generate_blockchain_dispatch(coin: &CoinItem, file_content: &mut FileContent) -> Result<()> { + let blockchain_type = coin.blockchain_type(); + let blockchain_entry_const = coin.blockchain_entry_upper_snake(); + + let mut dispatcher_region = file_content + .find_region_with_comments(BLOCKCHAIN_DISPATCHER_START, BLOCKCHAIN_DISPATCHER_END)?; + dispatcher_region.push_line(format!( + " BlockchainType::{blockchain_type} => Ok(&{blockchain_entry_const})," + )); + dispatcher_region.sort(); + + Ok(()) + } +} diff --git a/codegen-v2/src/codegen/rust/blockchain_type_generator.rs b/codegen-v2/src/codegen/rust/blockchain_type_generator.rs new file mode 100644 index 00000000000..4895bf8a923 --- /dev/null +++ b/codegen-v2/src/codegen/rust/blockchain_type_generator.rs @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::codegen::rust::coin_registry_directory; +use crate::registry::CoinItem; +use crate::utils::FileContent; +use crate::Result; +use std::path::PathBuf; + +const BLOCKCHAIN_TYPE_START: &str = "start_of_blockchain_type"; +const BLOCKCHAIN_TYPE_END: &str = "end_of_blockchain_type"; + +pub fn blockchain_type_path() -> PathBuf { + coin_registry_directory() + .join("src") + .join("blockchain_type.rs") +} + +/// Represents `BlockchainType` enum generator. +pub struct BlockchainTypeGenerator; + +impl BlockchainTypeGenerator { + pub fn add_new_blockchain_type(coin: &CoinItem) -> Result<()> { + let blockchain_type_rs_path = blockchain_type_path(); + let blockchain_type = coin.blockchain_type(); + + println!("[EDIT] {blockchain_type_rs_path:?}"); + let mut blockchain_type_rs = FileContent::read(blockchain_type_rs_path)?; + + { + let mut enum_region = blockchain_type_rs + .find_region_with_comments(BLOCKCHAIN_TYPE_START, BLOCKCHAIN_TYPE_END)?; + enum_region.push_line(format!(" {blockchain_type},")); + enum_region.sort(); + } + + blockchain_type_rs.write() + } +} diff --git a/codegen-v2/src/codegen/rust/coin_address_derivation_test_generator.rs b/codegen-v2/src/codegen/rust/coin_address_derivation_test_generator.rs new file mode 100644 index 00000000000..4d339cb05ad --- /dev/null +++ b/codegen-v2/src/codegen/rust/coin_address_derivation_test_generator.rs @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::codegen::rust::tw_tests_directory; +use crate::registry::CoinItem; +use crate::utils::FileContent; +use crate::Result; +use std::path::PathBuf; + +const COIN_ADDRESS_DERIVATION_TEST_END: &str = + "end_of_coin_address_derivation_tests_marker_do_not_modify"; +const EVM_ADDRESS_DERIVATION_TEST_END: &str = + "end_of_evm_address_derivation_tests_marker_do_not_modify"; + +pub fn coin_address_derivation_test_path() -> PathBuf { + tw_tests_directory() + .join("tests") + .join("coin_address_derivation_test.rs") +} + +pub struct CoinAddressDerivationTestGenerator; + +impl CoinAddressDerivationTestGenerator { + pub fn generate_new_coin_type_case(coin: &CoinItem) -> Result<()> { + let test_path = coin_address_derivation_test_path(); + let coin_type = coin.coin_type(); + + println!("[EDIT] {test_path:?}"); + let mut coin_address_derivation_test_rs = FileContent::read(test_path)?; + + { + let mut end_of_test = coin_address_derivation_test_rs + .rfind_line(|line| line.contains(COIN_ADDRESS_DERIVATION_TEST_END))?; + end_of_test.push_line_before(format!(" CoinType::{coin_type} => todo!(),")); + } + + coin_address_derivation_test_rs.write() + } + + pub fn generate_new_evm_coin_type_case(coin: &CoinItem) -> Result<()> { + let test_path = coin_address_derivation_test_path(); + let coin_type = coin.coin_type(); + + println!("[EDIT] {test_path:?}"); + let mut coin_address_derivation_test_rs = FileContent::read(test_path)?; + + { + let mut end_of_test = coin_address_derivation_test_rs + .rfind_line(|line| line.contains(EVM_ADDRESS_DERIVATION_TEST_END))?; + end_of_test.push_line_before(format!(" | CoinType::{coin_type}")); + } + + coin_address_derivation_test_rs.write() + } +} diff --git a/codegen-v2/src/codegen/rust/coin_crate.rs b/codegen-v2/src/codegen/rust/coin_crate.rs new file mode 100644 index 00000000000..0e1b133f171 --- /dev/null +++ b/codegen-v2/src/codegen/rust/coin_crate.rs @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::codegen::rust::chains_directory; +use crate::codegen::template_generator::TemplateGenerator; +use crate::coin_id::CoinId; +use crate::registry::CoinItem; +use crate::Result; +use std::fs; +use std::path::PathBuf; + +const BLOCKCHAIN_ADDRESS_TEMPLATE: &str = include_str!("templates/blockchain_crate/address.rs"); +const BLOCKCHAIN_COMPILER_TEMPLATE: &str = include_str!("templates/blockchain_crate/compiler.rs"); +const BLOCKCHAIN_ENTRY_TEMPLATE: &str = include_str!("templates/blockchain_crate/entry.rs"); +const BLOCKCHAIN_MANIFEST_TEMPLATE: &str = include_str!("templates/blockchain_crate/Cargo.toml"); +const BLOCKCHAIN_LIB_TEMPLATE: &str = include_str!("templates/blockchain_crate/lib.rs"); +const BLOCKCHAIN_SIGNER_TEMPLATE: &str = include_str!("templates/blockchain_crate/signer.rs"); + +pub fn coin_source_directory(id: &CoinId) -> PathBuf { + chains_directory().join(id.to_tw_crate_name()) +} + +pub struct CoinCrate { + coin: CoinItem, +} + +impl CoinCrate { + pub fn new(coin: CoinItem) -> CoinCrate { + CoinCrate { coin } + } + + /// Creates a Cargo crate with `entry.rs` file. + /// Returns the path to the create crate. + pub fn create(self) -> Result { + let blockchain_path = coin_source_directory(&self.coin.id); + let blockchain_toml_path = blockchain_path.join("Cargo.toml"); + + let blockchain_src_path = blockchain_path.join("src"); + let blockchain_lib_rs_path = blockchain_src_path.join("lib.rs"); + let blockchain_entry_path = blockchain_src_path.join("entry.rs"); + let blockchain_compiler_path = blockchain_src_path.join("compiler.rs"); + let blockchain_address_rs_path = blockchain_src_path.join("address.rs"); + let blockchain_signer_rs_path = blockchain_src_path.join("signer.rs"); + + if blockchain_path.exists() { + let tw_crate_name = self.coin.id.to_tw_crate_name(); + println!( + "[SKIP] '{tw_crate_name}' blockchain crate already exists: {blockchain_path:?}" + ); + return Ok(blockchain_path); + } + + fs::create_dir_all(&blockchain_path)?; + fs::create_dir_all(&blockchain_src_path)?; + + println!("[ADD] {blockchain_toml_path:?}"); + TemplateGenerator::new(BLOCKCHAIN_MANIFEST_TEMPLATE) + .write_to(blockchain_toml_path) + .with_default_patterns(&self.coin) + .write()?; + + println!("[ADD] {blockchain_lib_rs_path:?}"); + TemplateGenerator::new(BLOCKCHAIN_LIB_TEMPLATE) + .write_to(blockchain_lib_rs_path) + .with_default_patterns(&self.coin) + .write()?; + + println!("[ADD] {blockchain_entry_path:?}"); + TemplateGenerator::new(BLOCKCHAIN_ENTRY_TEMPLATE) + .write_to(blockchain_entry_path) + .with_default_patterns(&self.coin) + .write()?; + + println!("[ADD] {blockchain_compiler_path:?}"); + TemplateGenerator::new(BLOCKCHAIN_COMPILER_TEMPLATE) + .write_to(blockchain_compiler_path) + .with_default_patterns(&self.coin) + .write()?; + + println!("[ADD] {blockchain_address_rs_path:?}"); + TemplateGenerator::new(BLOCKCHAIN_ADDRESS_TEMPLATE) + .write_to(blockchain_address_rs_path) + .with_default_patterns(&self.coin) + .write()?; + + println!("[ADD] {blockchain_signer_rs_path:?}"); + TemplateGenerator::new(BLOCKCHAIN_SIGNER_TEMPLATE) + .write_to(blockchain_signer_rs_path) + .with_default_patterns(&self.coin) + .write()?; + + Ok(blockchain_path) + } +} diff --git a/codegen-v2/src/codegen/rust/coin_integration_tests.rs b/codegen-v2/src/codegen/rust/coin_integration_tests.rs new file mode 100644 index 00000000000..067462aacfc --- /dev/null +++ b/codegen-v2/src/codegen/rust/coin_integration_tests.rs @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::codegen::rust::tw_tests_directory; +use crate::codegen::template_generator::TemplateGenerator; +use crate::coin_id::CoinId; +use crate::registry::CoinItem; +use crate::utils::FileContent; +use crate::Result; +use std::fs; +use std::path::PathBuf; + +const ADDRESS_TESTS_TEMPLATE: &str = include_str!("templates/integration_tests/address_tests.rs"); +const COSMOS_ADDRESS_TESTS_TEMPLATE: &str = + include_str!("templates/integration_tests/cosmos_address_tests.rs"); +const COMPILE_TESTS_TEMPLATE: &str = include_str!("templates/integration_tests/compile_tests.rs"); +const MOD_TESTS_TEMPLATE: &str = include_str!("templates/integration_tests/mod.rs"); +const MOD_ADDRESS_TESTS_TEMPLATE: &str = include_str!("templates/integration_tests/mod_address.rs"); +const SIGN_TESTS_TEMPLATE: &str = include_str!("templates/integration_tests/sign_tests.rs"); + +pub fn chains_integration_tests_directory() -> PathBuf { + tw_tests_directory().join("tests").join("chains") +} + +pub fn coin_integration_tests_directory(id: &CoinId) -> PathBuf { + chains_integration_tests_directory().join(id.as_str()) +} + +pub fn coin_address_derivation_test_path() -> PathBuf { + tw_tests_directory() + .join("tests") + .join("coin_address_derivation_test.rs") +} + +pub struct CoinIntegrationTests { + coin: CoinItem, +} + +impl CoinIntegrationTests { + pub fn new(coin: CoinItem) -> CoinIntegrationTests { + CoinIntegrationTests { coin } + } + + pub fn create(self) -> Result { + let blockchain_tests_path = self.coin_tests_directory(); + if blockchain_tests_path.exists() { + println!("[SKIP] integration tests already exists: {blockchain_tests_path:?}"); + return Ok(blockchain_tests_path); + } + + fs::create_dir_all(&blockchain_tests_path)?; + + self.list_blockchain_in_chains_mod()?; + self.create_address_tests(ADDRESS_TESTS_TEMPLATE)?; + self.create_compile_tests()?; + self.create_sign_tests()?; + self.create_chain_tests_mod_rs(MOD_TESTS_TEMPLATE)?; + + Ok(blockchain_tests_path) + } + + /// For a Cosmos chain, it's enough to create address tests only, but with additional Bech32 prefix tests. + pub fn create_cosmos(self) -> Result { + let blockchain_tests_path = self.coin_tests_directory(); + if blockchain_tests_path.exists() { + println!("[SKIP] integration tests already exists: {blockchain_tests_path:?}"); + return Ok(blockchain_tests_path); + } + + fs::create_dir_all(&blockchain_tests_path)?; + + self.list_blockchain_in_chains_mod()?; + self.create_address_tests(COSMOS_ADDRESS_TESTS_TEMPLATE)?; + // `mod.rs` should contain `{COIN_TYPE}_address` module only. + self.create_chain_tests_mod_rs(MOD_ADDRESS_TESTS_TEMPLATE)?; + + Ok(blockchain_tests_path) + } + + fn coin_tests_directory(&self) -> PathBuf { + coin_integration_tests_directory(&self.coin.id) + } + + fn create_address_tests(&self, template: &'static str) -> Result<()> { + let coin_id = self.coin.id.as_str(); + let address_tests_path = self + .coin_tests_directory() + .join(format!("{coin_id}_address.rs")); + + println!("[ADD] {address_tests_path:?}"); + TemplateGenerator::new(template) + .write_to(address_tests_path) + .with_default_patterns(&self.coin) + .write() + } + + fn create_compile_tests(&self) -> Result<()> { + let coin_id = self.coin.id.as_str(); + let compile_tests_path = self + .coin_tests_directory() + .join(format!("{coin_id}_compile.rs")); + + println!("[ADD] {compile_tests_path:?}"); + TemplateGenerator::new(COMPILE_TESTS_TEMPLATE) + .write_to(compile_tests_path) + .with_default_patterns(&self.coin) + .write() + } + + fn create_sign_tests(&self) -> Result<()> { + let coin_id = self.coin.id.as_str(); + let sign_tests_path = self + .coin_tests_directory() + .join(format!("{coin_id}_sign.rs")); + + println!("[ADD] {sign_tests_path:?}"); + TemplateGenerator::new(SIGN_TESTS_TEMPLATE) + .write_to(sign_tests_path) + .with_default_patterns(&self.coin) + .write() + } + + fn create_chain_tests_mod_rs(&self, template: &'static str) -> Result<()> { + let blockchain_tests_mod_path = self.coin_tests_directory().join("mod.rs"); + + println!("[ADD] {blockchain_tests_mod_path:?}"); + TemplateGenerator::new(template) + .write_to(blockchain_tests_mod_path) + .with_default_patterns(&self.coin) + .write() + } + + fn list_blockchain_in_chains_mod(&self) -> Result<()> { + let chains_mod_path = chains_integration_tests_directory().join("mod.rs"); + let chain_id = self.coin.id.as_str(); + + println!("[EDIT] {chains_mod_path:?}"); + let mut chains_mod_rs = FileContent::read(chains_mod_path)?; + + { + let mod_pattern = "mod "; + let mut mod_region = chains_mod_rs.find_region_with_prefix(mod_pattern)?; + mod_region.push_line(format!("mod {chain_id};")); + mod_region.sort(); + } + + chains_mod_rs.write() + } +} diff --git a/codegen-v2/src/codegen/rust/coin_registry_manifest_generator.rs b/codegen-v2/src/codegen/rust/coin_registry_manifest_generator.rs new file mode 100644 index 00000000000..2a63e90e336 --- /dev/null +++ b/codegen-v2/src/codegen/rust/coin_registry_manifest_generator.rs @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::codegen::rust::coin_registry_directory; +use crate::codegen::rust::toml_editor::Dependencies; +use crate::registry::CoinItem; +use crate::Result; +use std::path::Path; + +pub struct CoinRegistryManifestGenerator; + +impl CoinRegistryManifestGenerator { + pub fn add_dependency(coin: &CoinItem, path_to_new_blockchain_crate: &Path) -> Result<()> { + let path_to_cargo_manifest = coin_registry_directory().join("Cargo.toml"); + println!("[EDIT] {path_to_cargo_manifest:?}"); + Dependencies::new(path_to_cargo_manifest) + .insert_dependency(&coin.id.to_tw_crate_name(), path_to_new_blockchain_crate) + } +} diff --git a/codegen-v2/src/codegen/rust/mod.rs b/codegen-v2/src/codegen/rust/mod.rs new file mode 100644 index 00000000000..a9de11f38fa --- /dev/null +++ b/codegen-v2/src/codegen/rust/mod.rs @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use std::env; +use std::path::PathBuf; + +pub mod blockchain_dispatcher_generator; +pub mod blockchain_type_generator; +pub mod coin_address_derivation_test_generator; +pub mod coin_crate; +pub mod coin_integration_tests; +pub mod coin_registry_manifest_generator; +pub mod new_blockchain; +pub mod new_cosmos_chain; +pub mod new_evmchain; +pub mod toml_editor; + +pub fn rust_source_directory() -> PathBuf { + PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()) + .join("..") + .join("rust") +} + +pub fn chains_directory() -> PathBuf { + rust_source_directory().join("chains") +} + +pub fn tw_tests_directory() -> PathBuf { + rust_source_directory().join("tw_tests") +} + +pub fn workspace_toml_path() -> PathBuf { + rust_source_directory().join("Cargo.toml") +} + +pub fn coin_registry_directory() -> PathBuf { + rust_source_directory().join("tw_coin_registry") +} diff --git a/codegen-v2/src/codegen/rust/new_blockchain.rs b/codegen-v2/src/codegen/rust/new_blockchain.rs new file mode 100644 index 00000000000..ca27f77b08e --- /dev/null +++ b/codegen-v2/src/codegen/rust/new_blockchain.rs @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::codegen::rust::blockchain_dispatcher_generator::BlockchainDispatcherGenerator; +use crate::codegen::rust::blockchain_type_generator::BlockchainTypeGenerator; +use crate::codegen::rust::coin_address_derivation_test_generator::CoinAddressDerivationTestGenerator; +use crate::codegen::rust::coin_crate::CoinCrate; +use crate::codegen::rust::coin_integration_tests::CoinIntegrationTests; +use crate::codegen::rust::coin_registry_manifest_generator::CoinRegistryManifestGenerator; +use crate::codegen::rust::toml_editor::Workspace; +use crate::codegen::rust::workspace_toml_path; +use crate::registry::CoinItem; +use crate::Result; + +pub fn new_blockchain(coin: &CoinItem) -> Result<()> { + // Create blockchain's crate. + let blockchain_crate_path = CoinCrate::new(coin.clone()).create()?; + + // Insert the created crate to the workspace. + Workspace::new(workspace_toml_path()).insert_crate(&blockchain_crate_path)?; + + // Create integration tests. + CoinIntegrationTests::new(coin.clone()).create()?; + CoinAddressDerivationTestGenerator::generate_new_coin_type_case(coin)?; + + // Add the new blockchain to the `tw_coin_registry`. + BlockchainTypeGenerator::add_new_blockchain_type(coin)?; + CoinRegistryManifestGenerator::add_dependency(coin, &blockchain_crate_path)?; + BlockchainDispatcherGenerator::generate_new_blockchain_type_dispatching(coin)?; + + Ok(()) +} diff --git a/codegen-v2/src/codegen/rust/new_cosmos_chain.rs b/codegen-v2/src/codegen/rust/new_cosmos_chain.rs new file mode 100644 index 00000000000..96151ff6446 --- /dev/null +++ b/codegen-v2/src/codegen/rust/new_cosmos_chain.rs @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::codegen::rust::coin_address_derivation_test_generator::CoinAddressDerivationTestGenerator; +use crate::codegen::rust::coin_integration_tests::CoinIntegrationTests; +use crate::registry::CoinItem; +use crate::Result; + +pub fn new_cosmos_chain(coin: &CoinItem) -> Result<()> { + // Create integration tests. + CoinIntegrationTests::new(coin.clone()).create_cosmos()?; + CoinAddressDerivationTestGenerator::generate_new_coin_type_case(coin)?; + + Ok(()) +} diff --git a/codegen-v2/src/codegen/rust/new_evmchain.rs b/codegen-v2/src/codegen/rust/new_evmchain.rs new file mode 100644 index 00000000000..f754fa5ba1b --- /dev/null +++ b/codegen-v2/src/codegen/rust/new_evmchain.rs @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::codegen::rust::coin_address_derivation_test_generator::CoinAddressDerivationTestGenerator; +use crate::registry::CoinItem; +use crate::Result; + +pub fn new_evmchain(coin: &CoinItem) -> Result<()> { + // Modify integration tests. + CoinAddressDerivationTestGenerator::generate_new_evm_coin_type_case(coin) +} diff --git a/codegen-v2/src/codegen/rust/templates/blockchain_crate/Cargo.toml b/codegen-v2/src/codegen/rust/templates/blockchain_crate/Cargo.toml new file mode 100644 index 00000000000..9d5a7a7d04a --- /dev/null +++ b/codegen-v2/src/codegen/rust/templates/blockchain_crate/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "{TW_CRATE_NAME}" +version = "0.1.0" +edition = "2021" + +[dependencies] +tw_coin_entry = { path = "../../tw_coin_entry" } +tw_keypair = { path = "../../tw_keypair" } +tw_memory = { path = "../../tw_memory" } +tw_proto = { path = "../../tw_proto" } diff --git a/codegen-v2/src/codegen/rust/templates/blockchain_crate/address.rs b/codegen-v2/src/codegen/rust/templates/blockchain_crate/address.rs new file mode 100644 index 00000000000..3ec4f8516b5 --- /dev/null +++ b/codegen-v2/src/codegen/rust/templates/blockchain_crate/address.rs @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use std::fmt; +use std::str::FromStr; +use tw_coin_entry::coin_entry::CoinAddress; +use tw_coin_entry::error::prelude::*; +use tw_memory::Data; + +pub struct {BLOCKCHAIN}Address { + // TODO add necessary fields. +} + +impl CoinAddress for {BLOCKCHAIN}Address { + #[inline] + fn data(&self) -> Data { + todo!() + } +} + +impl FromStr for {BLOCKCHAIN}Address { + type Err = AddressError; + + fn from_str(_s: &str) -> Result { + todo!() + } +} + +impl fmt::Display for {BLOCKCHAIN}Address { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + todo!() + } +} diff --git a/codegen-v2/src/codegen/rust/templates/blockchain_crate/compiler.rs b/codegen-v2/src/codegen/rust/templates/blockchain_crate/compiler.rs new file mode 100644 index 00000000000..63d51f1df50 --- /dev/null +++ b/codegen-v2/src/codegen/rust/templates/blockchain_crate/compiler.rs @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use tw_coin_entry::coin_context::CoinContext; +use tw_coin_entry::coin_entry::{PublicKeyBytes, SignatureBytes}; +use tw_coin_entry::error::prelude::*; +use tw_coin_entry::signing_output_error; +use tw_proto::{BLOCKCHAIN}::Proto; +use tw_proto::TxCompiler::Proto as CompilerProto; + +pub struct {BLOCKCHAIN}Compiler; + +impl {BLOCKCHAIN}Compiler { + #[inline] + pub fn preimage_hashes( + coin: &dyn CoinContext, + input: Proto::SigningInput<'_>, + ) -> CompilerProto::PreSigningOutput<'static> { + Self::preimage_hashes_impl(coin, input) + .unwrap_or_else(|e| signing_output_error!(CompilerProto::PreSigningOutput, e)) + } + + fn preimage_hashes_impl( + _coin: &dyn CoinContext, + _input: Proto::SigningInput<'_>, + ) -> SigningResult> { + todo!() + } + + #[inline] + pub fn compile( + coin: &dyn CoinContext, + input: Proto::SigningInput<'_>, + signatures: Vec, + public_keys: Vec, + ) -> Proto::SigningOutput<'static> { + Self::compile_impl(coin, input, signatures, public_keys) + .unwrap_or_else(|e| signing_output_error!(Proto::SigningOutput, e)) + } + + fn compile_impl( + _coin: &dyn CoinContext, + _input: Proto::SigningInput<'_>, + _signatures: Vec, + _public_keys: Vec, + ) -> SigningResult> { + todo!() + } +} diff --git a/codegen-v2/src/codegen/rust/templates/blockchain_crate/entry.rs b/codegen-v2/src/codegen/rust/templates/blockchain_crate/entry.rs new file mode 100644 index 00000000000..e26b696fa59 --- /dev/null +++ b/codegen-v2/src/codegen/rust/templates/blockchain_crate/entry.rs @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::address::{BLOCKCHAIN}Address; +use crate::compiler::{BLOCKCHAIN}Compiler; +use crate::signer::{BLOCKCHAIN}Signer; +use std::str::FromStr; +use tw_coin_entry::coin_context::CoinContext; +use tw_coin_entry::coin_entry::{CoinEntry, PublicKeyBytes, SignatureBytes}; +use tw_coin_entry::derivation::Derivation; +use tw_coin_entry::error::prelude::*; +use tw_coin_entry::modules::json_signer::NoJsonSigner; +use tw_coin_entry::modules::message_signer::NoMessageSigner; +use tw_coin_entry::modules::plan_builder::NoPlanBuilder; +use tw_coin_entry::modules::transaction_decoder::NoTransactionDecoder; +use tw_coin_entry::modules::transaction_util::NoTransactionUtil; +use tw_coin_entry::modules::wallet_connector::NoWalletConnector; +use tw_coin_entry::prefix::NoPrefix; +use tw_keypair::tw::PublicKey; +use tw_proto::{BLOCKCHAIN}::Proto; +use tw_proto::TxCompiler::Proto as CompilerProto; + +pub struct {BLOCKCHAIN}Entry; + +impl CoinEntry for {BLOCKCHAIN}Entry { + type AddressPrefix = NoPrefix; + type Address = {BLOCKCHAIN}Address; + type SigningInput<'a> = Proto::SigningInput<'a>; + type SigningOutput = Proto::SigningOutput<'static>; + type PreSigningOutput = CompilerProto::PreSigningOutput<'static>; + + // Optional modules: + type JsonSigner = NoJsonSigner; + type PlanBuilder = NoPlanBuilder; + type MessageSigner = NoMessageSigner; + type WalletConnector = NoWalletConnector; + type TransactionDecoder = NoTransactionDecoder; + type TransactionUtil = NoTransactionUtil; + + #[inline] + fn parse_address( + &self, + _coin: &dyn CoinContext, + _address: &str, + _prefix: Option, + ) -> AddressResult { + todo!() + } + + #[inline] + fn parse_address_unchecked(&self, address: &str) -> AddressResult { + {BLOCKCHAIN}Address::from_str(address) + } + + #[inline] + fn derive_address( + &self, + _coin: &dyn CoinContext, + _public_key: PublicKey, + _derivation: Derivation, + _prefix: Option, + ) -> AddressResult { + todo!() + } + + #[inline] + fn sign(&self, coin: &dyn CoinContext, input: Self::SigningInput<'_>) -> Self::SigningOutput { + {BLOCKCHAIN}Signer::sign(coin, input) + } + + #[inline] + fn preimage_hashes( + &self, + coin: &dyn CoinContext, + input: Self::SigningInput<'_>, + ) -> Self::PreSigningOutput { + {BLOCKCHAIN}Compiler::preimage_hashes(coin, input) + } + + #[inline] + fn compile( + &self, + coin: &dyn CoinContext, + input: Self::SigningInput<'_>, + signatures: Vec, + public_keys: Vec, + ) -> Self::SigningOutput { + {BLOCKCHAIN}Compiler::compile(coin, input, signatures, public_keys) + } +} diff --git a/codegen-v2/src/codegen/rust/templates/blockchain_crate/lib.rs b/codegen-v2/src/codegen/rust/templates/blockchain_crate/lib.rs new file mode 100644 index 00000000000..c41edeb4471 --- /dev/null +++ b/codegen-v2/src/codegen/rust/templates/blockchain_crate/lib.rs @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +pub mod address; +pub mod compiler; +pub mod entry; +pub mod signer; diff --git a/codegen-v2/src/codegen/rust/templates/blockchain_crate/signer.rs b/codegen-v2/src/codegen/rust/templates/blockchain_crate/signer.rs new file mode 100644 index 00000000000..3a64018e599 --- /dev/null +++ b/codegen-v2/src/codegen/rust/templates/blockchain_crate/signer.rs @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use tw_coin_entry::coin_context::CoinContext; +use tw_coin_entry::error::prelude::*; +use tw_coin_entry::signing_output_error; +use tw_proto::{BLOCKCHAIN}::Proto; + +pub struct {BLOCKCHAIN}Signer; + +impl {BLOCKCHAIN}Signer { + pub fn sign( + coin: &dyn CoinContext, + input: Proto::SigningInput<'_>, + ) -> Proto::SigningOutput<'static> { + Self::sign_impl(coin, input) + .unwrap_or_else(|e| signing_output_error!(Proto::SigningOutput, e)) + } + + fn sign_impl( + _coin: &dyn CoinContext, + _input: Proto::SigningInput<'_>, + ) -> SigningResult> { + todo!() + } +} diff --git a/codegen-v2/src/codegen/rust/templates/integration_tests/address_tests.rs b/codegen-v2/src/codegen/rust/templates/integration_tests/address_tests.rs new file mode 100644 index 00000000000..1d417a77ed4 --- /dev/null +++ b/codegen-v2/src/codegen/rust/templates/integration_tests/address_tests.rs @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use tw_any_coin::test_utils::address_utils::{ + test_address_derive, test_address_get_data, test_address_invalid, test_address_normalization, + test_address_valid, +}; +use tw_coin_registry::coin_type::CoinType; + +#[test] +fn test_{COIN_ID}_address_derive() { + test_address_derive(CoinType::{COIN_TYPE}, "PRIVATE_KEY", "EXPECTED ADDRESS"); +} + +#[test] +fn test_{COIN_ID}_address_normalization() { + test_address_normalization(CoinType::{COIN_TYPE}, "DENORMALIZED", "EXPECTED"); +} + +#[test] +fn test_{COIN_ID}_address_is_valid() { + test_address_valid(CoinType::{COIN_TYPE}, "VALID ADDRESS"); +} + +#[test] +fn test_{COIN_ID}_address_invalid() { + test_address_invalid(CoinType::{COIN_TYPE}, "INVALID ADDRESS"); +} + +#[test] +fn test_{COIN_ID}_address_get_data() { + test_address_get_data(CoinType::{COIN_TYPE}, "ADDRESS", "HEX(DATA)"); +} diff --git a/codegen-v2/src/codegen/rust/templates/integration_tests/compile_tests.rs b/codegen-v2/src/codegen/rust/templates/integration_tests/compile_tests.rs new file mode 100644 index 00000000000..fad7f69330a --- /dev/null +++ b/codegen-v2/src/codegen/rust/templates/integration_tests/compile_tests.rs @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#[test] +fn test_{COIN_ID}_compile() { + todo!() +} diff --git a/codegen-v2/src/codegen/rust/templates/integration_tests/cosmos_address_tests.rs b/codegen-v2/src/codegen/rust/templates/integration_tests/cosmos_address_tests.rs new file mode 100644 index 00000000000..6bf6079ac9d --- /dev/null +++ b/codegen-v2/src/codegen/rust/templates/integration_tests/cosmos_address_tests.rs @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use tw_any_coin::test_utils::address_utils::{ + test_address_bech32_is_valid, test_address_create_bech32_with_public_key, + test_address_get_data, test_address_invalid, test_address_normalization, test_address_valid, + AddressBech32IsValid, AddressCreateBech32WithPublicKey, +}; +use tw_coin_registry::coin_type::CoinType; +use tw_keypair::tw::PublicKeyType; + +#[test] +fn test_{COIN_ID}_address_normalization() { + test_address_normalization(CoinType::{COIN_TYPE}, "DENORMALIZED", "EXPECTED"); +} + +#[test] +fn test_{COIN_ID}_address_is_valid() { + test_address_valid(CoinType::{COIN_TYPE}, "VALID {COIN_TYPE} ADDRESS"); +} + +#[test] +fn test_{COIN_ID}_address_invalid() { + test_address_invalid(CoinType::{COIN_TYPE}, "INVALID ADDRESS"); + // Cosmos has a different `hrp`. + test_address_invalid(CoinType::Cosmos, "VALID {COIN_TYPE} ADDRESS"); +} + +#[test] +fn test_{COIN_ID}_address_get_data() { + test_address_get_data(CoinType::{COIN_TYPE}, "ADDRESS", "HEX(DATA)"); +} + +#[test] +fn test_{COIN_ID}_is_valid_bech32() { + // {COIN_TYPE} address must be valid if its Base32 prefix passed. + test_address_bech32_is_valid(AddressBech32IsValid { + coin: CoinType::{COIN_TYPE}, + address: "{COIN_TYPE} ADDRESS", + hrp: "{HRP}", + }); + // {COIN_TYPE} address must be valid for the standard Cosmos hub if its Base32 prefix passed. + test_address_bech32_is_valid(AddressBech32IsValid { + coin: CoinType::Cosmos, + address: "{COIN_TYPE} ADDRESS", + hrp: "{HRP}", + }); + // Cosmos address must be valid with "cosmos" hrp. + test_address_bech32_is_valid(AddressBech32IsValid { + coin: CoinType::{COIN_TYPE}, + address: "cosmos1hsk6jryyqjfhp5dhc55tc9jtckygx0eph6dd02", + hrp: "cosmos", + }); +} + +#[test] +fn test_any_address_create_bech32_with_public_key() { + test_address_create_bech32_with_public_key(AddressCreateBech32WithPublicKey { + // TODO consider using `CoinType::{COIN_TYPE}` if the chain's `addressHasher` is different from Cosmos's. + coin: CoinType::Cosmos, + private_key: "PRIVATE_KEY", + // TODO consider using another `PublicKeyType` if the chain's `publicKeyType` is different from Cosmos's. + public_key_type: PublicKeyType::Secp256k1, + hrp: "{HRP}", + expected: "{COIN_TYPE} ADDRESS", + }); +} + diff --git a/codegen-v2/src/codegen/rust/templates/integration_tests/mod.rs b/codegen-v2/src/codegen/rust/templates/integration_tests/mod.rs new file mode 100644 index 00000000000..15dccad969f --- /dev/null +++ b/codegen-v2/src/codegen/rust/templates/integration_tests/mod.rs @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +mod {COIN_ID}_address; +mod {COIN_ID}_compile; +mod {COIN_ID}_sign; diff --git a/codegen-v2/src/codegen/rust/templates/integration_tests/mod_address.rs b/codegen-v2/src/codegen/rust/templates/integration_tests/mod_address.rs new file mode 100644 index 00000000000..6f501e180bc --- /dev/null +++ b/codegen-v2/src/codegen/rust/templates/integration_tests/mod_address.rs @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +mod {COIN_ID}_address; diff --git a/codegen-v2/src/codegen/rust/templates/integration_tests/sign_tests.rs b/codegen-v2/src/codegen/rust/templates/integration_tests/sign_tests.rs new file mode 100644 index 00000000000..38f01a4e0e1 --- /dev/null +++ b/codegen-v2/src/codegen/rust/templates/integration_tests/sign_tests.rs @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#[test] +fn test_{COIN_ID}_sign() { + todo!() +} diff --git a/codegen-v2/src/codegen/rust/toml_editor.rs b/codegen-v2/src/codegen/rust/toml_editor.rs new file mode 100644 index 00000000000..0811182365d --- /dev/null +++ b/codegen-v2/src/codegen/rust/toml_editor.rs @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::{Error, Result}; +use std::fs; +use std::path::{Path, PathBuf}; +use std::str::FromStr; +use toml_edit::{Document, InlineTable, Item, Value}; + +const NEW_LINE_TAB_DECORATOR: &str = "\n "; +const NO_DECORATOR: &str = ""; + +pub struct Workspace { + path_to_toml: PathBuf, +} + +impl Workspace { + pub fn new(path_to_toml: PathBuf) -> Workspace { + Workspace { path_to_toml } + } + + pub fn insert_crate(self, path_to_crate: &Path) -> Result<()> { + let manifest = fs::read_to_string(&self.path_to_toml)?; + let mut manifest = Document::from_str(&manifest)?; + + let members = manifest["workspace"]["members"] + .as_array_mut() + .ok_or(Error::TomlFormat( + "Invalid 'workspace' TOML format".to_string(), + ))?; + + // Try to get a path to the crate relative to the `Cargo.toml`. + let relative_path_to_crate = relative_path_to_crate(&self.path_to_toml, path_to_crate)?; + + // Push the new member, sort and save the manifest. + + let relative_path_to_crate_decorated = + Value::from(relative_path_to_crate).decorated(NEW_LINE_TAB_DECORATOR, NO_DECORATOR); + + members.push_formatted(relative_path_to_crate_decorated); + members.sort_by(|x, y| x.as_str().cmp(&y.as_str())); + + fs::write(self.path_to_toml, manifest.to_string())?; + Ok(()) + } +} + +pub struct Dependencies { + path_to_toml: PathBuf, +} + +impl Dependencies { + pub fn new(path_to_toml: PathBuf) -> Dependencies { + Dependencies { path_to_toml } + } + + pub fn insert_dependency(self, dep_name: &str, path_to_dep_crate: &Path) -> Result<()> { + let manifest = fs::read_to_string(&self.path_to_toml)?; + let mut manifest = Document::from_str(&manifest)?; + + let dependencies = manifest["dependencies"] + .as_table_like_mut() + .ok_or(Error::TomlFormat("Invalid 'Cargo.toml' format".to_string()))?; + + // Try to get a path to the crate relative to the `Cargo.toml`. + let relative_path_to_crate = relative_path_to_crate(&self.path_to_toml, path_to_dep_crate)?; + + // Create the new dependency member (aka a TOML inline table with `path` key-value). + let mut new_member = InlineTable::new(); + new_member.insert("path", relative_path_to_crate.into()); + + // Push the new member, sort and save the manifest. + dependencies.insert(dep_name, Item::Value(Value::InlineTable(new_member))); + dependencies.sort_values(); + + fs::write(self.path_to_toml, manifest.to_string())?; + + Ok(()) + } +} + +/// Returns a path to the dependency accordingly to the Cargo manifest file. +/// The result string can be put to `Cargo.toml` as: +/// ```toml +/// tw_foo = { path = "" } +/// ``` +fn relative_path_to_crate( + path_to_cargo_manifest: &Path, + path_to_dependency: &Path, +) -> Result { + let absolute_path_to_crate_directory = path_to_cargo_manifest + .parent() + .ok_or_else(|| Error::io_error_other("Cannot get a parent directory".to_string()))? + .canonicalize()?; + let absolute_path_to_dependency = path_to_dependency.canonicalize()?; + + let relative_path_to_dependency = pathdiff::diff_paths( + absolute_path_to_dependency, + absolute_path_to_crate_directory, + ) + .ok_or_else(|| { + Error::io_error_other("Cannot get a relative path to the dependency".to_string()) + })? + .to_str() + .ok_or_else(|| Error::io_error_other("Invalid path to the crate".to_string()))? + .to_string(); + + Ok(relative_path_to_dependency) +} diff --git a/codegen-v2/src/codegen/swift/functions.rs b/codegen-v2/src/codegen/swift/functions.rs new file mode 100644 index 00000000000..1f7e4aa8d39 --- /dev/null +++ b/codegen-v2/src/codegen/swift/functions.rs @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use super::*; +use crate::manifest::{FunctionInfo, TypeVariant}; +use heck::ToLowerCamelCase; + +/// This function checks each function and determines whether there's an +/// association with the passed on object (struct or enum), based on common name +/// prefix, and maps the data into a Swift structure. +/// +/// This function returns a tuple of associated Swift functions and the skipped +/// respectively non-associated functions. +pub(super) fn process_methods( + object: &ObjectVariant, + functions: Vec, +) -> Result<(Vec, Vec)> { + let mut swift_funcs = vec![]; + let mut skipped_funcs = vec![]; + + for func in functions { + if !func.name.starts_with(object.name()) { + // Function is not assciated with the object. + skipped_funcs.push(func); + continue; + } + + let mut ops = vec![]; + + // Initalize the 'self' type, which is then passed on to the underlying + // C FFI function, assuming the function is not static. + // + // E.g: + // - `let obj = self.rawValue` + // - `let obj = TWSomeEnum(rawValue: self.RawValue")` + if !func.is_static { + ops.push(match object { + ObjectVariant::Struct(_) => SwiftOperation::Call { + var_name: "obj".to_string(), + call: "self.rawValue".to_string(), + defer: None, + }, + ObjectVariant::Enum(name) => SwiftOperation::Call { + var_name: "obj".to_string(), + call: format!("{}(rawValue: self.rawValue)", name), + defer: None, + }, + }); + } + + // For each parameter, we track a list of `params` which is used for the + // function interface and add the necessary operations on how to process + // those parameters. + let mut params = vec![]; + for param in func.params { + // Skip self parameter + match ¶m.ty.variant { + TypeVariant::Enum(name) | TypeVariant::Struct(name) if name == object.name() => { + continue + } + _ => {} + } + + // Convert parameter to Swift parameter for the function interface. + params.push(SwiftParam { + name: param.name.clone(), + param_type: SwiftType::from(param.ty.variant.clone()), + is_nullable: param.ty.is_nullable, + }); + + // Process parameter. + if let Some(op) = param_c_ffi_call(¶m) { + ops.push(op) + } + } + + // Prepepare parameter list to be passed on to the underlying C FFI function. + let param_name = if func.is_static { vec![] } else { vec!["obj"] }; + let param_names = param_name + .into_iter() + .chain(params.iter().map(|p| p.name.as_str())) + .collect::>() + .join(","); + + // Call the underlying C FFI function, passing on the parameter list. + let (var_name, call) = ( + "result".to_string(), + format!("{}({})", func.name, param_names), + ); + if func.return_type.is_nullable { + ops.push(SwiftOperation::GuardedCall { var_name, call }); + } else { + ops.push(SwiftOperation::Call { + var_name, + call, + defer: None, + }); + } + + // Wrap result. + ops.push(wrap_return(&func.return_type)); + + // Convert return type for function interface. + let return_type = SwiftReturn { + param_type: SwiftType::from(func.return_type.variant), + is_nullable: func.return_type.is_nullable, + }; + + // Prettify name, remove object name prefix from this property. + let pretty_name = func + .name + .strip_prefix(object.name()) + // Panicing implies bug, checked at the start of the loop. + .unwrap() + .to_lower_camel_case(); + + // Special handling: some functions do not follow standard camelCase + // convention. + #[rustfmt::skip] + let pretty_name = if object.name() == "TWStoredKey" { + pretty_name + .replace("Json", "JSON") + .replace("Hd", "HD") + } else if object.name() == "TWPublicKey" { + pretty_name + .replace("Der", "DER") + } else if object.name() == "TWHash" { + pretty_name + .replace("ripemd", "RIPEMD") + .replace("Ripemd", "RIPEMD") + .replace("sha512256", "sha512_256") + .replace("sha3256", "sha3_256") + .replace("sha256sha256", "sha256SHA256") + } else if object.name() == "TWAES" { + pretty_name + .replace("Cbc", "CBC") + .replace("Ctr", "CTR") + } else { + pretty_name + }; + + swift_funcs.push(SwiftFunction { + name: pretty_name, + is_public: func.is_public, + is_static: func.is_static, + operations: ops, + params, + return_type, + comments: vec![], + }); + } + + Ok((swift_funcs, skipped_funcs)) +} diff --git a/codegen-v2/src/codegen/swift/inits.rs b/codegen-v2/src/codegen/swift/inits.rs new file mode 100644 index 00000000000..a1f140c326e --- /dev/null +++ b/codegen-v2/src/codegen/swift/inits.rs @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use super::*; +use crate::manifest::InitInfo; + +/// This function checks each constructor and determines whether there's an +/// association with the passed on object (struct or enum), based on common name +/// prefix, and maps the data into a Swift structure. +/// +/// This function returns a tuple of associated Swift constructor and the skipped +/// respectively non-associated constructors. +pub(super) fn process_inits( + object: &ObjectVariant, + inits: Vec, +) -> Result<(Vec, Vec)> { + let mut swift_inits = vec![]; + let mut skipped_inits = vec![]; + + for init in inits { + if !init.name.starts_with(object.name()) { + // Init is not assciated with the object. + skipped_inits.push(init); + continue; + } + + let mut ops = vec![]; + + // For each parameter, we track a list of `params` which is used for the + // function interface and add the necessary operations on how to process + // those parameters. + let mut params = vec![]; + for param in init.params { + // Convert parameter to Swift parameter. + params.push(SwiftParam { + name: param.name.clone(), + param_type: SwiftType::from(param.ty.variant.clone()), + is_nullable: param.ty.is_nullable, + }); + + // Process parameter. + if let Some(op) = param_c_ffi_call(¶m) { + ops.push(op); + } + } + + // Prepepare parameter list to be passed on to the underlying C FFI function. + let param_names = params + .iter() + .map(|p| p.name.as_str()) + .collect::>() + .join(","); + + // Call the underlying C FFI function, passing on the parameter list. + if init.is_nullable { + ops.push(SwiftOperation::GuardedCall { + var_name: "result".to_string(), + call: format!("{}({})", init.name, param_names), + }); + } else { + ops.push(SwiftOperation::Call { + var_name: "result".to_string(), + call: format!("{}({})", init.name, param_names), + defer: None, + }); + } + + // Note that we do not return a value here; the template sets a + // `self.rawValue = result` entry at the end of the constructor. + + // Prettify name, remove object name prefix from this property. + let pretty_name = init + .name + .strip_prefix(object.name()) + // Panicing implies bug, checked at the start of the loop. + .unwrap() + .to_string(); + + swift_inits.push(SwiftInit { + name: pretty_name, + is_nullable: init.is_nullable, + is_public: init.is_public, + params, + operations: ops, + comments: vec![], + }); + } + + Ok((swift_inits, skipped_inits)) +} + +pub(super) fn process_deinits( + object: &ObjectVariant, + deinit: Vec, +) -> Result<(Vec, Vec)> { + let mut swift_deinits = vec![]; + let mut skipped_deinits = vec![]; + + for deinit in deinit { + if deinit.name.starts_with(object.name()) { + swift_deinits.push(deinit) + } else { + // Deinit is not assciated with the object. + skipped_deinits.push(deinit); + continue; + } + } + + Ok((swift_deinits, skipped_deinits)) +} diff --git a/codegen-v2/src/codegen/swift/mod.rs b/codegen-v2/src/codegen/swift/mod.rs new file mode 100644 index 00000000000..4bc70e7e416 --- /dev/null +++ b/codegen-v2/src/codegen/swift/mod.rs @@ -0,0 +1,370 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use self::functions::process_methods; +use self::inits::process_inits; +use self::properties::process_properties; +use self::render::pretty_name; +use crate::manifest::{DeinitInfo, FileInfo, ParamInfo, ProtoInfo, TypeInfo, TypeVariant}; +use crate::{Error, Result}; +use handlebars::Handlebars; +use serde_json::json; +use std::fmt::Display; + +mod functions; +mod inits; +mod properties; +mod render; + +// Re-exports +pub use self::render::{ + generate_swift_types, render_to_strings, GeneratedSwiftTypes, GeneratedSwiftTypesStrings, + RenderIntput, +}; + +/// Represents a Swift struct or class. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SwiftStruct { + name: String, + is_class: bool, + is_public: bool, + init_instance: bool, + superclasses: Vec, + eq_operator: Option, + inits: Vec, + deinits: Vec, + methods: Vec, + properties: Vec, +} + +/// Represents a Swift enum. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SwiftEnum { + name: String, + is_public: bool, + add_description: bool, + superclasses: Vec, + variants: Vec, +} + +/// Represents a Swift enum variant. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SwiftEnumVariant { + name: String, + value: String, + as_string: Option, +} + +/// Represents associated methods and properties of an enum. Based on the first +/// codegen, those extensions are placed in a separate file. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SwiftEnumExtension { + name: String, + init_instance: bool, + methods: Vec, + properties: Vec, +} + +// Wrapper around a valid Swift type (built in or custom). Meant to be used as +// `>::from(...)`. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SwiftType(String); + +impl Display for SwiftType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +/// Represents a Swift function or method. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SwiftFunction { + pub name: String, + pub is_public: bool, + pub is_static: bool, + pub params: Vec, + pub operations: Vec, + #[serde(rename = "return")] + pub return_type: SwiftReturn, + pub comments: Vec, +} + +/// Represents a Swift property of a struct/class or enum. +#[derive(Debug, Clone, Serialize, Deserialize)] +struct SwiftProperty { + pub name: String, + pub is_public: bool, + pub operations: Vec, + #[serde(rename = "return")] + pub return_type: SwiftReturn, + pub comments: Vec, +} + +/// The operation to be interpreted by the templating engine. This handles +/// parameters and C FFI calls in an appropriate way, depending on context. +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum SwiftOperation { + // Results in: + // ```swift + // let = + // defer { + // () + // } + // ``` + Call { + var_name: String, + call: String, + defer: Option, + }, + // Results in: + // ```swift + // let ptr: UnsafeRawPointer? + // if let alphabet = alphabet { + // ptr = TWStringCreateWithNSString(alphabet) + // } else { + // ptr = nil + // } + // ``` + // ... with an optional `defer` operation. + CallOptional { + var_name: String, + call: String, + defer: Option, + }, + // Results in: + // ```swift + // let = + // guard let = else { + // return nil + // } + // ``` + GuardedCall { + var_name: String, + call: String, + }, + // Results in: + // ```swift + // return + // ``` + Return { + call: String, + }, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SwiftParam { + pub name: String, + #[serde(rename = "type")] + pub param_type: SwiftType, + pub is_nullable: bool, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SwiftReturn { + #[serde(rename = "type")] + pub param_type: SwiftType, + pub is_nullable: bool, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SwiftInit { + pub name: String, + pub is_nullable: bool, + pub is_public: bool, + pub params: Vec, + pub operations: Vec, + pub comments: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SwiftProto { + pub name: String, + pub c_ffi_name: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SwiftOperatorEquality { + pub c_ffi_name: String, +} + +/// Used for the individual `process_*` functions. +enum ObjectVariant<'a> { + Struct(&'a str), + Enum(&'a str), +} + +impl<'a> ObjectVariant<'a> { + fn name(&'a self) -> &'a str { + match self { + ObjectVariant::Struct(n) | ObjectVariant::Enum(n) => n, + } + } +} + +impl TryFrom for SwiftProto { + type Error = Error; + + fn try_from(value: ProtoInfo) -> std::result::Result { + Ok(SwiftProto { + // Convert the name into an appropriate format. + name: pretty_name(value.0.clone()), + c_ffi_name: value.0, + }) + } +} + +/// Convert the `TypeVariant` into the appropriate Swift type. +impl From for SwiftType { + fn from(value: TypeVariant) -> Self { + let res = match value { + TypeVariant::Void => "Void".to_string(), + TypeVariant::Bool => "Bool".to_string(), + TypeVariant::Char => "Character".to_string(), + TypeVariant::ShortInt => "Int16".to_string(), + TypeVariant::Int => "Int32".to_string(), + TypeVariant::UnsignedInt => "UInt32".to_string(), + TypeVariant::LongInt => "Int64".to_string(), + TypeVariant::Float => "Float".to_string(), + TypeVariant::Double => "Double".to_string(), + TypeVariant::SizeT => "Int".to_string(), + TypeVariant::Int8T => "Int8".to_string(), + TypeVariant::Int16T => "Int16".to_string(), + TypeVariant::Int32T => "Int32".to_string(), + TypeVariant::Int64T => "Int64".to_string(), + TypeVariant::UInt8T => "UInt8".to_string(), + TypeVariant::UInt16T => "UInt16".to_string(), + TypeVariant::UInt32T => "UInt32".to_string(), + TypeVariant::UInt64T => "UInt64".to_string(), + TypeVariant::String => "String".to_string(), + TypeVariant::Data => "Data".to_string(), + TypeVariant::Struct(n) | TypeVariant::Enum(n) => { + // We strip the "TW" prefix for Swift representations of + // structs/enums. + n.strip_prefix("TW").map(|n| n.to_string()).unwrap_or(n) + } + }; + + SwiftType(res) + } +} + +// Covenience function: process the parameter, returning the operation for +// handling the C FFI call (if any). +fn param_c_ffi_call(param: &ParamInfo) -> Option { + let op = match ¶m.ty.variant { + // E.g. `let param = TWStringCreateWithNSString(param)` + TypeVariant::String => { + let (var_name, call, defer) = ( + param.name.clone(), + format!("TWStringCreateWithNSString({})", param.name), + Some(format!("TWStringDelete({})", param.name)), + ); + + // If the parameter is nullable, add special handler. + if param.ty.is_nullable { + SwiftOperation::CallOptional { + var_name, + call, + defer, + } + } else { + SwiftOperation::Call { + var_name, + call, + defer, + } + } + } + TypeVariant::Data => { + let (var_name, call, defer) = ( + param.name.clone(), + format!("TWDataCreateWithNSData({})", param.name), + Some(format!("TWDataDelete({})", param.name)), + ); + + // If the parameter is nullable, add special handler. + if param.ty.is_nullable { + SwiftOperation::CallOptional { + var_name, + call, + defer, + } + } else { + SwiftOperation::Call { + var_name, + call, + defer, + } + } + } + // E.g. + // - `let param = param.rawValue` + // - `let param = param?.rawValue` + TypeVariant::Struct(_) => { + // For nullable structs, we do not use the special + // `CallOptional` handler but rather use the question mark + // operator. + let (var_name, call, defer) = if param.ty.is_nullable { + ( + param.name.clone(), + format!("{}?.rawValue", param.name), + None, + ) + } else { + (param.name.clone(), format!("{}.rawValue", param.name), None) + }; + + SwiftOperation::Call { + var_name, + call, + defer, + } + } + // E.g. `let param = TWSomeEnum(rawValue: param.rawValue)` + // Note that it calls the constructor of the enum, which calls + // the underlying "*Create*" C FFI function. + TypeVariant::Enum(enm) => SwiftOperation::Call { + var_name: param.name.clone(), + call: format!("{enm}(rawValue: {}.rawValue)", param.name), + defer: None, + }, + // Skip processing parameter, reference the parameter by name + // directly, as defined in the function interface (usually the + // case for primitive types). + _ => return None, + }; + + Some(op) +} + +// Convenience funcion: wrap the return value, returning the operation. Note +// that types are wrapped differently when returning, compared to +// `param_c_ffi_call`; such as using `TWStringNSString` instead of +// `TWDataCreateWithNSData` for Strings. +fn wrap_return(ty: &TypeInfo) -> SwiftOperation { + match &ty.variant { + // E.g.`return TWStringNSString(result)` + TypeVariant::String => SwiftOperation::Return { + call: "TWStringNSString(result)".to_string(), + }, + TypeVariant::Data => SwiftOperation::Return { + call: "TWDataNSData(result)".to_string(), + }, + // E.g. `return SomeEnum(rawValue: result.rawValue)` + TypeVariant::Enum(_) => SwiftOperation::Return { + call: format!( + "{}(rawValue: result.rawValue)!", + SwiftType::from(ty.variant.clone()) + ), + }, + // E.g. `return SomeStruct(rawValue: result)` + TypeVariant::Struct(_) => SwiftOperation::Return { + call: format!("{}(rawValue: result)", SwiftType::from(ty.variant.clone())), + }, + _ => SwiftOperation::Return { + call: "result".to_string(), + }, + } +} diff --git a/codegen-v2/src/codegen/swift/properties.rs b/codegen-v2/src/codegen/swift/properties.rs new file mode 100644 index 00000000000..61d73e7171f --- /dev/null +++ b/codegen-v2/src/codegen/swift/properties.rs @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use super::*; +use crate::manifest::PropertyInfo; +use heck::ToLowerCamelCase; + +/// This function checks each property and determines whether there's an +/// association with the passed on object (struct or enum), based on common name +/// prefix, and maps the data into a Swift structure. +/// +/// This function returns a tuple of associated Swift properties and skipped +/// respectively non-associated properties. +pub(super) fn process_properties( + object: &ObjectVariant, + properties: Vec, +) -> Result<(Vec, Vec)> { + let mut swift_props = vec![]; + let mut skipped_props = vec![]; + + for prop in properties { + if !prop.name.starts_with(object.name()) { + // Property is not assciated with the object. + skipped_props.push(prop); + continue; + } + + let mut ops = vec![]; + + // Initalize the 'self' type, which is then passed on to the underlying + // C FFI function. + ops.push(match object { + // E.g. `let obj = self.rawValue` + ObjectVariant::Struct(_) => SwiftOperation::Call { + var_name: "obj".to_string(), + call: "self.rawValue".to_string(), + defer: None, + }, + // E.g. `let obj = TWSomeEnum(rawValue: self.rawValue")` + ObjectVariant::Enum(name) => SwiftOperation::Call { + var_name: "obj".to_string(), + call: format!("{}(rawValue: self.rawValue)", name), + defer: None, + }, + }); + + // Call the underlying C FFI function, passing on the `obj` instance. + // + // E.g: `let result = TWSomeFunc(obj)`. + let (var_name, call) = ("result".to_string(), format!("{}(obj)", prop.name)); + if prop.return_type.is_nullable { + ops.push(SwiftOperation::GuardedCall { var_name, call }); + } else { + ops.push(SwiftOperation::Call { + var_name, + call, + defer: None, + }); + } + + // Wrap result. + ops.push(wrap_return(&prop.return_type)); + + // Prettify name, remove object name prefix from this property. + let pretty_name = prop + .name + .strip_prefix(object.name()) + // Panicing implies bug, checked at the start of the loop. + .unwrap() + .to_lower_camel_case(); + + // Convert return type for property interface. + let return_type = SwiftReturn { + param_type: SwiftType::from(prop.return_type.variant), + is_nullable: prop.return_type.is_nullable, + }; + + swift_props.push(SwiftProperty { + name: pretty_name, + is_public: prop.is_public, + operations: ops, + return_type, + comments: vec![], + }); + } + + Ok((swift_props, skipped_props)) +} diff --git a/codegen-v2/src/codegen/swift/render.rs b/codegen-v2/src/codegen/swift/render.rs new file mode 100644 index 00000000000..465a7277682 --- /dev/null +++ b/codegen-v2/src/codegen/swift/render.rs @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use super::{inits::process_deinits, *}; + +#[derive(Debug, Clone)] +pub struct RenderIntput<'a> { + pub file_info: FileInfo, + pub struct_template: &'a str, + pub enum_template: &'a str, + pub extension_template: &'a str, + pub proto_template: &'a str, + pub partial_init_template: &'a str, + pub partial_func_tempalte: &'a str, + pub partial_prop_tempalte: &'a str, +} + +#[derive(Debug, Clone, Default)] +pub struct GeneratedSwiftTypesStrings { + pub structs: Vec<(String, String)>, + pub enums: Vec<(String, String)>, + pub extensions: Vec<(String, String)>, + pub protos: Vec<(String, String)>, +} + +#[derive(Debug, Clone, Default)] +pub struct GeneratedSwiftTypes { + pub structs: Vec, + pub enums: Vec, + pub extensions: Vec, + pub protos: Vec, +} + +/// Convenience wrapper for setting copyright year when generating bindings. +#[derive(Debug, Clone, Serialize)] +struct WithYear<'a, T> { + pub current_year: u64, + #[serde(flatten)] + pub data: &'a T, +} + +pub fn pretty_name(name: String) -> String { + name.replace("_", "").replace("TW", "").replace("Proto", "") +} + +pub fn render_to_strings<'a>(input: RenderIntput<'a>) -> Result { + // The current year for the copyright header in the generated bindings. + let current_year = crate::current_year(); + // Convert the name into an appropriate format. + let pretty_file_name = pretty_name(input.file_info.name.clone()); + + let mut engine = Handlebars::new(); + // Unmatched variables should result in an error. + engine.set_strict_mode(true); + + engine.register_partial("struct", input.struct_template)?; + engine.register_partial("enum", input.enum_template)?; + engine.register_partial("extension", input.extension_template)?; + engine.register_partial("proto", input.proto_template)?; + engine.register_partial("partial_init", input.partial_init_template)?; + engine.register_partial("partial_func", input.partial_func_tempalte)?; + engine.register_partial("partial_prop", input.partial_prop_tempalte)?; + + let rendered = generate_swift_types(input.file_info)?; + let mut out_str = GeneratedSwiftTypesStrings::default(); + + // Render structs. + for strct in rendered.structs { + let out = engine.render( + "struct", + &WithYear { + current_year, + data: &strct, + }, + )?; + + out_str.structs.push((strct.name, out)); + } + + // Render enums. + for enm in rendered.enums { + let out = engine.render( + "enum", + &WithYear { + current_year, + data: &enm, + }, + )?; + + out_str.enums.push((enm.name, out)); + } + + // Render extensions. + for ext in rendered.extensions { + let out = engine.render( + "extension", + &WithYear { + current_year, + data: &ext, + }, + )?; + + out_str.extensions.push((ext.name, out)); + } + + // Render protos. + if !rendered.protos.is_empty() { + let out = engine.render( + "proto", + &WithYear { + current_year, + data: &json!({ + "protos": &rendered.protos + }), + }, + )?; + + out_str.protos.push((pretty_file_name, out)); + } + + Ok(out_str) +} + +/// Uses the given input templates to render all files. +pub fn generate_swift_types(mut info: FileInfo) -> Result { + let mut outputs = GeneratedSwiftTypes::default(); + + // Render structs/classes. + for strct in info.structs { + let obj = ObjectVariant::Struct(&strct.name); + + // Process items. + let (inits, deinits, mut methods, properties); + (inits, info.inits) = process_inits(&obj, info.inits)?; + (deinits, info.deinits) = process_deinits(&obj, info.deinits)?; + (methods, info.functions) = process_methods(&obj, info.functions)?; + (properties, info.properties) = process_properties(&obj, info.properties)?; + + // Avoid rendering empty structs. + if inits.is_empty() && methods.is_empty() && properties.is_empty() { + continue; + } + + // Convert the name into an appropriate format. + let pretty_struct_name = pretty_name(strct.name.clone()); + + // Add superclasses. + let superclasses = if pretty_struct_name.ends_with("Address") { + vec!["Address".to_string()] + } else { + vec![] + }; + + // Handle equality operator. + let eq_method = methods.iter().enumerate().find(|(_, f)| f.name == "equal"); + let eq_operator = if let Some((idx, _)) = eq_method { + let operator = SwiftOperatorEquality { + c_ffi_name: format!("{}Equal", strct.name), + }; + + // Remove that method from the `methods` list. + methods.remove(idx); + + Some(operator) + } else { + None + }; + + outputs.structs.push(SwiftStruct { + name: pretty_struct_name, + is_class: strct.is_class, + is_public: strct.is_public, + init_instance: strct.is_class, + superclasses, + eq_operator, + inits: inits, + deinits: deinits, + methods, + properties, + }); + } + + // Render enums. + for enm in info.enums { + let obj = ObjectVariant::Enum(&enm.name); + + // Process items. + let (methods, properties); + (methods, info.functions) = process_methods(&obj, info.functions)?; + (properties, info.properties) = process_properties(&obj, info.properties)?; + + // Convert the name into an appropriate format. + let pretty_enum_name = pretty_name(enm.name); + + // Add superclasses. + let value_type = SwiftType::from(enm.value_type); + let mut superclasses = vec![value_type.0, "CaseIterable".to_string()]; + + let mut add_class = false; + + // Convert to Swift enum variants + let variants = enm + .variants + .into_iter() + .map(|info| { + if info.as_string.is_some() { + add_class = true; + } + + SwiftEnumVariant { + name: info.name, + value: info.value, + as_string: info.as_string, + } + }) + .collect(); + + if add_class { + superclasses.push("CustomStringConvertible".to_string()); + } + + outputs.enums.push(SwiftEnum { + name: pretty_enum_name.clone(), + is_public: enm.is_public, + add_description: add_class, + superclasses, + variants, + }); + + // Avoid rendering empty extension for enums. + if methods.is_empty() && properties.is_empty() { + continue; + } + + outputs.extensions.push(SwiftEnumExtension { + name: pretty_enum_name, + init_instance: true, + methods, + properties, + }); + } + + // Render Protobufs. + if !info.protos.is_empty() { + for proto in info.protos { + outputs.protos.push(SwiftProto::try_from(proto)?); + } + } + + Ok(outputs) +} diff --git a/codegen-v2/src/codegen/swift/templates/WalletCore.h b/codegen-v2/src/codegen/swift/templates/WalletCore.h new file mode 100644 index 00000000000..76f61b9fa74 --- /dev/null +++ b/codegen-v2/src/codegen/swift/templates/WalletCore.h @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#import + +//! Project version number for TrustWalletCore. +FOUNDATION_EXPORT double WalletCoreVersionNumber; + +//! Project version string for TrustWalletCore. +FOUNDATION_EXPORT const unsigned char WalletCoreVersionString[]; + +#include "TWBase.h" +#include "TWData.h" +#include "TWString.h" + +#include "TWAnySigner.h" + +#include "TWAES.h" +#include "TWAESPaddingMode.h" +#include "TWAccount.h" +#include "TWAnyAddress.h" +#include "TWAsnParser.h" +#include "TWBarz.h" +#include "TWBase32.h" +#include "TWBase58.h" +#include "TWBase64.h" +#include "TWBitcoinAddress.h" +#include "TWBitcoinMessageSigner.h" +#include "TWBitcoinScript.h" +#include "TWBitcoinSigHashType.h" +#include "TWBlockchain.h" +#include "TWCardano.h" +#include "TWCoinType.h" +#include "TWCoinTypeConfiguration.h" +#include "TWCurve.h" +#include "TWDataVector.h" +#include "TWDerivation.h" +#include "TWDerivationPath.h" +#include "TWDerivationPathIndex.h" +#include "TWEthereum.h" +#include "TWEthereumAbi.h" +#include "TWEthereumAbiFunction.h" +#include "TWEthereumAbiValue.h" +#include "TWEthereumChainID.h" +#include "TWEthereumRlp.h" +#include "TWEthereumMessageSigner.h" +#include "TWFIOAccount.h" +#include "TWFilecoinAddressConverter.h" +#include "TWFilecoinAddressType.h" +#include "TWGroestlcoinAddress.h" +#include "TWHDVersion.h" +#include "TWHDWallet.h" +#include "TWHRP.h" +#include "TWHash.h" +#include "TWLiquidStaking.h" +#include "TWMnemonic.h" +#include "TWNEARAccount.h" +#include "TWNervosAddress.h" +#include "TWPBKDF2.h" +#include "TWPrivateKey.h" +#include "TWPrivateKeyType.h" +#include "TWPublicKey.h" +#include "TWPublicKeyType.h" +#include "TWPurpose.h" +#include "TWRippleXAddress.h" +#include "TWSS58AddressType.h" +#include "TWSegwitAddress.h" +#include "TWSolanaAddress.h" +#include "TWStarkExMessageSigner.h" +#include "TWStarkWare.h" +#include "TWStellarMemoType.h" +#include "TWStellarPassphrase.h" +#include "TWStellarVersionByte.h" +#include "TWStoredKey.h" +#include "TWStoredKeyEncryption.h" +#include "TWStoredKeyEncryptionLevel.h" +#include "TWTHORChainSwap.h" +#include "TWTezosMessageSigner.h" +#include "TWTransactionCompiler.h" +#include "TWTronMessageSigner.h" diff --git a/codegen-v2/src/codegen/swift/templates/enum.hbs b/codegen-v2/src/codegen/swift/templates/enum.hbs new file mode 100644 index 00000000000..5363fb776b4 --- /dev/null +++ b/codegen-v2/src/codegen/swift/templates/enum.hbs @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. +// +// This is a GENERATED FILE, changes made here WILL BE LOST. +// + +{{#if is_public}}public {{/if}}enum {{name}} + {{~#if superclasses}}: {{/if}}{{#each superclasses}}{{this}}{{#unless @last}}, {{/unless}}{{/each}} { + {{#each variants}} + case `{{this.name}}` = {{this.value}} + {{/each}} + {{#if add_description}} + + public var description: String { + switch self { + {{#each variants}} + case .{{this.name}}: return "{{this.as_string}}" + {{/each}} + } + } + {{/if}} +} diff --git a/codegen-v2/src/codegen/swift/templates/extension.hbs b/codegen-v2/src/codegen/swift/templates/extension.hbs new file mode 100644 index 00000000000..ddae1f95ba6 --- /dev/null +++ b/codegen-v2/src/codegen/swift/templates/extension.hbs @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. +// +// This is a GENERATED FILE, changes made here WILL BE LOST. +// + +extension {{name}} { + {{! Methods }} + {{#each methods}} + {{~> partial_func}} + {{#unless @last}} + + {{/unless}} + {{/each}} + {{! Properties }} + {{#each properties}} + {{~> partial_prop}} + {{#unless @last}} + + {{/unless}} + {{/each}} +} diff --git a/codegen-v2/src/codegen/swift/templates/partial_func.hbs b/codegen-v2/src/codegen/swift/templates/partial_func.hbs new file mode 100644 index 00000000000..5ebc73fd8e8 --- /dev/null +++ b/codegen-v2/src/codegen/swift/templates/partial_func.hbs @@ -0,0 +1,38 @@ + {{#if is_public}}public {{/if}}{{#if is_static}}static {{/if}}func {{name}}({{#each params}}{{name}}: {{type}}{{#if is_nullable}}?{{/if}}{{#unless @last}}, {{/unless}}{{/each}}) -> {{return.type}}{{#if return.is_nullable}}?{{/if}} { + {{#each operations}} + {{#if this.call}} + let {{this.call.var_name}} = {{this.call.call}} + {{#if this.call.defer}} + defer { + {{this.call.defer}} + } + + {{/if}} + {{/if}} + {{#if this.call_optional}} + let ptr: UnsafeRawPointer? + if let {{this.call_optional.var_name}} = {{this.call_optional.var_name}} { + ptr = {{this.call_optional.call}} + } else { + ptr = nil + } + {{#if this.call_optional.defer}} + defer { + if let {{this.call_optional.var_name}} = ptr { + {{this.call_optional.defer}} + } + } + {{/if}} + let {{this.call_optional.var_name}} = ptr + + {{/if}} + {{#if this.guarded_call}} + guard let {{this.guarded_call.var_name}} = {{this.guarded_call.call}} else { + return nil + } + {{/if}} + {{#if this.return}} + return {{this.return.call}} + {{/if}} + {{/each}} + } diff --git a/codegen-v2/src/codegen/swift/templates/partial_init.hbs b/codegen-v2/src/codegen/swift/templates/partial_init.hbs new file mode 100644 index 00000000000..c367bde8435 --- /dev/null +++ b/codegen-v2/src/codegen/swift/templates/partial_init.hbs @@ -0,0 +1,23 @@ + {{#if is_public}}public {{/if}}init{{#if is_nullable}}?{{/if}}({{#each params}}{{name}}: {{type}}{{#if is_nullable}}?{{/if}}{{#unless @last}}, {{/unless}}{{/each}}) { + {{#each operations}} + {{#if this.call}} + let {{this.call.var_name}} = {{this.call.call}} + {{#if this.call.defer}} + defer { + {{this.call.defer}} + } + + {{/if}} + {{/if}} + {{#if this.guarded_call}} + guard let {{this.guarded_call.var_name}} = {{this.guarded_call.call}} else { + return nil + } + {{/if}} + {{#if this.return}} + return {{this.return.call}} + {{/if}} + {{/each}} + + self.rawValue = result + } diff --git a/codegen-v2/src/codegen/swift/templates/partial_prop.hbs b/codegen-v2/src/codegen/swift/templates/partial_prop.hbs new file mode 100644 index 00000000000..fd1d5697866 --- /dev/null +++ b/codegen-v2/src/codegen/swift/templates/partial_prop.hbs @@ -0,0 +1,38 @@ + {{#if is_public}}public {{/if}}var {{name}}: {{return.type}}{{#if return.is_nullable}}?{{/if}} { + {{#each operations}} + {{#if this.call}} + let {{this.call.var_name}} = {{this.call.call}} + {{#if this.call.defer}} + defer { + {{this.call.defer}} + } + + {{/if}} + {{/if}} + {{#if this.call_optional}} + let ptr: UnsafeRawPointer? + if let {{this.call_optional.var_name}} = {{this.call_optional.var_name}} { + ptr = {{this.call_optional.call}} + } else { + ptr = nil + } + {{#if this.call_optional.defer}} + defer { + if let {{this.call_optional.var_name}} = ptr { + {{this.call_optional.defer}} + } + } + {{/if}} + let {{this.call_optional.var_name}} = ptr + + {{/if}} + {{#if this.guarded_call}} + guard let {{this.guarded_call.var_name}} = {{this.guarded_call.call}} else { + return nil + } + {{/if}} + {{#if this.return}} + return {{this.return.call}} + {{/if}} + {{/each}} + } diff --git a/codegen-v2/src/codegen/swift/templates/proto.hbs b/codegen-v2/src/codegen/swift/templates/proto.hbs new file mode 100644 index 00000000000..23e1c541698 --- /dev/null +++ b/codegen-v2/src/codegen/swift/templates/proto.hbs @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. +// +// This is a GENERATED FILE, changes made here WILL BE LOST. +// + +{{#each protos}} +public typealias {{name}} = {{c_ffi_name}} +{{/each}} diff --git a/codegen-v2/src/codegen/swift/templates/struct.hbs b/codegen-v2/src/codegen/swift/templates/struct.hbs new file mode 100644 index 00000000000..eccc0499fd7 --- /dev/null +++ b/codegen-v2/src/codegen/swift/templates/struct.hbs @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. +// +// This is a GENERATED FILE, changes made here WILL BE LOST. +// + +import Foundation + +{{#if is_public}}public {{/if}}{{#if is_class}}final class {{else}}struct {{/if}}{{name}} + {{~#if superclasses}}: {{/if}}{{#each superclasses}}{{this}}{{#unless @last}}, {{/unless}}{{/each}} { + {{#if init_instance}} + let rawValue: OpaquePointer + + init(rawValue: OpaquePointer) { + self.rawValue = rawValue + } + {{else}} + init() {} + {{/if}} + + {{! Equality operator, if available }} + {{#if eq_operator}} + public static func == (lhs: {{name}}, rhs: {{name}}) -> Bool { + return {{eq_operator.c_ffi_name}}(lhs.rawValue, rhs.rawValue) + } + + {{/if}} + {{! Inits }} + {{#each inits}} + {{~> partial_init}} + + {{/each}} + {{! Deinits }} + {{#each deinits}} + deinit { + {{name}}(self.rawValue) + } + + {{/each}} + {{! Methods }} + {{#each methods}} + {{~> partial_func}} + + {{/each}} + {{! Properties }} + {{#each properties}} + {{~> partial_prop}} + {{#unless @last}} + + {{/unless}} + {{/each}} +} diff --git a/codegen-v2/src/codegen/template_generator.rs b/codegen-v2/src/codegen/template_generator.rs new file mode 100644 index 00000000000..7b725ba74e7 --- /dev/null +++ b/codegen-v2/src/codegen/template_generator.rs @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::registry::CoinItem; +use crate::{current_year, Error, Result}; +use std::fs; +use std::path::PathBuf; + +const PATTERNS_CAPACITY: usize = 20; + +pub struct TemplateGenerator { + template_content: &'static str, + write_to: Option, + to_replace: Vec, + replace_with: Vec, +} + +impl TemplateGenerator { + pub fn new(template_content: &'static str) -> TemplateGenerator { + TemplateGenerator { + template_content, + write_to: None, + to_replace: Vec::with_capacity(PATTERNS_CAPACITY), + replace_with: Vec::with_capacity(PATTERNS_CAPACITY), + } + } + + pub fn write_to(mut self, write_to: PathBuf) -> TemplateGenerator { + self.write_to = Some(write_to); + self + } + + /// Use default patterns. + pub fn with_default_patterns(self, coin: &CoinItem) -> TemplateGenerator { + self.add_pattern("{YEAR}", current_year()) + .add_pattern("{BLOCKCHAIN}", coin.blockchain_type()) + .add_pattern("{TW_CRATE_NAME}", coin.id.to_tw_crate_name()) + .add_pattern("{COIN_ID}", coin.id.as_str()) + .add_pattern("{COIN_TYPE}", coin.coin_type()) + .add_pattern("{COIN_NAME}", if coin.display_name.len() > 0 { &coin.display_name } else { &coin.name }) + .add_pattern("{SYMBOL}", &coin.symbol) + .add_pattern("{DECIMALS}", coin.decimals) + .add_pattern("{P2PKH_PREFIX}", coin.p2pkh_prefix) + .add_pattern("{P2SH_PREFIX}", coin.p2sh_prefix) + .add_pattern("{HRP}", coin.hrp.as_str()) + .add_pattern("{STATIC_PREFIX}", coin.static_prefix) + .add_pattern("{EXPLORER_URL}", &coin.explorer.url) + .add_pattern("{EXPLORER_TX_PATH}", &coin.explorer.tx_path) + .add_pattern("{EXPLORER_ACCOUNT_PATH}", &coin.explorer.account_path) + .add_pattern("{EXPLORER_SAMPLE_TX}", &coin.explorer.sample_tx) + .add_pattern("{EXPLORER_SAMPLE_ACCOUNT}", &coin.explorer.sample_account) + } + + pub fn add_pattern( + mut self, + to_replace: K, + replace_with: V, + ) -> TemplateGenerator { + self.to_replace.push(to_replace.to_string()); + self.replace_with.push(replace_with.to_string()); + self + } + + pub fn write(self) -> Result<()> { + let write_to_path = self.write_to.ok_or_else(|| { + Error::io_error_other("Incorrect use of 'TemplateGenerator'".to_string()) + })?; + let file_to_write = fs::File::create(write_to_path)?; + + aho_corasick::AhoCorasick::new(self.to_replace) + .map_err(|e| Error::io_error_other(format!("Invalid patterns: {e}")))? + .try_stream_replace_all( + self.template_content.as_bytes(), + file_to_write, + &self.replace_with, + ) + .map_err(Error::from) + } +} diff --git a/codegen-v2/src/coin_id.rs b/codegen-v2/src/coin_id.rs new file mode 100644 index 00000000000..87a6b9e13c4 --- /dev/null +++ b/codegen-v2/src/coin_id.rs @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::{Error, Result}; +use serde::de::Error as SerdeError; +use serde::{Deserialize, Deserializer}; + +#[derive(Clone, Eq, PartialEq)] +pub struct CoinId(String); + +impl CoinId { + /// Returns `Ok` if only the given `id` is a valid Rust identifier. + pub fn new(id: String) -> Result { + let first_letter = id + .chars() + .next() + .ok_or(Error::RegistryError("Invalid 'id'".to_string()))?; + let valid_chars = id.chars().all(|ch| ch.is_ascii_alphanumeric() || ch == '_'); + + if first_letter.is_numeric() || !valid_chars { + return Err(Error::RegistryError("Invalid 'id'".to_string())); + } + Ok(CoinId(id)) + } + + pub fn to_tw_crate_name(&self) -> String { + format!("tw_{}", self.0) + } + + pub fn as_str(&self) -> &str { + &self.0 + } +} + +impl<'de> Deserialize<'de> for CoinId { + fn deserialize(deserializer: D) -> std::result::Result + where + D: Deserializer<'de>, + { + let id = String::deserialize(deserializer)?; + CoinId::new(id).map_err(|e| SerdeError::custom(format!("{e:?}"))) + } +} diff --git a/codegen-v2/src/lib.rs b/codegen-v2/src/lib.rs new file mode 100644 index 00000000000..3e2c2e2e59d --- /dev/null +++ b/codegen-v2/src/lib.rs @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#[macro_use] +extern crate serde; + +use handlebars::{RenderError, TemplateError}; +use serde_yaml::Error as YamlError; +use std::io; +use std::io::Error as IoError; +use toml_edit::TomlError; + +pub mod codegen; +pub mod coin_id; +pub mod manifest; +pub mod registry; +#[cfg(test)] +mod tests; +pub mod utils; + +pub type Result = std::result::Result; + +#[derive(Debug)] +pub enum Error { + IoError(IoError), + YamlError(YamlError), + RenderError(RenderError), + TemplateError(TemplateError), + BadFormat(String), + RegistryError(String), + TomlFormat(String), + InvalidCommand, +} + +impl Error { + pub fn io_error_other(err: String) -> Error { + Error::IoError(IoError::new(io::ErrorKind::Other, err)) + } +} + +impl From for Error { + fn from(err: IoError) -> Self { + Error::IoError(err) + } +} + +impl From for Error { + fn from(err: YamlError) -> Self { + Error::YamlError(err) + } +} + +impl From for Error { + fn from(err: RenderError) -> Self { + Error::RenderError(err) + } +} + +impl From for Error { + fn from(err: TemplateError) -> Self { + Error::TemplateError(err) + } +} + +impl From for Error { + fn from(err: TomlError) -> Self { + Error::TomlFormat(err.to_string()) + } +} + +fn current_year() -> u64 { + use std::time::{SystemTime, UNIX_EPOCH}; + + let now = SystemTime::now(); + let seconds_since_epoch = now + .duration_since(UNIX_EPOCH) + .expect("System's time is set before the start of the Unix epoch"); + + // One Gregorian calendar year has 365.2425 days, + // respectively 31556952 seconds. + 1970 + (seconds_since_epoch.as_secs() / 31556952) +} diff --git a/codegen-v2/src/main.rs b/codegen-v2/src/main.rs new file mode 100644 index 00000000000..53fd140cc65 --- /dev/null +++ b/codegen-v2/src/main.rs @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use libparser::codegen::swift::RenderIntput; +use libparser::codegen::{cpp, proto, rust}; +use libparser::coin_id::CoinId; +use libparser::manifest::parse_dir; +use libparser::registry::read_coin_from_registry; +use libparser::{Error, Result}; +use std::fs::read_to_string; + +fn main() -> Result<()> { + let args: Vec = std::env::args().collect(); + + if args.len() < 2 { + panic!("Invalid command"); + } + + match args[1].as_str() { + "new-blockchain-rust" => new_blockchain_rust(&args[2..]), + "new-blockchain" => new_blockchain(&args[2..]), + "new-evmchain" => new_evmchain(&args[2..]), + "new-cosmos-chain" => new_cosmos_chain(&args[2..]), + "swift" => generate_swift_bindings(), + _ => Err(Error::InvalidCommand), + } +} + +fn new_blockchain_rust(args: &[String]) -> Result<()> { + let coin_str = args.iter().next().ok_or_else(|| Error::InvalidCommand)?; + let coin_id = CoinId::new(coin_str.clone())?; + let coin_item = read_coin_from_registry(&coin_id)?; + + println!("New Rust blockchain template for coin '{coin_str}' requested"); + rust::new_blockchain::new_blockchain(&coin_item)?; + + Ok(()) +} + +fn new_blockchain(args: &[String]) -> Result<()> { + let coin_str = args.iter().next().ok_or_else(|| Error::InvalidCommand)?; + let coin_id = CoinId::new(coin_str.clone())?; + let coin_item = read_coin_from_registry(&coin_id)?; + + println!("New '{coin_str}' blockchain template requested"); + + proto::new_blockchain::new_blockchain(&coin_item)?; + rust::new_blockchain::new_blockchain(&coin_item)?; + cpp::new_blockchain::new_blockchain(&coin_item)?; + + Ok(()) +} + +fn new_evmchain(args: &[String]) -> Result<()> { + let coin_str = args.iter().next().ok_or_else(|| Error::InvalidCommand)?; + let coin_id = CoinId::new(coin_str.clone())?; + let coin_item = read_coin_from_registry(&coin_id)?; + + println!("New '{coin_str}' EVM chain template requested"); + + rust::new_evmchain::new_evmchain(&coin_item)?; + cpp::new_evmchain::new_evmchain(&coin_item)?; + + Ok(()) +} + +fn new_cosmos_chain(args: &[String]) -> Result<()> { + let coin_str = args.iter().next().ok_or_else(|| Error::InvalidCommand)?; + let coin_id = CoinId::new(coin_str.clone())?; + let coin_item = read_coin_from_registry(&coin_id)?; + + println!("New '{coin_str}' Cosmos chain template requested"); + + rust::new_cosmos_chain::new_cosmos_chain(&coin_item)?; + cpp::new_cosmos_chain::new_cosmos_chain(&coin_item)?; + + Ok(()) +} + +fn generate_swift_bindings() -> Result<()> { + // NOTE: The paths will be configurable, eventually. + const OUT_DIR: &str = "bindings/"; + const IN_DIR: &str = "src/codegen/swift/templates"; + + std::fs::create_dir_all(OUT_DIR)?; + + let struct_t = read_to_string(&format!("{IN_DIR}/struct.hbs"))?; + let enum_t = read_to_string(&format!("{IN_DIR}/enum.hbs"))?; + let ext_t = read_to_string(&format!("{IN_DIR}/extension.hbs"))?; + let proto_t = read_to_string(&format!("{IN_DIR}/proto.hbs"))?; + let part_init_t = read_to_string(&format!("{IN_DIR}/partial_init.hbs"))?; + let part_func_t = read_to_string(&format!("{IN_DIR}/partial_func.hbs"))?; + let part_prop_t = read_to_string(&format!("{IN_DIR}/partial_prop.hbs"))?; + + // Read the manifest dir, generate bindings for each entry. + let file_infos = parse_dir("manifest/")?; + + for file_info in file_infos { + let input = RenderIntput { + file_info, + struct_template: &struct_t, + enum_template: &enum_t, + extension_template: &ext_t, + proto_template: &proto_t, + partial_init_template: &part_init_t, + partial_func_tempalte: &part_func_t, + partial_prop_tempalte: &part_prop_t, + }; + + let rendered = libparser::codegen::swift::render_to_strings(input)?; + + // Enum declarations go into their own subfolder. + if !rendered.enums.is_empty() { + std::fs::create_dir_all(format!("{OUT_DIR}/Enums"))?; + } + + // Protobuf declarations go into their own subfolder. + if !rendered.protos.is_empty() { + std::fs::create_dir_all(format!("{OUT_DIR}/Protobuf"))?; + } + + for (name, rendered) in rendered.structs { + let file_path = format!("{OUT_DIR}/{name}.swift"); + std::fs::write(&file_path, rendered.as_bytes())?; + } + + for (name, rendered) in rendered.enums { + let file_path = format!("{OUT_DIR}/Enums/{name}.swift"); + std::fs::write(&file_path, rendered.as_bytes())?; + } + + // Enum extensions. + for (name, rendered) in rendered.extensions { + let file_path = format!("{OUT_DIR}/{name}+Extension.swift"); + std::fs::write(&file_path, rendered.as_bytes())?; + } + + // Protobuf messages. + for (name, rendered) in rendered.protos { + let file_path = format!("{OUT_DIR}/Protobuf/{name}+Proto.swift"); + std::fs::write(&file_path, rendered.as_bytes())?; + } + } + + println!("Created bindings in directory 'bindings/'!"); + Ok(()) +} diff --git a/codegen-v2/src/manifest.rs b/codegen-v2/src/manifest.rs new file mode 100644 index 00000000000..f70c24b2e5a --- /dev/null +++ b/codegen-v2/src/manifest.rs @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use super::Result; +use std::fs; +use std::path::Path; + +pub fn parse_dir>(path: P) -> Result> { + // Get a list of all files in the directory + let entries = fs::read_dir(path)?; + + let mut file_infos = vec![]; + for entry in entries { + let entry = entry?; + let file_path = entry.path(); + + // Skip directories + if file_path.is_dir() { + println!("Found unexpected directory: {}", file_path.display()); + continue; + } + + // Read the file into a string + let file_contents = fs::read_to_string(&file_path)?; + + // Deserialize the JSON into a struct + let info = parse_str(&file_contents)?; + file_infos.push(info); + } + + Ok(file_infos) +} + +pub fn parse_str(str: &str) -> Result { + serde_yaml::from_str(str).map_err(|err| err.into()) +} + +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub struct TypeInfo { + #[serde(flatten)] + pub variant: TypeVariant, + pub is_constant: bool, + pub is_nullable: bool, + pub is_pointer: bool, +} + +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[serde(tag = "variant", content = "value", rename_all = "snake_case")] +pub enum TypeVariant { + Void, + Bool, + Char, + ShortInt, + Int, + UnsignedInt, + LongInt, + Float, + Double, + SizeT, + Int8T, + Int16T, + Int32T, + Int64T, + UInt8T, + UInt16T, + UInt32T, + UInt64T, + Struct(String), + Enum(String), + Data, + String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct FileInfo { + pub name: String, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub structs: Vec, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub inits: Vec, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub deinits: Vec, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub enums: Vec, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub functions: Vec, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub properties: Vec, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub protos: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ImportInfo { + // Expressed as directories plus the final file. + // E.g. `to/some/file.h` ~= ["to", "some", "file.h"] + pub path: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ProtoInfo(pub String); + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct EnumInfo { + pub name: String, + pub is_public: bool, + pub value_type: TypeVariant, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub variants: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct EnumVariantInfo { + pub name: String, + pub value: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub as_string: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct StructInfo { + pub name: String, + pub is_public: bool, + pub is_class: bool, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub fields: Vec<(String, TypeInfo)>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct InitInfo { + pub name: String, + pub is_public: bool, + pub is_nullable: bool, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub params: Vec, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub comments: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct DeinitInfo { + pub name: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct FunctionInfo { + pub name: String, + pub is_public: bool, + pub is_static: bool, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub params: Vec, + pub return_type: TypeInfo, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub comments: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PropertyInfo { + pub name: String, + pub is_public: bool, + pub return_type: TypeInfo, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub comments: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ParamInfo { + pub name: String, + #[serde(rename = "type")] + pub ty: TypeInfo, +} diff --git a/codegen-v2/src/registry.rs b/codegen-v2/src/registry.rs new file mode 100644 index 00000000000..c83ef174dd0 --- /dev/null +++ b/codegen-v2/src/registry.rs @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::coin_id::CoinId; +use crate::{Error, Result}; +use convert_case::{Case, Casing}; +use std::path::PathBuf; +use std::{env, fs}; + +pub fn registry_json_path() -> PathBuf { + PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()) + .join("..") + .join("registry.json") +} + +#[derive(Clone, Deserialize)] +pub struct CoinExplorer { + pub url: String, + #[serde(rename = "txPath")] + pub tx_path: String, + #[serde(rename = "accountPath")] + pub account_path: String, + #[serde(rename = "sampleTx")] + #[serde(default)] + pub sample_tx: String, + #[serde(rename = "sampleAccount")] + #[serde(default)] + pub sample_account: String, +} + +#[derive(Clone, Deserialize)] +pub struct CoinItem { + pub id: CoinId, + pub name: String, + #[serde(rename = "displayName")] + #[serde(default)] + pub display_name: String, + #[serde(rename = "coinId")] + pub coin_id_number: u32, + pub symbol: String, + pub decimals: u8, + pub blockchain: String, + #[serde(rename = "p2pkhPrefix")] + #[serde(default)] + pub p2pkh_prefix: u8, + #[serde(rename = "p2shPrefix")] + #[serde(default)] + pub p2sh_prefix: u8, + #[serde(rename = "staticPrefix")] + #[serde(default)] + pub static_prefix: u8, + #[serde(default)] + pub hrp: String, + pub explorer: CoinExplorer, +} + +impl CoinItem { + /// Transforms a coin name to a Rust name. + /// https://github.com/trustwallet/wallet-core/blob/3769f31b7d0c75126b2f426bb065364429aaa379/codegen/lib/coin_skeleton_gen.rb#L15-L22 + pub fn coin_type(&self) -> String { + self.name.replace([' ', '.', '-'], "") + } + + /// Returns the blockchain type in `UpperCamel` case. + pub fn blockchain_type(&self) -> String { + self.blockchain.to_case(Case::UpperCamel) + } + + /// Returns the blockchain type in `UPPER_SNAKE` case. + pub fn blockchain_entry_upper_snake(&self) -> String { + self.blockchain.to_case(Case::UpperSnake) + } + + /// Returns a Rust blockchain entry of the blockchain. + pub fn blockchain_entry(&self) -> String { + format!("{}Entry", self.blockchain_type()) + } +} + +pub fn read_coin_from_registry(coin: &CoinId) -> Result { + let registry_path = registry_json_path(); + + let registry_bytes = fs::read(registry_path)?; + let coins: Vec = + serde_json::from_slice(®istry_bytes).map_err(|e| Error::RegistryError(e.to_string()))?; + + coins + .into_iter() + .find(|item| item.id == *coin) + .ok_or(Error::InvalidCommand) +} diff --git a/codegen-v2/src/tests/mod.rs b/codegen-v2/src/tests/mod.rs new file mode 100644 index 00000000000..6a889017da4 --- /dev/null +++ b/codegen-v2/src/tests/mod.rs @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::codegen::swift::{render_to_strings, RenderIntput}; +use crate::manifest::parse_str; + +/// Convenience function. +fn create_intput(yaml: &str) -> RenderIntput { + let file_info = parse_str(yaml).unwrap(); + + RenderIntput { + file_info, + struct_template: include_str!("../codegen/swift/templates/struct.hbs"), + enum_template: include_str!("../codegen/swift/templates/enum.hbs"), + extension_template: include_str!("../codegen/swift/templates/extension.hbs"), + proto_template: include_str!("../codegen/swift/templates/proto.hbs"), + partial_init_template: include_str!("../codegen/swift/templates/partial_init.hbs"), + partial_func_tempalte: include_str!("../codegen/swift/templates/partial_func.hbs"), + partial_prop_tempalte: include_str!("../codegen/swift/templates/partial_prop.hbs"), + } +} + +// Convenience function: runs the codegen on the given `input` and compares it +// with the `expected` value. Expects a single, rendered file as output. +fn render_and_compare_struct(input: &str, expected: &str) { + let input = create_intput(input); + let rendered = render_to_strings(input).unwrap(); + + assert_eq!(rendered.structs.len(), 1); + assert!(rendered.enums.is_empty()); + assert!(rendered.extensions.is_empty()); + assert!(rendered.protos.is_empty()); + + let (_name, output) = &rendered.structs[0]; + println!("{output}"); + assert_eq!(output, expected); +} + +fn render_and_compare_enum(input: &str, expected: &str) { + let input = create_intput(input); + let rendered = render_to_strings(input).unwrap(); + + assert!(rendered.structs.is_empty()); + assert_eq!(rendered.enums.len(), 1); + assert!(rendered.extensions.is_empty()); + assert!(rendered.protos.is_empty()); + + let (_name, output) = &rendered.enums[0]; + assert_eq!(output, expected); +} + +#[test] +fn single_struct() { + const INPUT: &str = include_str!("samples/struct.input.yaml"); + const EXPECTED: &str = include_str!("samples/struct.output.swift"); + + render_and_compare_struct(INPUT, EXPECTED); +} + +#[test] +fn single_class() { + const INPUT: &str = include_str!("samples/class.input.yaml"); + const EXPECTED: &str = include_str!("samples/class.output.swift"); + + render_and_compare_struct(INPUT, EXPECTED); +} + +#[test] +fn private() { + const INPUT: &str = include_str!("samples/private_class.input.yaml"); + const EXPECTED: &str = include_str!("samples/private_class.output.swift"); + + render_and_compare_struct(INPUT, EXPECTED); +} + +#[test] +fn optional() { + const INPUT: &str = include_str!("samples/optional.input.yaml"); + const EXPECTED: &str = include_str!("samples/optional.output.swift"); + + render_and_compare_struct(INPUT, EXPECTED); +} + +#[test] +fn enum_with_description() { + const INPUT: &str = include_str!("samples/enum.input.yaml"); + const EXPECTED: &str = include_str!("samples/enum.output.swift"); + + render_and_compare_enum(INPUT, EXPECTED); +} + +#[test] +fn privat_enum_with_description() { + const INPUT: &str = include_str!("samples/enum_private.input.yaml"); + const EXPECTED: &str = include_str!("samples/enum_private.output.swift"); + + render_and_compare_enum(INPUT, EXPECTED); +} + +#[test] +fn enum_with_extension() { + const INPUT: &str = include_str!("samples/enum_extension.input.yaml"); + const EXPECTED_ENUM: &str = include_str!("samples/enum.output.swift"); + const EXPECTED_EXTENSION: &str = include_str!("samples/enum_extension.output.swift"); + + let input = create_intput(INPUT); + let rendered = render_to_strings(input).unwrap(); + + assert!(rendered.structs.is_empty()); + assert_eq!(rendered.enums.len(), 1); + assert_eq!(rendered.extensions.len(), 1); + assert!(rendered.protos.is_empty()); + + // Check generated enum. + let (_name, output) = &rendered.enums[0]; + assert_eq!(output, EXPECTED_ENUM); + + // Check generated extension. + let (_name, output) = &rendered.extensions[0]; + assert_eq!(output, EXPECTED_EXTENSION); +} + +#[test] +fn non_associated() { + const INPUT: &str = include_str!("samples/non-associated.input.yaml"); + const EXPECTED: &str = include_str!("samples/non-associated.output.swift"); + + render_and_compare_struct(INPUT, EXPECTED); +} diff --git a/codegen-v2/src/tests/samples/class.input.yaml b/codegen-v2/src/tests/samples/class.input.yaml new file mode 100644 index 00000000000..2593f18a6dc --- /dev/null +++ b/codegen-v2/src/tests/samples/class.input.yaml @@ -0,0 +1,42 @@ +name: Class +structs: +- name: MainStruct + is_public: true + is_class: true +inits: +- name: MainStructCreate + is_public: true + is_nullable: false + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +deinits: +- name: MainStructDelete +functions: +- name: MainStructFirstFunction + is_public: true + is_static: true + params: + - name: first_param + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +properties: +- name: MainStructFirstProperty + is_public: true + return_type: + variant: bool + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/src/tests/samples/class.output.swift b/codegen-v2/src/tests/samples/class.output.swift new file mode 100644 index 00000000000..ed7c0b000ac --- /dev/null +++ b/codegen-v2/src/tests/samples/class.output.swift @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. +// +// This is a GENERATED FILE, changes made here WILL BE LOST. +// + +import Foundation + +public final class MainStruct { + let rawValue: OpaquePointer + + init(rawValue: OpaquePointer) { + self.rawValue = rawValue + } + + public init(string: String) { + let string = TWStringCreateWithNSString(string) + defer { + TWStringDelete(string) + } + + let result = MainStructCreate(string) + + self.rawValue = result + } + + deinit { + MainStructDelete(self.rawValue) + } + + public static func firstFunction(first_param: Int32) -> Bool { + let result = MainStructFirstFunction(first_param) + return result + } + + public var firstProperty: Bool { + let obj = self.rawValue + let result = MainStructFirstProperty(obj) + return result + } +} diff --git a/codegen-v2/src/tests/samples/enum.input.yaml b/codegen-v2/src/tests/samples/enum.input.yaml new file mode 100644 index 00000000000..32beb097c95 --- /dev/null +++ b/codegen-v2/src/tests/samples/enum.input.yaml @@ -0,0 +1,15 @@ +name: Enum +enums: +- name: MainEnum + is_public: true + value_type: + variant: u_int32_t + variants: + - name: one + value: 0 + as_string: one_string + - name: two + value: 1 + - name: three + value: 2 + as_string: three_string diff --git a/codegen-v2/src/tests/samples/enum.output.swift b/codegen-v2/src/tests/samples/enum.output.swift new file mode 100644 index 00000000000..0e5b8346d6f --- /dev/null +++ b/codegen-v2/src/tests/samples/enum.output.swift @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. +// +// This is a GENERATED FILE, changes made here WILL BE LOST. +// + +public enum MainEnum: UInt32, CaseIterable, CustomStringConvertible { + case `one` = 0 + case `two` = 1 + case `three` = 2 + + public var description: String { + switch self { + case .one: return "one_string" + case .two: return "" + case .three: return "three_string" + } + } +} diff --git a/codegen-v2/src/tests/samples/enum_extension.input.yaml b/codegen-v2/src/tests/samples/enum_extension.input.yaml new file mode 100644 index 00000000000..86551b52a83 --- /dev/null +++ b/codegen-v2/src/tests/samples/enum_extension.input.yaml @@ -0,0 +1,47 @@ +name: EnumExtension +enums: +- name: MainEnum + is_public: true + value_type: + variant: u_int32_t + variants: + - name: one + value: 0 + as_string: one_string + - name: two + value: 1 + - name: three + value: 2 + as_string: three_string +functions: +- name: MainEnumFirstFunction + is_public: true + is_static: true + params: + - name: first_param + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: MainEnumSecondFunction + is_public: true + is_static: true + params: + - name: first_param + type: + variant: struct + value: SomeStruct + is_constant: false + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false diff --git a/codegen-v2/src/tests/samples/enum_extension.output.swift b/codegen-v2/src/tests/samples/enum_extension.output.swift new file mode 100644 index 00000000000..706368ee760 --- /dev/null +++ b/codegen-v2/src/tests/samples/enum_extension.output.swift @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. +// +// This is a GENERATED FILE, changes made here WILL BE LOST. +// + +extension MainEnum { + public static func firstFunction(first_param: Int32) -> Bool { + let result = MainEnumFirstFunction(first_param) + return result + } + + public static func secondFunction(first_param: SomeStruct) -> Bool { + let first_param = first_param.rawValue + let result = MainEnumSecondFunction(first_param) + return result + } +} diff --git a/codegen-v2/src/tests/samples/enum_private.input.yaml b/codegen-v2/src/tests/samples/enum_private.input.yaml new file mode 100644 index 00000000000..db0ca4d0850 --- /dev/null +++ b/codegen-v2/src/tests/samples/enum_private.input.yaml @@ -0,0 +1,16 @@ +name: EnumPrivate +enums: +- name: MainEnum + is_public: false + value_type: + variant: u_int32_t + # Note that the `description` method is always public. + variants: + - name: one + value: 0 + as_string: one_string + - name: two + value: 1 + - name: three + value: 2 + as_string: three_string diff --git a/codegen-v2/src/tests/samples/enum_private.output.swift b/codegen-v2/src/tests/samples/enum_private.output.swift new file mode 100644 index 00000000000..b2cb22aea3a --- /dev/null +++ b/codegen-v2/src/tests/samples/enum_private.output.swift @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. +// +// This is a GENERATED FILE, changes made here WILL BE LOST. +// + +enum MainEnum: UInt32, CaseIterable, CustomStringConvertible { + case `one` = 0 + case `two` = 1 + case `three` = 2 + + public var description: String { + switch self { + case .one: return "one_string" + case .two: return "" + case .three: return "three_string" + } + } +} diff --git a/codegen-v2/src/tests/samples/non-associated.input.yaml b/codegen-v2/src/tests/samples/non-associated.input.yaml new file mode 100644 index 00000000000..21a42bf3a3d --- /dev/null +++ b/codegen-v2/src/tests/samples/non-associated.input.yaml @@ -0,0 +1,79 @@ +name: NonAssociated +structs: +- name: MainStruct + is_public: true + is_class: true +inits: +- name: MainStructCreate + is_public: true + is_nullable: false + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +# Non-associated. +- name: OtherStructCreate + is_public: true + is_nullable: false + params: + - name: number + type: + variant: int + is_constant: true + is_nullable: false + is_pointer: true +deinits: +- name: MainStructDelete +# Non-associated. +- name: OtherStructDelete +functions: +# Non-associated. +- name: OtherStructFirstFunction + is_public: true + is_static: true + params: + - name: first_param + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +- name: MainStructSecondFunction + is_public: true + is_static: true + params: + - name: first_param + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +properties: +- name: MainStructFirstProperty + is_public: true + return_type: + variant: bool + is_constant: true + is_nullable: false + is_pointer: true +# Non-associated. +- name: OtherStructSecondProperty + is_public: true + return_type: + variant: bool + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/src/tests/samples/non-associated.output.swift b/codegen-v2/src/tests/samples/non-associated.output.swift new file mode 100644 index 00000000000..478b8b1d6b5 --- /dev/null +++ b/codegen-v2/src/tests/samples/non-associated.output.swift @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. +// +// This is a GENERATED FILE, changes made here WILL BE LOST. +// + +import Foundation + +public final class MainStruct { + let rawValue: OpaquePointer + + init(rawValue: OpaquePointer) { + self.rawValue = rawValue + } + + public init(string: String) { + let string = TWStringCreateWithNSString(string) + defer { + TWStringDelete(string) + } + + let result = MainStructCreate(string) + + self.rawValue = result + } + + deinit { + MainStructDelete(self.rawValue) + } + + public static func secondFunction(first_param: Int32) -> Bool { + let result = MainStructSecondFunction(first_param) + return result + } + + public var firstProperty: Bool { + let obj = self.rawValue + let result = MainStructFirstProperty(obj) + return result + } +} diff --git a/codegen-v2/src/tests/samples/optional.input.yaml b/codegen-v2/src/tests/samples/optional.input.yaml new file mode 100644 index 00000000000..d235f0d6262 --- /dev/null +++ b/codegen-v2/src/tests/samples/optional.input.yaml @@ -0,0 +1,112 @@ +name: Optional +structs: +- name: MainStruct + is_public: true + is_class: true +inits: +- name: MainStructCreate + is_public: true + is_nullable: true + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: true + is_pointer: true +deinits: +- name: MainStructDelete +functions: +- name: MainStructWithOptionalInt + is_public: true + is_static: true + params: + - name: first_param + type: + variant: int + is_constant: false + is_nullable: true + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: true + is_pointer: false +- name: MainStructWithOptionalStruct + is_public: true + is_static: true + params: + - name: first_param + type: + variant: struct + value: SomeStruct + is_constant: false + is_nullable: true + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: true + is_pointer: false +- name: MainStructWithOptionalString + is_public: true + is_static: true + params: + - name: first_param + type: + variant: string + is_constant: false + is_nullable: true + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: true + is_pointer: false +- name: MainStructWithOptionalEnum + is_public: true + is_static: true + params: + - name: first_param + type: + variant: enum + value: SomeEnum + is_constant: false + is_nullable: true + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: true + is_pointer: false +properties: +- name: MainStructWithOptionalInt + is_public: true + return_type: + variant: int + is_constant: true + is_nullable: true + is_pointer: true +- name: MainStructWithOptionalString + is_public: true + return_type: + variant: string + is_constant: true + is_nullable: true + is_pointer: true +- name: MainStructWithOptionalStruct + is_public: true + return_type: + variant: struct + value: SomeStruct + is_constant: true + is_nullable: true + is_pointer: true +- name: MainStructWithOptionalEnum + is_public: true + return_type: + variant: enum + value: SomeEnum + is_constant: true + is_nullable: true + is_pointer: true diff --git a/codegen-v2/src/tests/samples/optional.output.swift b/codegen-v2/src/tests/samples/optional.output.swift new file mode 100644 index 00000000000..a33b4afea58 --- /dev/null +++ b/codegen-v2/src/tests/samples/optional.output.swift @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. +// +// This is a GENERATED FILE, changes made here WILL BE LOST. +// + +import Foundation + +public final class MainStruct { + let rawValue: OpaquePointer + + init(rawValue: OpaquePointer) { + self.rawValue = rawValue + } + + public init?(string: String?) { + guard let result = MainStructCreate(string) else { + return nil + } + + self.rawValue = result + } + + deinit { + MainStructDelete(self.rawValue) + } + + public static func withOptionalInt(first_param: Int32?) -> Bool? { + guard let result = MainStructWithOptionalInt(first_param) else { + return nil + } + return result + } + + public static func withOptionalStruct(first_param: SomeStruct?) -> Bool? { + let first_param = first_param?.rawValue + guard let result = MainStructWithOptionalStruct(first_param) else { + return nil + } + return result + } + + public static func withOptionalString(first_param: String?) -> Bool? { + let ptr: UnsafeRawPointer? + if let first_param = first_param { + ptr = TWStringCreateWithNSString(first_param) + } else { + ptr = nil + } + defer { + if let first_param = ptr { + TWStringDelete(first_param) + } + } + let first_param = ptr + + guard let result = MainStructWithOptionalString(first_param) else { + return nil + } + return result + } + + public static func withOptionalEnum(first_param: SomeEnum?) -> Bool? { + let first_param = SomeEnum(rawValue: first_param.rawValue) + guard let result = MainStructWithOptionalEnum(first_param) else { + return nil + } + return result + } + + public var withOptionalInt: Int32? { + let obj = self.rawValue + guard let result = MainStructWithOptionalInt(obj) else { + return nil + } + return result + } + + public var withOptionalString: String? { + let obj = self.rawValue + guard let result = MainStructWithOptionalString(obj) else { + return nil + } + return TWStringNSString(result) + } + + public var withOptionalStruct: SomeStruct? { + let obj = self.rawValue + guard let result = MainStructWithOptionalStruct(obj) else { + return nil + } + return SomeStruct(rawValue: result) + } + + public var withOptionalEnum: SomeEnum? { + let obj = self.rawValue + guard let result = MainStructWithOptionalEnum(obj) else { + return nil + } + return SomeEnum(rawValue: result.rawValue)! + } +} diff --git a/codegen-v2/src/tests/samples/private_class.input.yaml b/codegen-v2/src/tests/samples/private_class.input.yaml new file mode 100644 index 00000000000..65365d45781 --- /dev/null +++ b/codegen-v2/src/tests/samples/private_class.input.yaml @@ -0,0 +1,42 @@ +name: PrivateClass +structs: +- name: MainStruct + is_public: false + is_class: true +inits: +- name: MainStructCreate + is_public: false + is_nullable: false + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +deinits: +- name: MainStructDelete +functions: +- name: MainStructFirstFunction + is_public: false + is_static: true + params: + - name: first_param + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +properties: +- name: MainStructFirstProperty + is_public: false + return_type: + variant: bool + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/src/tests/samples/private_class.output.swift b/codegen-v2/src/tests/samples/private_class.output.swift new file mode 100644 index 00000000000..2362367af00 --- /dev/null +++ b/codegen-v2/src/tests/samples/private_class.output.swift @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. +// +// This is a GENERATED FILE, changes made here WILL BE LOST. +// + +import Foundation + +final class MainStruct { + let rawValue: OpaquePointer + + init(rawValue: OpaquePointer) { + self.rawValue = rawValue + } + + init(string: String) { + let string = TWStringCreateWithNSString(string) + defer { + TWStringDelete(string) + } + + let result = MainStructCreate(string) + + self.rawValue = result + } + + deinit { + MainStructDelete(self.rawValue) + } + + static func firstFunction(first_param: Int32) -> Bool { + let result = MainStructFirstFunction(first_param) + return result + } + + var firstProperty: Bool { + let obj = self.rawValue + let result = MainStructFirstProperty(obj) + return result + } +} diff --git a/codegen-v2/src/tests/samples/struct.input.yaml b/codegen-v2/src/tests/samples/struct.input.yaml new file mode 100644 index 00000000000..1e21a100e81 --- /dev/null +++ b/codegen-v2/src/tests/samples/struct.input.yaml @@ -0,0 +1,42 @@ +name: Struct +structs: +- name: MainStruct + is_public: true + is_class: false +inits: +- name: MainStructCreate + is_public: true + is_nullable: false + params: + - name: string + type: + variant: string + is_constant: true + is_nullable: false + is_pointer: true +deinits: +- name: MainStructDelete +functions: +- name: MainStructFirstFunction + is_public: true + is_static: true + params: + - name: first_param + type: + variant: int + is_constant: false + is_nullable: false + is_pointer: true + return_type: + variant: bool + is_constant: false + is_nullable: false + is_pointer: false +properties: +- name: MainStructFirstProperty + is_public: true + return_type: + variant: bool + is_constant: true + is_nullable: false + is_pointer: true diff --git a/codegen-v2/src/tests/samples/struct.output.swift b/codegen-v2/src/tests/samples/struct.output.swift new file mode 100644 index 00000000000..34f310c1eb8 --- /dev/null +++ b/codegen-v2/src/tests/samples/struct.output.swift @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. +// +// This is a GENERATED FILE, changes made here WILL BE LOST. +// + +import Foundation + +public struct MainStruct { + init() {} + + public init(string: String) { + let string = TWStringCreateWithNSString(string) + defer { + TWStringDelete(string) + } + + let result = MainStructCreate(string) + + self.rawValue = result + } + + deinit { + MainStructDelete(self.rawValue) + } + + public static func firstFunction(first_param: Int32) -> Bool { + let result = MainStructFirstFunction(first_param) + return result + } + + public var firstProperty: Bool { + let obj = self.rawValue + let result = MainStructFirstProperty(obj) + return result + } +} diff --git a/codegen-v2/src/utils.rs b/codegen-v2/src/utils.rs new file mode 100644 index 00000000000..a61222fc3fd --- /dev/null +++ b/codegen-v2/src/utils.rs @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::{Error, Result}; +use std::fs; +use std::path::{Path, PathBuf}; + +pub fn read_lines>(path: P) -> Result> { + let lines = fs::read_to_string(path)? + .split('\n') + .map(|line| line.to_string()) + .collect(); + Ok(lines) +} + +pub fn write_lines>(path: P, lines: Vec) -> Result<()> { + let content = lines.join("\n"); + fs::write(path, content).map_err(Error::from) +} + +pub struct FileContent { + path: PathBuf, + lines: Vec, +} + +impl FileContent { + pub fn read(path: PathBuf) -> Result { + read_lines(&path).map(|lines| FileContent { path, lines }) + } + + pub fn find_region_with_prefix(&mut self, prefix: &str) -> Result> { + // Find the first line that starts with the `prefix`. + let region_starts_at = self + .lines + .iter() + .position(|line| line.starts_with(prefix)) + .ok_or_else(|| Error::io_error_other(format!("Cannot find the `{prefix}` region")))?; + + // Find the last line that starts with the `prefix`. + let region_ends_at = self + .lines + .iter() + .rposition(|line| line.starts_with(prefix)) + .ok_or_else(|| Error::io_error_other(format!("Cannot find the `{prefix}` region")))?; + + Ok(FileRegion { + lines: &mut self.lines, + region_starts_at, + region_ends_at, + }) + } + + pub fn find_region_with_comments( + &mut self, + start_comment: &str, + end_comment: &str, + ) -> Result> { + // Find the position of the `start_comment`. + let start_comment_at = self + .lines + .iter() + .position(|line| line.contains(start_comment)) + .ok_or_else(|| { + Error::io_error_other(format!("Cannot find the `{start_comment}` line")) + })?; + let end_comment_at = self + .lines + .iter() + .skip(start_comment_at) + .position(|line| line.contains(end_comment)) + .ok_or_else(|| { + Error::io_error_other(format!("Cannot find the `{end_comment}` line")) + })? + + start_comment_at; + + let region_starts_at = start_comment_at + 1; + let region_ends_at = end_comment_at - 1; + + if region_starts_at > region_ends_at { + return Err(Error::io_error_other(format!( + "There must be the content between {start_comment} and {end_comment}" + ))); + } + + Ok(FileRegion { + lines: &mut self.lines, + region_starts_at, + region_ends_at, + }) + } + + pub fn rfind_line(&mut self, f: F) -> Result> + where + F: Fn(&str) -> bool, + { + let line_idx = self.lines.iter().rposition(|line| f(line)).ok_or_else(|| { + Error::io_error_other(format!( + "{:?} file does not contain a required pattern", + self.path + )) + })?; + Ok(LinePointer { + lines: &mut self.lines, + line_idx, + }) + } + + pub fn write(self) -> Result<()> { + write_lines(self.path, self.lines) + } +} + +pub struct FileRegion<'a> { + lines: &'a mut Vec, + region_starts_at: usize, + region_ends_at: usize, +} + +impl<'a> FileRegion<'a> { + pub fn push_line(&mut self, line: String) { + self.lines.insert(self.region_ends_at + 1, line); + self.region_ends_at += 1; + } + + pub fn sort(&mut self) { + self.lines[self.region_starts_at..=self.region_ends_at].sort() + } + + pub fn count_lines(&self) -> usize { + self.region_ends_at - self.region_starts_at + } +} + +pub struct LinePointer<'a> { + lines: &'a mut Vec, + line_idx: usize, +} + +impl<'a> LinePointer<'a> { + /// Please note that the line pointer will be shifted to the same line on which it pointed before. + pub fn push_line_before(&mut self, line: String) { + self.lines.insert(self.line_idx, line); + self.line_idx += 1; + } + + pub fn push_paragraph_before(&mut self, paragraph: String) { + for line in paragraph.split("\n") { + self.push_line_before(line.to_string()); + } + } + + /// Please note that the line pointer will not be shifted to the pushed element. + pub fn push_line_after(&mut self, line: String) { + self.lines.insert(self.line_idx + 1, line); + } +} diff --git a/codegen/bin/codegen b/codegen/bin/codegen index 8fc86c7e86e..5cd99179bb8 100755 --- a/codegen/bin/codegen +++ b/codegen/bin/codegen @@ -22,6 +22,7 @@ options.jni_h = true options.jni_c = true options.wasm_cpp = true options.ts_declaration = true +options.kotlin = true OptionParser.new do |opts| opts.banner = 'Usage: codegen [options]' @@ -50,6 +51,9 @@ OptionParser.new do |opts| opts.on('-t', '--typescript-declaration', "Generate typescript declaration file Default: #{options.ts_declaration}") do |v| options.ts_declaration = v end + opts.on('-k', '--kotlin', "Generate Kotlin code. Default: #{options.kotlin}") do |v| + options.kotlin = v + end opts.on_tail('-h', '--help', 'Show this message') do puts opts exit @@ -88,3 +92,12 @@ end if options.ts_declaration generator.render_ts_declaration end +if options.kotlin + generator.render_kotlin_common + generator.render_kotlin_android + generator.render_kotlin_ios + generator.render_kotlin_js + generator.render_kotlin_js_accessors + generator.render_kotlin_jni_h + generator.render_kotlin_jni_c +end diff --git a/codegen/bin/coins b/codegen/bin/coins index a5ea5909e05..c5a3690c1a4 100755 --- a/codegen/bin/coins +++ b/codegen/bin/coins @@ -4,6 +4,10 @@ require 'erb' require 'fileutils' require 'json' +CurrentDir = File.dirname(__FILE__) +$LOAD_PATH.unshift(File.join(CurrentDir, '..', 'lib')) +require 'derivation' + # Transforms a coin name to a C++ name def self.format_name(n) formatted = n @@ -18,24 +22,10 @@ def self.coin_name(coin) coin['displayName'] || coin['name'] end -def self.derivation_path(coin) - coin['derivation'][0]['path'] -end - def self.camel_case(id) id[0].upcase + id[1..].downcase end -def self.derivation_name(deriv) - return "" if deriv['name'].nil? - deriv['name'].downcase -end - -def self.derivation_enum_name(deriv, coin) - return "TWDerivationDefault" if deriv['name'].nil? - "TWDerivation" + format_name(coin['name']) + camel_case(deriv['name']) -end - def self.coin_img(coin) "" end @@ -55,7 +45,6 @@ coins = JSON.parse(json_string).sort_by { |x| x['coinId'] } enum_count = 0 erbs = [ - {'template' => 'TWDerivation.h.erb', 'folder' => 'include/TrustWalletCore', 'file' => 'TWDerivation.h'}, {'template' => 'CoinInfoData.cpp.erb', 'folder' => 'src/Generated', 'file' => 'CoinInfoData.cpp'}, {'template' => 'registry.md.erb', 'folder' => 'docs', 'file' => 'registry.md'}, {'template' => 'hrp.cpp.erb', 'folder' => 'src/Generated', 'file' => 'TWHRP.cpp'}, @@ -63,6 +52,9 @@ erbs = [ {'template' => 'TWEthereumChainID.h.erb', 'folder' => 'include/TrustWalletCore', 'file' => 'TWEthereumChainID.h'} ] +# Update coins derivations if changed. +update_derivation_enum(coins) + FileUtils.mkdir_p File.join('src', 'Generated') erbs.each do |erb| path = File.expand_path(erb['template'], File.join(File.dirname(__FILE__), '..', 'lib', 'templates')) diff --git a/codegen/bin/newcoin b/codegen/bin/newcoin index af985bd292b..ee14b241f7a 100755 --- a/codegen/bin/newcoin +++ b/codegen/bin/newcoin @@ -1,96 +1,14 @@ #!/usr/bin/env ruby -# Sript for creating new skeleton files for a new coin -# 1. Add relevsant entry to registry.json (in order to minimize merge conflict, don't add at the very end) +# Sript for creating new skeleton files for a new coin. See also `newevmchain`. +# 1. Add relevant entry to registry.json (in order to minimize merge conflict, don't add at the very end) # 2. Invoke this script with the id of the coin, e.g.: codegen/bin/newcoin ethereum -require 'erb' require 'fileutils' -require 'json' CurrentDir = File.dirname(__FILE__) $LOAD_PATH.unshift(File.join(CurrentDir, '..', 'lib')) -require 'entity_decl' -require 'code_generator' -require 'coin_test_gen' - -$flag_comment = " // TODO remove if the blockchain already exists, or just remove this comment if not" - -# Transforms a coin name to a C++ name -def self.format_name(coin) - formatted = coin['name'] - formatted = formatted.gsub(/-/, ' ') - formatted = formatted.gsub(/\./, ' ') - formatted = formatted.gsub(/\s/, '') - formatted -end - -def self.format_name_lowercase(coin) - format_name(coin).downcase -end - -def self.format_name_uppercase(coin) - format_name(coin).upcase -end - -def self.generate_file(templateFile, folder, fileName, coin) - @coin = coin - name = format_name(coin) - path = File.expand_path(templateFile, File.join(File.dirname(__FILE__), '..', 'lib', 'templates')) - template = ERB.new(File.read(path), nil, '-') - result = template.result(binding) - - FileUtils.mkdir_p folder - path = File.join(folder, fileName) - File.write(path, result) - puts "Generated file " + path -end - -def self.insert_coin_type(coin) - target_file = "include/TrustWalletCore/TWCoinType.h" - target_line = " TWCoinType#{format_name(coin)} = #{coin['coinId']},\n" - if insert_target_line(target_file, target_line, "};\n") - insert_blockchain_type(coin) - end -end - -def insert_blockchain_type(coin) - target_file = "include/TrustWalletCore/TWBlockchain.h" - line_number = File.readlines(target_file).count + 2 # add offset because of removed blockchain enum type - target_line = " TWBlockchain#{coin['blockchain']} = #{line_number - 17}, " + $flag_comment + "\n" - insert_target_line(target_file, target_line, "};\n") -end - -def insert_coin_entry(coin) - target_file = "src/Coin.cpp" - entryName = coin['blockchain'] - target_line = "#include \"#{entryName}/Entry.h\"" + $flag_comment + "\n" - insert_target_line(target_file, target_line, "// end_of_coin_includes_marker_do_not_modify\n") - target_line = "#{entryName}::Entry #{entryName}DP;" + $flag_comment + "\n" - insert_target_line(target_file, target_line, "// end_of_coin_dipatcher_declarations_marker_do_not_modify\n") - target_line = " case TWBlockchain#{entryName}: entry = &#{entryName}DP; break;" + $flag_comment + "\n" - insert_target_line(target_file, target_line, " // end_of_coin_dipatcher_switch_marker_do_not_modify\n") -end - -def self.insert_target_line(target_file, target_line, original_line) - lines = File.readlines(target_file) - index = lines.index(target_line) - if !index.nil? - puts "Line is already present, file: #{target_file} line: #{target_line}" - return true - end - index = lines.index(original_line) - if index.nil? - puts "WARNING: Could not find line! file: #{target_file} line: #{original_line}" - return false - end - lines.insert(index, target_line) - File.open(target_file, "w+") do |f| - f.puts(lines) - end - puts "Updated file: #{target_file} new line: #{target_line}" - return true -end +require 'coin_skeleton_gen' command_line_args = ARGV if command_line_args.length < 1 @@ -99,49 +17,5 @@ if command_line_args.length < 1 end coin_id = command_line_args[0] -puts "New coin template for coin '#{coin_id}' requested" - -json_string = File.read('registry.json') -coins = JSON.parse(json_string).sort_by { |x| x['name'] } - -entity = EntityDecl.new(name: "New" + coin_id, is_struct: false, comment: '') -file = "new"+ coin_id - -generator = CodeGenerator.new(entities: [entity], files: [file], output_folder: ".") - -@coins = coins - -coin_test_gen = CoinTestGen.new() - -# Find coin in list of coins, by Id -coinSelect = coins.select {|c| c['id'] == coin_id} -if coinSelect.length() == 0 - puts "Error: coin #{coin_id} not found!" - return -end -coin = coinSelect.first -name = format_name(coin) - - -insert_coin_type(coin) -insert_coin_entry(coin) - -generate_file("newcoin/Address.h.erb", "src/#{name}", "Address.h", coin) -generate_file("newcoin/Address.cpp.erb", "src/#{name}", "Address.cpp", coin) -generate_file("newcoin/Entry.h.erb", "src/#{name}", "Entry.h", coin) -generate_file("newcoin/Entry.cpp.erb", "src/#{name}", "Entry.cpp", coin) -generate_file("newcoin/Proto.erb", "src/proto", "#{name}.proto", coin) -generate_file("newcoin/Signer.h.erb", "src/#{name}", "Signer.h", coin) -generate_file("newcoin/Signer.cpp.erb", "src/#{name}", "Signer.cpp", coin) - -generate_file("newcoin/AddressTests.cpp.erb", "tests/#{name}", "AddressTests.cpp", coin) -generate_file("newcoin/SignerTests.cpp.erb", "tests/#{name}", "SignerTests.cpp", coin) -generate_file("newcoin/TWAddressTests.cpp.erb", "tests/#{name}", "TWAnyAddressTests.cpp", coin) -generate_file("newcoin/TWSignerTests.cpp.erb", "tests/#{name}", "TWAnySignerTests.cpp", coin) -generate_file("newcoin/AddressTests.kt.erb", "android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/#{format_name_lowercase(coin)}", "Test#{name}Address.kt", coin) -generate_file("newcoin/SignerTests.kt.erb", "android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/#{format_name_lowercase(coin)}", "Test#{name}Signer.kt", coin) -generate_file("newcoin/Tests.swift.erb", "swift/Tests/Blockchains", "#{name}Tests.swift", coin) - -coin_test_gen.generate_coin_test_file(coin, 'TWCoinTypeTests.cpp.erb', true) -puts "please tools/generate-files to generate Swift/Java/Protobuf files" +generate_skeleton(coin_id, "full") diff --git a/codegen/bin/newcoin-mobile-tests b/codegen/bin/newcoin-mobile-tests new file mode 100755 index 00000000000..d6ea29a84c9 --- /dev/null +++ b/codegen/bin/newcoin-mobile-tests @@ -0,0 +1,22 @@ +#!/usr/bin/env ruby + +# Sript for creating new skeleton files for new coin mobile tests. See also `newcoin` or `newevmchain`. +# It is considered to be used by codegen-v2 tool until Swift and Android tests generating supported. +# 1. Add relevant entry to registry.json (in order to minimize merge conflict, don't add at the very end) +# 2. Invoke this script with the id of the coin, e.g.: codegen/bin/newcoin-mobile-tests ethereum + +require 'fileutils' + +CurrentDir = File.dirname(__FILE__) +$LOAD_PATH.unshift(File.join(CurrentDir, '..', 'lib')) +require 'coin_skeleton_gen' + +command_line_args = ARGV +if command_line_args.length < 1 + puts "Usage: newcoin-mobile-tests " + return +end + +coin_id = command_line_args[0] + +generate_skeleton(coin_id, "mobile-tests") diff --git a/codegen/bin/newevmchain b/codegen/bin/newevmchain new file mode 100755 index 00000000000..e5fed2a97fb --- /dev/null +++ b/codegen/bin/newevmchain @@ -0,0 +1,21 @@ +#!/usr/bin/env ruby + +# Sript for creating new skeleton files for a new EVM chain, subset of newcoin +# 1. Add relevant entry to registry.json (in order to minimize merge conflict, don't add at the very end) +# 2. Invoke this script with the id of the coin, e.g.: codegen/bin/newevmchain ethereumclone + +require 'fileutils' + +CurrentDir = File.dirname(__FILE__) +$LOAD_PATH.unshift(File.join(CurrentDir, '..', 'lib')) +require 'coin_skeleton_gen' + +command_line_args = ARGV +if command_line_args.length < 1 + puts "Usage: newevmchain " + return +end + +coin_id = command_line_args[0] + +generate_skeleton(coin_id, "evm") diff --git a/codegen/lib/code_generator.rb b/codegen/lib/code_generator.rb index 7896c2f8dca..d1fcf3881af 100644 --- a/codegen/lib/code_generator.rb +++ b/codegen/lib/code_generator.rb @@ -7,6 +7,8 @@ require 'swift_helper' require 'wasm_cpp_helper' require 'ts_helper' +require 'kotlin_helper' +require 'kotlin_jni_helper' # Code generation class CodeGenerator @@ -47,7 +49,7 @@ def render_swift_enum_template(file:, header:, template:, output_subfolder:, ext end # Renders a template - def render_template(header:, template:, output_subfolder:, extension:) + def render_template(header:, template:, output_subfolder:, extension:, file_prefix: "") FileUtils.mkdir_p File.join(output_folder, output_subfolder) @entities.zip(files) do |entity, file| # Make current entity available to templates @@ -63,7 +65,7 @@ def render_template(header:, template:, output_subfolder:, extension:) code << "\n" unless header.nil? code << string - path = File.expand_path(File.join(output_folder, output_subfolder, "#{file}.#{extension}")) + path = File.expand_path(File.join(output_folder, output_subfolder, "#{file_prefix}#{file}.#{extension}")) File.write(path, code) end end @@ -83,11 +85,11 @@ def render_java end def render_jni_h - render_template(header: 'copyright_header.erb', template: 'jni_h.erb', output_subfolder: 'jni/cpp/generated', extension: 'h') + render_template(header: 'copyright_header.erb', template: 'jni_h.erb', output_subfolder: 'jni/android/generated', extension: 'h') end def render_jni_c - render_template(header: 'copyright_header.erb', template: 'jni_c.erb', output_subfolder: 'jni/cpp/generated', extension: 'c') + render_template(header: 'copyright_header.erb', template: 'jni_c.erb', output_subfolder: 'jni/android/generated', extension: 'c') end def render_wasm_h @@ -103,10 +105,38 @@ def render_ts_declaration TsHelper.combine_declaration_files() end + def render_kotlin_common + render_template(header: nil, template: 'kotlin_common.erb', output_subfolder: 'kotlin/wallet-core-kotlin/src/commonMain/generated/com/trustwallet/core', extension: 'kt') + end + + def render_kotlin_android + render_template(header: nil, template: 'kotlin_android.erb', output_subfolder: 'kotlin/wallet-core-kotlin/src/commonAndroidJvmMain/generated/com/trustwallet/core', extension: 'kt') + end + + def render_kotlin_ios + render_template(header: nil, template: 'kotlin_ios.erb', output_subfolder: 'kotlin/wallet-core-kotlin/src/iosMain/generated/com/trustwallet/core', extension: 'kt') + end + + def render_kotlin_js + render_template(header: nil, template: 'kotlin_js.erb', output_subfolder: 'kotlin/wallet-core-kotlin/src/jsMain/generated/com/trustwallet/core', extension: 'kt') + end + + def render_kotlin_js_accessors + render_template(header: nil, template: 'kotlin_js_accessors.erb', output_subfolder: 'kotlin/wallet-core-kotlin/src/jsMain/generated/com/trustwallet/core', extension: 'kt', file_prefix: "Js") + end + + def render_kotlin_jni_h + render_template(header: 'copyright_header.erb', template: 'kotlin_jni_h.erb', output_subfolder: 'kotlin/wallet-core-kotlin/src/commonAndroidJvmMain/cpp/generated', extension: 'h') + end + + def render_kotlin_jni_c + render_template(header: 'copyright_header.erb', template: 'kotlin_jni_c.erb', output_subfolder: 'kotlin/wallet-core-kotlin/src/commonAndroidJvmMain/cpp/generated', extension: 'c') + end + def render(file, locals = {}) @locals = locals path = File.expand_path(file, File.join(File.dirname(__FILE__), 'templates')) - template = ERB.new(File.read(path), nil, '-') + template = ERB.new(File.read(path), trim_mode: '-') template.result(binding) end diff --git a/codegen/lib/coin_skeleton_gen.rb b/codegen/lib/coin_skeleton_gen.rb new file mode 100755 index 00000000000..feec8fef8e6 --- /dev/null +++ b/codegen/lib/coin_skeleton_gen.rb @@ -0,0 +1,140 @@ +# frozen_string_literal: true + +require 'erb' +require 'fileutils' +require 'json' + +require 'entity_decl' +require 'code_generator' +require 'coin_test_gen' +require 'file_editor' + +# Coin template generation + +$flag_comment = " // TODO remove if the blockchain already exists, or just remove this comment if not" + +# Transforms a coin name to a C++ name +def self.format_name(coin) + formatted = coin['name'] + formatted = formatted.gsub(/-/, ' ') + formatted = formatted.gsub(/\./, ' ') + formatted = formatted.gsub(/\s/, '') + formatted +end + +def self.format_name_lowercase(coin) +format_name(coin).downcase +end + +def self.format_name_uppercase(coin) +format_name(coin).upcase +end + +def self.generate_file(templateFile, folder, fileName, coin) + @coin = coin + name = format_name(coin) + path = File.expand_path(templateFile, File.join(File.dirname(__FILE__), '..', 'lib', 'templates')) + template = ERB.new(File.read(path), nil, '-') + result = template.result(binding) + + FileUtils.mkdir_p folder + path = File.join(folder, fileName) + File.write(path, result) + puts "Generated file " + path +end + +def self.insert_coin_type(coin, mode) + target_file = "include/TrustWalletCore/TWCoinType.h" + target_line = " TWCoinType#{format_name(coin)} = #{coin['coinId']},\n" + if insert_target_line(target_file, target_line, "};\n") + if (mode != "evm") + insert_blockchain_type(coin) + end + end +end + +def insert_blockchain_type(coin) + target_file = "include/TrustWalletCore/TWBlockchain.h" + line_number = File.readlines(target_file).count + 2 # add offset because of removed blockchain enum type + target_line = " TWBlockchain#{coin['blockchain']} = #{line_number - 17}, " + $flag_comment + "\n" + insert_target_line(target_file, target_line, "};\n") +end + +def insert_coin_entry(coin) + target_file = "src/Coin.cpp" + entryName = coin['blockchain'] + target_line = "#include \"#{entryName}/Entry.h\"" + $flag_comment + "\n" + insert_target_line(target_file, target_line, "// end_of_coin_includes_marker_do_not_modify\n") + target_line = "#{entryName}::Entry #{entryName}DP;" + $flag_comment + "\n" + insert_target_line(target_file, target_line, "// end_of_coin_dipatcher_declarations_marker_do_not_modify\n") + target_line = " case TWBlockchain#{entryName}: entry = &#{entryName}DP; break;" + $flag_comment + "\n" + insert_target_line(target_file, target_line, " // end_of_coin_dipatcher_switch_marker_do_not_modify\n") +end + +def generate_blockchain_files(coin) + name = format_name(coin) + + generate_file("newcoin/Address.h.erb", "src/#{name}", "Address.h", coin) + generate_file("newcoin/Address.cpp.erb", "src/#{name}", "Address.cpp", coin) + generate_file("newcoin/Entry.h.erb", "src/#{name}", "Entry.h", coin) + generate_file("newcoin/Entry.cpp.erb", "src/#{name}", "Entry.cpp", coin) + generate_file("newcoin/Proto.erb", "src/proto", "#{name}.proto", coin) + generate_file("newcoin/Signer.h.erb", "src/#{name}", "Signer.h", coin) + generate_file("newcoin/Signer.cpp.erb", "src/#{name}", "Signer.cpp", coin) + + generate_file("newcoin/AddressTests.cpp.erb", "tests/chains/#{name}", "AddressTests.cpp", coin) + generate_file("newcoin/SignerTests.cpp.erb", "tests/chains/#{name}", "SignerTests.cpp", coin) + generate_file("newcoin/TransactionCompilerTests.cpp.erb", "tests/chains/#{name}", "TransactionCompilerTests.cpp", coin) + generate_file("newcoin/TWAddressTests.cpp.erb", "tests/chains/#{name}", "TWAnyAddressTests.cpp", coin) + generate_file("newcoin/TWSignerTests.cpp.erb", "tests/chains/#{name}", "TWAnySignerTests.cpp", coin) +end + +def generate_mobile_tests(coin) + name = format_name(coin) + + generate_file("newcoin/AddressTests.kt.erb", "android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/#{format_name_lowercase(coin)}", "Test#{name}Address.kt", coin) + generate_file("newcoin/SignerTests.kt.erb", "android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/#{format_name_lowercase(coin)}", "Test#{name}Signer.kt", coin) + generate_file("newcoin/Tests.swift.erb", "swift/Tests/Blockchains", "#{name}Tests.swift", coin) +end + +def generate_coin_type_tests(coin) + coin_test_gen = CoinTestGen.new() + coin_test_gen.generate_coin_test_file(coin, 'TWCoinTypeTests.cpp.erb', true) +end + +def generate_skeleton(coin_id, mode) + puts "New coin template for coin '#{coin_id}' #{mode} requested" + + json_string = File.read('registry.json') + coins = JSON.parse(json_string).sort_by { |x| x['name'] } + + entity = EntityDecl.new(name: "New" + coin_id, is_struct: false, comment: '') + file = "new"+ coin_id + + generator = CodeGenerator.new(entities: [entity], files: [file], output_folder: ".") + + @coins = coins + + # Find coin in list of coins, by Id + coinSelect = coins.select {|c| c['id'] == coin_id} + if coinSelect.length() == 0 + puts "Error: coin #{coin_id} not found!" + return + end + coin = coinSelect.first + + if (mode == "full") + insert_coin_type(coin, mode) + insert_coin_entry(coin) + generate_blockchain_files(coin) + generate_mobile_tests(coin) + generate_coin_type_tests(coin) + elsif (mode == "evm") + insert_coin_type(coin, mode) + generate_coin_type_tests(coin) + elsif (mode == "mobile-tests") + generate_mobile_tests(coin) + end + + puts "please tools/generate-files to generate Swift/Java/Protobuf files" +end diff --git a/codegen/lib/coin_test_gen.rb b/codegen/lib/coin_test_gen.rb index e4d7d845fce..0b831bfb277 100755 --- a/codegen/lib/coin_test_gen.rb +++ b/codegen/lib/coin_test_gen.rb @@ -63,7 +63,7 @@ def generate_coin_test_file(coin, templateFile, overwriteExisting = true) template = ERB.new(File.read(path), nil, '-') result = template.result(binding) - folder = 'tests/' + folder = 'tests/chains/' if coin.key?('testFolderName') folder += format_name(coin['testFolderName']) else diff --git a/codegen/lib/derivation.rb b/codegen/lib/derivation.rb new file mode 100644 index 00000000000..1b9b8233e78 --- /dev/null +++ b/codegen/lib/derivation.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +require 'file_editor' + +$derivation_file = "include/TrustWalletCore/TWDerivation.h" +$derivation_file_rust = "rust/tw_coin_registry/src/tw_derivation.rs" + +# Returns a derivation name if specified. +def derivation_name(deriv) + return "" if deriv['name'].nil? + deriv['name'].downcase +end + +# Returns a string of `` if derivation's name is specified, otherwise returns `Default`. +def derivation_enum_name_no_prefix(deriv, coin) + return "Default" if deriv['name'].nil? + format_name(coin['name']) + camel_case(deriv['name']) +end + +# Returns a string of `TWDerivation` if derivation's name is specified, otherwise returns `TWDerivationDefault`. +def derivation_enum_name(deriv, coin) + return "TWDerivation" + derivation_enum_name_no_prefix(deriv, coin) +end + +# Returns a derivation path. +def derivation_path(coin) + coin['derivation'][0]['path'] +end + +# Get the last `TWDerivation` enum variant ID. +def get_last_derivation(file_path) + last_derivation_id = nil + + File.open(file_path, "r") do |file| + file.each_line do |line| + # Match lines that define a TWDerivation enum value + if line =~ /TWDerivation\w+\s*=\s*(\d+),/ + last_derivation_id = $1.to_i + end + end + end + + last_derivation_id +end + +# Returns whether the TWDerivation enum contains the given `derivation` variant. +def find_derivation(file_path, derivation) + File.open(file_path, "r") do |file| + file.each_line do |line| + return true if line.include?(derivation) + end + end + return false +end + +# Insert a new `TWDerivation = N,` to the end of the enum. +def insert_derivation(file_path, derivation, derivation_id) + target_line = " #{derivation} = #{derivation_id}," + insert_target_line(file_path, target_line, " // end_of_derivation_enum - USED TO GENERATE CODE\n") +end + +# Update TWDerivation enum variants if new derivation appeared. +def update_derivation_enum(coins) + coins.each do |coin| + coin['derivation'].each_with_index do |deriv, index| + deriv_name = derivation_enum_name(deriv, coin) + if !find_derivation($derivation_file, deriv_name) + new_derivation_id = get_last_derivation($derivation_file) + 1 + insert_derivation($derivation_file, deriv_name, new_derivation_id) + + rust_deriv_name = derivation_enum_name_no_prefix(deriv, coin) + insert_derivation($derivation_file_rust, rust_deriv_name, new_derivation_id) + end + end + end +end diff --git a/codegen/lib/file_editor.rb b/codegen/lib/file_editor.rb new file mode 100644 index 00000000000..15e60726d67 --- /dev/null +++ b/codegen/lib/file_editor.rb @@ -0,0 +1,19 @@ +def insert_target_line(target_file, target_line, original_line) + lines = File.readlines(target_file) + index = lines.index(target_line) + if !index.nil? + puts "Line is already present, file: #{target_file} line: #{target_line}" + return true + end + index = lines.index(original_line) + if index.nil? + puts "WARNING: Could not find line! file: #{target_file} line: #{original_line}" + return false + end + lines.insert(index, target_line) + File.open(target_file, "w+") do |f| + f.puts(lines) + end + puts "Updated file: #{target_file} new line: #{target_line}" + return true +end diff --git a/codegen/lib/kotlin_helper.rb b/codegen/lib/kotlin_helper.rb new file mode 100644 index 00000000000..b37537b4fa4 --- /dev/null +++ b/codegen/lib/kotlin_helper.rb @@ -0,0 +1,252 @@ +# frozen_string_literal: true + +module KotlinHelper + # Transforms an interface name to a Java method name + def self.format_name(name) + return 'equals' if name == 'Equal' + + result = name + match = /^([A-Z]+)/.match(name) + result = name.sub(match[1], match[1].downcase) unless match.nil? + + result.sub(/_/, '') + end + + def self.parameters(params) + names = params.map do |param| + name = fix_name(param.name) + "#{name}: #{type(param.type)}" + end + names.join(', ') + end + + def self.js_parameters(params) + names = params.map do |param| + name = fix_name(param.name) + "#{name}: #{js_type(param.type)}" + end + names.join(', ') + end + + def self.calling_parameters_ios(params) + names = params.map do |param| + name = fix_name(param.name) + "#{name}#{convert_calling_type_ios(param.type)}" + end + names.join(', ') + end + + def self.calling_parameters_android(params) + names = params.map do |param| + fix_name(param.name) + end + names.join(', ') + end + + def self.calling_parameters_js(params) + names = params.map do |param| + name = fix_name(param.name) + "#{name}#{convert_calling_type_js(param.type)}" + end + names.join(', ') + end + + def self.fix_name(name) + case name + when '' + "value" + when 'val' + "value" + when 'return' + '`return`' + else + name + end + end + + def self.convert_calling_type_ios(t) + case t.name + when :data + "#{if t.is_nullable then '?' else '' end}.toTwData()" + when :string + "#{if t.is_nullable then '?' else '' end}.toTwString()" + else + if t.is_enum + "#{if t.is_nullable then '?' else '' end}.nativeValue" + elsif t.is_class + "#{if t.is_nullable then '?' else '' end}.pointer" + else + '' + end + end + end + + def self.convert_calling_type_js(t) + case t.name + when :data + "#{if t.is_nullable then '?' else '' end}.asUInt8Array()" + when :uint8 + ".toByte()" + when :uint16 + ".toShort()" + when :uint32 + ".toInt()" + when :uint64 + ".toInt()" + when :int64 + ".toInt()" + when :size + ".toInt()" + else + if t.is_enum + "#{if t.is_nullable then '?' else '' end}.jsValue" + elsif t.is_class + "#{if t.is_nullable then '?' else '' end}.jsValue" + else + '' + end + end + end + + def self.convert_calling_return_type_ios(t, expression = '') + case t.name + when :data + "#{expression}.readTwBytes()#{if t.is_nullable then '' else '!!' end}" + when :string + "#{expression}.fromTwString()#{if t.is_nullable then '' else '!!' end}" + else + if t.is_enum + "#{t.name}.fromValue(#{expression})#{if t.is_nullable then '' else '!!' end}" + elsif t.is_class + if t.is_nullable + "#{expression}?.let { #{t.name}(it) }" + else + "#{t.name}(#{expression}!!)" + end + else + expression + end + end + end + + def self.convert_calling_return_type_js(t, expression = '') + nullable = "#{if t.is_nullable then '?' else '' end}" + case t.name + when :void + expression + when :data + "#{expression}#{nullable}.asByteArray()" + when :int + "#{expression}.toInt()" + when :uint8 + "#{expression}.toByte().toUByte()" + when :uint16 + "#{expression}.toShort().toUShort()" + when :uint32 + "#{expression}.toInt().toUInt()" + when :uint64 + "#{expression}.toLong().toULong()" + when :int8 + "#{expression}.toByte()" + when :int16 + "#{expression}.toShort()" + when :int32 + "#{expression}.toInt()" + when :int64 + "#{expression}.toLong()" + when :size + "#{expression}.toLong().toULong()" + else + if t.is_enum + "#{t.name}.fromValue(#{expression})" + elsif t.is_class + if t.is_nullable + "#{expression}?.let { #{t.name}(it) }" + else + "#{t.name}(#{expression})" + end + else + expression + end + end + end + + def self.arguments(params) + params.map do |param| + param.name || 'value' + end.join(', ') + end + + def self.type(t) + nullable = "#{if t.is_nullable then '?' else '' end}" + case t.name + when :void + "" + when :bool + "Boolean#{nullable}" + when :int + "Int#{nullable}" + when :uint8 + "UByte#{nullable}" + when :uint16 + "UShort#{nullable}" + when :uint32 + "UInt#{nullable}" + when :uint64 + "ULong#{nullable}" + when :int8 + "Byte#{nullable}" + when :int16 + "Short#{nullable}" + when :int32 + "Int#{nullable}" + when :int64 + "Long#{nullable}" + when :size + "ULong#{nullable}" + when :data + "ByteArray#{nullable}" + when :string + "String#{nullable}" + else + "#{t.name}#{nullable}" + end + end + + def self.return_type(t) + case t.name + when :void + "" + else + ": #{type(t)}" + end + end + + def self.js_type(t) + nullable = "#{if t.is_nullable then '?' else '' end}" + case t.name + when :void + "" + when :bool + "Boolean#{nullable}" + when :int, :uint8, :int8, :uint16, :int16, :uint32, :int32, :uint64, :int64, :size + "Number#{nullable}" + when :data + "UInt8Array#{nullable}" + when :string + "String#{nullable}" + else + "Js#{t.name}#{nullable}" + end + end + + def self.js_return_type(t) + case t.name + when :void + "" + else + ": #{js_type(t)}" + end + end + +end diff --git a/codegen/lib/kotlin_jni_helper.rb b/codegen/lib/kotlin_jni_helper.rb new file mode 100644 index 00000000000..b1303a6d69e --- /dev/null +++ b/codegen/lib/kotlin_jni_helper.rb @@ -0,0 +1,113 @@ +# frozen_string_literal: true + +module KotlinJniHelper + # Transforms an interface name to a JNI method name + def self.format_name(name) + return 'equals' if name == 'Equal' + + result = name + match = /^([A-Z]+)/.match(name) + result = name.sub(match[1], match[1].downcase) unless match.nil? + + result.sub(/_/, '') + end + + # Transforms a method/property name to a JNI function name + def self.function_name(entity:, function:, native_prefix: false) + "Java_com_trustwallet_core_#{entity.name}_#{format_name(function.name)}" + end + + # Transforms a proto name name to a JNI class name + def self.proto_to_class(name) + parts = name.split('_') + return nil if parts.count < 3 || parts[0] != 'TW' + + if parts.count == 3 + "wallet/core/jni/proto/Common$#{parts.last}" + else + "wallet/core/jni/proto/#{parts[1]}$#{parts[3]}" + end + end + + def self.parameters(params) + names = params.map do |param| + ", #{type(param.type)} #{param.name || 'value'}" + end + names.join('') + end + + def self.arguments(params) + params.map do |param| + if param.type.is_class + (param.name || 'value') + 'Instance' + elsif param.type.is_struct + '*' + (param.name || 'value') + 'Instance' + elsif param.type.name == :data + (param.name || 'value') + 'Data' + elsif param.type.name == :string + (param.name || 'value') + 'String' + elsif param.type.is_enum + (param.name || 'value') + 'Value' + elsif param.type.is_proto + (param.name || 'value') + 'Data' + else + param.name || 'value' + end + end + end + + def self.type(t) + case t.name + when :void + 'void' + when :bool + 'jboolean' + when :int + 'jint' + when :uint8 + 'jchar' + when :uint16 + 'jshort' + when :uint32 + 'jint' + when :uint64 + 'jlong' + when :int8 + 'jbyte' + when :int16 + 'jshort' + when :int32 + 'jint' + when :int64 + 'jlong' + when :size + 'jsize' + when :data + 'jbyteArray' + when 'Data' + 'jbyteArray' + when :string + 'jstring' + else + if t.is_class || t.is_struct + 'jobject' + elsif t.is_enum + 'jobject' + elsif t.is_proto + 'jobject' + else + raise "Invalid type #{t.name}" + end + end + end + + def self.compareMethod(entity) + FunctionDecl.new( + name: 'compareTo', + entity: entity, + is_method: true, + return_type: TypeDecl.new(name: :int), + parameters: [Parameter.new(name: 'thisObject', type: entity.type), Parameter.new(name: 'other', type: entity.type)], + static: false) + end +end diff --git a/codegen/lib/templates/CoinInfoData.cpp.erb b/codegen/lib/templates/CoinInfoData.cpp.erb index 44dd8acd044..d2bbb5d6b71 100644 --- a/codegen/lib/templates/CoinInfoData.cpp.erb +++ b/codegen/lib/templates/CoinInfoData.cpp.erb @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. // // This is a GENERATED FILE, changes made here WILL BE LOST. // @@ -36,6 +34,7 @@ static const CoinInfo defaultsForMissing = { "", "", 0, + 0 }; /// Get coin from map, if missing returns defaults (not to have contains-check in each accessor method) @@ -73,6 +72,7 @@ const CoinInfo getCoinInfo(TWCoinType coin) { "<%= explorer_tx_url(coin) %>", "<%= explorer_account_url(coin) %>", <% if coin['slip44'].nil? -%><%= coin['coinId'] %><% else -%><%= coin['slip44'] %><% end -%>, + <% if coin['ss58Prefix'].nil? -%>0<% else -%><%= coin['ss58Prefix'] %><% end -%>, }; <% end -%> default: diff --git a/codegen/lib/templates/TWCoinTypeTests.cpp.erb b/codegen/lib/templates/TWCoinTypeTests.cpp.erb index 4c8cd77e4fc..bb8cbdadb79 100644 --- a/codegen/lib/templates/TWCoinTypeTests.cpp.erb +++ b/codegen/lib/templates/TWCoinTypeTests.cpp.erb @@ -1,14 +1,12 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. // // This is a GENERATED FILE, changes made here MAY BE LOST. // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/codegen/lib/templates/TWDerivation.h.erb b/codegen/lib/templates/TWDerivation.h.erb index 06266d5cb82..e2c9a53a494 100644 --- a/codegen/lib/templates/TWDerivation.h.erb +++ b/codegen/lib/templates/TWDerivation.h.erb @@ -1,8 +1,6 @@ -// Copyright © 2017-2021 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. // // This is a GENERATED FILE from \registry.json, changes made here WILL BE LOST. // @@ -20,14 +18,12 @@ enum TWDerivation { TWDerivationCustom = 1, // custom, for any coin <% enum_count += 1 -%> <% coins.each do |coin| -%> -<% if coin['derivation'].count > 1 -%> <% coin['derivation'].each_with_index do |deriv, index| -%> <% if index > 0 or !deriv['name'].nil? -%> <%= derivation_enum_name(deriv, coin) %> = <% enum_count += 1 -%><%= enum_count %>, <% end -%> <% end -%> <% end -%> -<% end -%> }; TW_EXTERN_C_END diff --git a/codegen/lib/templates/TWEthereumChainID.h.erb b/codegen/lib/templates/TWEthereumChainID.h.erb index 99862693b3f..3e6385e1b77 100644 --- a/codegen/lib/templates/TWEthereumChainID.h.erb +++ b/codegen/lib/templates/TWEthereumChainID.h.erb @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. // // This is a GENERATED FILE from \registry.json, changes made here WILL BE LOST. // diff --git a/codegen/lib/templates/copyright_header.erb b/codegen/lib/templates/copyright_header.erb index be628ee1f6e..39239c27440 100644 --- a/codegen/lib/templates/copyright_header.erb +++ b/codegen/lib/templates/copyright_header.erb @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. // // This is a GENERATED FILE, changes made here WILL BE LOST. // diff --git a/codegen/lib/templates/hrp.cpp.erb b/codegen/lib/templates/hrp.cpp.erb index 24eede081df..c3705bd5a9f 100644 --- a/codegen/lib/templates/hrp.cpp.erb +++ b/codegen/lib/templates/hrp.cpp.erb @@ -1,8 +1,6 @@ -// Copyright © 2017-2021 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. // // This is a GENERATED FILE from \registry.json, changes made here WILL BE LOST. // diff --git a/codegen/lib/templates/hrp.h.erb b/codegen/lib/templates/hrp.h.erb index 0f4ed0432f1..4691fbafc5b 100644 --- a/codegen/lib/templates/hrp.h.erb +++ b/codegen/lib/templates/hrp.h.erb @@ -1,8 +1,6 @@ -// Copyright © 2017-2021 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. // // This is a GENERATED FILE from \registry.json, changes made here WILL BE LOST. // diff --git a/codegen/lib/templates/java/class.erb b/codegen/lib/templates/java/class.erb index 69cd027f403..fa491ff2560 100644 --- a/codegen/lib/templates/java/class.erb +++ b/codegen/lib/templates/java/class.erb @@ -5,9 +5,9 @@ import java.util.HashSet; <% equal = entity.static_methods.detect{ |i| i.name == 'Equal' } -%> <%= entity.comment %> <% if !less.nil? && !equal.nil? -%> -public class <%= entity.name %> implements Comparable<<%= entity.name %>> { +public final class <%= entity.name %> implements Comparable<<%= entity.name %>> { <% else -%> -public class <%= entity.name %> { +public final class <%= entity.name %> { <% end -%> private long nativeHandle; diff --git a/codegen/lib/templates/java/header.erb b/codegen/lib/templates/java/header.erb index b1b1aeabc86..3c5da1f81ed 100644 --- a/codegen/lib/templates/java/header.erb +++ b/codegen/lib/templates/java/header.erb @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. // // This is a GENERATED FILE, changes made here WILL BE LOST. // diff --git a/codegen/lib/templates/java/struct.erb b/codegen/lib/templates/java/struct.erb index bb57cf25017..6f09dda87d2 100644 --- a/codegen/lib/templates/java/struct.erb +++ b/codegen/lib/templates/java/struct.erb @@ -4,9 +4,9 @@ import java.security.InvalidParameterException; <% equal = entity.static_methods.detect{ |i| i.name == 'Equal' } -%> <%= entity.comment %> <% if !less.nil? && !equal.nil? -%> -public class <%= entity.name %> implements Comparable<<%= entity.name %>> { +public final class <%= entity.name %> implements Comparable<<%= entity.name %>> { <% else -%> -public class <%= entity.name %> { +public final class <%= entity.name %> { <% end -%> private byte[] bytes; diff --git a/codegen/lib/templates/jni/parameter_access.erb b/codegen/lib/templates/jni/parameter_access.erb index 71bc2641c41..4c3ceb9f2fa 100644 --- a/codegen/lib/templates/jni/parameter_access.erb +++ b/codegen/lib/templates/jni/parameter_access.erb @@ -1,6 +1,6 @@ <% method = locals[:method] - if method.static && !method.name.include?('Init') + if method.static && !method.name.start_with?('Init') parameters = method.parameters else parameters = method.parameters.drop(1) diff --git a/codegen/lib/templates/jni/parameter_release.erb b/codegen/lib/templates/jni/parameter_release.erb index 147e40c3496..1db6f1a86e1 100644 --- a/codegen/lib/templates/jni/parameter_release.erb +++ b/codegen/lib/templates/jni/parameter_release.erb @@ -1,6 +1,6 @@ <% method = locals[:method] - if method.static && !method.name.include?('Init') + if method.static && !method.name.start_with?('Init') parameters = method.parameters else parameters = method.parameters.drop(1) diff --git a/codegen/lib/templates/kotlin/android_class.erb b/codegen/lib/templates/kotlin/android_class.erb new file mode 100644 index 00000000000..3091b094ca7 --- /dev/null +++ b/codegen/lib/templates/kotlin/android_class.erb @@ -0,0 +1,63 @@ +<%= render('kotlin/package.erb') %> + +<% constructors = entity.static_methods.select { |method| method.name.start_with?('Create') } -%> +<% methods = entity.methods.select { |method| not method.name.start_with?('Delete') } -%> +<% static_methods = entity.static_methods.select { |method| not method.name.start_with?('Create') } -%> +actual class <%= entity.name %> private constructor( + private val nativeHandle: Long, +) { + + init { + if (nativeHandle == 0L) throw IllegalArgumentException() + } +<%# Constructors -%> +<%- constructors.each do |constructor| -%> + +<% if constructor.return_type.is_nullable -%> + @Throws(IllegalArgumentException::class) +<% end -%> + actual constructor(<%= KotlinHelper.parameters(constructor.parameters) %>) : this(<%= KotlinHelper.format_name(constructor.name) %>(<%= KotlinHelper.calling_parameters_android(constructor.parameters) %>)) +<% end -%> +<%# Property declarations -%> +<% entity.properties.each do |property| -%> + + actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> + @JvmName("<%= KotlinHelper.format_name(property.name) %>") + external get +<% end -%> +<%# Method declarations -%> +<% methods.each do |method| -%> + + @JvmName("<%= KotlinHelper.format_name(method.name) %>") + actual external fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters.drop(1)) %>)<%= KotlinHelper.return_type(method.return_type) %> +<% end -%> +<% if entity.static_properties.any? || static_methods.any? || constructors.any? -%> + + <%= if entity.static_properties.any? || static_methods.any? then "actual" else "private" end %> companion object { +<%# Static property declarations -%> +<% entity.static_properties.each do |property| -%> + + actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> + @JvmName("<%= KotlinHelper.format_name(property.name) %>") + external get +<% end -%> +<%# Static method declarations -%> +<% static_methods.each do |method| -%> + + @JvmStatic + @JvmName("<%= KotlinHelper.format_name(method.name) %>") + actual external fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters) %>)<%= KotlinHelper.return_type(method.return_type) %> +<% end -%> + + @JvmStatic + @JvmName("createFromNative") + private fun createFromNative(nativeHandle: Long) = <%= entity.name %>(nativeHandle) +<%- constructors.each do |constructor| -%> + + @JvmStatic + @JvmName("<%= KotlinHelper.format_name(constructor.name) %>") + private external fun <%= KotlinHelper.format_name(constructor.name) %>(<%= KotlinHelper.parameters(constructor.parameters) %>): Long +<%- end -%> + } +<% end -%> +} diff --git a/codegen/lib/templates/kotlin/android_enum.erb b/codegen/lib/templates/kotlin/android_enum.erb new file mode 100644 index 00000000000..e00cb92f5bc --- /dev/null +++ b/codegen/lib/templates/kotlin/android_enum.erb @@ -0,0 +1,44 @@ +<%= render('kotlin/package.erb') %> + +<% has_string = entity.cases.all? { |c| !c.string.nil? } -%> +actual enum class <%= entity.name %>( + @get:JvmName("value") + actual val value: UInt, +<% if has_string -%> + actual val stringValue: String, +<% end -%> +) { +<%# Cases -%> +<% entity.cases.each_with_index do |c, i| -%> +<% if has_string -%> + <%= c.name %>(<%= c.value %>u, <%= c.string %>), +<% else -%> + <%= c.name %>(<%= c.value %>u), +<% end -%> +<% end -%> + ; +<%# Property declarations -%> +<%- entity.properties.each do |property| -%> + + actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> + @JvmName("<%= KotlinHelper.format_name(property.name) %>") + external get +<%- end -%> +<%# Method declarations -%> +<%- entity.methods.each do |method| -%> +<%- next if method.name.start_with?('Delete') -%> + + @JvmName("<%= KotlinHelper.format_name(method.name) %>") + actual external fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters.drop(1)) %>)<%= KotlinHelper.return_type(method.return_type) %> +<%- end -%> +<%# Value -%> +<% if entity.cases.any? { |e| !e.value.nil? } -%> + + actual companion object { + @JvmStatic + @JvmName("createFromValue") + actual fun fromValue(value: UInt): <%= entity.name %>? = + values().firstOrNull { it.value == value } + } +<% end -%> +} diff --git a/codegen/lib/templates/kotlin/android_struct.erb b/codegen/lib/templates/kotlin/android_struct.erb new file mode 100644 index 00000000000..099704dd35b --- /dev/null +++ b/codegen/lib/templates/kotlin/android_struct.erb @@ -0,0 +1,19 @@ +<%= render('kotlin/package.erb') %> + +actual object <%= entity.name %> { +<%# Static property declarations -%> +<% entity.static_properties.each do |property| -%> + + actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> + @JvmName("<%= KotlinHelper.format_name(property.name) %>") + external get +<% end -%> +<%# Static method declarations -%> +<% entity.static_methods.each do |method| -%> +<% next if method.name.start_with?('Create') -%> + + @JvmStatic + @JvmName("<%= KotlinHelper.format_name(method.name) %>") + actual external fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters) %>)<%= KotlinHelper.return_type(method.return_type) %> +<% end -%> +} diff --git a/codegen/lib/templates/kotlin/common_class.erb b/codegen/lib/templates/kotlin/common_class.erb new file mode 100644 index 00000000000..0cd6d4a506a --- /dev/null +++ b/codegen/lib/templates/kotlin/common_class.erb @@ -0,0 +1,60 @@ +<%= render('kotlin/package.erb') %> + +<% constructors = entity.static_methods.select { |method| method.name.start_with?('Create') } -%> +<% methods = entity.methods.select { |method| not method.name.start_with?('Delete') } -%> +<% static_methods = entity.static_methods.select { |method| not method.name.start_with?('Create') } -%> +<% if constructors.one? -%> +<% if constructors.first.return_type.is_nullable -%> +expect class <%= entity.name %> @Throws(IllegalArgumentException::class) constructor( +<% else -%> +expect class <%= entity.name %>( +<% end -%> +<%- constructors.first.parameters.each do |parameter| -%> + <%= KotlinHelper.parameters([parameter]) %>, +<%- end -%> +) { +<%- else -%> +expect class <%= entity.name %> { +<%# Constructors -%> +<%- constructors.each do |constructor| -%> + +<% if constructor.return_type.is_nullable -%> + @Throws(IllegalArgumentException::class) +<% end -%> + constructor(<%= KotlinHelper.parameters(constructor.parameters) %>) +<%- end -%> +<% end -%> +<%# Property declarations -%> +<% if entity.properties.any? -%> + +<% end -%> +<% entity.properties.each do |property| -%> + val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> +<% end -%> +<%# Method declarations -%> +<% if methods.any? -%> + +<% end -%> +<% methods.each do |method| -%> + fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters.drop(1)) %>)<%= KotlinHelper.return_type(method.return_type) %> +<% end -%> +<% if entity.static_properties.any? || static_methods.any? -%> + + companion object { +<%# Static property declarations -%> +<% if entity.static_properties.any? -%> + +<% end -%> +<% entity.static_properties.each do |property| -%> + val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> +<% end -%> +<%# Static method declarations -%> +<% if static_methods.any? -%> + +<% end -%> +<% static_methods.each do |method| -%> + fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters) %>)<%= KotlinHelper.return_type(method.return_type) %> +<% end -%> + } +<% end -%> +} diff --git a/codegen/lib/templates/kotlin/common_enum.erb b/codegen/lib/templates/kotlin/common_enum.erb new file mode 100644 index 00000000000..234df7e8d28 --- /dev/null +++ b/codegen/lib/templates/kotlin/common_enum.erb @@ -0,0 +1,34 @@ +<%= render('kotlin/package.erb') %> + +<% has_string = entity.cases.all? { |c| !c.string.nil? } -%> +expect enum class <%= entity.name %> { +<%# Cases -%> +<% entity.cases.each_with_index do |c, i| -%> + <%= c.name %>, +<% end -%> + ; + + val value: UInt +<% if has_string -%> + val stringValue: String +<% end -%> +<%# Property declarations -%> +<%- entity.properties.each do |property| -%> + val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> +<%- end -%> +<%# Method declarations -%> +<% if entity.methods.any? -%> + +<% end -%> +<%- entity.methods.each do |method| -%> +<%- next if method.name.start_with?('Delete') -%> + fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters.drop(1)) %>)<%= KotlinHelper.return_type(method.return_type) %> +<%- end -%> +<%# Value -%> +<% if entity.cases.any? { |e| !e.value.nil? } -%> + + companion object { + fun fromValue(value: UInt): <%= entity.name %>? + } +<% end -%> +} diff --git a/codegen/lib/templates/kotlin/common_struct.erb b/codegen/lib/templates/kotlin/common_struct.erb new file mode 100644 index 00000000000..39e085799ea --- /dev/null +++ b/codegen/lib/templates/kotlin/common_struct.erb @@ -0,0 +1,13 @@ +<%= render('kotlin/package.erb') %> + +expect object <%= entity.name %> { +<%# Static property declarations -%> +<% entity.static_properties.each do |property| -%> + val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> +<% end -%> +<%# Static method declarations -%> +<% entity.static_methods.each do |method| -%> +<% next if method.name.start_with?('Create') -%> + fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters) %>)<%= KotlinHelper.return_type(method.return_type) %> +<% end -%> +} diff --git a/codegen/lib/templates/kotlin/ios_class.erb b/codegen/lib/templates/kotlin/ios_class.erb new file mode 100644 index 00000000000..36bc94e8276 --- /dev/null +++ b/codegen/lib/templates/kotlin/ios_class.erb @@ -0,0 +1,54 @@ +<%= render('kotlin/package.erb') %> + +import cnames.structs.TW<%= entity.name %> +import kotlinx.cinterop.CPointer + +<% constructors = entity.static_methods.select { |method| method.name.start_with?('Create') } -%> +<% methods = entity.methods.select { |method| not method.name.start_with?('Delete') } -%> +<% static_methods = entity.static_methods.select { |method| not method.name.start_with?('Create') } -%> +actual class <%= entity.name %> constructor( + val pointer: CPointer>, +) { +<%# Constructors -%> +<%- constructors.each do |constructor| -%> + +<% if constructor.return_type.is_nullable -%> + @Throws(IllegalArgumentException::class) + actual constructor(<%= KotlinHelper.parameters(constructor.parameters) %>) : this( + TW<%= entity.name %><%= constructor.name %>(<%= KotlinHelper.calling_parameters_ios(constructor.parameters) %>) ?: throw IllegalArgumentException() +<% else -%> + actual constructor(<%= KotlinHelper.parameters(constructor.parameters) %>) : this( + TW<%= entity.name %><%= constructor.name %>(<%= KotlinHelper.calling_parameters_ios(constructor.parameters) %>)!! +<% end -%> + ) +<% end -%> +<%# Property declarations -%> +<% entity.properties.each do |property| -%> + + actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> + get() = <%= KotlinHelper.convert_calling_return_type_ios(property.return_type, "TW#{entity.name}#{property.name}(pointer)") %> +<% end -%> +<%# Method declarations -%> +<% methods.each do |method| -%> + + actual fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters.drop(1)) %>)<%= KotlinHelper.return_type(method.return_type) %> = + <%= KotlinHelper.convert_calling_return_type_ios(method.return_type, "TW#{entity.name}#{method.name}(pointer#{', ' if not method.parameters.one?}#{KotlinHelper.calling_parameters_ios(method.parameters.drop(1))})") %> +<% end -%> +<% if entity.static_properties.any? || static_methods.any? -%> + + actual companion object { +<%# Static property declarations -%> +<% entity.static_properties.each do |property| -%> + + actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> + get() = TW<%= entity.name %><%= property.name %>()<%= KotlinHelper.convert_calling_return_type_ios(property.return_type) %> +<% end -%> +<%# Static method declarations -%> +<% static_methods.each do |method| -%> + + actual fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters) %>)<%= KotlinHelper.return_type(method.return_type) %> = + <%= KotlinHelper.convert_calling_return_type_ios(method.return_type, "TW#{entity.name}#{method.name}(#{KotlinHelper.calling_parameters_ios(method.parameters)})") %> +<% end -%> + } +<% end -%> +} diff --git a/codegen/lib/templates/kotlin/ios_enum.erb b/codegen/lib/templates/kotlin/ios_enum.erb new file mode 100644 index 00000000000..5f64c80a7fa --- /dev/null +++ b/codegen/lib/templates/kotlin/ios_enum.erb @@ -0,0 +1,63 @@ +<%= render('kotlin/package.erb') %> + +<% has_string = entity.cases.all? { |c| !c.string.nil? } -%> +<% if has_string -%> +import com.trustwallet.core.<%= "TW#{entity.name}" %>.* + +<% end -%> +<% type = ": TW#{entity.name}" -%> +actual enum class <%= entity.name %>( +<% if has_string -%> + val nativeValue<%= type %>, + actual val stringValue: String, +<% else -%> + val nativeValue<%= type %>, +<% end -%> +) { +<%# Cases -%> +<% entity.cases.each_with_index do |c, i| -%> +<% if has_string -%> + <%= c.name %>(TW<%= entity.name %><%= c.name %>, <%= c.string %>), +<% else -%> + <%= c.name %>(TW<%= entity.name %><%= c.name %>), +<% end -%> +<% end -%> + ; + +<% if has_string -%> + actual val value: UInt + get() = nativeValue.value +<% else -%> + actual val value<%= type %> + get() = nativeValue +<% end -%> +<%# Property declarations -%> +<%- entity.properties.each do |property| -%> + + actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> + get() = <%= KotlinHelper.convert_calling_return_type_ios(property.return_type, "TW#{entity.name}#{property.name}(value)") %> +<%- end -%> +<%# Method declarations -%> +<%- entity.methods.each do |method| -%> +<%- next if method.name.start_with?('Delete') -%> + + actual fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters.drop(1)) %>)<%= KotlinHelper.return_type(method.return_type) %> = + TW<%= entity.name %><%= method.name %>(value<%= ', ' if not method.parameters.one? %><%= KotlinHelper.calling_parameters_ios(method.parameters.drop(1)) %>)<%= KotlinHelper.convert_calling_return_type_ios(method.return_type) %> +<%- end -%> +<%# Value -%> +<% if entity.cases.any? { |e| !e.value.nil? } -%> + + actual companion object { +<% if has_string -%> + actual fun fromValue(value: UInt): <%= entity.name %>? = + values().firstOrNull { it.value == value } + + fun fromValue(value<%= type %>): <%= entity.name %> = + fromValue(value.value)!! +<% else -%> + actual fun fromValue(value<%= type %>): <%= entity.name %>? = + values().firstOrNull { it.value == value } +<% end -%> + } +<% end -%> +} diff --git a/codegen/lib/templates/kotlin/ios_struct.erb b/codegen/lib/templates/kotlin/ios_struct.erb new file mode 100644 index 00000000000..6bf3da876ee --- /dev/null +++ b/codegen/lib/templates/kotlin/ios_struct.erb @@ -0,0 +1,16 @@ +<%= render('kotlin/package.erb') %> + +actual object <%= entity.name %> { +<%# Static property declarations -%> +<% entity.static_properties.each do |property| -%> + actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> + get() = TODO() +<% end -%> +<%# Static method declarations -%> +<% entity.static_methods.each do |method| -%> +<% next if method.name.start_with?('Create') -%> + + actual fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters) %>)<%= KotlinHelper.return_type(method.return_type) %> = + <%= KotlinHelper.convert_calling_return_type_ios(method.return_type, "TW#{entity.name}#{method.name}(#{KotlinHelper.calling_parameters_ios(method.parameters)})") %> +<% end -%> +} diff --git a/codegen/lib/templates/kotlin/js_accessors_class.erb b/codegen/lib/templates/kotlin/js_accessors_class.erb new file mode 100644 index 00000000000..77645552c83 --- /dev/null +++ b/codegen/lib/templates/kotlin/js_accessors_class.erb @@ -0,0 +1,23 @@ +@file:Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE") + +<%= render('kotlin/package.erb') %> + +@JsModule("@trustwallet/wallet-core") +@JsName("<%= entity.name %>") +external interface Js<%= entity.name %> { +<%- entity.properties.each do |property| -%> + fun <%= KotlinHelper.fix_name(WasmCppHelper.format_name(property.name)) %>()<%= KotlinHelper.js_return_type(property.return_type) %> +<%- end -%> +<% entity.methods.each do |method| -%> +<% next if method.name == "Delete" -%> + fun <%= KotlinHelper.fix_name(WasmCppHelper.format_name(method.name)) %>(<%= KotlinHelper.js_parameters(method.parameters.drop(1)) %>)<%= KotlinHelper.js_return_type(method.return_type) %> +<% end -%> + companion object { +<% entity.static_methods.each do |method| -%> + fun <%= KotlinHelper.fix_name(WasmCppHelper.function_name(entity: entity, function: method)) %>(<%= KotlinHelper.js_parameters(method.parameters) %>)<%= KotlinHelper.js_return_type(method.return_type) %> +<% end -%> + } +} + +inline val JsWalletCore.<%= entity.name %>: Js<%= entity.name %>.Companion + get() = asDynamic().<%= entity.name %>.unsafeCast.Companion>() diff --git a/codegen/lib/templates/kotlin/js_accessors_enum.erb b/codegen/lib/templates/kotlin/js_accessors_enum.erb new file mode 100644 index 00000000000..feaa2e82caf --- /dev/null +++ b/codegen/lib/templates/kotlin/js_accessors_enum.erb @@ -0,0 +1,36 @@ +@file:Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE") + +<%= render('kotlin/package.erb') %> + +@JsModule("@trustwallet/wallet-core") +@JsName("<%= entity.name %>") +external interface Js<%= entity.name %> { + val value: Number + companion object { +<% entity.cases.each do |c| -%> + val <%= KotlinHelper.fix_name(WasmCppHelper.format_name(c.name)) %>: Js<%= entity.name %> +<% end -%> + } +} + +inline val JsWalletCore.<%= entity.name %>: Js<%= entity.name %>.Companion + get() = asDynamic().<%= entity.name %>.unsafeCast.Companion>() + +<% if entity.properties.any? || entity.methods.any? -%> +@JsModule("@trustwallet/wallet-core") +@JsName("<%= entity.name %>Ext") +external interface Js<%= entity.name %>Ext { +<%# Static method declarations -%> +<%- entity.properties.each do |property| -%> + fun <%= KotlinHelper.fix_name(WasmCppHelper.format_name(property.name)) %>(<%= KotlinHelper.js_parameters(property.parameters) %>)<%= KotlinHelper.js_return_type(property.return_type) %> +<%- end -%> +<% entity.methods.each do |method| -%> +<% next if method.name.start_with?('Create') -%> + fun <%= KotlinHelper.fix_name(WasmCppHelper.function_name(entity: entity, function: method)) %>(<%= KotlinHelper.js_parameters(method.parameters) %>)<%= KotlinHelper.js_return_type(method.return_type) %> +<% end -%> +} + +inline val JsWalletCore.<%= entity.name %>Ext: Js<%= entity.name %>Ext + get() = asDynamic().<%= entity.name %>Ext.unsafeCastExt>() + +<% end -%> \ No newline at end of file diff --git a/codegen/lib/templates/kotlin/js_accessors_struct.erb b/codegen/lib/templates/kotlin/js_accessors_struct.erb new file mode 100644 index 00000000000..911024dc9ee --- /dev/null +++ b/codegen/lib/templates/kotlin/js_accessors_struct.erb @@ -0,0 +1,14 @@ +<%= render('kotlin/package.erb') %> + +@JsModule("@trustwallet/wallet-core") +@JsName("<%= entity.name %>") +external interface Js<%= entity.name %> { +<%# Static method declarations -%> +<% entity.static_methods.each do |method| -%> +<% next if method.name.start_with?('Create') -%> + fun <%= KotlinHelper.fix_name(WasmCppHelper.function_name(entity: entity, function: method)) %>(<%= KotlinHelper.js_parameters(method.parameters) %>)<%= KotlinHelper.js_return_type(method.return_type) %> +<% end -%> +} + +inline val JsWalletCore.<%= entity.name %>: Js<%= entity.name %> + get() = asDynamic().<%= entity.name %>.unsafeCast>() diff --git a/codegen/lib/templates/kotlin/js_class.erb b/codegen/lib/templates/kotlin/js_class.erb new file mode 100644 index 00000000000..14cd6ef5e40 --- /dev/null +++ b/codegen/lib/templates/kotlin/js_class.erb @@ -0,0 +1,48 @@ +<%= render('kotlin/package.erb') %> + +<% constructors = entity.static_methods.select { |method| method.name.start_with?('Create') } -%> +<% methods = entity.methods.select { |method| not method.name.start_with?('Delete') } -%> +<% static_methods = entity.static_methods.select { |method| not method.name.start_with?('Create') } -%> +actual class <%= entity.name %> constructor( + val jsValue: Js<%= entity.name %>, +) { +<%# Constructors -%> +<%- constructors.each do |constructor| -%> + + actual constructor(<%= KotlinHelper.parameters(constructor.parameters) %>) : +<% if constructor.return_type.is_nullable -%> + this(WalletCore.Instance.<%= entity.name %>.<%= WasmCppHelper.function_name(entity: entity, function: constructor) %>(<%= KotlinHelper.calling_parameters_js(constructor.parameters) %>) ?: throw IllegalArgumentException()) +<% else -%> + this(WalletCore.Instance.<%= entity.name %>.<%= WasmCppHelper.function_name(entity: entity, function: constructor) %>(<%= KotlinHelper.calling_parameters_js(constructor.parameters) %>)) +<% end -%> +<% end -%> +<%# Property declarations -%> +<% entity.properties.each do |property| -%> + + actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> + get() = <%= KotlinHelper.convert_calling_return_type_js(property.return_type, "jsValue.#{WasmCppHelper.function_name(entity: entity, function: property)}()") %> +<% end -%> +<%# Method declarations -%> +<% methods.each do |method| -%> + + actual fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters.drop(1)) %>)<%= KotlinHelper.return_type(method.return_type) %> = + <%= KotlinHelper.convert_calling_return_type_js(method.return_type, "jsValue.#{WasmCppHelper.function_name(entity: entity, function: method)}(#{KotlinHelper.calling_parameters_js(method.parameters.drop(1))})") %> +<% end -%> +<% if entity.static_properties.any? || static_methods.any? -%> + + <%= if entity.static_properties.any? || static_methods.any? then "actual" else "private" end %> companion object { +<%# Static property declarations -%> +<% entity.static_properties.each do |property| -%> + + actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> + get() = TODO() +<% end -%> +<%# Static method declarations -%> +<% static_methods.each do |method| -%> + + actual fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters) %>)<%= KotlinHelper.return_type(method.return_type) %> = + <%= KotlinHelper.convert_calling_return_type_js(method.return_type, "WalletCore.Instance.#{entity.name}.#{WasmCppHelper.function_name(entity: entity, function: method)}(#{KotlinHelper.calling_parameters_js(method.parameters)})") %> +<% end -%> + } +<% end -%> +} diff --git a/codegen/lib/templates/kotlin/js_enum.erb b/codegen/lib/templates/kotlin/js_enum.erb new file mode 100644 index 00000000000..2b910a5e7aa --- /dev/null +++ b/codegen/lib/templates/kotlin/js_enum.erb @@ -0,0 +1,46 @@ +<%= render('kotlin/package.erb') %> + +<% has_string = entity.cases.all? { |c| !c.string.nil? } -%> +actual enum class <%= entity.name %>( + val jsValue: Js<%= entity.name %>, +<% if has_string -%> + actual val stringValue: String, +<% end -%> +) { +<%# Cases -%> +<% entity.cases.each_with_index do |c, i| -%> +<% if has_string -%> + <%= c.name %>(WalletCore.Instance.<%= entity.name %>.<%= KotlinHelper.fix_name(WasmCppHelper.format_name(c.name)) %>, <%= c.string %>), +<% else -%> + <%= c.name %>(WalletCore.Instance.<%= entity.name %>.<%= KotlinHelper.fix_name(WasmCppHelper.format_name(c.name)) %>), +<% end -%> +<% end -%> + ; + + actual val value: UInt + get() = jsValue.value.toInt().toUInt() +<%# Property declarations -%> +<%- entity.properties.each do |property| -%> + + actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> + get() = <%= KotlinHelper.convert_calling_return_type_js(property.return_type, "WalletCore.Instance.#{entity.name}Ext.#{WasmCppHelper.function_name(entity: entity, function: property)}(jsValue)") %> +<%- end -%> +<%# Method declarations -%> +<%- entity.methods.each do |method| -%> +<%- next if method.name.start_with?('Delete') -%> + + actual fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters.drop(1)) %>)<%= KotlinHelper.return_type(method.return_type) %> = + <%= KotlinHelper.convert_calling_return_type_js(method.return_type, "WalletCore.Instance.#{entity.name}Ext.#{WasmCppHelper.function_name(entity: entity, function: method)}(jsValue#{', ' if not method.parameters.one?}#{KotlinHelper.calling_parameters_js(method.parameters.drop(1))})") %> +<%- end -%> +<%# Value -%> +<% if entity.cases.any? { |e| !e.value.nil? } -%> + + actual companion object { + actual fun fromValue(value: UInt): <%= entity.name %>? = + values().first { it.value == value } + + fun fromValue(jsValue: Js<%= entity.name %>): <%= entity.name %> = + values().first { it.jsValue.value == jsValue.value } + } +<% end -%> +} diff --git a/codegen/lib/templates/kotlin/js_struct.erb b/codegen/lib/templates/kotlin/js_struct.erb new file mode 100644 index 00000000000..80fd05feb72 --- /dev/null +++ b/codegen/lib/templates/kotlin/js_struct.erb @@ -0,0 +1,16 @@ +<%= render('kotlin/package.erb') %> + +actual object <%= entity.name %> { +<%# Static property declarations -%> +<% entity.static_properties.each do |property| -%> + actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> + get() = TODO() +<% end -%> +<%# Static method declarations -%> +<% entity.static_methods.each do |method| -%> +<% next if method.name.start_with?('Create') -%> + + actual fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters) %>)<%= KotlinHelper.return_type(method.return_type) %> = + <%= KotlinHelper.convert_calling_return_type_js(method.return_type, "WalletCore.Instance.#{entity.name}.#{WasmCppHelper.function_name(entity: entity, function: method)}(#{KotlinHelper.calling_parameters_js(method.parameters)})") %> +<% end -%> +} diff --git a/codegen/lib/templates/kotlin/package.erb b/codegen/lib/templates/kotlin/package.erb new file mode 100644 index 00000000000..64142a21c30 --- /dev/null +++ b/codegen/lib/templates/kotlin/package.erb @@ -0,0 +1 @@ +package com.trustwallet.core \ No newline at end of file diff --git a/codegen/lib/templates/kotlin_android.erb b/codegen/lib/templates/kotlin_android.erb new file mode 100644 index 00000000000..a9767e71d97 --- /dev/null +++ b/codegen/lib/templates/kotlin_android.erb @@ -0,0 +1,7 @@ +<%- if entity.is_a?(EnumDecl) -%> +<%= render('kotlin/android_enum.erb') -%> +<%- elsif entity.is_struct -%> +<%= render('kotlin/android_struct.erb') -%> +<%- else -%> +<%= render('kotlin/android_class.erb') -%> +<%- end -%> diff --git a/codegen/lib/templates/kotlin_common.erb b/codegen/lib/templates/kotlin_common.erb new file mode 100644 index 00000000000..31db319babd --- /dev/null +++ b/codegen/lib/templates/kotlin_common.erb @@ -0,0 +1,7 @@ +<%- if entity.is_a?(EnumDecl) -%> +<%= render('kotlin/common_enum.erb') -%> +<%- elsif entity.is_struct -%> +<%= render('kotlin/common_struct.erb') -%> +<%- else -%> +<%= render('kotlin/common_class.erb') -%> +<%- end -%> diff --git a/codegen/lib/templates/kotlin_ios.erb b/codegen/lib/templates/kotlin_ios.erb new file mode 100644 index 00000000000..272ad2cf1df --- /dev/null +++ b/codegen/lib/templates/kotlin_ios.erb @@ -0,0 +1,7 @@ +<%- if entity.is_a?(EnumDecl) -%> +<%= render('kotlin/ios_enum.erb') -%> +<%- elsif entity.is_struct -%> +<%= render('kotlin/ios_struct.erb') -%> +<%- else -%> +<%= render('kotlin/ios_class.erb') -%> +<%- end -%> diff --git a/codegen/lib/templates/kotlin_jni/class_access.erb b/codegen/lib/templates/kotlin_jni/class_access.erb new file mode 100644 index 00000000000..a260b8cfd35 --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/class_access.erb @@ -0,0 +1,6 @@ +<% param = locals[:param] -%> +<% name = param.name -%> +<% type = param.type -%> + jclass <%= name %>Class = (*env)->GetObjectClass(env, <%= name %>); + jfieldID <%= name %>HandleFieldID = (*env)->GetFieldID(env, <%= name %>Class, "nativeHandle", "J"); + struct TW<%= type.name %> *<%= name %>Instance = (struct TW<%= type.name %> *) (*env)->GetLongField(env, <%= name %>, <%= name %>HandleFieldID); diff --git a/codegen/lib/templates/kotlin_jni/compare_to.erb b/codegen/lib/templates/kotlin_jni/compare_to.erb new file mode 100644 index 00000000000..253a8584b6e --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/compare_to.erb @@ -0,0 +1,22 @@ +<% less = locals[:less] -%> +<% equal = locals[:equal] -%> +<% compareMethod = KotlinJniHelper.compareMethod(entity) -%> +<%= render('kotlin_jni/method_prototype.erb', { method: compareMethod }) %> { +<%= render('kotlin_jni/instance_access.erb', { entity: entity }) %> +<%= render('kotlin_jni/parameter_access.erb', { method: compareMethod }) -%> +<% if entity.struct? -%> + jboolean equal = (jboolean) TW<%= entity.name %>Equal(*instance, *otherInstance); +<% else -%> + jboolean equal = (jboolean) TW<%= entity.name %>Equal(instance, otherInstance); +<% end -%> + if (equal) { + return 0; + } +<% if entity.struct? -%> + jboolean less = (jboolean) TW<%= entity.name %>Less(*instance, *otherInstance); +<% else -%> + jboolean less = (jboolean) TW<%= entity.name %>Less(instance, otherInstance); +<% end -%> +<%= render('kotlin_jni/instance_release.erb', { entity: entity }) %> + return less ? -1 : 1; +} diff --git a/codegen/lib/templates/kotlin_jni/enum_access.erb b/codegen/lib/templates/kotlin_jni/enum_access.erb new file mode 100644 index 00000000000..43d612c0fa0 --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/enum_access.erb @@ -0,0 +1,6 @@ +<% param = locals[:param] -%> +<% name = param.name -%> +<% type = param.type -%> + jclass <%= name %>Class = (*env)->GetObjectClass(env, <%= name %>); + jmethodID <%= name %>ValueMethodID = (*env)->GetMethodID(env, <%= name %>Class, "value", "()I"); + jint <%= name %>Value = (*env)->CallIntMethod(env, <%= name %>, <%= name %>ValueMethodID); diff --git a/codegen/lib/templates/kotlin_jni/instance_access.erb b/codegen/lib/templates/kotlin_jni/instance_access.erb new file mode 100644 index 00000000000..5654c472858 --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/instance_access.erb @@ -0,0 +1,14 @@ +<% entity = locals[:entity] -%> + jclass thisClass = (*env)->GetObjectClass(env, thisObject); +<% if entity.struct? -%> + jfieldID bytesFieldID = (*env)->GetFieldID(env, thisClass, "bytes", "[B"); + jbyteArray bytesArray = (*env)->GetObjectField(env, thisObject, bytesFieldID); + jbyte* bytesBuffer = (*env)->GetByteArrayElements(env, bytesArray, NULL); + struct TW<%= entity.name %> *instance = (struct TW<%= entity.name %> *) bytesBuffer; +<% elsif entity.enum? -%> + jfieldID handleFieldID = (*env)->GetFieldID(env, thisClass, "value", "I"); + enum TW<%= entity.name %> instance = (enum TW<%= entity.name %>) (*env)->GetIntField(env, thisObject, handleFieldID); +<% else -%> + jfieldID handleFieldID = (*env)->GetFieldID(env, thisClass, "nativeHandle", "J"); + struct TW<%= entity.name %> *instance = (struct TW<%= entity.name %> *) (*env)->GetLongField(env, thisObject, handleFieldID); +<% end -%> diff --git a/codegen/lib/templates/kotlin_jni/instance_release.erb b/codegen/lib/templates/kotlin_jni/instance_release.erb new file mode 100644 index 00000000000..1231d03119b --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/instance_release.erb @@ -0,0 +1,6 @@ +<% entity = locals[:entity] -%> +<% if entity.struct? -%> + (*env)->ReleaseByteArrayElements(env, bytesArray, bytesBuffer, JNI_ABORT); + (*env)->DeleteLocalRef(env, bytesArray); +<% end -%> + (*env)->DeleteLocalRef(env, thisClass); \ No newline at end of file diff --git a/codegen/lib/templates/kotlin_jni/method.erb b/codegen/lib/templates/kotlin_jni/method.erb new file mode 100644 index 00000000000..f41b05435a8 --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/method.erb @@ -0,0 +1,8 @@ +<% method = locals[:method] -%> +<%= render('kotlin_jni/method_prototype.erb', { method: method }) %> { +<% if !method.static -%> +<%= render('kotlin_jni/instance_access.erb', { entity: entity }) %> +<% end -%> +<%= render('kotlin_jni/parameter_access.erb', { method: method }) -%> +<%= render('kotlin_jni/method_forward.erb', { method: method }) -%> +} diff --git a/codegen/lib/templates/kotlin_jni/method_call.erb b/codegen/lib/templates/kotlin_jni/method_call.erb new file mode 100644 index 00000000000..68dfee4205a --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/method_call.erb @@ -0,0 +1,6 @@ +<% + method = locals[:method] + instance = (method.entity.struct? ? '*' : '') + 'instance' + arguments = locals[:arguments] || [instance] + KotlinJniHelper.arguments(method.parameters.drop(1)) +-%> +TW<%= entity.name %><%= method.name %>(<%= arguments.join(', ') %>) \ No newline at end of file diff --git a/codegen/lib/templates/kotlin_jni/method_forward.erb b/codegen/lib/templates/kotlin_jni/method_forward.erb new file mode 100644 index 00000000000..3673db58a48 --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/method_forward.erb @@ -0,0 +1,118 @@ +<% + method = locals[:method] + if method.static + arguments = locals[:arguments] || KotlinJniHelper.arguments(method.parameters) + call = render('kotlin_jni/method_call.erb', { method: method, arguments: arguments }) + else + instance = (method.entity.struct? ? '*' : '') + 'instance' + arguments = locals[:arguments] || [instance] + KotlinJniHelper.arguments(method.parameters.drop(1)) + call = render('kotlin_jni/method_call.erb', { method: method, arguments: arguments }) + end + + # Method returns data + if should_return_data(method) -%> + <%= KotlinJniHelper.type(method.return_type) %> result = NULL; + TWData *resultData = <%= call %>; +<% if method.return_type.is_nullable %> + if (resultData == NULL) { + goto cleanup; + } +<% end -%> + result = TWDataJByteArray(resultData, env); +<% if method.return_type.is_nullable %> +cleanup: +<% end -%> +<%= render('kotlin_jni/parameter_release.erb', { method: method }) -%> +<% if !method.static %> +<%= render('kotlin_jni/instance_release.erb', { entity: entity }) %> +<% end -%> + return result; +<% + # Method returns a string + elsif should_return_string(method) -%> + jstring result = NULL; + TWString *resultString = <%= call %>; +<% if method.return_type.is_nullable %> + if (resultString == NULL) { + goto cleanup; + } +<% end -%> + result = TWStringJString(resultString, env); +<% if method.return_type.is_nullable %> +cleanup: +<% end -%> +<%= render('kotlin_jni/parameter_release.erb', { method: method }) -%> +<% if !method.static %> +<%= render('kotlin_jni/instance_release.erb', { entity: entity }) %> +<% end -%> + return result; +<% + # Method returns proto + elsif method.return_type.is_proto -%> + jbyteArray resultData = TWDataJByteArray(<%= call %>, env); + jclass resultClass = (*env)->FindClass(env, "<%= KotlinJniHelper.proto_to_class(method.return_type.name) %>"); + jmethodID parseFromMethodID = (*env)->GetStaticMethodID(env, resultClass, "parseFrom", "([B)L<%= KotlinJniHelper.proto_to_class(method.return_type.name) %>;"); + jobject result = (*env)->CallStaticObjectMethod(env, resultClass, parseFromMethodID, resultData); + + (*env)->DeleteLocalRef(env, resultClass); +<%= render('kotlin_jni/parameter_release.erb', { method: method }) -%> +<% if !method.static %> +<%= render('kotlin_jni/instance_release.erb', { entity: entity }) %> +<% end -%> + + return result; +<% + # Method returns an object + elsif method.return_type.is_struct || method.return_type.is_class || method.return_type.is_enum + if method.return_type.is_struct -%> + struct TW<%= method.return_type.name %> result = <%= call %>; +<% elsif method.return_type.is_class -%> + struct TW<%= method.return_type.name %> *result = <%= call %>; +<% elsif method.return_type.is_enum -%> + enum TW<%= method.return_type.name %> result = <%= call %>; +<% else -%> + TW<%= method.return_type.name %> *result = <%= call %>; +<% end -%> + +<%= render('kotlin_jni/parameter_release.erb', { method: method }) -%> +<% if !method.static %> +<%= render('kotlin_jni/instance_release.erb', { entity: entity }) %> +<% end -%> + + jclass class = (*env)->FindClass(env, "com/trustwallet/core/<%= method.return_type.name %>"); +<% if method.return_type.is_struct -%> + jbyteArray resultArray = (*env)->NewByteArray(env, sizeof(struct TW<%= method.return_type.name %>)); + (*env)->SetByteArrayRegion(env, resultArray, 0, sizeof(struct TW<%= method.return_type.name %>), (jbyte *) &result); + jmethodID method = (*env)->GetStaticMethodID(env, class, "createFromNative", "([B)Lcom/trustwallet/core/<%= method.return_type.name %>;"); + return (*env)->CallStaticObjectMethod(env, class, method, resultArray); +<% elsif method.return_type.is_enum -%> + jmethodID method = (*env)->GetStaticMethodID(env, class, "createFromValue", "(I)Lcom/trustwallet/core/<%= method.return_type.name %>;"); + return (*env)->CallStaticObjectMethod(env, class, method, (jint) result); +<% else -%> + if (result == NULL) { + return NULL; + } + jmethodID method = (*env)->GetStaticMethodID(env, class, "createFromNative", "(J)Lcom/trustwallet/core/<%= method.return_type.name %>;"); + return (*env)->CallStaticObjectMethod(env, class, method, (jlong) result); +<% end + + # Method returns void + elsif method.return_type.name == :void -%> + <%= call %>; + +<%= render('kotlin_jni/parameter_release.erb', { method: method }) -%> +<% if !method.static %> +<%= render('kotlin_jni/instance_release.erb', { entity: entity }) %> +<% end + + # Method returns a primitive + else -%> + <%= KotlinJniHelper.type(method.return_type) %> resultValue = (<%= KotlinJniHelper.type(method.return_type) %>) <%= call %>; + +<%= render('kotlin_jni/parameter_release.erb', { method: method }) -%> +<% if !method.static %> +<%= render('kotlin_jni/instance_release.erb', { entity: entity }) %> +<% end -%> + + return resultValue; +<%end -%> \ No newline at end of file diff --git a/codegen/lib/templates/kotlin_jni/method_prototype.erb b/codegen/lib/templates/kotlin_jni/method_prototype.erb new file mode 100644 index 00000000000..a971ce95bd5 --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/method_prototype.erb @@ -0,0 +1,9 @@ +<% + method = locals[:method] + if method.static + parameters = 'jclass thisClass' + KotlinJniHelper.parameters(method.parameters) + else + parameters = 'jobject thisObject' + KotlinJniHelper.parameters(method.parameters.drop(1)) + end +-%> +<%= KotlinJniHelper.type(method.return_type) %> JNICALL <%= KotlinJniHelper.function_name(entity: entity, function: method) %>(JNIEnv *env, <%= parameters %>)<% -%> diff --git a/codegen/lib/templates/kotlin_jni/parameter_access.erb b/codegen/lib/templates/kotlin_jni/parameter_access.erb new file mode 100644 index 00000000000..a5dcae13aa1 --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/parameter_access.erb @@ -0,0 +1,23 @@ +<% + method = locals[:method] + if method.static && !method.name.start_with?('Init') + parameters = method.parameters + else + parameters = method.parameters.drop(1) + end + + parameters.each do |param| + if param.type.name == :data -%> + TWData *<%= param.name %>Data = TWDataCreateWithJByteArray(env, <%= param.name %>); +<% elsif param.type.name == :string -%> + TWString *<%= param.name %>String = TWStringCreateWithJString(env, <%= param.name %>); +<% elsif param.type.is_struct -%> +<%= render('kotlin_jni/struct_access.erb', { param: param }) -%> +<% elsif param.type.is_class -%> +<%= render('kotlin_jni/class_access.erb', { param: param }) -%> +<% elsif param.type.is_enum -%> +<%= render('kotlin_jni/enum_access.erb', { param: param }) -%> +<% elsif param.type.is_proto -%> +<%= render('kotlin_jni/proto_access.erb', { param: param }) -%> +<% end -%> +<%end -%> diff --git a/codegen/lib/templates/kotlin_jni/parameter_release.erb b/codegen/lib/templates/kotlin_jni/parameter_release.erb new file mode 100644 index 00000000000..1db6f1a86e1 --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/parameter_release.erb @@ -0,0 +1,26 @@ +<% + method = locals[:method] + if method.static && !method.name.start_with?('Init') + parameters = method.parameters + else + parameters = method.parameters.drop(1) + end + + parameters.each do |param| + if param.type.name == :data -%> + TWDataDelete(<%= param.name %>Data); +<% elsif param.type.name == :string -%> + TWStringDelete(<%= param.name %>String); +<% elsif param.type.is_struct -%> + (*env)->ReleaseByteArrayElements(env, <%= param.name %>BytesArray, <%= param.name %>BytesBuffer, JNI_ABORT); + (*env)->DeleteLocalRef(env, <%= param.name %>BytesArray); + (*env)->DeleteLocalRef(env, <%= param.name %>Class); +<% elsif param.type.is_class -%> + (*env)->DeleteLocalRef(env, <%= param.name %>Class); +<% elsif param.type.is_enum -%> + (*env)->DeleteLocalRef(env, <%= param.name %>Class); +<% elsif param.type.is_proto -%> + (*env)->DeleteLocalRef(env, <%= param.name %>ByteArray); + (*env)->DeleteLocalRef(env, <%= param.name %>Class); +<% end -%> +<%end -%> diff --git a/codegen/lib/templates/kotlin_jni/proto_access.erb b/codegen/lib/templates/kotlin_jni/proto_access.erb new file mode 100644 index 00000000000..36d930a73cd --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/proto_access.erb @@ -0,0 +1,7 @@ +<% param = locals[:param] -%> +<% name = param.name -%> +<% type = param.type -%> + jclass <%= name %>Class = (*env)->GetObjectClass(env, <%= name %>); + jmethodID <%= name %>ToByteArrayMethodID = (*env)->GetMethodID(env, <%= name %>Class, "toByteArray", "()[B"); + jbyteArray <%= name %>ByteArray = (*env)->CallObjectMethod(env, <%= name %>, <%= name %>ToByteArrayMethodID); + TWData *<%= param.name %>Data = TWDataCreateWithJByteArray(env, <%= name %>ByteArray); diff --git a/codegen/lib/templates/kotlin_jni/struct_access.erb b/codegen/lib/templates/kotlin_jni/struct_access.erb new file mode 100644 index 00000000000..ed8c88c027b --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/struct_access.erb @@ -0,0 +1,8 @@ +<% param = locals[:param] -%> +<% name = param.name -%> +<% type = param.type -%> + jclass <%= name %>Class = (*env)->GetObjectClass(env, <%= name %>); + jfieldID <%= name %>BytesFieldID = (*env)->GetFieldID(env, <%= name %>Class, "bytes", "[B"); + jbyteArray <%= name %>BytesArray = (*env)->GetObjectField(env, <%= name %>, <%= name %>BytesFieldID); + jbyte* <%= name %>BytesBuffer = (*env)->GetByteArrayElements(env, <%= name %>BytesArray, NULL); + struct TW<%= type.name %> *<%= name %>Instance = (struct TW<%= type.name %> *) <%= name %>BytesBuffer; diff --git a/codegen/lib/templates/kotlin_jni_c.erb b/codegen/lib/templates/kotlin_jni_c.erb new file mode 100644 index 00000000000..3b1f05b0588 --- /dev/null +++ b/codegen/lib/templates/kotlin_jni_c.erb @@ -0,0 +1,90 @@ +#include +#include +#include + +<% require 'set' -%> +<% includes = Set.new([entity.name]) -%> +<% entity.static_methods.each do |method| -%> +<% includes << method.return_type.name if method.return_type.is_struct || method.return_type.is_class -%> +<% method.parameters.each do |param| -%> +<% includes << param.type.name if param.type.is_struct || param.type.is_class -%> +<% end -%> +<% end -%> +<% includes.each do |include| -%> +#include .h> +<% end -%> + +#include "TWJNI.h" +#include "<%= entity.name %>.h" + +<%# Constructors -%> +<% entity.static_methods.each do |method| -%> +<% next unless method.name.start_with?('Create') -%> +jlong JNICALL <%= KotlinJniHelper.function_name(entity: entity, function: method, native_prefix: true) %>(JNIEnv *env, jclass thisClass<%= KotlinJniHelper.parameters(method.parameters) %>) { +<%= render('kotlin_jni/parameter_access.erb', { method: method }) -%> + struct TW<%= entity.name %> *instance = TW<%= entity.name %><%= method.name %>(<%= KotlinJniHelper.arguments(method.parameters).join(', ') %>); +<%= render('kotlin_jni/parameter_release.erb', { method: method }) -%> + return (jlong) instance; +} + +<% end -%> +<%# Destructors -%> +<% entity.methods.each do |method| -%> +<% next unless method.name.start_with?('Delete') -%> +void JNICALL <%= KotlinJniHelper.function_name(entity: entity, function: method, native_prefix: true) %>(JNIEnv *env, jclass thisClass, jlong handle) { + TW<%= entity.name %>Delete((struct TW<%= entity.name %> *) handle); +} + +<% end -%> +<%# Initializers -%> +<% entity.static_methods.each do |method| -%> +<% next unless method.name.start_with?('Init') -%> +jbyteArray JNICALL <%= KotlinJniHelper.function_name(entity: entity, function: method) %>(JNIEnv *env, jclass thisClass<%= KotlinJniHelper.parameters(method.parameters.drop(1)) %>) { + jbyteArray array = (*env)->NewByteArray(env, sizeof(struct TW<%= entity.name %>)); + jbyte* bytesBuffer = (*env)->GetByteArrayElements(env, array, NULL); + struct TW<%= entity.name %> *instance = (struct TW<%= entity.name %> *) bytesBuffer; +<%= render('kotlin_jni/parameter_access.erb', { method: method }) -%> +<% if method.return_type.name != :void -%> + <%= KotlinJniHelper.type(method.return_type) %> result = (<%= KotlinJniHelper.type(method.return_type) %>) TW<%= entity.name %><%= method.name %>(instance, <%= KotlinJniHelper.arguments(method.parameters.drop(1)).join(', ') %>); +<% else -%> + TW<%= entity.name %><%= method.name %>(instance, <%= KotlinJniHelper.arguments(method.parameters.drop(1)).join(', ') %>); +<% end -%> +<%= render('kotlin_jni/parameter_release.erb', { method: method }) -%> + (*env)->ReleaseByteArrayElements(env, array, bytesBuffer, 0); + +<% if method.return_type.name != :void -%> + if (result) { + return array; + } else { + (*env)->DeleteLocalRef(env, array); + return NULL; + } +<% else -%> + return array; +<% end -%> +} + +<% end -%> +<%# Static properties -%> +<% entity.static_properties.each do |method| -%> +<%= render('kotlin_jni/method.erb', { method: method }) %> +<% end -%> +<%# Static methods -%> +<% entity.static_methods.each do |method| -%> +<% next if method.name.start_with?('Create') || method.name.start_with?('Init') -%> +<%= render('kotlin_jni/method.erb', { method: method }) %> +<% end -%> +<%# Properties -%> +<% entity.properties.each do |method| -%> +<%= render('kotlin_jni/method.erb', { method: method }) %> +<% end -%> +<%# Methods -%> +<% entity.methods.each do |method| -%> +<% next if method.name == "Delete" -%> +<%= render('kotlin_jni/method.erb', { method: method }) %> +<% end -%> +<% less = entity.static_methods.detect{ |i| i.name == 'Less' } -%> +<% equal = entity.static_methods.detect{ |i| i.name == 'Equal' } -%> +<% if !less.nil? && !equal.nil? -%> +<%= render('kotlin_jni/compare_to.erb', { less: less, equal: equal }) %> +<% end -%> diff --git a/codegen/lib/templates/kotlin_jni_h.erb b/codegen/lib/templates/kotlin_jni_h.erb new file mode 100644 index 00000000000..44e3bec9cf8 --- /dev/null +++ b/codegen/lib/templates/kotlin_jni_h.erb @@ -0,0 +1,66 @@ +#ifndef JNI_TW_<%= entity.name.upcase %>_H +#define JNI_TW_<%= entity.name.upcase %>_H + +#include +#include + +TW_EXTERN_C_BEGIN + +<%# Constructor declarations -%> +<% entity.static_methods.each do |method| -%> +<% next unless method.name.start_with?('Create') -%> +JNIEXPORT +jlong JNICALL <%= KotlinJniHelper.function_name(entity: entity, function: method, native_prefix: true) %>(JNIEnv *env, jclass thisClass<%= KotlinJniHelper.parameters(method.parameters) %>); + +<% end -%> +<%# Destructor declarations -%> +<% entity.methods.each do |method| -%> +<% next unless method.name.start_with?('Delete') -%> +JNIEXPORT +void JNICALL <%= KotlinJniHelper.function_name(entity: entity, function: method, native_prefix: true) %>(JNIEnv *env, jclass thisClass, jlong handle); + +<% end -%> +<%# Initializer declarations -%> +<% entity.static_methods.each do |method| -%> +<% next unless method.name.start_with?('Init') -%> +JNIEXPORT +jbyteArray JNICALL <%= KotlinJniHelper.function_name(entity: entity, function: method) %>(JNIEnv *env, jclass thisClass<%= KotlinJniHelper.parameters(method.parameters.drop(1)) %>); + +<% end -%> +<%# Static property declarations -%> +<% entity.static_properties.each do |property| -%> +JNIEXPORT +<%= render('kotlin_jni/method_prototype.erb', { method: property }) %>; + +<% end -%> +<%# Static method declarations -%> +<% entity.static_methods.each do |method| -%> +<% next if method.name.start_with?('Create') || method.name.start_with?('Init') -%> +JNIEXPORT +<%= render('kotlin_jni/method_prototype.erb', { method: method }) %>; + +<% end -%> +<%# Property declarations -%> +<% entity.properties.each do |property| -%> +JNIEXPORT +<%= render('kotlin_jni/method_prototype.erb', { method: property }) %>; + +<% end -%> +<%# Method declarations -%> +<% entity.methods.each do |method| -%> +<% next if method.name.start_with?('Delete') -%> +JNIEXPORT +<%= render('kotlin_jni/method_prototype.erb', { method: method }) %>; + +<% end -%> +<% less = entity.static_methods.detect{ |i| i.name == 'Less' } -%> +<% equal = entity.static_methods.detect{ |i| i.name == 'Equal' } -%> +<% if !less.nil? && !equal.nil? -%> +JNIEXPORT +<%= render('kotlin_jni/method_prototype.erb', { method: KotlinJniHelper.compareMethod(entity) }) %>; + +<% end -%> + +TW_EXTERN_C_END + +#endif // JNI_TW_<%= entity.name.upcase %>_H diff --git a/codegen/lib/templates/kotlin_js.erb b/codegen/lib/templates/kotlin_js.erb new file mode 100644 index 00000000000..db9c23dd567 --- /dev/null +++ b/codegen/lib/templates/kotlin_js.erb @@ -0,0 +1,7 @@ +<%- if entity.is_a?(EnumDecl) -%> +<%= render('kotlin/js_enum.erb') -%> +<%- elsif entity.is_struct -%> +<%= render('kotlin/js_struct.erb') -%> +<%- else -%> +<%= render('kotlin/js_class.erb') -%> +<%- end -%> diff --git a/codegen/lib/templates/kotlin_js_accessors.erb b/codegen/lib/templates/kotlin_js_accessors.erb new file mode 100644 index 00000000000..63dda74b3b2 --- /dev/null +++ b/codegen/lib/templates/kotlin_js_accessors.erb @@ -0,0 +1,7 @@ +<%- if entity.is_a?(EnumDecl) -%> +<%= render('kotlin/js_accessors_enum.erb') -%> +<%- elsif entity.is_struct -%> +<%= render('kotlin/js_accessors_struct.erb') -%> +<%- else -%> +<%= render('kotlin/js_accessors_class.erb') -%> +<%- end -%> diff --git a/codegen/lib/templates/newcoin/Address.cpp.erb b/codegen/lib/templates/newcoin/Address.cpp.erb index e9eb3b1412f..ea1c354db0e 100644 --- a/codegen/lib/templates/newcoin/Address.cpp.erb +++ b/codegen/lib/templates/newcoin/Address.cpp.erb @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #include "Address.h" diff --git a/codegen/lib/templates/newcoin/Address.h.erb b/codegen/lib/templates/newcoin/Address.h.erb index 9c6f60df4f6..7fe392b92df 100644 --- a/codegen/lib/templates/newcoin/Address.h.erb +++ b/codegen/lib/templates/newcoin/Address.h.erb @@ -1,13 +1,11 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once -#include "../Data.h" -#include "../PublicKey.h" +#include "Data.h" +#include "PublicKey.h" #include diff --git a/codegen/lib/templates/newcoin/AddressTests.cpp.erb b/codegen/lib/templates/newcoin/AddressTests.cpp.erb index ca9d99d3139..27c4c09ab89 100644 --- a/codegen/lib/templates/newcoin/AddressTests.cpp.erb +++ b/codegen/lib/templates/newcoin/AddressTests.cpp.erb @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #include "HexCoding.h" #include "<%= format_name(coin) %>/Address.h" diff --git a/codegen/lib/templates/newcoin/AddressTests.kt.erb b/codegen/lib/templates/newcoin/AddressTests.kt.erb index 34781800a4c..20bbd774cc9 100644 --- a/codegen/lib/templates/newcoin/AddressTests.kt.erb +++ b/codegen/lib/templates/newcoin/AddressTests.kt.erb @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.<%= format_name_lowercase(coin) %> diff --git a/codegen/lib/templates/newcoin/Entry.cpp.erb b/codegen/lib/templates/newcoin/Entry.cpp.erb index d0585ed64b9..793f5bf8f3f 100644 --- a/codegen/lib/templates/newcoin/Entry.cpp.erb +++ b/codegen/lib/templates/newcoin/Entry.cpp.erb @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #include "Entry.h" @@ -13,11 +11,11 @@ namespace TW::<%= format_name(coin) %> { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } -std::string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } @@ -25,4 +23,12 @@ void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) con signTemplate(dataIn, dataOut); } +TW::Data Entry::preImageHashes(TWCoinType coin, const Data& txInputData) const { + return TW::Data(); +} + +void Entry::compile(TWCoinType coin, const Data& txInputData, const std::vector& signatures, const std::vector& publicKeys, Data& dataOut) const { + +} + } // namespace TW::<%= format_name(coin) %> diff --git a/codegen/lib/templates/newcoin/Entry.h.erb b/codegen/lib/templates/newcoin/Entry.h.erb index 1b58f5f78cd..32b48e0e42c 100644 --- a/codegen/lib/templates/newcoin/Entry.h.erb +++ b/codegen/lib/templates/newcoin/Entry.h.erb @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once @@ -12,13 +10,16 @@ namespace TW::<%= format_name(coin) %> { /// Entry point for implementation of <%= format_name(coin) %> coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry : public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; // normalizeAddress(): implement this if needed, e.g. Ethereum address is EIP55 checksummed // plan(): implement this if the blockchain is UTXO based + + Data preImageHashes(TWCoinType coin, const Data& txInputData) const; + void compile(TWCoinType coin, const Data& txInputData, const std::vector& signatures, const std::vector& publicKeys, Data& dataOut) const; }; } // namespace TW::<%= format_name(coin) %> diff --git a/codegen/lib/templates/newcoin/Proto.erb b/codegen/lib/templates/newcoin/Proto.erb index 3065a609020..bbd242d66be 100644 --- a/codegen/lib/templates/newcoin/Proto.erb +++ b/codegen/lib/templates/newcoin/Proto.erb @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. syntax = "proto3"; diff --git a/codegen/lib/templates/newcoin/Signer.cpp.erb b/codegen/lib/templates/newcoin/Signer.cpp.erb index 7dec6579529..aeedceda863 100644 --- a/codegen/lib/templates/newcoin/Signer.cpp.erb +++ b/codegen/lib/templates/newcoin/Signer.cpp.erb @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #include "Signer.h" #include "Address.h" diff --git a/codegen/lib/templates/newcoin/Signer.h.erb b/codegen/lib/templates/newcoin/Signer.h.erb index 1261f9c6149..f77982f3ac3 100644 --- a/codegen/lib/templates/newcoin/Signer.h.erb +++ b/codegen/lib/templates/newcoin/Signer.h.erb @@ -1,12 +1,10 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once -#include "../Data.h" +#include "Data.h" #include "../PrivateKey.h" #include "../proto/<%= name %>.pb.h" @@ -19,7 +17,10 @@ public: Signer() = delete; /// Signs a Proto::SigningInput transaction - static Proto::SigningOutput sign(const Proto::SigningInput& input) noexcept; + static Proto::SigningOutput sign(const Proto::SigningInput& input, std::optional optionalExternalSigs = {}) noexcept; + + /// Collect pre-image hashes to be signed + static PreSigningOutput preImageHashes(const SigningInput& input) noexcept; }; } // namespace TW::<%= name %> diff --git a/codegen/lib/templates/newcoin/SignerTests.cpp.erb b/codegen/lib/templates/newcoin/SignerTests.cpp.erb index 9df8b26ee1e..d88ad46994f 100644 --- a/codegen/lib/templates/newcoin/SignerTests.cpp.erb +++ b/codegen/lib/templates/newcoin/SignerTests.cpp.erb @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #include "<%= format_name(coin) %>/Signer.h" #include "<%= format_name(coin) %>/Address.h" diff --git a/codegen/lib/templates/newcoin/SignerTests.kt.erb b/codegen/lib/templates/newcoin/SignerTests.kt.erb index e0512c55b1d..4add9add89f 100644 --- a/codegen/lib/templates/newcoin/SignerTests.kt.erb +++ b/codegen/lib/templates/newcoin/SignerTests.kt.erb @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package com.trustwallet.core.app.blockchains.<%= format_name_lowercase(coin) %> diff --git a/codegen/lib/templates/newcoin/TWAddressTests.cpp.erb b/codegen/lib/templates/newcoin/TWAddressTests.cpp.erb index 0a4ea03764d..91a0cbf0729 100644 --- a/codegen/lib/templates/newcoin/TWAddressTests.cpp.erb +++ b/codegen/lib/templates/newcoin/TWAddressTests.cpp.erb @@ -1,13 +1,11 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #include #include "HexCoding.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include using namespace TW; diff --git a/codegen/lib/templates/newcoin/TWSignerTests.cpp.erb b/codegen/lib/templates/newcoin/TWSignerTests.cpp.erb index 4e72ef5fa5f..8e8193db07c 100644 --- a/codegen/lib/templates/newcoin/TWSignerTests.cpp.erb +++ b/codegen/lib/templates/newcoin/TWSignerTests.cpp.erb @@ -1,13 +1,11 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #include #include "HexCoding.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include using namespace TW; diff --git a/codegen/lib/templates/newcoin/Tests.swift.erb b/codegen/lib/templates/newcoin/Tests.swift.erb index 583696882c5..e28d0ec1bc2 100644 --- a/codegen/lib/templates/newcoin/Tests.swift.erb +++ b/codegen/lib/templates/newcoin/Tests.swift.erb @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. import WalletCore import XCTest diff --git a/codegen/lib/templates/newcoin/TransactionCompilerTests.cpp.erb b/codegen/lib/templates/newcoin/TransactionCompilerTests.cpp.erb new file mode 100644 index 00000000000..c996dd2c6ab --- /dev/null +++ b/codegen/lib/templates/newcoin/TransactionCompilerTests.cpp.erb @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#include "<%= format_name(coin) %>/Signer.h" +#include "<%= format_name(coin) %>/Address.h" +#include "HexCoding.h" +#include "PrivateKey.h" +#include "PublicKey.h" +#include "TestUtilities.h" +#include "TransactionCompiler.h" + +#include "proto/<%= format_name(coin) %>.pb.h" +#include "proto/TransactionCompiler.pb.h" + +#include + +#include + +using namespace TW; + +namespace TW::<%= format_name(coin) %> { + +TEST(<%= format_name(coin) %>Compiler, CompileWithSignatures) { + // TODO: Finalize test implementation +} + +} // namespace TW::<%= format_name(coin) %> diff --git a/codegen/lib/templates/swift/TrustWalletCore.h.erb b/codegen/lib/templates/swift/TrustWalletCore.h.erb index 085c7e80064..5e2ac88537a 100644 --- a/codegen/lib/templates/swift/TrustWalletCore.h.erb +++ b/codegen/lib/templates/swift/TrustWalletCore.h.erb @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #import diff --git a/codegen/lib/templates/swift/parameter_access.erb b/codegen/lib/templates/swift/parameter_access.erb index 8521c18bb4a..ddf4335753f 100644 --- a/codegen/lib/templates/swift/parameter_access.erb +++ b/codegen/lib/templates/swift/parameter_access.erb @@ -10,12 +10,14 @@ let <%= param.name %>String: UnsafeRawPointer? if let s = <%= param.name %> { <%= param.name %>String = TWStringCreateWithNSString(s) - defer { - TWStringDelete(s) - } } else { <%= param.name %>String = nil } + defer { + if let s = <%= param.name %>String { + TWStringDelete(s) + } + } <% else -%> let <%= param.name %>String = TWStringCreateWithNSString(<%= param.name %>) defer { diff --git a/coverage.stats b/coverage.stats index b99dacf6dff..8b3541cc00d 100644 --- a/coverage.stats +++ b/coverage.stats @@ -1 +1 @@ -95.0 \ No newline at end of file +93.0 diff --git a/docs/registry-fields.md b/docs/registry-fields.md index f4662d510cd..ff6b0e539e6 100644 --- a/docs/registry-fields.md +++ b/docs/registry-fields.md @@ -31,7 +31,7 @@ Ex.: `10000118` for Osmosis, `118` for Cosmos; `20000714` for BNB Smart Chain. See also: `slip44` and `chainId`. **`slip44`** -Optionally, SLIP-44 (BIP-44) coin ID can be specified here, in case it differs from `coinId`. Most of the case the two are the same, so this can be omitted. +Optionally, SLIP-44 (BIP-44) coin ID can be specified here, in case it differs from `coinId`. In most cases the two are the same, so this can be omitted. Ex.: `60` for Optimism (coinID is `10000070`). **`symbol`** @@ -67,7 +67,7 @@ Note that the second number, the BIP-44 ID, usually matches the coinId. Some blockchains may support additional alternative derivations. These have: - a name -- a alternative derivation path (optional) +- an alternative derivation path (optional) Derivation may differ in the derivation path, or by address generation method (based on the derivation name). The first derivation is considered the default. @@ -126,7 +126,7 @@ Defines the prefix byte used in P2PKH and P2SH addresses, Bitcoin style. Ex. `0` and `5` for Bitcoin. **`hrp`** -Human Readable Prefix used to prefix an address, used to indicate type of address, to minimalize risk of accidental address mix-up across chains. +Human Readable Prefix used to prefix an address, used to indicate type of address, to minimize risk of accidental address mix-up across chains. Ex. `'bc'` for Bitcoin, `'cosmos'` for Cosmos. **`chainId`** @@ -150,7 +150,7 @@ Ex.: `'sha256d'` for Bitcoin, `'blake256d'` for Decred. **`addressHasher`** Hash method used in the publicKey -> address generation. -Only some chain implementation use this setting, in most implementation this is fixed (and value here is only informative). +Only some chain implementations use this setting, in most implementations this is fixed (and value here is only informative). Default is `sha256ripemd`. Ex.: missing ('sha256ripemd') for Bitcoin, `'keccak256'` for Ethereum, `'sha256ripemd'` for Cosmos, `'keccak256'` for Native Evmos, despite being a Cosmos fork. @@ -189,7 +189,7 @@ Link to the default implementation of the node or RPC gateway that can be used b Optional URL to an available public RPC service. **`info/documentation`** -Main porject documentation site/subsite. +Main project documentation site/subsite. **`deprecated`** If set to `true`, the project is considered deprecated: its info is kept here, but it will not be supported. diff --git a/docs/registry.md b/docs/registry.md index 755c49365ac..a5045889d19 100644 --- a/docs/registry.md +++ b/docs/registry.md @@ -13,29 +13,41 @@ This list is generated from [./registry.json](../registry.json) | 20 | DigiByte | DGB | | | | 22 | Monacoin | MONA | | | | 42 | Decred | DCR | | | +| 57 | Syscoin | SYS | | | | 60 | Ethereum | ETH | | | | 61 | Ethereum Classic | ETC | | | | 74 | ICON | ICX | | | +| 77 | Verge | XVG | | | | 118 | Cosmos Hub | ATOM | | | +| 119 | Pivx | PIVX | | | +| 121 | Zen | ZEN | | | | 133 | Zcash | ZEC | | | | 136 | Firo | FIRO | | | +| 137 | Rootstock | RBTC | | | +| 141 | Komodo | KMD | | | | 144 | XRP | XRP | | | | 145 | Bitcoin Cash | BCH | | | +| 146 | Nebl | NEBL | | | | 148 | Stellar | XLM | | | | 156 | Bitcoin Gold | BTG | | | | 165 | Nano | XNO | | | +| 169 | Manta Pacific | ETH | | | | 175 | Ravencoin | RVN | | | | 178 | POA Network | POA | | | | 194 | EOS | EOS | | | | 195 | Tron | TRX | | | +| 204 | OpBNB | BNB | | | +| 223 | Internet Computer | ICP | | | | 235 | FIO | FIO | | | | 242 | Nimiq | NIM | | | | 283 | Algorand | ALGO | | | +| 291 | IOST | IOST | | | | 304 | IoTeX | IOTX | | | | 309 | Nervos | CKB | | | | 313 | Zilliqa | ZIL | | | | 330 | Terra Classic | LUNC | | | | 354 | Polkadot | DOT | | | +| 361 | Theta Fuel | TFUEL | | | | 394 | Crypto.org | CRO | | | | 396 | Everscale | EVER | | | | 397 | NEAR | NEAR | | | @@ -49,49 +61,103 @@ This list is generated from [./registry.json](../registry.json) | 494 | BandChain | BAND | | | | 500 | Theta | THETA | | | | 501 | Solana | SOL | | | -| 508 | Elrond | eGLD | | | -| 714 | BNB Beacon Chain | BNB | | | +| 508 | MultiversX | eGLD | | | +| 529 | Secret | SCRT | | | +| 564 | Agoric | BLD | | | +| 607 | TON | TON | | | +| 637 | Aptos | APT | | | +| 714 | BNB Beacon Chain | BNB | | | +| 784 | Sui | SUI | | | +| 787 | Acala | ACA | | | | 818 | VeChain | VET | | | | 820 | Callisto | CLO | | | | 888 | NEO | NEO | | | -| 889 | TomoChain | TOMO | | | +| 889 | Viction | VIC | | | | 899 | eCash | XEC | | | | 931 | THORChain | RUNE | | | -| 966 | Polygon | MATIC | | | +| 966 | Polygon | POL | | | | 996 | OKX Chain | OKT | | | -| 1001 | Thunder Token | TT | | | +| 999 | Bitcoin Diamond | BCD | | | +| 1001 | ThunderCore | TT | | | | 1023 | Harmony | ONE | | | | 1024 | Ontology | ONT | | | +| 1030 | Conflux eSpace | CFX | | | | 1729 | Tezos | XTZ | | | | 1815 | Cardano | ADA | | | +| 1890 | Lightlink Phoenix | ETH | | | | 2301 | Qtum | QTUM | | | | 2718 | Nebulas | NAS | | | +| 3030 | Hedera | HBAR | | | +| 4200 | Merlin | BTC | | | +| 5000 | Mantle | MNT | | | +| 5600 | BNB Greenfield | BNB | | | +| 6001 | BounceBit | BB | | | | 6060 | GoChain | GO | | | +| 7332 | Zen EON | ZEN | | | +| 8453 | Base | ETH | | | | 8964 | NULS | NULS | | | +| 14001 | WAX | WAXP | | | | 18000 | Meter | MTR | | | | 19167 | Flux | FLUX | | | +| 21888 | Pactus | PAC | | | | 52752 | Celo | CELO | | | +| 59144 | Linea | ETH | | | +| 81457 | Blast | ETH | | | +| 105105 | Stratis | STRAX | | | +| 534352 | Scroll | ETH | | | +| 810180 | zkLink Nova Mainnet | ETH | | | | 5718350 | Wanchain | WAN | | | | 5741564 | Waves | WAVES | | | | 10000025 | Cronos Chain | CRO | | | -| 10000070 | Optimistic Ethereum | ETH | | | +| 10000060 | Native Injective | INJ | | | +| 10000070 | OP Mainnet | ETH | | | | 10000100 | Gnosis Chain | xDAI | | | | 10000118 | Osmosis | OSMO | | | | 10000145 | Smart Bitcoin Cash | BCH | | | | 10000250 | Fantom | FTM | | | | 10000288 | Boba | BOBAETH | | | | 10000321 | KuCoin Community Chain | KCS | | | +| 10000324 | zkSync Era | ETH | | | | 10000330 | Terra | LUNA | | | | 10000553 | Huobi ECO Chain | HT | | | +| 10000787 | Acala EVM | ACA | | | +| 10000990 | Coreum | CORE | | | | 10001088 | Metis | METIS | | | +| 10001101 | Polygon zkEVM | ETH | | | | 10001284 | Moonbeam | GLMR | | | | 10001285 | Moonriver | MOVR | | | | 10002020 | Ronin | RON | | | | 10002222 | KavaEvm | KAVA | | | -| 10008217 | Klaytn | KLAY | | | +| 10004689 | IoTeX EVM | IOTX | | | +| 10007000 | NativeZetaChain | ZETA | | | +| 10007700 | NativeCanto | CANTO | | | +| 10008217 | Kaia | KLAY | | | | 10009000 | Avalanche C-Chain | AVAX | | | | 10009001 | Evmos | EVMOS | | | +| 10042170 | Arbitrum Nova | ETH | | | | 10042221 | Arbitrum | ETH | | | +| 11000118 | Sommelier | SOMM | | | +| 12000118 | Fetch AI | FET | | | +| 13000118 | Mars Hub | MARS | | | +| 14000118 | Umee | UMEE | | | +| 15000118 | Quasar | QSR | | | +| 16000118 | Persistence | XPRT | | | +| 17000118 | Akash | AKT | | | +| 18000118 | Noble | USDC | | | +| 19000118 | Sei | SEI | | | +| 20000118 | Stargaze | STARS | | | | 20000714 | BNB Smart Chain | BNB | | | +| 20007000 | Zeta EVM | ZETA | | | | 20009001 | Native Evmos | EVMOS | | | +| 21000118 | Celestia | TIA | | | +| 22000118 | dYdX | DYDX | | | +| 30000118 | Juno | JUNO | | | +| 30000714 | TBNB | BNB | | | +| 40000118 | Stride | STRD | | | +| 50000118 | Axelar | AXL | | | +| 60000118 | Crescent | CRE | | | +| 70000118 | Kujira | KUJI | | | +| 80000118 | Comdex | CMDX | | | +| 90000118 | Neutron | NTRN | | | +| 245022934 | Neon | NEON | | | | 1323161554 | Aurora | ETH | | | diff --git a/include/TrustWalletCore/TWAES.h b/include/TrustWalletCore/TWAES.h index b44041f36f2..e4a30c656d1 100644 --- a/include/TrustWalletCore/TWAES.h +++ b/include/TrustWalletCore/TWAES.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWAESPaddingMode.h b/include/TrustWalletCore/TWAESPaddingMode.h index 5cfe2103172..da271a5b989 100644 --- a/include/TrustWalletCore/TWAESPaddingMode.h +++ b/include/TrustWalletCore/TWAESPaddingMode.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWAccount.h b/include/TrustWalletCore/TWAccount.h index c5d6f5e33ce..a5cc0fc0e2f 100644 --- a/include/TrustWalletCore/TWAccount.h +++ b/include/TrustWalletCore/TWAccount.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once @@ -28,7 +26,8 @@ struct TWAccount; /// \param extendedPublicKey Base58 encoded extended public key. /// \return A new Account. TW_EXPORT_STATIC_METHOD -struct TWAccount* _Nonnull TWAccountCreate(TWString* _Nonnull address, enum TWCoinType coin, +struct TWAccount* _Nonnull TWAccountCreate(TWString* _Nonnull address, + enum TWCoinType coin, enum TWDerivation derivation, TWString* _Nonnull derivationPath, TWString* _Nonnull publicKey, @@ -45,6 +44,12 @@ void TWAccountDelete(struct TWAccount *_Nonnull account); TW_EXPORT_PROPERTY TWString *_Nonnull TWAccountAddress(struct TWAccount *_Nonnull account); +/// Return CoinType enum of an account. +/// +/// \param account Account to get the coin type of. +TW_EXPORT_PROPERTY +enum TWCoinType TWAccountCoin(struct TWAccount* _Nonnull account); + /// Returns the derivation enum of an account. /// /// \param account Account to get the derivation enum of. @@ -69,10 +74,4 @@ TWString* _Nonnull TWAccountPublicKey(struct TWAccount* _Nonnull account); TW_EXPORT_PROPERTY TWString* _Nonnull TWAccountExtendedPublicKey(struct TWAccount* _Nonnull account); -/// Return CoinType enum of an account. -/// -/// \param account Account to get the coin type of. -TW_EXPORT_PROPERTY -enum TWCoinType TWAccountCoin(struct TWAccount* _Nonnull account); - TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWAnyAddress.h b/include/TrustWalletCore/TWAnyAddress.h index a815607989e..49b604aa9fc 100644 --- a/include/TrustWalletCore/TWAnyAddress.h +++ b/include/TrustWalletCore/TWAnyAddress.h @@ -1,14 +1,14 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once #include "TWBase.h" #include "TWCoinType.h" #include "TWData.h" +#include "TWFilecoinAddressType.h" +#include "TWFiroAddressType.h" #include "TWString.h" TW_EXTERN_C_BEGIN @@ -35,6 +35,24 @@ bool TWAnyAddressEqual(struct TWAnyAddress* _Nonnull lhs, struct TWAnyAddress* _ TW_EXPORT_STATIC_METHOD bool TWAnyAddressIsValid(TWString* _Nonnull string, enum TWCoinType coin); +/// Determines if the string is a valid Any address with the given hrp. +/// +/// \param string address to validate. +/// \param coin coin type of the address. +/// \param hrp explicit given hrp of the given address. +/// \return bool indicating if the address is valid. +TW_EXPORT_STATIC_METHOD +bool TWAnyAddressIsValidBech32(TWString* _Nonnull string, enum TWCoinType coin, TWString* _Nonnull hrp); + +/// Determines if the string is a valid Any address with the given SS58 network prefix. +/// +/// \param string address to validate. +/// \param coin coin type of the address. +/// \param ss58Prefix ss58Prefix of the given address. +/// \return bool indicating if the address is valid. +TW_EXPORT_STATIC_METHOD +bool TWAnyAddressIsValidSS58(TWString* _Nonnull string, enum TWCoinType coin, uint32_t ss58Prefix); + /// Creates an address from a string representation and a coin type. Must be deleted with TWAnyAddressDelete after use. /// /// \param string address to create. @@ -43,6 +61,25 @@ bool TWAnyAddressIsValid(TWString* _Nonnull string, enum TWCoinType coin); TW_EXPORT_STATIC_METHOD struct TWAnyAddress* _Nullable TWAnyAddressCreateWithString(TWString* _Nonnull string, enum TWCoinType coin); +/// Creates an bech32 address from a string representation, a coin type and the given hrp. Must be deleted with TWAnyAddressDelete after use. +/// +/// \param string address to create. +/// \param coin coin type of the address. +/// \param hrp hrp of the address. +/// \return TWAnyAddress pointer or nullptr if address and coin are invalid. +TW_EXPORT_STATIC_METHOD +struct TWAnyAddress* _Nullable TWAnyAddressCreateBech32(TWString* _Nonnull string, enum TWCoinType coin, TWString* _Nonnull hrp); + +/// Creates an SS58 address from a string representation, a coin type and the given ss58Prefix. Must be deleted with TWAnyAddressDelete after use. +/// +/// \param string address to create. +/// \param coin coin type of the address. +/// \param ss58Prefix ss58Prefix of the SS58 address. +/// \return TWAnyAddress pointer or nullptr if address and coin are invalid. +TW_EXPORT_STATIC_METHOD +struct TWAnyAddress* _Nullable TWAnyAddressCreateSS58(TWString* _Nonnull string, enum TWCoinType coin, uint32_t ss58Prefix); + + /// Creates an address from a public key. /// /// \param publicKey derivates the address from the public key. @@ -51,6 +88,49 @@ struct TWAnyAddress* _Nullable TWAnyAddressCreateWithString(TWString* _Nonnull s TW_EXPORT_STATIC_METHOD struct TWAnyAddress* _Nonnull TWAnyAddressCreateWithPublicKey(struct TWPublicKey* _Nonnull publicKey, enum TWCoinType coin); +/// Creates an address from a public key and derivation option. +/// +/// \param publicKey derivates the address from the public key. +/// \param coin coin type of the address. +/// \param derivation the custom derivation to use. +/// \return TWAnyAddress pointer or nullptr if public key is invalid. +TW_EXPORT_STATIC_METHOD +struct TWAnyAddress* _Nonnull TWAnyAddressCreateWithPublicKeyDerivation(struct TWPublicKey* _Nonnull publicKey, enum TWCoinType coin, enum TWDerivation derivation); + +/// Creates an bech32 address from a public key and a given hrp. +/// +/// \param publicKey derivates the address from the public key. +/// \param coin coin type of the address. +/// \param hrp hrp of the address. +/// \return TWAnyAddress pointer or nullptr if public key is invalid. +TW_EXPORT_STATIC_METHOD +struct TWAnyAddress* _Nonnull TWAnyAddressCreateBech32WithPublicKey(struct TWPublicKey* _Nonnull publicKey, enum TWCoinType coin, TWString* _Nonnull hrp); + +/// Creates an SS58 address from a public key and a given ss58Prefix. +/// +/// \param publicKey derivates the address from the public key. +/// \param coin coin type of the address. +/// \param ss58Prefix ss58Prefix of the SS58 address. +/// \return TWAnyAddress pointer or nullptr if public key is invalid. +TW_EXPORT_STATIC_METHOD +struct TWAnyAddress* _Nonnull TWAnyAddressCreateSS58WithPublicKey(struct TWPublicKey* _Nonnull publicKey, enum TWCoinType coin, uint32_t ss58Prefix); + +/// Creates a Filecoin address from a public key and a given address type. +/// +/// \param publicKey derivates the address from the public key. +/// \param filecoinAddressType Filecoin address type. +/// \return TWAnyAddress pointer or nullptr if public key is invalid. +TW_EXPORT_STATIC_METHOD +struct TWAnyAddress* _Nonnull TWAnyAddressCreateWithPublicKeyFilecoinAddressType(struct TWPublicKey* _Nonnull publicKey, enum TWFilecoinAddressType filecoinAddressType); + +/// Creates a Firo address from a public key and a given address type. +/// +/// \param publicKey derivates the address from the public key. +/// \param firoAddressType Firo address type. +/// \return TWAnyAddress pointer or nullptr if public key is invalid. +TW_EXPORT_STATIC_METHOD +struct TWAnyAddress* _Nonnull TWAnyAddressCreateWithPublicKeyFiroAddressType(struct TWPublicKey* _Nonnull publicKey, enum TWFiroAddressType firoAddressType); + /// Deletes an address. /// /// \param address address to delete. diff --git a/include/TrustWalletCore/TWAnySigner.h b/include/TrustWalletCore/TWAnySigner.h index f3864bcfa83..a50f1246618 100644 --- a/include/TrustWalletCore/TWAnySigner.h +++ b/include/TrustWalletCore/TWAnySigner.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once #include "TWBase.h" diff --git a/include/TrustWalletCore/TWAsnParser.h b/include/TrustWalletCore/TWAsnParser.h new file mode 100644 index 00000000000..b008a0578d8 --- /dev/null +++ b/include/TrustWalletCore/TWAsnParser.h @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#pragma once + +#include "TWData.h" + +TW_EXTERN_C_BEGIN + +/// Represents an ASN.1 DER parser. +TW_EXPORT_STRUCT +struct TWAsnParser; + +/// Parses the given ECDSA signature from ASN.1 DER encoded bytes. +/// +/// \param encoded The ASN.1 DER encoded signature. +/// \return The ECDSA signature standard binary representation: RS, where R - 32 byte array, S - 32 byte array. +TW_EXPORT_STATIC_METHOD +TWData* _Nullable TWAsnParserEcdsaSignatureFromDer(TWData* _Nonnull encoded); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWBarz.h b/include/TrustWalletCore/TWBarz.h new file mode 100644 index 00000000000..1454e219b5d --- /dev/null +++ b/include/TrustWalletCore/TWBarz.h @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. +#pragma once + +#include "TWBase.h" +#include "TWData.h" +#include "TWString.h" +#include "TWPublicKey.h" + +TW_EXTERN_C_BEGIN + +/// Barz functions +TW_EXPORT_STRUCT +struct TWBarz; + +/// Calculate a counterfactual address for the smart contract wallet +/// +/// \param input The serialized data of ContractAddressInput. +/// \return The address. +TW_EXPORT_STATIC_METHOD +TWString *_Nonnull TWBarzGetCounterfactualAddress(TWData *_Nonnull input); + +/// Returns the init code parameter of ERC-4337 User Operation +/// +/// \param factory Wallet factory address (BarzFactory) +/// \param publicKey Public key for the verification facet +/// \param verificationFacet Verification facet address +/// \return The address. +TW_EXPORT_STATIC_METHOD +TWData *_Nonnull TWBarzGetInitCode(TWString* _Nonnull factory, struct TWPublicKey* _Nonnull publicKey, TWString* _Nonnull verificationFacet, uint32_t salt); + +/// Converts the original ASN-encoded signature from webauthn to the format accepted by Barz +/// +/// \param signature Original signature +/// \param challenge The original challenge that was signed +/// \param authenticatorData Returned from Webauthn API +/// \param clientDataJSON Returned from Webauthn API +/// \return Bytes of the formatted signature +TW_EXPORT_STATIC_METHOD +TWData *_Nonnull TWBarzGetFormattedSignature(TWData* _Nonnull signature, TWData* _Nonnull challenge, TWData* _Nonnull authenticatorData, TWString* _Nonnull clientDataJSON); + +/// Returns the final hash to be signed by Barz for signing messages & typed data +/// +/// \param msgHash Original msgHash +/// \param barzAddress The address of Barz wallet signing the message +/// \param chainId The chainId of the network the verification will happen +/// \return The final hash to be signed +TW_EXPORT_STATIC_METHOD +TWData *_Nonnull TWBarzGetPrefixedMsgHash(TWData* _Nonnull msgHash, TWString* _Nonnull barzAddress, uint32_t chainId); + +/// Returns the encoded diamondCut function call for Barz contract upgrades +/// +/// \param input The serialized data of DiamondCutInput +/// \return The encoded bytes of diamondCut function call +TW_EXPORT_STATIC_METHOD +TWData *_Nonnull TWBarzGetDiamondCutCode(TWData *_Nonnull input); +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWBase.h b/include/TrustWalletCore/TWBase.h index 17e618ace45..1e334d18679 100644 --- a/include/TrustWalletCore/TWBase.h +++ b/include/TrustWalletCore/TWBase.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #if !defined(TW_EXTERN_C_BEGIN) #if defined(__cplusplus) @@ -55,6 +53,13 @@ #define TW_ASSUME_NONNULL_END #endif +#if defined(__cplusplus) && (__cplusplus >= 201402L) +# define TW_DEPRECATED(since) [[deprecated("Since " #since)]] +# define TW_DEPRECATED_FOR(since, replacement) [[deprecated("Since " #since "; use " #replacement)]] +#else +# define TW_DEPRECATED(since) +# define TW_DEPRECATED_FOR(since, replacement) +#endif #if !__has_feature(nullability) #ifndef _Nullable diff --git a/include/TrustWalletCore/TWBase32.h b/include/TrustWalletCore/TWBase32.h index 871bbf8b561..a8f09039ec8 100644 --- a/include/TrustWalletCore/TWBase32.h +++ b/include/TrustWalletCore/TWBase32.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once @@ -19,34 +17,34 @@ struct TWBase32; /// Decode a Base32 input with the given alphabet /// /// \param string Encoded base32 input to be decoded -/// \param alphabet Decode with the given alphabet, if empty ALPHABET_RFC4648 is used by default +/// \param alphabet Decode with the given alphabet, if nullptr ALPHABET_RFC4648 is used by default /// \return The decoded data, can be null. /// \note ALPHABET_RFC4648 doesn't support padding in the default alphabet TW_EXPORT_STATIC_METHOD -TWData* _Nullable TWBase32DecodeWithAlphabet(TWString* _Nonnull string, TWString* _Nonnull alphabet); +TWData* _Nullable TWBase32DecodeWithAlphabet(TWString* _Nonnull string, TWString* _Nullable alphabet); /// Decode a Base32 input with the default alphabet (ALPHABET_RFC4648) /// /// \param string Encoded input to be decoded /// \return The decoded data -/// \note Call TWBase32DecodeWithAlphabet with empty string. +/// \note Call TWBase32DecodeWithAlphabet with nullptr. TW_EXPORT_STATIC_METHOD TWData* _Nullable TWBase32Decode(TWString* _Nonnull string); /// Encode an input to Base32 with the given alphabet /// /// \param data Data to be encoded (raw bytes) -/// \param alphabet Encode with the given alphabet, if empty ALPHABET_RFC4648 is used by default +/// \param alphabet Encode with the given alphabet, if nullptr ALPHABET_RFC4648 is used by default /// \return The encoded data /// \note ALPHABET_RFC4648 doesn't support padding in the default alphabet TW_EXPORT_STATIC_METHOD -TWString *_Nonnull TWBase32EncodeWithAlphabet(TWData *_Nonnull data, TWString* _Nonnull alphabet); +TWString *_Nonnull TWBase32EncodeWithAlphabet(TWData *_Nonnull data, TWString* _Nullable alphabet); /// Encode an input to Base32 with the default alphabet (ALPHABET_RFC4648) /// /// \param data Data to be encoded (raw bytes) /// \return The encoded data -/// \note Call TWBase32EncodeWithAlphabet with empty string. +/// \note Call TWBase32EncodeWithAlphabet with nullptr. TW_EXPORT_STATIC_METHOD TWString *_Nonnull TWBase32Encode(TWData *_Nonnull data); diff --git a/include/TrustWalletCore/TWBase58.h b/include/TrustWalletCore/TWBase58.h index 6e5dbd30a48..a35ae178865 100644 --- a/include/TrustWalletCore/TWBase58.h +++ b/include/TrustWalletCore/TWBase58.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once @@ -33,14 +31,14 @@ TWString *_Nonnull TWBase58EncodeNoCheck(TWData *_Nonnull data); /// Decodes a Base58 string, checking the checksum. Returns null if the string is not a valid Base58 string. /// /// \param string The Base58 string to decode. -/// \return the decoded data, empty if the string is not a valid Base58 string with checksum. +/// \return the decoded data, null if the string is not a valid Base58 string with checksum. TW_EXPORT_STATIC_METHOD TWData *_Nullable TWBase58Decode(TWString *_Nonnull string); /// Decodes a Base58 string, w/o checking the checksum. Returns null if the string is not a valid Base58 string. /// /// \param string The Base58 string to decode. -/// \return the decoded data, empty if the string is not a valid Base58 string without checksum. +/// \return the decoded data, null if the string is not a valid Base58 string without checksum. TW_EXPORT_STATIC_METHOD TWData *_Nullable TWBase58DecodeNoCheck(TWString *_Nonnull string); diff --git a/include/TrustWalletCore/TWBase64.h b/include/TrustWalletCore/TWBase64.h index fa1c29173d1..5b3cff51a73 100644 --- a/include/TrustWalletCore/TWBase64.h +++ b/include/TrustWalletCore/TWBase64.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWBech32.h b/include/TrustWalletCore/TWBech32.h new file mode 100644 index 00000000000..53c0ab8973b --- /dev/null +++ b/include/TrustWalletCore/TWBech32.h @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#pragma once + +#include "TWBase.h" +#include "TWData.h" +#include "TWString.h" + +TW_EXTERN_C_BEGIN + +/// Bech32 encode / decode functions +TW_EXPORT_STRUCT +struct TWBech32; + +/// Encodes data as a Bech32 string. +/// +/// \param hrp The human-readable part. +/// \param data The data part. +/// \return the encoded Bech32 string. +TW_EXPORT_STATIC_METHOD +TWString *_Nonnull TWBech32Encode(TWString* _Nonnull hrp, TWData *_Nonnull data); + +/// Decodes a Bech32 string. Returns null if the string is not a valid Bech32 string. +/// +/// \param string The Bech32 string to decode. +/// \return the decoded data, null if the string is not a valid Bech32 string. Note that the human-readable part is not returned. +TW_EXPORT_STATIC_METHOD +TWData *_Nullable TWBech32Decode(TWString *_Nonnull string); + +/// Encodes data as a Bech32m string. +/// +/// \param hrp The human-readable part. +/// \param data The data part. +/// \return the encoded Bech32m string. +TW_EXPORT_STATIC_METHOD +TWString *_Nonnull TWBech32EncodeM(TWString* _Nonnull hrp, TWData *_Nonnull data); + +/// Decodes a Bech32m string. Returns null if the string is not a valid Bech32m string. +/// +/// \param string The Bech32m string to decode. +/// \return the decoded data, null if the string is not a valid Bech32m string. Note that the human-readable part is not returned. +TW_EXPORT_STATIC_METHOD +TWData *_Nullable TWBech32DecodeM(TWString *_Nonnull string); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWBitcoinAddress.h b/include/TrustWalletCore/TWBitcoinAddress.h index 77ae6bf1d5d..5fd4d2172a0 100644 --- a/include/TrustWalletCore/TWBitcoinAddress.h +++ b/include/TrustWalletCore/TWBitcoinAddress.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWBitcoinMessageSigner.h b/include/TrustWalletCore/TWBitcoinMessageSigner.h new file mode 100644 index 00000000000..4090ff4850f --- /dev/null +++ b/include/TrustWalletCore/TWBitcoinMessageSigner.h @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#pragma once + +#include "TWBase.h" +#include "TWData.h" +#include "TWString.h" +#include "TWPrivateKey.h" + +TW_EXTERN_C_BEGIN + +/// Bitcoin message signing and verification. +/// +/// Bitcoin Core and some other wallets support a message signing & verification format, to create a proof (a signature) +/// that someone has access to the private keys of a specific address. +/// This feature currently works on old legacy addresses only. +TW_EXPORT_STRUCT +struct TWBitcoinMessageSigner; + +/// Sign a message. +/// +/// \param privateKey: the private key used for signing +/// \param address: the address that matches the privateKey, must be a legacy address (P2PKH) +/// \param message: A custom message which is input to the signing. +/// \note Address is derived assuming compressed public key format. +/// \returns the signature, Base64-encoded. On invalid input empty string is returned. Returned object needs to be deleteed after use. +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWBitcoinMessageSignerSignMessage(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull address, TWString* _Nonnull message); + +/// Verify signature for a message. +/// +/// \param address: address to use, only legacy is supported +/// \param message: the message signed (without prefix) +/// \param signature: in Base64-encoded form. +/// \returns false on any invalid input (does not throw). +TW_EXPORT_STATIC_METHOD +bool TWBitcoinMessageSignerVerifyMessage(TWString* _Nonnull address, TWString* _Nonnull message, TWString* _Nonnull signature); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWBitcoinScript.h b/include/TrustWalletCore/TWBitcoinScript.h index c04611ab166..b49e65ae1f8 100644 --- a/include/TrustWalletCore/TWBitcoinScript.h +++ b/include/TrustWalletCore/TWBitcoinScript.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2021 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once @@ -200,7 +198,11 @@ struct TWBitcoinScript* _Nonnull TWBitcoinScriptBuildPayToWitnessScriptHash(TWDa /// \note Must be deleted with \TWBitcoinScriptDelete /// \return A pointer to the built script TW_EXPORT_STATIC_METHOD -struct TWBitcoinScript* _Nonnull TWBitcoinScriptLockScriptForAddress(TWString* _Nonnull address, enum TWCoinType coin); +struct TWBitcoinScript *_Nonnull TWBitcoinScriptLockScriptForAddress(TWString* _Nonnull address, enum TWCoinType coin); + +/// Builds a appropriate lock script for the given address with replay. +TW_EXPORT_STATIC_METHOD +struct TWBitcoinScript *_Nonnull TWBitcoinScriptLockScriptForAddressReplay(TWString *_Nonnull address, enum TWCoinType coin, TWData *_Nonnull blockHash, int64_t blockHeight); /// Return the default HashType for the given coin, such as TWBitcoinSigHashTypeAll. /// diff --git a/include/TrustWalletCore/TWBitcoinSigHashType.h b/include/TrustWalletCore/TWBitcoinSigHashType.h index b2682d67074..4d7e9c49a38 100644 --- a/include/TrustWalletCore/TWBitcoinSigHashType.h +++ b/include/TrustWalletCore/TWBitcoinSigHashType.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWBlockchain.h b/include/TrustWalletCore/TWBlockchain.h index eb289fc6d43..eeb2f744474 100644 --- a/include/TrustWalletCore/TWBlockchain.h +++ b/include/TrustWalletCore/TWBlockchain.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once @@ -40,11 +38,12 @@ enum TWBlockchain { TWBlockchainHarmony = 25, TWBlockchainNEAR = 26, TWBlockchainAlgorand = 27, + TWBlockchainIOST = 28, TWBlockchainPolkadot = 29, TWBlockchainCardano = 30, TWBlockchainNEO = 31, TWBlockchainFilecoin = 32, - TWBlockchainElrondNetwork = 33, + TWBlockchainMultiversX = 33, TWBlockchainOasisNetwork = 34, TWBlockchainDecred = 35, // Bitcoin TWBlockchainZcash = 36, // Bitcoin @@ -52,8 +51,22 @@ enum TWBlockchain { TWBlockchainThorchain = 38, // Cosmos TWBlockchainRonin = 39, // Ethereum TWBlockchainKusama = 40, // Polkadot - TWBlockchainNervos = 41, - TWBlockchainEverscale = 42, + TWBlockchainZen = 41, // Bitcoin + TWBlockchainBitcoinDiamond = 42, // Bitcoin + TWBlockchainVerge = 43, // Bitcoin + TWBlockchainNervos = 44, + TWBlockchainEverscale = 45, + TWBlockchainAptos = 46, // Aptos + TWBlockchainNebl = 47, // Bitcoin + TWBlockchainHedera = 48, // Hedera + TWBlockchainTheOpenNetwork = 49, + TWBlockchainSui = 50, + TWBlockchainGreenfield = 51, + TWBlockchainInternetComputer = 52, + TWBlockchainNativeEvmos = 53, // Cosmos + TWBlockchainNativeInjective = 54, // Cosmos + TWBlockchainBitcoinCash = 55, + TWBlockchainPactus = 56, }; TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWCardano.h b/include/TrustWalletCore/TWCardano.h index 0def3db33b6..17bd9ebb61f 100644 --- a/include/TrustWalletCore/TWCardano.h +++ b/include/TrustWalletCore/TWCardano.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once @@ -18,12 +16,23 @@ struct TWCardano; /// Calculates the minimum ADA amount needed for a UTXO. /// +/// \deprecated consider using `TWCardanoOutputMinAdaAmount` instead. /// \see reference https://docs.cardano.org/native-tokens/minimum-ada-value-requirement /// \param tokenBundle serialized data of TW.Cardano.Proto.TokenBundle. /// \return the minimum ADA amount. TW_EXPORT_STATIC_METHOD uint64_t TWCardanoMinAdaAmount(TWData *_Nonnull tokenBundle) TW_VISIBILITY_DEFAULT; +/// Calculates the minimum ADA amount needed for an output. +/// +/// \see reference https://docs.cardano.org/native-tokens/minimum-ada-value-requirement +/// \param toAddress valid destination address, as string. +/// \param tokenBundle serialized data of TW.Cardano.Proto.TokenBundle. +/// \param coinsPerUtxoByte cost per one byte of a serialized UTXO (Base-10 decimal string). +/// \return the minimum ADA amount (Base-10 decimal string). +TW_EXPORT_STATIC_METHOD +TWString *_Nullable TWCardanoOutputMinAdaAmount(TWString *_Nonnull toAddress, TWData *_Nonnull tokenBundle, TWString *_Nonnull coinsPerUtxoByte) TW_VISIBILITY_DEFAULT; + /// Return the staking address associated to (contained in) this address. Must be a Base address. /// Empty string is returned on error. Result must be freed. /// \param baseAddress A valid base address, as string. @@ -31,4 +40,10 @@ uint64_t TWCardanoMinAdaAmount(TWData *_Nonnull tokenBundle) TW_VISIBILITY_DEFAU TW_EXPORT_STATIC_METHOD TWString *_Nonnull TWCardanoGetStakingAddress(TWString *_Nonnull baseAddress) TW_VISIBILITY_DEFAULT; +/// Return the legacy(byron) address. +/// \param publicKey A valid public key with TWPublicKeyTypeED25519Cardano type. +/// \return the legacy(byron) address, as string, or empty string on error. +TW_EXPORT_STATIC_METHOD +TWString *_Nonnull TWCardanoGetByronAddress(struct TWPublicKey *_Nonnull publicKey); + TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index 002b622c28a..9d2f10e36c9 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -1,23 +1,28 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once #include "TWBase.h" #include "TWBlockchain.h" #include "TWCurve.h" +#include "TWDerivation.h" #include "TWHDVersion.h" #include "TWHRP.h" -#include "TWPrivateKey.h" #include "TWPurpose.h" #include "TWString.h" #include "TWDerivation.h" +#include "TWPublicKeyType.h" TW_EXTERN_C_BEGIN +/// Represents a private key. +struct TWPrivateKey; + +/// Represents a public key. +struct TWPublicKey; + /// Coin type for Level 2 of BIP44. /// /// \see https://github.com/satoshilabs/slips/blob/master/slip-0044.md @@ -32,11 +37,13 @@ enum TWCoinType { TWCoinTypeCallisto = 820, TWCoinTypeCardano = 1815, // Note: Cardano Shelley testnet uses purpose 1852 (not 44) 1852/1815 TWCoinTypeCosmos = 118, + TWCoinTypePivx = 119, TWCoinTypeDash = 5, TWCoinTypeDecred = 42, TWCoinTypeDigiByte = 20, TWCoinTypeDogecoin = 3, TWCoinTypeEOS = 194, + TWCoinTypeWAX = 14001, TWCoinTypeEthereum = 60, TWCoinTypeEthereumClassic = 61, TWCoinTypeFIO = 235, @@ -61,9 +68,9 @@ enum TWCoinType { TWCoinTypeStellar = 148, TWCoinTypeTezos = 1729, TWCoinTypeTheta = 500, - TWCoinTypeThunderToken = 1001, + TWCoinTypeThunderCore = 1001, TWCoinTypeNEO = 888, - TWCoinTypeTomoChain = 889, + TWCoinTypeViction = 889, TWCoinTypeTron = 195, TWCoinTypeVeChain = 818, TWCoinTypeViacoin = 14, @@ -81,15 +88,17 @@ enum TWCoinType { TWCoinTypeKusama = 434, TWCoinTypePolkadot = 354, TWCoinTypeFilecoin = 461, - TWCoinTypeElrond = 508, + TWCoinTypeMultiversX = 508, TWCoinTypeBandChain = 494, TWCoinTypeSmartChainLegacy = 10000714, TWCoinTypeSmartChain = 20000714, + TWCoinTypeTBinance = 30000714, TWCoinTypeOasis = 474, TWCoinTypePolygon = 966, TWCoinTypeTHORChain = 931, TWCoinTypeBluzelle = 483, TWCoinTypeOptimism = 10000070, + TWCoinTypeZksync = 10000324, TWCoinTypeArbitrum = 10042221, TWCoinTypeECOChain = 10000553, TWCoinTypeAvalancheCChain = 10009000, @@ -100,22 +109,85 @@ enum TWCoinType { TWCoinTypeRonin = 10002020, TWCoinTypeOsmosis = 10000118, TWCoinTypeECash = 899, + TWCoinTypeIOST = 291, TWCoinTypeCronosChain = 10000025, TWCoinTypeSmartBitcoinCash = 10000145, TWCoinTypeKuCoinCommunityChain = 10000321, + TWCoinTypeBitcoinDiamond = 999, TWCoinTypeBoba = 10000288, - TWCoinTypeMetis = 1001088, + TWCoinTypeSyscoin = 57, + TWCoinTypeVerge = 77, + TWCoinTypeZen = 121, + TWCoinTypeMetis = 10001088, TWCoinTypeAurora = 1323161554, TWCoinTypeEvmos = 10009001, TWCoinTypeNativeEvmos = 20009001, TWCoinTypeMoonriver = 10001285, TWCoinTypeMoonbeam = 10001284, TWCoinTypeKavaEvm = 10002222, - TWCoinTypeKlaytn = 10008217, + TWCoinTypeKaia = 10008217, TWCoinTypeMeter = 18000, TWCoinTypeOKXChain = 996, + TWCoinTypeStratis = 105105, + TWCoinTypeKomodo = 141, TWCoinTypeNervos = 309, TWCoinTypeEverscale = 396, + TWCoinTypeAptos = 637, + TWCoinTypeNebl = 146, + TWCoinTypeHedera = 3030, + TWCoinTypeSecret = 529, + TWCoinTypeNativeInjective = 10000060, + TWCoinTypeAgoric = 564, + TWCoinTypeTON = 607, + TWCoinTypeSui = 784, + TWCoinTypeStargaze = 20000118, + TWCoinTypePolygonzkEVM = 10001101, + TWCoinTypeJuno = 30000118, + TWCoinTypeStride = 40000118, + TWCoinTypeAxelar = 50000118, + TWCoinTypeCrescent = 60000118, + TWCoinTypeKujira = 70000118, + TWCoinTypeIoTeXEVM = 10004689, + TWCoinTypeNativeCanto = 10007700, + TWCoinTypeComdex = 80000118, + TWCoinTypeNeutron = 90000118, + TWCoinTypeSommelier = 11000118, + TWCoinTypeFetchAI = 12000118, + TWCoinTypeMars = 13000118, + TWCoinTypeUmee = 14000118, + TWCoinTypeCoreum = 10000990, + TWCoinTypeQuasar = 15000118, + TWCoinTypePersistence = 16000118, + TWCoinTypeAkash = 17000118, + TWCoinTypeNoble = 18000118, + TWCoinTypeScroll = 534352, + TWCoinTypeRootstock = 137, + TWCoinTypeThetaFuel = 361, + TWCoinTypeConfluxeSpace = 1030, + TWCoinTypeAcala = 787, + TWCoinTypeAcalaEVM = 10000787, + TWCoinTypeOpBNB = 204, + TWCoinTypeNeon = 245022934, + TWCoinTypeBase = 8453, + TWCoinTypeSei = 19000118, + TWCoinTypeArbitrumNova = 10042170, + TWCoinTypeLinea = 59144, + TWCoinTypeGreenfield = 5600, + TWCoinTypeMantle = 5000, + TWCoinTypeZenEON = 7332, + TWCoinTypeInternetComputer = 223, + TWCoinTypeTia = 21000118, + TWCoinTypeMantaPacific = 169, + TWCoinTypeNativeZetaChain = 10007000, + TWCoinTypeZetaEVM = 20007000, + TWCoinTypeDydx = 22000118, + TWCoinTypeMerlin = 4200, + TWCoinTypeLightlink = 1890, + TWCoinTypeBlast = 81457, + TWCoinTypeBounceBit = 6001, + TWCoinTypeZkLinkNova = 810180, + TWCoinTypePactus = 21888, + // end_of_tw_coin_type_marker_do_not_modify }; /// Returns the blockchain for a coin type. @@ -194,6 +266,12 @@ TW_EXPORT_METHOD TWString* _Nonnull TWCoinTypeDeriveAddressFromPublicKey(enum TWCoinType coin, struct TWPublicKey* _Nonnull publicKey); +/// Derives the address for a particular coin from the public key with the derivation. +TW_EXPORT_METHOD +TWString* _Nonnull TWCoinTypeDeriveAddressFromPublicKeyAndDerivation(enum TWCoinType coin, + struct TWPublicKey* _Nonnull publicKey, + enum TWDerivation derivation); + /// HRP for this coin type /// /// \param coin A coin type @@ -237,6 +315,13 @@ TWString* _Nonnull TWCoinTypeChainId(enum TWCoinType coin); TW_EXPORT_PROPERTY uint32_t TWCoinTypeSlip44Id(enum TWCoinType coin); +/// SS58Prefix for this coin type +/// +/// \param coin A coin type +/// \return SS58Prefix for the given coin type +TW_EXPORT_PROPERTY +uint32_t TWCoinTypeSS58Prefix(enum TWCoinType coin); + /// public key type for this coin type /// /// \param coin A coin type diff --git a/include/TrustWalletCore/TWCoinTypeConfiguration.h b/include/TrustWalletCore/TWCoinTypeConfiguration.h index 1a04fab57d8..ca71f4dc56e 100644 --- a/include/TrustWalletCore/TWCoinTypeConfiguration.h +++ b/include/TrustWalletCore/TWCoinTypeConfiguration.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWCryptoBox.h b/include/TrustWalletCore/TWCryptoBox.h new file mode 100644 index 00000000000..abd27ca8191 --- /dev/null +++ b/include/TrustWalletCore/TWCryptoBox.h @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#pragma once + +#include "TWBase.h" +#include "TWCryptoBoxPublicKey.h" +#include "TWCryptoBoxSecretKey.h" +#include "TWData.h" +#include "TWString.h" + +TW_EXTERN_C_BEGIN + +/// `crypto_box` encryption algorithms. +TW_EXPORT_STRUCT +struct TWCryptoBox; + +/// Encrypts message using `my_secret` and `other_pubkey`. +/// The output will have a randomly generated nonce prepended to it. +/// The output will be Overhead + 24 bytes longer than the original. +/// +/// \param mySecret *non-null* pointer to my secret key. +/// \param otherPubkey *non-null* pointer to other's public key. +/// \param message *non-null* pointer to the message to be encrypted. +/// \return *nullable* pointer to the encrypted message with randomly generated nonce prepended to it. +TW_EXPORT_STATIC_METHOD +TWData* _Nonnull TWCryptoBoxEncryptEasy(struct TWCryptoBoxSecretKey* _Nonnull mySecret, struct TWCryptoBoxPublicKey* _Nonnull otherPubkey, TWData* _Nonnull message); + +/// Decrypts box produced by `TWCryptoBoxEncryptEasy`. +/// We assume a 24-byte nonce is prepended to the encrypted text in box. +/// +/// \param mySecret *non-null* pointer to my secret key. +/// \param otherPubkey *non-null* pointer to other's public key. +/// \param encrypted *non-null* pointer to the encrypted message with nonce prepended to it. +/// \return *nullable* pointer to the decrypted message. +TW_EXPORT_STATIC_METHOD +TWData* _Nullable TWCryptoBoxDecryptEasy(struct TWCryptoBoxSecretKey* _Nonnull mySecret, struct TWCryptoBoxPublicKey* _Nonnull otherPubkey, TWData* _Nonnull encrypted); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWCryptoBoxPublicKey.h b/include/TrustWalletCore/TWCryptoBoxPublicKey.h new file mode 100644 index 00000000000..e46ea72feae --- /dev/null +++ b/include/TrustWalletCore/TWCryptoBoxPublicKey.h @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#pragma once + +#include "TWBase.h" +#include "TWData.h" +#include "TWString.h" + +TW_EXTERN_C_BEGIN + +/// Public key used in `crypto_box` cryptography. +TW_EXPORT_CLASS +struct TWCryptoBoxPublicKey; + +/// Determines if the given public key is valid or not. +/// +/// \param data *non-null* byte array. +/// \return true if the public key is valid, false otherwise. +TW_EXPORT_STATIC_METHOD +bool TWCryptoBoxPublicKeyIsValid(TWData* _Nonnull data); + +/// Create a `crypto_box` public key with the given block of data. +/// +/// \param data *non-null* byte array. Expected to have 32 bytes. +/// \note Should be deleted with \tw_crypto_box_public_key_delete. +/// \return Nullable pointer to Public Key. +TW_EXPORT_STATIC_METHOD +struct TWCryptoBoxPublicKey* _Nullable TWCryptoBoxPublicKeyCreateWithData(TWData* _Nonnull data); + +/// Delete the given public key. +/// +/// \param publicKey *non-null* pointer to public key. +TW_EXPORT_METHOD +void TWCryptoBoxPublicKeyDelete(struct TWCryptoBoxPublicKey* _Nonnull publicKey); + +/// Returns the raw data of the given public-key. +/// +/// \param publicKey *non-null* pointer to a public key. +/// \return C-compatible result with a C-compatible byte array. +TW_EXPORT_PROPERTY +TWData* _Nonnull TWCryptoBoxPublicKeyData(struct TWCryptoBoxPublicKey* _Nonnull publicKey); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWCryptoBoxSecretKey.h b/include/TrustWalletCore/TWCryptoBoxSecretKey.h new file mode 100644 index 00000000000..f93ad92eb56 --- /dev/null +++ b/include/TrustWalletCore/TWCryptoBoxSecretKey.h @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#pragma once + +#include "TWBase.h" +#include "TWCryptoBoxPublicKey.h" +#include "TWData.h" +#include "TWString.h" + +TW_EXTERN_C_BEGIN + +/// Secret key used in `crypto_box` cryptography. +TW_EXPORT_CLASS +struct TWCryptoBoxSecretKey; + +/// Determines if the given secret key is valid or not. +/// +/// \param data *non-null* byte array. +/// \return true if the secret key is valid, false otherwise. +TW_EXPORT_STATIC_METHOD +bool TWCryptoBoxSecretKeyIsValid(TWData* _Nonnull data); + +/// Create a random secret key. +/// +/// \note Should be deleted with \tw_crypto_box_secret_key_delete. +/// \return *non-null* pointer to Secret Key. +TW_EXPORT_STATIC_METHOD +struct TWCryptoBoxSecretKey* _Nonnull TWCryptoBoxSecretKeyCreate(); + +/// Create a `crypto_box` secret key with the given block of data. +/// +/// \param data *non-null* byte array. Expected to have 32 bytes. +/// \note Should be deleted with \tw_crypto_box_secret_key_delete. +/// \return Nullable pointer to Secret Key. +TW_EXPORT_STATIC_METHOD +struct TWCryptoBoxSecretKey* _Nullable TWCryptoBoxSecretKeyCreateWithData(TWData* _Nonnull data); + +/// Delete the given secret `key`. +/// +/// \param key *non-null* pointer to secret key. +TW_EXPORT_METHOD +void TWCryptoBoxSecretKeyDelete(struct TWCryptoBoxSecretKey* _Nonnull key); + +/// Returns the public key associated with the given `key`. +/// +/// \param key *non-null* pointer to the private key. +/// \return *non-null* pointer to the corresponding public key. +TW_EXPORT_METHOD +struct TWCryptoBoxPublicKey* _Nonnull TWCryptoBoxSecretKeyGetPublicKey(struct TWCryptoBoxSecretKey* _Nonnull key); + +/// Returns the raw data of the given secret-key. +/// +/// \param secretKey *non-null* pointer to a secret key. +/// \return C-compatible result with a C-compatible byte array. +TW_EXPORT_PROPERTY +TWData* _Nonnull TWCryptoBoxSecretKeyData(struct TWCryptoBoxSecretKey* _Nonnull secretKey); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWCurve.h b/include/TrustWalletCore/TWCurve.h index 79d2891aa40..3b7f2b003bd 100644 --- a/include/TrustWalletCore/TWCurve.h +++ b/include/TrustWalletCore/TWCurve.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once @@ -19,6 +17,7 @@ enum TWCurve { TWCurveCurve25519 /* "curve25519" */, TWCurveNIST256p1 /* "nist256p1" */, TWCurveED25519ExtendedCardano /* "ed25519-cardano-seed" */, + TWCurveStarkex /* "starkex" */, TWCurveNone }; diff --git a/include/TrustWalletCore/TWData.h b/include/TrustWalletCore/TWData.h index 2eebf174c39..77dc7c625b6 100644 --- a/include/TrustWalletCore/TWData.h +++ b/include/TrustWalletCore/TWData.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWDataVector.h b/include/TrustWalletCore/TWDataVector.h index 6e2e88912d0..fbfae776ad2 100644 --- a/include/TrustWalletCore/TWDataVector.h +++ b/include/TrustWalletCore/TWDataVector.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWDerivation.h b/include/TrustWalletCore/TWDerivation.h new file mode 100644 index 00000000000..3437313e934 --- /dev/null +++ b/include/TrustWalletCore/TWDerivation.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. +// +// This is a GENERATED FILE from \registry.json, changes made here WILL BE LOST. +// + +#pragma once + +#include "TWBase.h" + +TW_EXTERN_C_BEGIN + +/// Non-default coin address derivation names (default, unnamed derivations are not included). +/// Note the enum variant must be sync with `TWDerivation` enum in Rust: +/// https://github.com/trustwallet/wallet-core/blob/master/rust/tw_coin_registry/src/tw_derivation.rs +TW_EXPORT_ENUM() +enum TWDerivation { + TWDerivationDefault = 0, // default, for any coin + TWDerivationCustom = 1, // custom, for any coin + TWDerivationBitcoinSegwit = 2, + TWDerivationBitcoinLegacy = 3, + TWDerivationBitcoinTestnet = 4, + TWDerivationLitecoinLegacy = 5, + TWDerivationSolanaSolana = 6, + TWDerivationStratisSegwit = 7, + TWDerivationBitcoinTaproot = 8, + // end_of_derivation_enum - USED TO GENERATE CODE +}; + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWDerivationPath.h b/include/TrustWalletCore/TWDerivationPath.h index 910288f600f..ccec3051138 100644 --- a/include/TrustWalletCore/TWDerivationPath.h +++ b/include/TrustWalletCore/TWDerivationPath.h @@ -1,14 +1,11 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once #include "TWBase.h" #include "TWCoinType.h" -#include "TWDerivationPath.h" #include "TWPurpose.h" #include "TWString.h" diff --git a/include/TrustWalletCore/TWDerivationPathIndex.h b/include/TrustWalletCore/TWDerivationPathIndex.h index 72bd2b8344e..a015f37b5f5 100644 --- a/include/TrustWalletCore/TWDerivationPathIndex.h +++ b/include/TrustWalletCore/TWDerivationPathIndex.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWEthereum.h b/include/TrustWalletCore/TWEthereum.h new file mode 100644 index 00000000000..9ff49f208b2 --- /dev/null +++ b/include/TrustWalletCore/TWEthereum.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#pragma once + +#include "TWBase.h" +#include "TWString.h" + +TW_EXTERN_C_BEGIN + +TW_EXPORT_STRUCT +struct TWEthereum; + +/// Generate a layer 2 eip2645 derivation path from eth address, layer, application and given index. +/// +/// \param wallet non-null TWHDWallet +/// \param ethAddress non-null Ethereum address +/// \param layer non-null layer 2 name (E.G starkex) +/// \param application non-null layer 2 application (E.G immutablex) +/// \param index non-null layer 2 index (E.G 1) +/// \return a valid eip2645 layer 2 derivation path as a string +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWEthereumEip2645GetPath(TWString* _Nonnull ethAddress, TWString* _Nonnull layer, TWString* _Nonnull application, TWString* _Nonnull index); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWEthereumAbi.h b/include/TrustWalletCore/TWEthereumAbi.h index 5baf7161942..f2d23a4dec5 100644 --- a/include/TrustWalletCore/TWEthereumAbi.h +++ b/include/TrustWalletCore/TWEthereumAbi.h @@ -1,14 +1,13 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once #include "TWBase.h" -#include "TWString.h" +#include "TWCoinType.h" #include "TWData.h" +#include "TWString.h" TW_EXTERN_C_BEGIN @@ -18,6 +17,38 @@ struct TWEthereumAbiFunction; TW_EXPORT_STRUCT struct TWEthereumAbi; +/// Decode a contract call (function input) according to an ABI json. +/// +/// \param coin EVM-compatible coin type. +/// \param input The serialized data of `TW.EthereumAbi.Proto.ContractCallDecodingInput`. +/// \return The serialized data of a `TW.EthereumAbi.Proto.ContractCallDecodingOutput` proto object. +TW_EXPORT_STATIC_METHOD +TWData* _Nonnull TWEthereumAbiDecodeContractCall(enum TWCoinType coin, TWData* _Nonnull input); + +/// Decode a function input or output data according to a given ABI. +/// +/// \param coin EVM-compatible coin type. +/// \param input The serialized data of `TW.EthereumAbi.Proto.ParamsDecodingInput`. +/// \return The serialized data of a `TW.EthereumAbi.Proto.ParamsDecodingOutput` proto object. +TW_EXPORT_STATIC_METHOD +TWData* _Nonnull TWEthereumAbiDecodeParams(enum TWCoinType coin, TWData* _Nonnull input); + +/// /// Decodes an Eth ABI value according to a given type. +/// +/// \param coin EVM-compatible coin type. +/// \param input The serialized data of `TW.EthereumAbi.Proto.ValueDecodingInput`. +/// \return The serialized data of a `TW.EthereumAbi.Proto.ValueDecodingOutput` proto object. +TW_EXPORT_STATIC_METHOD +TWData* _Nonnull TWEthereumAbiDecodeValue(enum TWCoinType coin, TWData* _Nonnull input); + +/// Encode function to Eth ABI binary. +/// +/// \param coin EVM-compatible coin type. +/// \param input The serialized data of `TW.EthereumAbi.Proto.FunctionEncodingInput`. +/// \return The serialized data of a `TW.EthereumAbi.Proto.FunctionEncodingOutput` proto object. +TW_EXPORT_STATIC_METHOD +TWData* _Nonnull TWEthereumAbiEncodeFunction(enum TWCoinType coin, TWData* _Nonnull input); + /// Encode function to Eth ABI binary /// /// \param fn Non-null Eth abi function diff --git a/include/TrustWalletCore/TWEthereumAbiFunction.h b/include/TrustWalletCore/TWEthereumAbiFunction.h index 4034ade5180..cb5fbb9407c 100644 --- a/include/TrustWalletCore/TWEthereumAbiFunction.h +++ b/include/TrustWalletCore/TWEthereumAbiFunction.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWEthereumAbiValue.h b/include/TrustWalletCore/TWEthereumAbiValue.h index 9bbf6ce34eb..fcbe14de839 100644 --- a/include/TrustWalletCore/TWEthereumAbiValue.h +++ b/include/TrustWalletCore/TWEthereumAbiValue.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWEthereumMessageSigner.h b/include/TrustWalletCore/TWEthereumMessageSigner.h new file mode 100644 index 00000000000..6d73c338f6c --- /dev/null +++ b/include/TrustWalletCore/TWEthereumMessageSigner.h @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#pragma once + +#include "TWBase.h" +#include "TWData.h" +#include "TWString.h" +#include "TWPrivateKey.h" +#include "TWPublicKey.h" + +TW_EXTERN_C_BEGIN + +/// Ethereum message signing and verification. +/// +/// Ethereum and some other wallets support a message signing & verification format, to create a proof (a signature) +/// that someone has access to the private keys of a specific address. +TW_EXPORT_STRUCT +struct TWEthereumMessageSigner; + +/// Sign a typed message EIP-712 V4. +/// +/// \param privateKey: the private key used for signing +/// \param messageJson: A custom typed data message in json +/// \returns the signature, Hex-encoded. On invalid input empty string is returned. Returned object needs to be deleted after use. +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWEthereumMessageSignerSignTypedMessage(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull messageJson); + +/// Sign a typed message EIP-712 V4 with EIP-155 replay attack protection. +/// +/// \param privateKey: the private key used for signing +/// \param messageJson: A custom typed data message in json +/// \param chainId: chainId for eip-155 protection +/// \returns the signature, Hex-encoded. On invalid input empty string is returned or invalid chainId error message. Returned object needs to be deleted after use. +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWEthereumMessageSignerSignTypedMessageEip155(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull messageJson, int chainId); + +/// Sign a message. +/// +/// \param privateKey: the private key used for signing +/// \param message: A custom message which is input to the signing. +/// \returns the signature, Hex-encoded. On invalid input empty string is returned. Returned object needs to be deleted after use. +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWEthereumMessageSignerSignMessage(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull message); + +/// Sign a message with Immutable X msg type. +/// +/// \param privateKey: the private key used for signing +/// \param message: A custom message which is input to the signing. +/// \returns the signature, Hex-encoded. On invalid input empty string is returned. Returned object needs to be deleted after use. +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWEthereumMessageSignerSignMessageImmutableX(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull message); + +/// Sign a message with Eip-155 msg type. +/// +/// \param privateKey: the private key used for signing +/// \param message: A custom message which is input to the signing. +/// \param chainId: chainId for eip-155 protection +/// \returns the signature, Hex-encoded. On invalid input empty string is returned. Returned object needs to be deleted after use. +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWEthereumMessageSignerSignMessageEip155(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull message, int chainId); + +/// Verify signature for a message. +/// +/// \param pubKey: pubKey that will verify and recover the message from the signature +/// \param message: the message signed (without prefix) +/// \param signature: in Hex-encoded form. +/// \returns false on any invalid input (does not throw), true if the message can be recovered from the signature +TW_EXPORT_STATIC_METHOD +bool TWEthereumMessageSignerVerifyMessage(const struct TWPublicKey* _Nonnull pubKey, TWString* _Nonnull message, TWString* _Nonnull signature); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWEthereumRlp.h b/include/TrustWalletCore/TWEthereumRlp.h new file mode 100644 index 00000000000..361ac305cbc --- /dev/null +++ b/include/TrustWalletCore/TWEthereumRlp.h @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#pragma once + +#include "TWBase.h" +#include "TWCoinType.h" +#include "TWData.h" +#include "TWString.h" + +TW_EXTERN_C_BEGIN + +TW_EXPORT_STRUCT +struct TWEthereumRlp; + +/// Encode an item or a list of items as Eth RLP binary format. +/// +/// \param coin EVM-compatible coin type. +/// \param input Non-null serialized `EthereumRlp::Proto::EncodingInput`. +/// \return serialized `EthereumRlp::Proto::EncodingOutput`. +TW_EXPORT_STATIC_METHOD +TWData* _Nonnull TWEthereumRlpEncode(enum TWCoinType coin, TWData* _Nonnull input); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWFIOAccount.h b/include/TrustWalletCore/TWFIOAccount.h index 876aabbda7d..e11a65c4b3d 100644 --- a/include/TrustWalletCore/TWFIOAccount.h +++ b/include/TrustWalletCore/TWFIOAccount.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWFilecoinAddressConverter.h b/include/TrustWalletCore/TWFilecoinAddressConverter.h new file mode 100644 index 00000000000..b6c3689984c --- /dev/null +++ b/include/TrustWalletCore/TWFilecoinAddressConverter.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#pragma once + +#include "TWBase.h" +#include "TWData.h" +#include "TWString.h" + +TW_EXTERN_C_BEGIN + +/// Filecoin-Ethereum address converter. +TW_EXPORT_STRUCT +struct TWFilecoinAddressConverter; + +/// Converts a Filecoin address to Ethereum. +/// +/// \param filecoinAddress: a Filecoin address. +/// \returns the Ethereum address. On invalid input empty string is returned. Returned object needs to be deleted after use. +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWFilecoinAddressConverterConvertToEthereum(TWString* _Nonnull filecoinAddress); + +/// Converts an Ethereum address to Filecoin. +/// +/// \param ethAddress: an Ethereum address. +/// \returns the Filecoin address. On invalid input empty string is returned. Returned object needs to be deleted after use. +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWFilecoinAddressConverterConvertFromEthereum(TWString* _Nonnull ethAddress); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWFilecoinAddressType.h b/include/TrustWalletCore/TWFilecoinAddressType.h new file mode 100644 index 00000000000..5bab60774c5 --- /dev/null +++ b/include/TrustWalletCore/TWFilecoinAddressType.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#pragma once + +#include "TWBase.h" + +TW_EXTERN_C_BEGIN + +/// Filecoin address type. +TW_EXPORT_ENUM(uint32_t) +enum TWFilecoinAddressType { + TWFilecoinAddressTypeDefault = 0, // default + TWFilecoinAddressTypeDelegated = 1, +}; + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWFiroAddressType.h b/include/TrustWalletCore/TWFiroAddressType.h new file mode 100644 index 00000000000..55fa3a84259 --- /dev/null +++ b/include/TrustWalletCore/TWFiroAddressType.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#pragma once + +#include "TWBase.h" + +TW_EXTERN_C_BEGIN + +/// Firo address type. +TW_EXPORT_ENUM(uint32_t) +enum TWFiroAddressType { + TWFiroAddressTypeDefault = 0, // default + TWFiroAddressTypeExchange = 1, +}; + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWGroestlcoinAddress.h b/include/TrustWalletCore/TWGroestlcoinAddress.h index b35ce21ee64..52114afd736 100644 --- a/include/TrustWalletCore/TWGroestlcoinAddress.h +++ b/include/TrustWalletCore/TWGroestlcoinAddress.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWHDVersion.h b/include/TrustWalletCore/TWHDVersion.h index dec82a60ebc..ceb7733e676 100644 --- a/include/TrustWalletCore/TWHDVersion.h +++ b/include/TrustWalletCore/TWHDVersion.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once @@ -24,12 +22,18 @@ enum TWHDVersion { TWHDVersionYPRV = 0x049d7878, TWHDVersionZPUB = 0x04b24746, TWHDVersionZPRV = 0x04b2430c, + TWHDVersionVPUB = 0x045f1cf6, + TWHDVersionVPRV = 0x045f18bc, + TWHDVersionTPUB = 0x043587cf, + TWHDVersionTPRV = 0x04358394, // Litecoin TWHDVersionLTUB = 0x019da462, TWHDVersionLTPV = 0x019d9cfe, TWHDVersionMTUB = 0x01b26ef6, TWHDVersionMTPV = 0x01b26792, + TWHDVersionTTUB = 0x0436f6e1, + TWHDVersionTTPV = 0x0436ef7d, // Decred TWHDVersionDPUB = 0x2fda926, diff --git a/include/TrustWalletCore/TWHDWallet.h b/include/TrustWalletCore/TWHDWallet.h index 55ab3e13b4a..9e902a55587 100644 --- a/include/TrustWalletCore/TWHDWallet.h +++ b/include/TrustWalletCore/TWHDWallet.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2021 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once @@ -11,7 +9,9 @@ #include "TWCurve.h" #include "TWData.h" #include "TWDerivation.h" +#include "TWDerivationPath.h" #include "TWHDVersion.h" +#include "TWDerivation.h" #include "TWPrivateKey.h" #include "TWPublicKey.h" #include "TWPurpose.h" @@ -100,8 +100,10 @@ TWData* _Nonnull TWHDWalletEntropy(struct TWHDWallet* _Nonnull wallet); TW_EXPORT_METHOD struct TWPrivateKey* _Nonnull TWHDWalletGetMasterKey(struct TWHDWallet* _Nonnull wallet, enum TWCurve curve); -/// Generates the default private key for the specified coin. +/// Generates the default private key for the specified coin, using default derivation. /// +/// \see TWHDWalletGetKey +/// \see TWHDWalletGetKeyDerivation /// \param wallet non-null TWHDWallet /// \param coin a coin type /// \note Returned object needs to be deleted with \TWPrivateKeyDelete @@ -109,16 +111,29 @@ struct TWPrivateKey* _Nonnull TWHDWalletGetMasterKey(struct TWHDWallet* _Nonnull TW_EXPORT_METHOD struct TWPrivateKey* _Nonnull TWHDWalletGetKeyForCoin(struct TWHDWallet* _Nonnull wallet, enum TWCoinType coin); -/// Generates the default address for the specified coin (without exposing intermediary private key). +/// Generates the default address for the specified coin (without exposing intermediary private key), default derivation. /// +/// \see TWHDWalletGetAddressDerivation /// \param wallet non-null TWHDWallet /// \param coin a coin type /// \return return the default address for the specified coin as a non-null TWString TW_EXPORT_METHOD TWString* _Nonnull TWHDWalletGetAddressForCoin(struct TWHDWallet* _Nonnull wallet, enum TWCoinType coin); +/// Generates the default address for the specified coin and derivation (without exposing intermediary private key). +/// +/// \see TWHDWalletGetAddressForCoin +/// \param wallet non-null TWHDWallet +/// \param coin a coin type +/// \param derivation a (custom) derivation to use +/// \return return the default address for the specified coin as a non-null TWString +TW_EXPORT_METHOD +TWString* _Nonnull TWHDWalletGetAddressDerivation(struct TWHDWallet* _Nonnull wallet, enum TWCoinType coin, enum TWDerivation derivation); + /// Generates the private key for the specified derivation path. /// +/// \see TWHDWalletGetKeyForCoin +/// \see TWHDWalletGetKeyDerivation /// \param wallet non-null TWHDWallet /// \param coin a coin type /// \param derivationPath a non-null derivation path @@ -127,6 +142,18 @@ TWString* _Nonnull TWHDWalletGetAddressForCoin(struct TWHDWallet* _Nonnull walle TW_EXPORT_METHOD struct TWPrivateKey* _Nonnull TWHDWalletGetKey(struct TWHDWallet* _Nonnull wallet, enum TWCoinType coin, TWString* _Nonnull derivationPath); +/// Generates the private key for the specified derivation. +/// +/// \see TWHDWalletGetKey +/// \see TWHDWalletGetKeyForCoin +/// \param wallet non-null TWHDWallet +/// \param coin a coin type +/// \param derivation a (custom) derivation to use +/// \note Returned object needs to be deleted with \TWPrivateKeyDelete +/// \return The private key for the specified derivation path/coin +TW_EXPORT_METHOD +struct TWPrivateKey* _Nonnull TWHDWalletGetKeyDerivation(struct TWHDWallet* _Nonnull wallet, enum TWCoinType coin, enum TWDerivation derivation); + /// Generates the private key for the specified derivation path and curve. /// /// \param wallet non-null TWHDWallet diff --git a/include/TrustWalletCore/TWHash.h b/include/TrustWalletCore/TWHash.h index ccdb7d0fb9e..06024bb4e4f 100644 --- a/include/TrustWalletCore/TWHash.h +++ b/include/TrustWalletCore/TWHash.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once @@ -103,6 +101,9 @@ TWData *_Nonnull TWHashBlake2b(TWData *_Nonnull data, size_t size); /// /// \param data Non-null block of data /// \return Non-null computed Groestl512 block of data +TW_EXPORT_STATIC_METHOD +TWData *_Nonnull TWHashBlake2bPersonal(TWData *_Nonnull data, TWData * _Nonnull personal, size_t outlen); + TW_EXPORT_STATIC_METHOD TWData *_Nonnull TWHashGroestl512(TWData *_Nonnull data); diff --git a/include/TrustWalletCore/TWLiquidStaking.h b/include/TrustWalletCore/TWLiquidStaking.h new file mode 100644 index 00000000000..a50f3e2709b --- /dev/null +++ b/include/TrustWalletCore/TWLiquidStaking.h @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. +#pragma once + +#include "TWBase.h" +#include "TWData.h" +#include "TWString.h" + +TW_EXTERN_C_BEGIN + +/// THORChain swap functions +TW_EXPORT_STRUCT +struct TWLiquidStaking; + +/// Builds a LiquidStaking transaction input. +/// +/// \param input The serialized data of LiquidStakingInput. +/// \return The serialized data of LiquidStakingOutput. +TW_EXPORT_STATIC_METHOD +TWData *_Nonnull TWLiquidStakingBuildRequest(TWData *_Nonnull input); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWMnemonic.h b/include/TrustWalletCore/TWMnemonic.h index f74b6ad164f..2cfba1dba70 100644 --- a/include/TrustWalletCore/TWMnemonic.h +++ b/include/TrustWalletCore/TWMnemonic.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2021 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWNEARAccount.h b/include/TrustWalletCore/TWNEARAccount.h index 73e7662fe34..cd8fbb4b97a 100644 --- a/include/TrustWalletCore/TWNEARAccount.h +++ b/include/TrustWalletCore/TWNEARAccount.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWNervosAddress.h b/include/TrustWalletCore/TWNervosAddress.h index b12e663aec1..0254c2bf5cf 100644 --- a/include/TrustWalletCore/TWNervosAddress.h +++ b/include/TrustWalletCore/TWNervosAddress.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWPBKDF2.h b/include/TrustWalletCore/TWPBKDF2.h index a7edcc65380..86c6cca6801 100644 --- a/include/TrustWalletCore/TWPBKDF2.h +++ b/include/TrustWalletCore/TWPBKDF2.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWPrivateKey.h b/include/TrustWalletCore/TWPrivateKey.h index ee4cf3fc7e2..5fdfc61bcde 100644 --- a/include/TrustWalletCore/TWPrivateKey.h +++ b/include/TrustWalletCore/TWPrivateKey.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once @@ -10,6 +8,7 @@ #include "TWCurve.h" #include "TWData.h" #include "TWPublicKey.h" +#include "TWCoinType.h" TW_EXTERN_C_BEGIN @@ -63,6 +62,22 @@ bool TWPrivateKeyIsValid(TWData* _Nonnull data, enum TWCurve curve); TW_EXPORT_PROPERTY TWData* _Nonnull TWPrivateKeyData(struct TWPrivateKey* _Nonnull pk); +/// Returns the public key associated with the given coinType and privateKey +/// +/// \param pk Non-null pointer to the private key +/// \param coinType coinType of the given private key +/// \return Non-null pointer to the corresponding public key +TW_EXPORT_METHOD +struct TWPublicKey* _Nonnull TWPrivateKeyGetPublicKey(struct TWPrivateKey* _Nonnull pk, enum TWCoinType coinType); + +/// Returns the public key associated with the given pubkeyType and privateKey +/// +/// \param pk Non-null pointer to the private key +/// \param pubkeyType pubkeyType of the given private key +/// \return Non-null pointer to the corresponding public key +TW_EXPORT_METHOD +struct TWPublicKey* _Nonnull TWPrivateKeyGetPublicKeyByType(struct TWPrivateKey* _Nonnull pk, enum TWPublicKeyType pubkeyType); + /// Returns the Secp256k1 public key associated with the given private key /// /// \param pk Non-null pointer to the private key @@ -106,16 +121,6 @@ struct TWPublicKey* _Nonnull TWPrivateKeyGetPublicKeyEd25519Cardano(struct TWPri TW_EXPORT_METHOD struct TWPublicKey* _Nonnull TWPrivateKeyGetPublicKeyCurve25519(struct TWPrivateKey* _Nonnull pk); -/// Computes an EC Diffie-Hellman secret in constant time -/// Supported curves: secp256k1 -/// -/// \param pk Non-null pointer to a Private key -/// \param publicKey Non-null pointer to the corresponding public key -/// \param curve Eliptic curve -/// \return The corresponding shared key as a non-null block of data -TW_EXPORT_METHOD -TWData* _Nullable TWPrivateKeyGetSharedKey(const struct TWPrivateKey* _Nonnull pk, const struct TWPublicKey* _Nonnull publicKey, enum TWCurve curve); - /// Signs a digest using ECDSA and given curve. /// /// \param pk Non-null pointer to a Private key diff --git a/include/TrustWalletCore/TWPrivateKeyType.h b/include/TrustWalletCore/TWPrivateKeyType.h index 868b5d2dfea..ee9255e0893 100644 --- a/include/TrustWalletCore/TWPrivateKeyType.h +++ b/include/TrustWalletCore/TWPrivateKeyType.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWPublicKey.h b/include/TrustWalletCore/TWPublicKey.h index d9164855382..7187ac564af 100644 --- a/include/TrustWalletCore/TWPublicKey.h +++ b/include/TrustWalletCore/TWPublicKey.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWPublicKeyType.h b/include/TrustWalletCore/TWPublicKeyType.h index e9d0e53b347..f175fc8c471 100644 --- a/include/TrustWalletCore/TWPublicKeyType.h +++ b/include/TrustWalletCore/TWPublicKeyType.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once @@ -21,6 +19,7 @@ enum TWPublicKeyType { TWPublicKeyTypeED25519Blake2b = 5, TWPublicKeyTypeCURVE25519 = 6, TWPublicKeyTypeED25519Cardano = 7, + TWPublicKeyTypeStarkex = 8, }; TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWPurpose.h b/include/TrustWalletCore/TWPurpose.h index 509b813bbec..027a5a76844 100644 --- a/include/TrustWalletCore/TWPurpose.h +++ b/include/TrustWalletCore/TWPurpose.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once @@ -20,6 +18,7 @@ enum TWPurpose { TWPurposeBIP44 = 44, TWPurposeBIP49 = 49, // Derivation scheme for P2WPKH-nested-in-P2SH TWPurposeBIP84 = 84, // Derivation scheme for P2WPKH + TWPurposeBIP86 = 86, // Derivation scheme for P2TR TWPurposeBIP1852 = 1852, // Derivation scheme used by Cardano-Shelley }; diff --git a/include/TrustWalletCore/TWRippleXAddress.h b/include/TrustWalletCore/TWRippleXAddress.h index 401b885e554..3c9256d2613 100644 --- a/include/TrustWalletCore/TWRippleXAddress.h +++ b/include/TrustWalletCore/TWRippleXAddress.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWSS58AddressType.h b/include/TrustWalletCore/TWSS58AddressType.h index b6bf7e50927..9f9010c670e 100644 --- a/include/TrustWalletCore/TWSS58AddressType.h +++ b/include/TrustWalletCore/TWSS58AddressType.h @@ -1,9 +1,7 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWSegwitAddress.h b/include/TrustWalletCore/TWSegwitAddress.h index 3e106375527..452b4bc2ed0 100644 --- a/include/TrustWalletCore/TWSegwitAddress.h +++ b/include/TrustWalletCore/TWSegwitAddress.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWSolanaAddress.h b/include/TrustWalletCore/TWSolanaAddress.h index b8a372155e6..3a21460e759 100644 --- a/include/TrustWalletCore/TWSolanaAddress.h +++ b/include/TrustWalletCore/TWSolanaAddress.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once @@ -37,6 +35,14 @@ void TWSolanaAddressDelete(struct TWSolanaAddress* _Nonnull address); TW_EXPORT_METHOD TWString* _Nullable TWSolanaAddressDefaultTokenAddress(struct TWSolanaAddress* _Nonnull address, TWString* _Nonnull tokenMintAddress); +/// Derive token 2022 address for token +/// +/// \param address Non-null pointer to a Solana Address +/// \param tokenMintAddress Non-null pointer to a token mint address as a string +/// \return Null pointer if the token 2022 address for a token is not found, valid pointer otherwise +TW_EXPORT_METHOD +TWString* _Nullable TWSolanaAddressToken2022Address(struct TWSolanaAddress* _Nonnull address, TWString* _Nonnull tokenMintAddress); + /// Returns the address string representation. /// /// \param address Non-null pointer to a Solana Address diff --git a/include/TrustWalletCore/TWSolanaTransaction.h b/include/TrustWalletCore/TWSolanaTransaction.h new file mode 100644 index 00000000000..871393fc840 --- /dev/null +++ b/include/TrustWalletCore/TWSolanaTransaction.h @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#pragma once + +#include "TWBase.h" +#include "TWData.h" +#include "TWDataVector.h" +#include "TWString.h" + +TW_EXTERN_C_BEGIN + +TW_EXPORT_STRUCT +struct TWSolanaTransaction; + +/// Decode Solana transaction, update the recent blockhash and re-sign the transaction. +/// +/// # Warning +/// +/// This is a temporary solution. It will be removed when `Solana.proto` supports +/// direct transaction signing. +/// +/// \param encodedTx base64 encoded Solana transaction. +/// \param recentBlockhash base58 encoded recent blockhash. +/// \param privateKeys list of private keys that should be used to re-sign the transaction. +/// \return serialized `Solana::Proto::SigningOutput`. +TW_EXPORT_STATIC_METHOD +TWData *_Nonnull TWSolanaTransactionUpdateBlockhashAndSign(TWString *_Nonnull encodedTx, + TWString *_Nonnull recentBlockhash, + const struct TWDataVector *_Nonnull privateKeys); + +/// Try to find a `ComputeBudgetInstruction::SetComputeUnitPrice` instruction in the given transaction, +/// and returns the specified Unit Price. +/// +/// \param encodedTx base64 encoded Solana transaction. +/// \return nullable Unit Price as a decimal string. Null if no instruction found. +TW_EXPORT_STATIC_METHOD +TWString *_Nullable TWSolanaTransactionGetComputeUnitPrice(TWString *_Nonnull encodedTx); + +/// Try to find a `ComputeBudgetInstruction::SetComputeUnitLimit` instruction in the given transaction, +/// and returns the specified Unit Limit. +/// +/// \param encodedTx base64 encoded Solana transaction. +/// \return nullable Unit Limit as a decimal string. Null if no instruction found. +TW_EXPORT_STATIC_METHOD +TWString *_Nullable TWSolanaTransactionGetComputeUnitLimit(TWString *_Nonnull encodedTx); + +/// Adds or updates a `ComputeBudgetInstruction::SetComputeUnitPrice` instruction of the given transaction, +/// and returns the updated transaction. +/// +/// \param encodedTx base64 encoded Solana transaction. +/// \price Unit Price as a decimal string. +/// \return base64 encoded Solana transaction. Null if an error occurred. +TW_EXPORT_STATIC_METHOD +TWString *_Nullable TWSolanaTransactionSetComputeUnitPrice(TWString *_Nonnull encodedTx, TWString *_Nonnull price); + +/// Adds or updates a `ComputeBudgetInstruction::SetComputeUnitLimit` instruction of the given transaction, +/// and returns the updated transaction. +/// +/// \param encodedTx base64 encoded Solana transaction. +/// \limit Unit Limit as a decimal string. +/// \return base64 encoded Solana transaction. Null if an error occurred. +TW_EXPORT_STATIC_METHOD +TWString *_Nullable TWSolanaTransactionSetComputeUnitLimit(TWString *_Nonnull encodedTx, TWString *_Nonnull limit); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWStarkExMessageSigner.h b/include/TrustWalletCore/TWStarkExMessageSigner.h new file mode 100644 index 00000000000..d5299f4f026 --- /dev/null +++ b/include/TrustWalletCore/TWStarkExMessageSigner.h @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#pragma once + +#include "TWBase.h" +#include "TWData.h" +#include "TWString.h" +#include "TWPrivateKey.h" + +TW_EXTERN_C_BEGIN + +/// StarkEx message signing and verification. +/// +/// StarkEx and some other wallets support a message signing & verification format, to create a proof (a signature) +/// that someone has access to the private keys of a specific address. +TW_EXPORT_STRUCT +struct TWStarkExMessageSigner; + +/// Sign a message. +/// +/// \param privateKey: the private key used for signing +/// \param message: A custom hex message which is input to the signing. +/// \returns the signature, Hex-encoded. On invalid input empty string is returned. Returned object needs to be deleted after use. +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWStarkExMessageSignerSignMessage(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull message); + +/// Verify signature for a message. +/// +/// \param pubKey: pubKey that will verify and recover the message from the signature +/// \param message: the message signed (without prefix) in hex +/// \param signature: in Hex-encoded form. +/// \returns false on any invalid input (does not throw), true if the message can be recovered from the signature +TW_EXPORT_STATIC_METHOD +bool TWStarkExMessageSignerVerifyMessage(const struct TWPublicKey* _Nonnull pubKey, TWString* _Nonnull message, TWString* _Nonnull signature); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWStarkWare.h b/include/TrustWalletCore/TWStarkWare.h new file mode 100644 index 00000000000..1ff02199f71 --- /dev/null +++ b/include/TrustWalletCore/TWStarkWare.h @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#pragma once + +#include "TWBase.h" +#include "TWPrivateKey.h" +#include "TWString.h" +#include "TWDerivationPath.h" + +TW_EXTERN_C_BEGIN + +TW_EXPORT_STRUCT +struct TWStarkWare; + +/// Generates the private stark key at the given derivation path from a valid eth signature +/// +/// \param derivationPath non-null StarkEx Derivation path +/// \param signature valid eth signature +/// \return The private key for the specified derivation path/signature +TW_EXPORT_STATIC_METHOD +struct TWPrivateKey* _Nonnull TWStarkWareGetStarkKeyFromSignature(const struct TWDerivationPath* _Nonnull derivationPath, TWString* _Nonnull signature); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWStellarMemoType.h b/include/TrustWalletCore/TWStellarMemoType.h index ef3f42702e4..8f6b66eec8f 100644 --- a/include/TrustWalletCore/TWStellarMemoType.h +++ b/include/TrustWalletCore/TWStellarMemoType.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWStellarPassphrase.h b/include/TrustWalletCore/TWStellarPassphrase.h index 4854a4d3977..307afb84865 100644 --- a/include/TrustWalletCore/TWStellarPassphrase.h +++ b/include/TrustWalletCore/TWStellarPassphrase.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWStellarVersionByte.h b/include/TrustWalletCore/TWStellarVersionByte.h index 4439d1a555a..94f125ab94c 100644 --- a/include/TrustWalletCore/TWStellarVersionByte.h +++ b/include/TrustWalletCore/TWStellarVersionByte.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWStoredKey.h b/include/TrustWalletCore/TWStoredKey.h index 02bd0ae4dad..58a07e521c0 100644 --- a/include/TrustWalletCore/TWStoredKey.h +++ b/include/TrustWalletCore/TWStoredKey.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once @@ -13,6 +11,7 @@ #include "TWHDWallet.h" #include "TWPrivateKey.h" #include "TWStoredKeyEncryptionLevel.h" +#include "TWStoredKeyEncryption.h" #include "TWString.h" TW_EXTERN_C_BEGIN @@ -40,6 +39,18 @@ struct TWStoredKey* _Nullable TWStoredKeyLoad(TWString* _Nonnull path); TW_EXPORT_STATIC_METHOD struct TWStoredKey* _Nullable TWStoredKeyImportPrivateKey(TWData* _Nonnull privateKey, TWString* _Nonnull name, TWData* _Nonnull password, enum TWCoinType coin); +/// Imports a private key. +/// +/// \param privateKey Non-null Block of data private key +/// \param name The name of the stored key to import as a non-null string +/// \param password Non-null block of data, password of the stored key +/// \param coin the coin type +/// \param encryption cipher encryption mode +/// \note Returned object needs to be deleted with \TWStoredKeyDelete +/// \return Nullptr if the key can't be imported, the stored key otherwise +TW_EXPORT_STATIC_METHOD +struct TWStoredKey* _Nullable TWStoredKeyImportPrivateKeyWithEncryption(TWData* _Nonnull privateKey, TWString* _Nonnull name, TWData* _Nonnull password, enum TWCoinType coin, enum TWStoredKeyEncryption encryption); + /// Imports an HD wallet. /// /// \param mnemonic Non-null bip39 mnemonic @@ -51,6 +62,18 @@ struct TWStoredKey* _Nullable TWStoredKeyImportPrivateKey(TWData* _Nonnull priva TW_EXPORT_STATIC_METHOD struct TWStoredKey* _Nullable TWStoredKeyImportHDWallet(TWString* _Nonnull mnemonic, TWString* _Nonnull name, TWData* _Nonnull password, enum TWCoinType coin); +/// Imports an HD wallet. +/// +/// \param mnemonic Non-null bip39 mnemonic +/// \param name The name of the stored key to import as a non-null string +/// \param password Non-null block of data, password of the stored key +/// \param coin the coin type +/// \param encryption cipher encryption mode +/// \note Returned object needs to be deleted with \TWStoredKeyDelete +/// \return Nullptr if the key can't be imported, the stored key otherwise +TW_EXPORT_STATIC_METHOD +struct TWStoredKey* _Nullable TWStoredKeyImportHDWalletWithEncryption(TWString* _Nonnull mnemonic, TWString* _Nonnull name, TWData* _Nonnull password, enum TWCoinType coin, enum TWStoredKeyEncryption encryption); + /// Imports a key from JSON. /// /// \param json Json stored key import format as a non-null block of data @@ -59,16 +82,28 @@ struct TWStoredKey* _Nullable TWStoredKeyImportHDWallet(TWString* _Nonnull mnemo TW_EXPORT_STATIC_METHOD struct TWStoredKey* _Nullable TWStoredKeyImportJSON(TWData* _Nonnull json); -/// Creates a new key, with given encryption strength level. Returned object needs to be deleted. +/// Creates a new key, with given encryption strength level. Returned object needs to be deleted. /// /// \param name The name of the key to be stored /// \param password Non-null block of data, password of the stored key /// \param encryptionLevel The level of encryption, see \TWStoredKeyEncryptionLevel /// \note Returned object needs to be deleted with \TWStoredKeyDelete /// \return The stored key as a non-null pointer +TW_DEPRECATED_FOR("3.1.1", "TWStoredKeyCreateLevelAndEncryption") TW_EXPORT_STATIC_METHOD struct TWStoredKey* _Nonnull TWStoredKeyCreateLevel(TWString* _Nonnull name, TWData* _Nonnull password, enum TWStoredKeyEncryptionLevel encryptionLevel); +/// Creates a new key, with given encryption strength level. Returned object needs to be deleted. +/// +/// \param name The name of the key to be stored +/// \param password Non-null block of data, password of the stored key +/// \param encryptionLevel The level of encryption, see \TWStoredKeyEncryptionLevel +/// \param encryption cipher encryption mode +/// \note Returned object needs to be deleted with \TWStoredKeyDelete +/// \return The stored key as a non-null pointer +TW_EXPORT_STATIC_METHOD +struct TWStoredKey* _Nonnull TWStoredKeyCreateLevelAndEncryption(TWString* _Nonnull name, TWData* _Nonnull password, enum TWStoredKeyEncryptionLevel encryptionLevel, enum TWStoredKeyEncryption encryption); + /// Creates a new key. /// /// \deprecated use TWStoredKeyCreateLevel. @@ -78,6 +113,16 @@ struct TWStoredKey* _Nonnull TWStoredKeyCreateLevel(TWString* _Nonnull name, TWD /// \return The stored key as a non-null pointer TW_EXPORT_STATIC_METHOD struct TWStoredKey* _Nonnull TWStoredKeyCreate(TWString* _Nonnull name, TWData* _Nonnull password); +/// Creates a new key. +/// +/// \deprecated use TWStoredKeyCreateLevel. +/// \param name The name of the key to be stored +/// \param password Non-null block of data, password of the stored key +/// \param encryption cipher encryption mode +/// \note Returned object needs to be deleted with \TWStoredKeyDelete +/// \return The stored key as a non-null pointer +TW_EXPORT_STATIC_METHOD struct TWStoredKey* _Nonnull TWStoredKeyCreateEncryption(TWString* _Nonnull name, TWData* _Nonnull password, enum TWStoredKeyEncryption encryption); + /// Delete a stored key /// /// \param key The key to be deleted @@ -250,6 +295,16 @@ TWData* _Nullable TWStoredKeyExportJSON(struct TWStoredKey* _Nonnull key); TW_EXPORT_METHOD bool TWStoredKeyFixAddresses(struct TWStoredKey* _Nonnull key, TWData* _Nonnull password); +/// Re-derives address for the account(s) associated with the given coin. +/// This method can be used if address format has been changed. +/// In case of multiple accounts, all of them will be updated. +/// +/// \param key Non-null pointer to a stored key +/// \param coin Account(s) coin type to be updated +/// \return `false` if there are no accounts associated with the given coin, true otherwise +TW_EXPORT_METHOD +bool TWStoredKeyUpdateAddress(struct TWStoredKey* _Nonnull key, enum TWCoinType coin); + /// Retrieve stored key encoding parameters, as JSON string. /// /// \param key Non-null pointer to a stored key diff --git a/include/TrustWalletCore/TWStoredKeyEncryption.h b/include/TrustWalletCore/TWStoredKeyEncryption.h new file mode 100644 index 00000000000..ccb0d7cfcac --- /dev/null +++ b/include/TrustWalletCore/TWStoredKeyEncryption.h @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#pragma once + +#include "TWBase.h" + +TW_EXTERN_C_BEGIN + +/// Preset encryption kind +TW_EXPORT_ENUM(uint32_t) +enum TWStoredKeyEncryption { + TWStoredKeyEncryptionAes128Ctr = 0, + TWStoredKeyEncryptionAes128Cbc = 1, + TWStoredKeyEncryptionAes192Ctr = 2, + TWStoredKeyEncryptionAes256Ctr = 3, +}; + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWStoredKeyEncryptionLevel.h b/include/TrustWalletCore/TWStoredKeyEncryptionLevel.h index 6b0b79476ea..6a7ceb7bcbc 100644 --- a/include/TrustWalletCore/TWStoredKeyEncryptionLevel.h +++ b/include/TrustWalletCore/TWStoredKeyEncryptionLevel.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWString.h b/include/TrustWalletCore/TWString.h index f02eef86ae3..9cfc8e77bfc 100644 --- a/include/TrustWalletCore/TWString.h +++ b/include/TrustWalletCore/TWString.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/include/TrustWalletCore/TWTHORChainSwap.h b/include/TrustWalletCore/TWTHORChainSwap.h index 27708cec96f..11844425bbe 100644 --- a/include/TrustWalletCore/TWTHORChainSwap.h +++ b/include/TrustWalletCore/TWTHORChainSwap.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2021 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once #include "TWBase.h" diff --git a/include/TrustWalletCore/TWTONAddressConverter.h b/include/TrustWalletCore/TWTONAddressConverter.h new file mode 100644 index 00000000000..39bb4dfed7e --- /dev/null +++ b/include/TrustWalletCore/TWTONAddressConverter.h @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#pragma once + +#include "TWBase.h" +#include "TWString.h" + +TW_EXTERN_C_BEGIN + +/// TON address operations. +TW_EXPORT_CLASS +struct TWTONAddressConverter; + +/// Converts a TON user address into a Bag of Cells (BoC) with a single root Cell. +/// The function is mostly used to request a Jetton user address via `get_wallet_address` RPC. +/// https://docs.ton.org/develop/dapps/asset-processing/jettons#retrieving-jetton-wallet-addresses-for-a-given-user +/// +/// \param address Address to be converted into a Bag Of Cells (BoC). +/// \return Pointer to a base64 encoded Bag Of Cells (BoC). Null if invalid address provided. +TW_EXPORT_STATIC_METHOD +TWString *_Nullable TWTONAddressConverterToBoc(TWString *_Nonnull address); + +/// Parses a TON address from a Bag of Cells (BoC) with a single root Cell. +/// The function is mostly used to parse a Jetton user address received on `get_wallet_address` RPC. +/// https://docs.ton.org/develop/dapps/asset-processing/jettons#retrieving-jetton-wallet-addresses-for-a-given-user +/// +/// \param boc Base64 encoded Bag Of Cells (BoC). +/// \return Pointer to a Jetton address. +TW_EXPORT_STATIC_METHOD +TWString *_Nullable TWTONAddressConverterFromBoc(TWString *_Nonnull boc); + +/// Converts any TON address format to user friendly with the given parameters. +/// +/// \param address raw or user-friendly address to be converted. +/// \param bounceable whether the result address should be bounceable. +/// \param testnet whether the result address should be testnet. +/// \return user-friendly address str. +TW_EXPORT_STATIC_METHOD +TWString *_Nullable TWTONAddressConverterToUserFriendly(TWString *_Nonnull address, bool bounceable, bool testnet); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWTONMessageSigner.h b/include/TrustWalletCore/TWTONMessageSigner.h new file mode 100644 index 00000000000..c9c73876ee3 --- /dev/null +++ b/include/TrustWalletCore/TWTONMessageSigner.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#pragma once + +#include "TWBase.h" +#include "TWPrivateKey.h" +#include "TWString.h" + +TW_EXTERN_C_BEGIN + +/// TON message signing. +TW_EXPORT_CLASS +struct TWTONMessageSigner; + +/// Signs an arbitrary message to prove ownership of an address for off-chain services. +/// https://github.com/ton-foundation/specs/blob/main/specs/wtf-0002.md +/// +/// \param privateKey: the private key used for signing +/// \param message: A custom message which is input to the signing. +/// \returns the signature, Hex-encoded. On invalid input null is returned. Returned object needs to be deleted after use. +TW_EXPORT_STATIC_METHOD +TWString *_Nullable TWTONMessageSignerSignMessage(struct TWPrivateKey *_Nonnull privateKey, TWString* _Nonnull message); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWTONWallet.h b/include/TrustWalletCore/TWTONWallet.h new file mode 100644 index 00000000000..098702faa6a --- /dev/null +++ b/include/TrustWalletCore/TWTONWallet.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#pragma once + +#include "TWBase.h" +#include "TWPublicKey.h" +#include "TWString.h" + +TW_EXTERN_C_BEGIN + +/// TON wallet operations. +TW_EXPORT_CLASS +struct TWTONWallet; + +/// Constructs a TON Wallet V4R2 stateInit encoded as BoC (BagOfCells) for the given `public_key`. +/// +/// \param publicKey wallet's public key. +/// \param workchain TON workchain to which the wallet belongs. Usually, base chain is used (0). +/// \param walletId wallet's ID allows to create multiple wallets for the same private key. +/// \return Pointer to a base64 encoded Bag Of Cells (BoC) StateInit. Null if invalid public key provided. +TW_EXPORT_STATIC_METHOD +TWString *_Nullable TWTONWalletBuildV4R2StateInit(struct TWPublicKey *_Nonnull publicKey, int32_t workchain, int32_t walletId); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWTezosMessageSigner.h b/include/TrustWalletCore/TWTezosMessageSigner.h new file mode 100644 index 00000000000..be1f586f448 --- /dev/null +++ b/include/TrustWalletCore/TWTezosMessageSigner.h @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#pragma once + +#include "TWBase.h" +#include "TWData.h" +#include "TWString.h" +#include "TWPrivateKey.h" +#include "TWPublicKey.h" + +TW_EXTERN_C_BEGIN + +/// Tezos message signing, verification and utilities. +TW_EXPORT_STRUCT +struct TWTezosMessageSigner; + +/// Implement format input as described in https://tezostaquito.io/docs/signing/ +/// +/// \param message message to format e.g: Hello, World +/// \param dAppUrl the app url, e.g: testUrl +/// \returns the formatted message as a string +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWTezosMessageSignerFormatMessage(TWString* _Nonnull message, TWString* _Nonnull url); + +/// Implement input to payload as described in: https://tezostaquito.io/docs/signing/ +/// +/// \param message formatted message to be turned into an hex payload +/// \return the hexpayload of the formated message as a hex string +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWTezosMessageSignerInputToPayload(TWString* _Nonnull message); + +/// Sign a message as described in https://tezostaquito.io/docs/signing/ +/// +/// \param privateKey: the private key used for signing +/// \param message: A custom message payload (hex) which is input to the signing. +/// \returns the signature, Hex-encoded. On invalid input empty string is returned. Returned object needs to be deleted after use. +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWTezosMessageSignerSignMessage(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull message); + +/// Verify signature for a message as described in https://tezostaquito.io/docs/signing/ +/// +/// \param pubKey: pubKey that will verify the message from the signature +/// \param message: the message signed as a payload (hex) +/// \param signature: in Base58-encoded form. +/// \returns false on any invalid input (does not throw), true if the message can be verified from the signature +TW_EXPORT_STATIC_METHOD +bool TWTezosMessageSignerVerifyMessage(const struct TWPublicKey* _Nonnull pubKey, TWString* _Nonnull message, TWString* _Nonnull signature); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWTransactionCompiler.h b/include/TrustWalletCore/TWTransactionCompiler.h index 93e68c65cce..67dfc4f0124 100644 --- a/include/TrustWalletCore/TWTransactionCompiler.h +++ b/include/TrustWalletCore/TWTransactionCompiler.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2022 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once @@ -18,22 +16,6 @@ TW_EXTERN_C_BEGIN TW_EXPORT_STRUCT struct TWTransactionCompiler; -/// Builds a coin-specific SigningInput (proto object) from a simple transaction. -/// -/// \param coin coin type. -/// \param from sender of the transaction. -/// \param to receiver of the transaction. -/// \param amount transaction amount in string -/// \param asset optional asset name, like "BNB" -/// \param memo optional memo -/// \param chainId optional chainId to override default -/// \return serialized data of the SigningInput proto object. -TW_EXPORT_STATIC_METHOD -TWData* _Nonnull TWTransactionCompilerBuildInput(enum TWCoinType coinType, TWString* _Nonnull from, - TWString* _Nonnull to, TWString* _Nonnull amount, - TWString* _Nonnull asset, TWString* _Nonnull memo, - TWString* _Nonnull chainId); - /// Obtains pre-signing hashes of a transaction. /// /// We provide a default `PreSigningOutput` in TransactionCompiler.proto. @@ -60,4 +42,10 @@ TWData* _Nonnull TWTransactionCompilerCompileWithSignatures( enum TWCoinType coinType, TWData* _Nonnull txInputData, const struct TWDataVector* _Nonnull signatures, const struct TWDataVector* _Nonnull publicKeys); +TW_EXPORT_STATIC_METHOD +TWData *_Nonnull TWTransactionCompilerCompileWithSignaturesAndPubKeyType( + enum TWCoinType coinType, TWData *_Nonnull txInputData, + const struct TWDataVector *_Nonnull signatures, const struct TWDataVector *_Nonnull publicKeys, + enum TWPublicKeyType pubKeyType); + TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWTransactionDecoder.h b/include/TrustWalletCore/TWTransactionDecoder.h new file mode 100644 index 00000000000..2d1a22cffe4 --- /dev/null +++ b/include/TrustWalletCore/TWTransactionDecoder.h @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#pragma once + +#include "TWBase.h" +#include "TWCoinType.h" +#include "TWData.h" +#include "TWString.h" + +TW_EXTERN_C_BEGIN + +TW_EXPORT_STRUCT +struct TWTransactionDecoder; + +/// Decodes a transaction from a binary representation. +/// +/// \param coin coin type. +/// \param encodedTx encoded transaction data. +/// \return serialized protobuf message specific for the given coin. +TW_EXPORT_STATIC_METHOD +TWData *_Nonnull TWTransactionDecoderDecode(enum TWCoinType coinType, TWData *_Nonnull encodedTx); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWTransactionUtil.h b/include/TrustWalletCore/TWTransactionUtil.h new file mode 100644 index 00000000000..55b2a811428 --- /dev/null +++ b/include/TrustWalletCore/TWTransactionUtil.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#pragma once + +#include "TWBase.h" +#include "TWCoinType.h" +#include "TWData.h" + +TW_EXTERN_C_BEGIN + +TW_EXPORT_STRUCT +struct TWTransactionUtil; + +/// Calculate the TX hash of a transaction. +/// +/// \param coin coin type. +/// \param encodedTx encoded transaction data. +/// \return The TX hash of a transaction, If the input is invalid or the chain is unsupported, null is returned. +TW_EXPORT_STATIC_METHOD +TWString* _Nullable TWTransactionUtilCalcTxHash(enum TWCoinType coinType, TWString* _Nonnull encodedTx); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWTronMessageSigner.h b/include/TrustWalletCore/TWTronMessageSigner.h new file mode 100644 index 00000000000..d20baba14c1 --- /dev/null +++ b/include/TrustWalletCore/TWTronMessageSigner.h @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#pragma once + +#include "TWBase.h" +#include "TWData.h" +#include "TWString.h" +#include "TWPrivateKey.h" +#include "TWPublicKey.h" + +TW_EXTERN_C_BEGIN + +/// Tron message signing and verification. +/// +/// Tron and some other wallets support a message signing & verification format, to create a proof (a signature) +/// that someone has access to the private keys of a specific address. +TW_EXPORT_STRUCT +struct TWTronMessageSigner; + +/// Sign a message. +/// +/// \param privateKey: the private key used for signing +/// \param message: A custom message which is input to the signing. +/// \returns the signature, Hex-encoded. On invalid input empty string is returned. Returned object needs to be deleted after use. +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWTronMessageSignerSignMessage(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull message); + +/// Verify signature for a message. +/// +/// \param pubKey: pubKey that will verify and recover the message from the signature +/// \param message: the message signed (without prefix) +/// \param signature: in Hex-encoded form. +/// \returns false on any invalid input (does not throw), true if the message can be recovered from the signature +TW_EXPORT_STATIC_METHOD +bool TWTronMessageSignerVerifyMessage(const struct TWPublicKey* _Nonnull pubKey, TWString* _Nonnull message, TWString* _Nonnull signature); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWWalletConnectRequest.h b/include/TrustWalletCore/TWWalletConnectRequest.h new file mode 100644 index 00000000000..41ba895457c --- /dev/null +++ b/include/TrustWalletCore/TWWalletConnectRequest.h @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#pragma once + +#include "TWBase.h" +#include "TWCoinType.h" +#include "TWData.h" + +TW_EXTERN_C_BEGIN + +/// Represents a WalletConnect signing request. +TW_EXPORT_CLASS +struct TWWalletConnectRequest; + +/// Parses the WalletConnect signing request as a `SigningInput`. +/// +/// \param coin The given coin type to plan the transaction for. +/// \param input The serialized data of a `WalletConnect::Proto::ParseRequestInput` proto object. +/// \return The serialized data of `WalletConnect::Proto::ParseRequestOutput` proto object. +TW_EXPORT_STATIC_METHOD +TWData* _Nonnull TWWalletConnectRequestParse(enum TWCoinType coin, TWData* _Nonnull input); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWWebAuthn.h b/include/TrustWalletCore/TWWebAuthn.h new file mode 100644 index 00000000000..c3f24b27a2b --- /dev/null +++ b/include/TrustWalletCore/TWWebAuthn.h @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. +#pragma once + +#include "TWBase.h" +#include "TWData.h" +#include "TWPublicKey.h" + +TW_EXTERN_C_BEGIN + +TW_EXPORT_STRUCT +struct TWWebAuthn; + +/// Converts attestation object to the public key on P256 curve +/// +/// \param attestationObject Attestation object retrieved from webuthn.get method +/// \return Public key. +TW_EXPORT_STATIC_METHOD +struct TWPublicKey *_Nullable TWWebAuthnGetPublicKey(TWData *_Nonnull attestationObject); + +/// Uses ASN parser to extract r and s values from a webauthn signature +/// +/// \param signature ASN encoded webauthn signature: https://www.w3.org/TR/webauthn-2/#sctn-signature-attestation-types +/// \return Concatenated r and s values. +TW_EXPORT_STATIC_METHOD +TWData *_Nonnull TWWebAuthnGetRSValues(TWData *_Nonnull signature); + +/// Reconstructs the original message that was signed via P256 curve. Can be used for signature validation. +/// +/// \param authenticatorData Authenticator Data: https://www.w3.org/TR/webauthn-2/#authenticator-data +/// \param clientDataJSON clientDataJSON: https://www.w3.org/TR/webauthn-2/#dom-authenticatorresponse-clientdatajson +/// \return original messages. +TW_EXPORT_STATIC_METHOD +TWData *_Nonnull TWWebAuthnReconstructOriginalMessage(TWData* _Nonnull authenticatorData, TWData* _Nonnull clientDataJSON); +TW_EXTERN_C_END \ No newline at end of file diff --git a/jni/android/AnySigner.c b/jni/android/AnySigner.c new file mode 100644 index 00000000000..fd1704562f5 --- /dev/null +++ b/jni/android/AnySigner.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#include +#include +#include + +#include "AnySigner.h" +#include "TWJNI.h" + +jbyteArray JNICALL Java_wallet_core_java_AnySigner_nativeSign(JNIEnv *env, jclass thisClass, jbyteArray input, jint coin) { + TWData *inputData = TWDataCreateWithJByteArray(env, input); + TWData *outputData = TWAnySignerSign(inputData, coin); + jbyteArray resultData = TWDataJByteArray(outputData, env); + TWDataDelete(inputData); + return resultData; +} + +jboolean JNICALL Java_wallet_core_java_AnySigner_supportsJSON(JNIEnv *env, jclass thisClass, jint coin) { + return TWAnySignerSupportsJSON(coin); +} + +jstring JNICALL Java_wallet_core_java_AnySigner_signJSON(JNIEnv *env, jclass thisClass, jstring json, jbyteArray key, jint coin) { + TWString *jsonString = TWStringCreateWithJString(env, json); + TWData *keyData = TWDataCreateWithJByteArray(env, key); + TWString *result = TWAnySignerSignJSON(jsonString, keyData, coin); + TWDataDelete(keyData); + TWStringDelete(jsonString); + return TWStringJString(result, env); +} + +jbyteArray JNICALL Java_wallet_core_java_AnySigner_nativePlan(JNIEnv *env, jclass thisClass, jbyteArray input, jint coin) { + TWData *inputData = TWDataCreateWithJByteArray(env, input); + TWData *outputData = TWAnySignerPlan(inputData, coin); + jbyteArray resultData = TWDataJByteArray(outputData, env); + TWDataDelete(inputData); + return resultData; +} diff --git a/jni/android/AnySigner.h b/jni/android/AnySigner.h new file mode 100644 index 00000000000..566d446a7ee --- /dev/null +++ b/jni/android/AnySigner.h @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#ifndef JNI_TW_ANYSIGNER_H +#define JNI_TW_ANYSIGNER_H + +#include +#include + +TW_EXTERN_C_BEGIN + +JNIEXPORT +jbyteArray JNICALL Java_wallet_core_java_AnySigner_nativeSign(JNIEnv *env, jclass thisClass, jbyteArray input, jint coin); + +JNIEXPORT +jboolean JNICALL Java_wallet_core_java_AnySigner_supportsJSON(JNIEnv *env, jclass thisClass, jint coin); + +JNIEXPORT +jbyteArray JNICALL Java_wallet_core_java_AnySigner_signJSON(JNIEnv *env, jclass thisClass, jstring json, jbyteArray key, jint coin); + +JNIEXPORT +jbyteArray JNICALL Java_wallet_core_java_AnySigner_nativePlan(JNIEnv *env, jclass thisClass, jbyteArray input, jint coin); + +TW_EXTERN_C_END + +#endif // JNI_TW_ANYSIGNER_H diff --git a/jni/cpp/AnySigner.c b/jni/cpp/AnySigner.c deleted file mode 100644 index d9ac054adc4..00000000000 --- a/jni/cpp/AnySigner.c +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright © 2017-2020 Trust Wallet. -// -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. - -#include -#include -#include - -#include "AnySigner.h" -#include "TWJNI.h" - -jbyteArray JNICALL Java_wallet_core_java_AnySigner_nativeSign(JNIEnv *env, jclass thisClass, jbyteArray input, jint coin) { - TWData *inputData = TWDataCreateWithJByteArray(env, input); - TWData *outputData = TWAnySignerSign(inputData, coin); - jbyteArray resultData = TWDataJByteArray(outputData, env); - TWDataDelete(inputData); - return resultData; -} - -jboolean JNICALL Java_wallet_core_java_AnySigner_supportsJSON(JNIEnv *env, jclass thisClass, jint coin) { - return TWAnySignerSupportsJSON(coin); -} - -jstring JNICALL Java_wallet_core_java_AnySigner_signJSON(JNIEnv *env, jclass thisClass, jstring json, jbyteArray key, jint coin) { - TWString *jsonString = TWStringCreateWithJString(env, json); - TWData *keyData = TWDataCreateWithJByteArray(env, key); - TWString *result = TWAnySignerSignJSON(jsonString, keyData, coin); - TWDataDelete(keyData); - TWStringDelete(jsonString); - return TWStringJString(result, env); -} - -jbyteArray JNICALL Java_wallet_core_java_AnySigner_nativePlan(JNIEnv *env, jclass thisClass, jbyteArray input, jint coin) { - TWData *inputData = TWDataCreateWithJByteArray(env, input); - TWData *outputData = TWAnySignerPlan(inputData, coin); - jbyteArray resultData = TWDataJByteArray(outputData, env); - TWDataDelete(inputData); - return resultData; -} diff --git a/jni/cpp/AnySigner.h b/jni/cpp/AnySigner.h deleted file mode 100644 index b51323a6554..00000000000 --- a/jni/cpp/AnySigner.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright © 2017-2020 Trust Wallet. -// -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. - -#ifndef JNI_TW_ANYSIGNER_H -#define JNI_TW_ANYSIGNER_H - -#include -#include - -TW_EXTERN_C_BEGIN - -JNIEXPORT -jbyteArray JNICALL Java_wallet_core_java_AnySigner_nativeSign(JNIEnv *env, jclass thisClass, jbyteArray input, jint coin); - -JNIEXPORT -jboolean JNICALL Java_wallet_core_java_AnySigner_supportsJSON(JNIEnv *env, jclass thisClass, jint coin); - -JNIEXPORT -jbyteArray JNICALL Java_wallet_core_java_AnySigner_signJSON(JNIEnv *env, jclass thisClass, jstring json, jbyteArray key, jint coin); - -JNIEXPORT -jbyteArray JNICALL Java_wallet_core_java_AnySigner_nativePlan(JNIEnv *env, jclass thisClass, jbyteArray input, jint coin); - -TW_EXTERN_C_END - -#endif // JNI_TW_ANYSIGNER_H diff --git a/jni/cpp/Random.cpp b/jni/cpp/Random.cpp index de97baff225..216c61d46cc 100644 --- a/jni/cpp/Random.cpp +++ b/jni/cpp/Random.cpp @@ -1,11 +1,11 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #include #include +#include +#include static JavaVM* cachedJVM; @@ -26,26 +26,42 @@ uint32_t random32() { } void random_buffer(uint8_t *buf, size_t len) { - JNIEnv *env; - cachedJVM->AttachCurrentThread(&env, NULL); + if (cachedJVM) + { + JNIEnv *env; + +#if defined(__ANDROID__) || defined(ANDROID) + cachedJVM->AttachCurrentThread(&env, nullptr); +#else + cachedJVM->AttachCurrentThread((void **) &env, nullptr); +#endif - // SecureRandom random = new SecureRandom(); - jclass secureRandomClass = env->FindClass("java/security/SecureRandom"); - jmethodID constructor = env->GetMethodID(secureRandomClass, "", "()V"); - jobject random = env->NewObject(secureRandomClass, constructor); + // SecureRandom random = new SecureRandom(); + jclass secureRandomClass = env->FindClass("java/security/SecureRandom"); + jmethodID constructor = env->GetMethodID(secureRandomClass, "", "()V"); + jobject random = env->NewObject(secureRandomClass, constructor); - //byte array[] = new byte[len]; - jbyteArray array = env->NewByteArray(static_cast(len)); + //byte array[] = new byte[len]; + jbyteArray array = env->NewByteArray(static_cast(len)); - //random.nextBytes(bytes); - jmethodID nextBytes = env->GetMethodID(secureRandomClass, "nextBytes", "([B)V"); - env->CallVoidMethod(random, nextBytes, array); + //random.nextBytes(bytes); + jmethodID nextBytes = env->GetMethodID(secureRandomClass, "nextBytes", "([B)V"); + env->CallVoidMethod(random, nextBytes, array); - jbyte* bytes = env->GetByteArrayElements(array, nullptr); - memcpy(buf, bytes, len); - env->ReleaseByteArrayElements(array, bytes, JNI_ABORT); + jbyte* bytes = env->GetByteArrayElements(array, nullptr); + memcpy(buf, bytes, len); + env->ReleaseByteArrayElements(array, bytes, JNI_ABORT); - env->DeleteLocalRef(array); - env->DeleteLocalRef(random); - env->DeleteLocalRef(secureRandomClass); + env->DeleteLocalRef(array); + env->DeleteLocalRef(random); + env->DeleteLocalRef(secureRandomClass); + } + else + { + std::ifstream randomData("/dev/urandom", std::ios::in | std::ios::binary); + if (randomData.is_open()) { + randomData.read(reinterpret_cast(buf), len); + randomData.close(); + } + } } diff --git a/jni/cpp/TWJNI.h b/jni/cpp/TWJNI.h index 29bf14ba4df..86fc962ca29 100644 --- a/jni/cpp/TWJNI.h +++ b/jni/cpp/TWJNI.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/jni/cpp/TWJNIData.cpp b/jni/cpp/TWJNIData.cpp index c0577f31442..942505f593f 100644 --- a/jni/cpp/TWJNIData.cpp +++ b/jni/cpp/TWJNIData.cpp @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #include #include @@ -10,7 +8,7 @@ #include "TWJNIData.h" jbyteArray TWDataJByteArray(TWData *_Nonnull data, JNIEnv *env) { - jsize dataSize = static_cast(TWDataSize(data)); + auto dataSize = static_cast(TWDataSize(data)); jbyteArray array = env->NewByteArray(dataSize); env->SetByteArrayRegion(array, 0, dataSize, (jbyte *) TWDataBytes(data)); TWDataDelete(data); diff --git a/jni/cpp/TWJNIData.h b/jni/cpp/TWJNIData.h index a7002bffce5..9d1c6730368 100644 --- a/jni/cpp/TWJNIData.h +++ b/jni/cpp/TWJNIData.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/jni/cpp/TWJNIString.cpp b/jni/cpp/TWJNIString.cpp index 2bb220fb6fc..996eb0c747c 100644 --- a/jni/cpp/TWJNIString.cpp +++ b/jni/cpp/TWJNIString.cpp @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #include #include @@ -15,8 +13,8 @@ jstring _Nonnull TWStringJString(TWString *_Nonnull string, JNIEnv *env) { } TWString *_Nonnull TWStringCreateWithJString(JNIEnv *env, jstring _Nonnull string) { - auto chars = env->GetStringUTFChars(string, nullptr); - auto twstring = TWStringCreateWithUTF8Bytes(chars); + const auto *chars = env->GetStringUTFChars(string, nullptr); + const auto *twstring = TWStringCreateWithUTF8Bytes(chars); env->ReleaseStringUTFChars(string, chars); return twstring; } diff --git a/jni/cpp/TWJNIString.h b/jni/cpp/TWJNIString.h index 95f0f967898..1691fe47abb 100644 --- a/jni/cpp/TWJNIString.h +++ b/jni/cpp/TWJNIString.h @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. #pragma once diff --git a/jni/java/wallet/core/java/AnySigner.java b/jni/java/wallet/core/java/AnySigner.java index 49c7770d3d1..21caaa185d4 100644 --- a/jni/java/wallet/core/java/AnySigner.java +++ b/jni/java/wallet/core/java/AnySigner.java @@ -1,8 +1,6 @@ -// Copyright © 2017-2020 Trust Wallet. +// SPDX-License-Identifier: Apache-2.0 // -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. +// Copyright © 2017 Trust Wallet. package wallet.core.java; diff --git a/jni/kotlin/AnySigner.c b/jni/kotlin/AnySigner.c new file mode 100644 index 00000000000..83211fb3512 --- /dev/null +++ b/jni/kotlin/AnySigner.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#include +#include +#include + +#include "AnySigner.h" +#include "TWJNI.h" + +jbyteArray JNICALL Java_com_trustwallet_core_AnySigner_sign(JNIEnv *env, jclass thisClass, jbyteArray input, jobject coin) { + jclass coinClass = (*env)->GetObjectClass(env, coin); + jmethodID coinValueMethodID = (*env)->GetMethodID(env, coinClass, "value", "()I"); + uint32_t coinValue = (*env)->CallIntMethod(env, coin, coinValueMethodID); + + TWData *inputData = TWDataCreateWithJByteArray(env, input); + TWData *outputData = TWAnySignerSign(inputData, coinValue); + jbyteArray resultData = TWDataJByteArray(outputData, env); + TWDataDelete(inputData); + return resultData; +} + +jboolean JNICALL Java_com_trustwallet_core_AnySigner_supportsJson(JNIEnv *env, jclass thisClass, jobject coin) { + jclass coinClass = (*env)->GetObjectClass(env, coin); + jmethodID coinValueMethodID = (*env)->GetMethodID(env, coinClass, "value", "()I"); + uint32_t coinValue = (*env)->CallIntMethod(env, coin, coinValueMethodID); + return TWAnySignerSupportsJSON(coinValue); +} + +jstring JNICALL Java_com_trustwallet_core_AnySigner_signJson(JNIEnv *env, jclass thisClass, jstring json, jbyteArray key, jobject coin) { + jclass coinClass = (*env)->GetObjectClass(env, coin); + jmethodID coinValueMethodID = (*env)->GetMethodID(env, coinClass, "value", "()I"); + uint32_t coinValue = (*env)->CallIntMethod(env, coin, coinValueMethodID); + + TWString *jsonString = TWStringCreateWithJString(env, json); + TWData *keyData = TWDataCreateWithJByteArray(env, key); + TWString *result = TWAnySignerSignJSON(jsonString, keyData, coinValue); + TWDataDelete(keyData); + TWStringDelete(jsonString); + return TWStringJString(result, env); +} + +jbyteArray JNICALL Java_com_trustwallet_core_AnySigner_plan(JNIEnv *env, jclass thisClass, jbyteArray input, jobject coin) { + jclass coinClass = (*env)->GetObjectClass(env, coin); + jmethodID coinValueMethodID = (*env)->GetMethodID(env, coinClass, "value", "()I"); + uint32_t coinValue = (*env)->CallIntMethod(env, coin, coinValueMethodID); + + TWData *inputData = TWDataCreateWithJByteArray(env, input); + TWData *outputData = TWAnySignerPlan(inputData, coinValue); + jbyteArray resultData = TWDataJByteArray(outputData, env); + TWDataDelete(inputData); + return resultData; +} diff --git a/jni/kotlin/AnySigner.h b/jni/kotlin/AnySigner.h new file mode 100644 index 00000000000..eac2bd9340b --- /dev/null +++ b/jni/kotlin/AnySigner.h @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#ifndef JNI_TW_ANYSIGNER_H +#define JNI_TW_ANYSIGNER_H + +#include +#include + +TW_EXTERN_C_BEGIN + +JNIEXPORT +jbyteArray JNICALL Java_com_trustwallet_core_AnySigner_sign(JNIEnv *env, jclass thisClass, jbyteArray input, jobject coin); + +JNIEXPORT +jboolean JNICALL Java_com_trustwallet_core_AnySigner_supportsJson(JNIEnv *env, jclass thisClass, jobject coin); + +JNIEXPORT +jstring JNICALL Java_com_trustwallet_core_AnySigner_signJson(JNIEnv *env, jclass thisClass, jstring json, jbyteArray key, jobject coin); + +JNIEXPORT +jbyteArray JNICALL Java_com_trustwallet_core_AnySigner_plan(JNIEnv *env, jclass thisClass, jbyteArray input, jobject coin); + +TW_EXTERN_C_END + +#endif // JNI_TW_ANYSIGNER_H diff --git a/jni/proto/.gitkeep b/jni/proto/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/kotlin/.editorconfig b/kotlin/.editorconfig new file mode 100644 index 00000000000..87dad77100a --- /dev/null +++ b/kotlin/.editorconfig @@ -0,0 +1,21 @@ +root = true + +[*] +indent_style = space +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +max_line_length = 120 + +[*.{kt,kts}] +indent_size = 4 +ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL +ij_kotlin_imports_layout = * +ij_kotlin_allow_trailing_comma = true +ij_kotlin_allow_trailing_comma_on_call_site = true +ij_kotlin_enum_constants_wrap = split_into_lines +ij_kotlin_name_count_to_use_star_import = 5 +ij_kotlin_name_count_to_use_star_import_for_members = 3 +ij_kotlin_packages_to_use_import_on_demand = * +ij_kotlin_wrap_first_method_in_call_chain = true diff --git a/kotlin/.gitignore b/kotlin/.gitignore new file mode 100644 index 00000000000..f8ed7018916 --- /dev/null +++ b/kotlin/.gitignore @@ -0,0 +1,2 @@ +.gradle +local.properties diff --git a/kotlin/README.md b/kotlin/README.md new file mode 100644 index 00000000000..d80405f6046 --- /dev/null +++ b/kotlin/README.md @@ -0,0 +1,3 @@ +### Tasks: + +- `./gradlew :wallet-core-kotlin:generateProtos` – Generates Kotlin classes for Protos diff --git a/kotlin/build-logic/build.gradle.kts b/kotlin/build-logic/build.gradle.kts new file mode 100644 index 00000000000..1f41e03775b --- /dev/null +++ b/kotlin/build-logic/build.gradle.kts @@ -0,0 +1,19 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + `kotlin-dsl` +} + +allprojects { + tasks.withType { + sourceCompatibility = "17" + targetCompatibility = "17" + } + tasks.withType { + compilerOptions { + allWarningsAsErrors.set(true) + jvmTarget.set(JvmTarget.JVM_17) + } + } +} diff --git a/kotlin/build-logic/settings.gradle.kts b/kotlin/build-logic/settings.gradle.kts new file mode 100644 index 00000000000..5cab7b66872 --- /dev/null +++ b/kotlin/build-logic/settings.gradle.kts @@ -0,0 +1,23 @@ +@file:Suppress("UnstableApiUsage") + +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } + + versionCatalogs { + create("libs") { + from(files("../gradle/libs.versions.toml")) + } + } +} diff --git a/kotlin/build-logic/src/main/kotlin/convention.maven-publish.gradle.kts b/kotlin/build-logic/src/main/kotlin/convention.maven-publish.gradle.kts new file mode 100644 index 00000000000..37072540d89 --- /dev/null +++ b/kotlin/build-logic/src/main/kotlin/convention.maven-publish.gradle.kts @@ -0,0 +1,21 @@ +plugins { + `maven-publish` +} + +group = "com.trustwallet" +if (version == Project.DEFAULT_VERSION) { + version = "0.0.0-alpha" +} + +publishing { + repositories { + maven { + name = "GitHubPackages" + url = uri("https://maven.pkg.github.com/trustwallet/wallet-core") + credentials { + username = System.getenv("GITHUB_USER") + password = System.getenv("GITHUB_TOKEN") + } + } + } +} diff --git a/kotlin/build-logic/src/main/kotlin/convention.proto-generation.gradle.kts b/kotlin/build-logic/src/main/kotlin/convention.proto-generation.gradle.kts new file mode 100644 index 00000000000..112de933e3a --- /dev/null +++ b/kotlin/build-logic/src/main/kotlin/convention.proto-generation.gradle.kts @@ -0,0 +1,56 @@ +val libs = extensions.getByType().named("libs") + +val copyProtoTask = task("copyProtos") { + val sourceDir = rootDir.parentFile.resolve("src/proto") + val destinationDir = projectDir.resolve("build/tmp/proto") + + doFirst { + destinationDir.deleteRecursively() + } + + from(sourceDir) { + include("*.proto") + } + into(destinationDir) + + doLast { + destinationDir + .listFiles { file -> file.extension == "proto" } + .orEmpty() + .forEach { file -> + val packageName = file.nameWithoutExtension.lowercase() + file + .readText() + .replaceFirst( + oldValue = """option java_package = "wallet.core.jni.proto";""", + newValue = """option java_package = "com.trustwallet.core.$packageName";""", + ) + .let { file.writeText(it) } + } + } +} + +val wire: Configuration by configurations.creating +dependencies { + wire(libs.findLibrary("wire.compiler").get().get()) +} + +val generateProtosTask = task("generateProtos") { + dependsOn(copyProtoTask) + + val sourceDir = projectDir.resolve("build/tmp/proto") + val destinationDir = projectDir.resolve("src/commonMain/proto") + + doFirst { + destinationDir.deleteRecursively() + destinationDir.mkdirs() + } + + mainClass.set("com.squareup.wire.WireCompiler") + classpath = wire + + args( + "--proto_path=$sourceDir", + "--kotlin_out=$destinationDir", + ) +} diff --git a/kotlin/build.gradle.kts b/kotlin/build.gradle.kts new file mode 100644 index 00000000000..387b99278c9 --- /dev/null +++ b/kotlin/build.gradle.kts @@ -0,0 +1,21 @@ +// Workaround https://github.com/gradle/gradle/issues/22797 +@file:Suppress("DSL_SCOPE_VIOLATION") + +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + id("com.android.application") version libs.versions.agp.get() apply false + id("com.android.library") version libs.versions.agp.get() apply false + kotlin("android") version libs.versions.kotlin.get() apply false + kotlin("multiplatform") version libs.versions.kotlin.get() apply false +} + +allprojects { + tasks.withType { + compilerOptions { + allWarningsAsErrors.set(true) + jvmTarget.set(JvmTarget.JVM_17) + } + } +} diff --git a/kotlin/gradle.properties b/kotlin/gradle.properties new file mode 100644 index 00000000000..e77b878e37e --- /dev/null +++ b/kotlin/gradle.properties @@ -0,0 +1,11 @@ +# Gradle +org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 +org.gradle.parallel=true +# Kotlin +kotlin.code.style=official +kotlin.js.compiler=ir +kotlin.mpp.androidSourceSetLayoutVersion=2 +kotlin.mpp.enableCInteropCommonization=true +# Android +android.useAndroidX=true +android.nonTransitiveRClass=true diff --git a/kotlin/gradle/libs.versions.toml b/kotlin/gradle/libs.versions.toml new file mode 100644 index 00000000000..e6e4289dd86 --- /dev/null +++ b/kotlin/gradle/libs.versions.toml @@ -0,0 +1,14 @@ +[versions] +android-sdk-tools = "33.0.2" +android-sdk-min = "24" +android-sdk-compile = "33" +android-cmake = "3.22.1" +android-ndk = "25.2.9519653" + +kotlin = "1.8.21" +agp = "8.0.0" +wire = "4.5.6" + +[libraries] +wire-runtime = { module = "com.squareup.wire:wire-runtime", version.ref = "wire" } +wire-compiler = { module = "com.squareup.wire:wire-compiler", version.ref = "wire" } diff --git a/kotlin/gradle/wrapper/gradle-wrapper.jar b/kotlin/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000000..c1962a79e29 Binary files /dev/null and b/kotlin/gradle/wrapper/gradle-wrapper.jar differ diff --git a/kotlin/gradle/wrapper/gradle-wrapper.properties b/kotlin/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..8707e8b5067 --- /dev/null +++ b/kotlin/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-all.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/kotlin/gradlew b/kotlin/gradlew new file mode 100755 index 00000000000..aeb74cbb43e --- /dev/null +++ b/kotlin/gradlew @@ -0,0 +1,245 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/kotlin/gradlew.bat b/kotlin/gradlew.bat new file mode 100755 index 00000000000..6689b85beec --- /dev/null +++ b/kotlin/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/kotlin/kotlin-js-store/yarn.lock b/kotlin/kotlin-js-store/yarn.lock new file mode 100644 index 00000000000..0995b488885 --- /dev/null +++ b/kotlin/kotlin-js-store/yarn.lock @@ -0,0 +1,2238 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.10.4": + version "7.23.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" + integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== + dependencies: + "@babel/highlight" "^7.23.4" + chalk "^2.4.2" + +"@babel/helper-validator-identifier@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" + integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== + +"@babel/highlight@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" + integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== + dependencies: + "@babel/helper-validator-identifier" "^7.22.20" + chalk "^2.4.2" + js-tokens "^4.0.0" + +"@colors/colors@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" + integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== + +"@discoveryjs/json-ext@^0.5.0": + version "0.5.7" + resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" + integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== + +"@jridgewell/gen-mapping@^0.3.0": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/source-map@^0.3.3": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.5.tgz#a3bb4d5c6825aab0d281268f47f6ad5853431e91" + integrity sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.20" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f" + integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@rollup/plugin-commonjs@^21.0.1": + version "21.1.0" + resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-21.1.0.tgz#45576d7b47609af2db87f55a6d4b46e44fc3a553" + integrity sha512-6ZtHx3VHIp2ReNNDxHjuUml6ur+WcQ28N1yHgCQwsbNkQg2suhxGMDQGJOn/KuDxKtd1xuZP5xSTwBA4GQ8hbA== + dependencies: + "@rollup/pluginutils" "^3.1.0" + commondir "^1.0.1" + estree-walker "^2.0.1" + glob "^7.1.6" + is-reference "^1.2.1" + magic-string "^0.25.7" + resolve "^1.17.0" + +"@rollup/plugin-node-resolve@^13.1.3": + version "13.3.0" + resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.3.0.tgz#da1c5c5ce8316cef96a2f823d111c1e4e498801c" + integrity sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw== + dependencies: + "@rollup/pluginutils" "^3.1.0" + "@types/resolve" "1.17.1" + deepmerge "^4.2.2" + is-builtin-module "^3.1.0" + is-module "^1.0.0" + resolve "^1.19.0" + +"@rollup/plugin-typescript@^8.3.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@rollup/plugin-typescript/-/plugin-typescript-8.5.0.tgz#7ea11599a15b0a30fa7ea69ce3b791d41b862515" + integrity sha512-wMv1/scv0m/rXx21wD2IsBbJFba8wGF3ErJIr6IKRfRj49S85Lszbxb4DCo8iILpluTjk2GAAu9CoZt4G3ppgQ== + dependencies: + "@rollup/pluginutils" "^3.1.0" + resolve "^1.17.0" + +"@rollup/pluginutils@^3.0.9", "@rollup/pluginutils@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b" + integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg== + dependencies: + "@types/estree" "0.0.39" + estree-walker "^1.0.1" + picomatch "^2.2.2" + +"@socket.io/component-emitter@~3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553" + integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg== + +"@types/cookie@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d" + integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q== + +"@types/cors@^2.8.12": + version "2.8.17" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.17.tgz#5d718a5e494a8166f569d986794e49c48b216b2b" + integrity sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA== + dependencies: + "@types/node" "*" + +"@types/eslint-scope@^3.7.3": + version "3.7.7" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5" + integrity sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "8.44.9" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.44.9.tgz#5799663009645637bd1c45b2e1a7c8f4caf89534" + integrity sha512-6yBxcvwnnYoYT1Uk2d+jvIfsuP4mb2EdIxFnrPABj5a/838qe5bGkNLFOiipX4ULQ7XVQvTxOh7jO+BTAiqsEw== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*", "@types/estree@^1.0.0": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" + integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== + +"@types/estree@0.0.39": + version "0.0.39" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" + integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== + +"@types/json-schema@*", "@types/json-schema@^7.0.8": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +"@types/node@*", "@types/node@>=10.0.0": + version "20.10.4" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.4.tgz#b246fd84d55d5b1b71bf51f964bd514409347198" + integrity sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg== + dependencies: + undici-types "~5.26.4" + +"@types/node@^12.12.14": + version "12.20.55" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" + integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== + +"@types/resolve@1.17.1": + version "1.17.1" + resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6" + integrity sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw== + dependencies: + "@types/node" "*" + +"@ungap/promise-all-settled@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" + integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== + +"@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24" + integrity sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + +"@webassemblyjs/floating-point-hex-parser@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" + integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== + +"@webassemblyjs/helper-api-error@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" + integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== + +"@webassemblyjs/helper-buffer@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz#b66d73c43e296fd5e88006f18524feb0f2c7c093" + integrity sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA== + +"@webassemblyjs/helper-numbers@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" + integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" + integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== + +"@webassemblyjs/helper-wasm-section@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz#ff97f3863c55ee7f580fd5c41a381e9def4aa577" + integrity sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/wasm-gen" "1.11.6" + +"@webassemblyjs/ieee754@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" + integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" + integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" + integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== + +"@webassemblyjs/wasm-edit@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz#c72fa8220524c9b416249f3d94c2958dfe70ceab" + integrity sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/helper-wasm-section" "1.11.6" + "@webassemblyjs/wasm-gen" "1.11.6" + "@webassemblyjs/wasm-opt" "1.11.6" + "@webassemblyjs/wasm-parser" "1.11.6" + "@webassemblyjs/wast-printer" "1.11.6" + +"@webassemblyjs/wasm-gen@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz#fb5283e0e8b4551cc4e9c3c0d7184a65faf7c268" + integrity sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wasm-opt@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz#d9a22d651248422ca498b09aa3232a81041487c2" + integrity sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/wasm-gen" "1.11.6" + "@webassemblyjs/wasm-parser" "1.11.6" + +"@webassemblyjs/wasm-parser@1.11.6", "@webassemblyjs/wasm-parser@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz#bb85378c527df824004812bbdb784eea539174a1" + integrity sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wast-printer@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz#a7bf8dd7e362aeb1668ff43f35cb849f188eff20" + integrity sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@xtuc/long" "4.2.2" + +"@webpack-cli/configtest@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.2.0.tgz#7b20ce1c12533912c3b217ea68262365fa29a6f5" + integrity sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg== + +"@webpack-cli/info@^1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.5.0.tgz#6c78c13c5874852d6e2dd17f08a41f3fe4c261b1" + integrity sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ== + dependencies: + envinfo "^7.7.3" + +"@webpack-cli/serve@^1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.7.0.tgz#e1993689ac42d2b16e9194376cfb6753f6254db1" + integrity sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q== + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +abab@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" + integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== + +accepts@~1.3.4: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +acorn-import-assertions@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" + integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== + +acorn@^8.7.1, acorn@^8.8.2: + version "8.11.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.2.tgz#ca0d78b51895be5390a5903c5b3bdcdaf78ae40b" + integrity sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w== + +ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-colors@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +atob@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64id@2.0.0, base64id@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" + integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +body-parser@^1.19.0: + version "1.20.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" + integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== + dependencies: + bytes "3.1.2" + content-type "~1.0.5" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.2" + type-is "~1.6.18" + unpipe "1.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +browserslist@^4.14.5: + version "4.22.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.2.tgz#704c4943072bd81ea18997f3bd2180e89c77874b" + integrity sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A== + dependencies: + caniuse-lite "^1.0.30001565" + electron-to-chromium "^1.4.601" + node-releases "^2.0.14" + update-browserslist-db "^1.0.13" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +builtin-modules@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" + integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +call-bind@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" + integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== + dependencies: + function-bind "^1.1.2" + get-intrinsic "^1.2.1" + set-function-length "^1.1.1" + +camelcase@^6.0.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001565: + version "1.0.30001570" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001570.tgz#b4e5c1fa786f733ab78fc70f592df6b3f23244ca" + integrity sha512-+3e0ASu4sw1SWaoCtvPeyXp+5PsjigkSt8OXZbF9StH5pQWbxEjLAZE3n8Aup5udop1uRiKA7a4utUk/uoSpUw== + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chokidar@3.5.3, chokidar@^3.5.1: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chrome-trace-event@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" + integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colorette@^2.0.14: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +connect@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/connect/-/connect-3.7.0.tgz#5d49348910caa5e07a01800b030d0c35f20484f8" + integrity sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ== + dependencies: + debug "2.6.9" + finalhandler "1.1.2" + parseurl "~1.3.3" + utils-merge "1.0.1" + +content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +cookie@~0.4.1: + version "0.4.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" + integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== + +cors@~2.8.5: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + +cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +custom-event@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425" + integrity sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg== + +date-format@^4.0.14: + version "4.0.14" + resolved "https://registry.yarnpkg.com/date-format/-/date-format-4.0.14.tgz#7a8e584434fb169a521c8b7aa481f355810d9400" + integrity sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg== + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@4.3.4, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + +decode-uri-component@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" + integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== + +deepmerge@^4.2.2: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + +define-data-property@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" + integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ== + dependencies: + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + +di@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" + integrity sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA== + +diff@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== + +dom-serialize@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/dom-serialize/-/dom-serialize-2.2.1.tgz#562ae8999f44be5ea3076f5419dcd59eb43ac95b" + integrity sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ== + dependencies: + custom-event "~1.0.0" + ent "~2.2.0" + extend "^3.0.0" + void-elements "^2.0.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +electron-to-chromium@^1.4.601: + version "1.4.612" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.612.tgz#350c6fd4201d677307519b931949fa64dae6a5cc" + integrity sha512-dM8BMtXtlH237ecSMnYdYuCkib2QHq0kpWfUnavjdYsyr/6OsAwg5ZGUfnQ9KD1Ga4QgB2sqXlB2NT8zy2GnVg== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +engine.io-parser@~5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.2.1.tgz#9f213c77512ff1a6cc0c7a86108a7ffceb16fcfb" + integrity sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ== + +engine.io@~6.5.2: + version "6.5.4" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.5.4.tgz#6822debf324e781add2254e912f8568508850cdc" + integrity sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg== + dependencies: + "@types/cookie" "^0.4.1" + "@types/cors" "^2.8.12" + "@types/node" ">=10.0.0" + accepts "~1.3.4" + base64id "2.0.0" + cookie "~0.4.1" + cors "~2.8.5" + debug "~4.3.1" + engine.io-parser "~5.2.1" + ws "~8.11.0" + +enhanced-resolve@^5.15.0: + version "5.15.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35" + integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +ent@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" + integrity sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA== + +envinfo@^7.7.3: + version "7.11.0" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.11.0.tgz#c3793f44284a55ff8c82faf1ffd91bc6478ea01f" + integrity sha512-G9/6xF1FPbIw0TtalAMaVPpiq2aDEuKLXM314jPVAO9r2fo2a4BLqMNkmRS7O/xPPZ+COAhGIz3ETvHEV3eUcg== + +es-module-lexer@^1.2.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.4.1.tgz#41ea21b43908fe6a287ffcbe4300f790555331f5" + integrity sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w== + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +eslint-scope@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +estree-walker@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700" + integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg== + +estree-walker@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + +eventemitter3@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +events@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +extend@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fastest-levenshtein@^1.0.12: + version "1.0.16" + resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" + integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +find-up@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +find-up@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +flatted@^3.2.7: + version "3.2.9" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf" + integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== + +follow-redirects@^1.0.0: + version "1.15.3" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a" + integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q== + +format-util@1.0.5, format-util@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/format-util/-/format-util-1.0.5.tgz#1ffb450c8a03e7bccffe40643180918cc297d271" + integrity sha512-varLbTj0e0yVyRpqQhuWV+8hlePAgaoFRhNFj50BNjEIrw1/DphHSObtqwskVCPWNgzwPoQrZAbfa/SBiicNeg== + +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" + integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA== + dependencies: + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + +glob@7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.3, glob@^7.1.6, glob@^7.1.7: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz#52ba30b6c5ec87fd89fa574bc1c39125c6f65340" + integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg== + dependencies: + get-intrinsic "^1.2.2" + +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +hasown@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" + integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== + dependencies: + function-bind "^1.1.2" + +he@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +http-proxy@^1.18.1: + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +interpret@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" + integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-builtin-module@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169" + integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A== + dependencies: + builtin-modules "^3.3.0" + +is-core-module@^2.13.0: + version "2.13.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + dependencies: + hasown "^2.0.0" + +is-docker@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" + integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g== + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-reference@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7" + integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ== + dependencies: + "@types/estree" "*" + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +isbinaryfile@^4.0.8: + version "4.0.10" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.10.tgz#0c5b5e30c2557a2f06febd37b7322946aaee42b3" + integrity sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== + +jest-worker@^26.2.1: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" + integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^7.0.0" + +jest-worker@^27.4.5: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-parse-even-better-errors@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== + optionalDependencies: + graceful-fs "^4.1.6" + +karma-chrome-launcher@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-3.1.1.tgz#baca9cc071b1562a1db241827257bfe5cab597ea" + integrity sha512-hsIglcq1vtboGPAN+DGCISCFOxW+ZVnIqhDQcCMqqCp+4dmJ0Qpq5QAjkbA0X2L9Mi6OBkHi2Srrbmm7pUKkzQ== + dependencies: + which "^1.2.1" + +karma-mocha@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/karma-mocha/-/karma-mocha-2.0.1.tgz#4b0254a18dfee71bdbe6188d9a6861bf86b0cd7d" + integrity sha512-Tzd5HBjm8his2OA4bouAsATYEpZrp9vC7z5E5j4C5Of5Rrs1jY67RAwXNcVmd/Bnk1wgvQRou0zGVLey44G4tQ== + dependencies: + minimist "^1.2.3" + +karma-sourcemap-loader@0.3.8: + version "0.3.8" + resolved "https://registry.yarnpkg.com/karma-sourcemap-loader/-/karma-sourcemap-loader-0.3.8.tgz#d4bae72fb7a8397328a62b75013d2df937bdcf9c" + integrity sha512-zorxyAakYZuBcHRJE+vbrK2o2JXLFWK8VVjiT/6P+ltLBUGUvqTEkUiQ119MGdOrK7mrmxXHZF1/pfT6GgIZ6g== + dependencies: + graceful-fs "^4.1.2" + +karma-webpack@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/karma-webpack/-/karma-webpack-5.0.0.tgz#2a2c7b80163fe7ffd1010f83f5507f95ef39f840" + integrity sha512-+54i/cd3/piZuP3dr54+NcFeKOPnys5QeM1IY+0SPASwrtHsliXUiCL50iW+K9WWA7RvamC4macvvQ86l3KtaA== + dependencies: + glob "^7.1.3" + minimatch "^3.0.4" + webpack-merge "^4.1.5" + +karma@6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/karma/-/karma-6.4.0.tgz#82652dfecdd853ec227b74ed718a997028a99508" + integrity sha512-s8m7z0IF5g/bS5ONT7wsOavhW4i4aFkzD4u4wgzAQWT4HGUeWI3i21cK2Yz6jndMAeHETp5XuNsRoyGJZXVd4w== + dependencies: + "@colors/colors" "1.5.0" + body-parser "^1.19.0" + braces "^3.0.2" + chokidar "^3.5.1" + connect "^3.7.0" + di "^0.0.1" + dom-serialize "^2.2.1" + glob "^7.1.7" + graceful-fs "^4.2.6" + http-proxy "^1.18.1" + isbinaryfile "^4.0.8" + lodash "^4.17.21" + log4js "^6.4.1" + mime "^2.5.2" + minimatch "^3.0.4" + mkdirp "^0.5.5" + qjobs "^1.2.0" + range-parser "^1.2.1" + rimraf "^3.0.2" + socket.io "^4.4.1" + source-map "^0.6.1" + tmp "^0.2.1" + ua-parser-js "^0.7.30" + yargs "^16.1.1" + +kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +loader-runner@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" + integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash@^4.17.15, lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-symbols@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +log4js@^6.4.1: + version "6.9.1" + resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.9.1.tgz#aba5a3ff4e7872ae34f8b4c533706753709e38b6" + integrity sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g== + dependencies: + date-format "^4.0.14" + debug "^4.3.4" + flatted "^3.2.7" + rfdc "^1.3.0" + streamroller "^3.1.5" + +magic-string@^0.25.7: + version "0.25.9" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c" + integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ== + dependencies: + sourcemap-codec "^1.4.8" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.27, mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@^2.5.2: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" + integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== + +minimatch@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" + integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.3, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +mkdirp@^0.5.5: + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +mocha@10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.0.0.tgz#205447d8993ec755335c4b13deba3d3a13c4def9" + integrity sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA== + dependencies: + "@ungap/promise-all-settled" "1.1.2" + ansi-colors "4.1.1" + browser-stdout "1.3.1" + chokidar "3.5.3" + debug "4.3.4" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.2.0" + he "1.2.0" + js-yaml "4.1.0" + log-symbols "4.1.0" + minimatch "5.0.1" + ms "2.1.3" + nanoid "3.3.3" + serialize-javascript "6.0.0" + strip-json-comments "3.1.1" + supports-color "8.1.1" + workerpool "6.2.1" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nanoid@3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" + integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== + +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +node-releases@^2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" + integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +object-assign@^4: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-inspect@^1.9.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww== + dependencies: + ee-first "1.1.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +qjobs@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071" + integrity sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg== + +qs@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +range-parser@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +rechoir@^0.7.0: + version "0.7.1" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.1.tgz#9478a96a1ca135b5e88fc027f03ee92d6c645686" + integrity sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg== + dependencies: + resolve "^1.9.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve@^1.17.0, resolve@^1.19.0, resolve@^1.9.0: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +rfdc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" + integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== + +rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +rollup-plugin-sourcemaps@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/rollup-plugin-sourcemaps/-/rollup-plugin-sourcemaps-0.6.3.tgz#bf93913ffe056e414419607f1d02780d7ece84ed" + integrity sha512-paFu+nT1xvuO1tPFYXGe+XnQvg4Hjqv/eIhG8i5EspfYYPBKL57X7iVbfv55aNVASg3dzWvES9dmWsL2KhfByw== + dependencies: + "@rollup/pluginutils" "^3.0.9" + source-map-resolve "^0.6.0" + +rollup-plugin-terser@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz#e8fbba4869981b2dc35ae7e8a502d5c6c04d324d" + integrity sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ== + dependencies: + "@babel/code-frame" "^7.10.4" + jest-worker "^26.2.1" + serialize-javascript "^4.0.0" + terser "^5.0.0" + +rollup@^2.68.0: + version "2.79.1" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.79.1.tgz#bedee8faef7c9f93a2647ac0108748f497f081c7" + integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw== + optionalDependencies: + fsevents "~2.3.2" + +safe-buffer@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +schema-utils@^3.1.1, schema-utils@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" + integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +serialize-javascript@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + +serialize-javascript@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" + integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw== + dependencies: + randombytes "^2.1.0" + +serialize-javascript@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.1.tgz#b206efb27c3da0b0ab6b52f48d170b7996458e5c" + integrity sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w== + dependencies: + randombytes "^2.1.0" + +set-function-length@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed" + integrity sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ== + dependencies: + define-data-property "^1.1.1" + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +socket.io-adapter@~2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz#5de9477c9182fdc171cd8c8364b9a8894ec75d12" + integrity sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA== + dependencies: + ws "~8.11.0" + +socket.io-parser@~4.2.4: + version "4.2.4" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.4.tgz#c806966cf7270601e47469ddeec30fbdfda44c83" + integrity sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.1" + +socket.io@^4.4.1: + version "4.7.2" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.7.2.tgz#22557d76c3f3ca48f82e73d68b7add36a22df002" + integrity sha512-bvKVS29/I5fl2FGLNHuXlQaUH/BlzX1IN6S+NKLNZpBsPZIDH+90eQmCs2Railn4YUiww4SzUedJ6+uzwFnKLw== + dependencies: + accepts "~1.3.4" + base64id "~2.0.0" + cors "~2.8.5" + debug "~4.3.2" + engine.io "~6.5.2" + socket.io-adapter "~2.5.2" + socket.io-parser "~4.2.4" + +source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +source-map-loader@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-4.0.0.tgz#bdc6b118bc6c87ee4d8d851f2d4efcc5abdb2ef5" + integrity sha512-i3KVgM3+QPAHNbGavK+VBq03YoJl24m9JWNbLgsjTj8aJzXG9M61bantBTNBt7CNwY2FYf+RJRYJ3pzalKjIrw== + dependencies: + abab "^2.0.6" + iconv-lite "^0.6.3" + source-map-js "^1.0.2" + +source-map-resolve@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.6.0.tgz#3d9df87e236b53f16d01e58150fc7711138e5ed2" + integrity sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w== + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + +source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +sourcemap-codec@^1.4.8: + version "1.4.8" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" + integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== + +streamroller@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-3.1.5.tgz#1263182329a45def1ffaef58d31b15d13d2ee7ff" + integrity sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw== + dependencies: + date-format "^4.0.14" + debug "^4.3.4" + fs-extra "^8.1.0" + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-json-comments@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@8.1.1, supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.0.0, supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +tapable@^2.1.1, tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +terser-webpack-plugin@^5.3.7: + version "5.3.9" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz#832536999c51b46d468067f9e37662a3b96adfe1" + integrity sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.17" + jest-worker "^27.4.5" + schema-utils "^3.1.1" + serialize-javascript "^6.0.1" + terser "^5.16.8" + +terser@^5.0.0, terser@^5.16.8: + version "5.26.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.26.0.tgz#ee9f05d929f4189a9c28a0feb889d96d50126fe1" + integrity sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ== + dependencies: + "@jridgewell/source-map" "^0.3.3" + acorn "^8.8.2" + commander "^2.20.0" + source-map-support "~0.5.20" + +tmp@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== + dependencies: + rimraf "^3.0.0" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +tslib@^2.3.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typescript@4.7.4: + version "4.7.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" + integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== + +typescript@^3.7.2: + version "3.9.10" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8" + integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q== + +ua-parser-js@^0.7.30: + version "0.7.37" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.37.tgz#e464e66dac2d33a7a1251d7d7a99d6157ec27832" + integrity sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA== + +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +update-browserslist-db@^1.0.13: + version "1.0.13" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" + integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +vary@^1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +void-elements@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" + integrity sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung== + +watchpack@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" + integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + +webpack-cli@4.10.0: + version "4.10.0" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.10.0.tgz#37c1d69c8d85214c5a65e589378f53aec64dab31" + integrity sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w== + dependencies: + "@discoveryjs/json-ext" "^0.5.0" + "@webpack-cli/configtest" "^1.2.0" + "@webpack-cli/info" "^1.5.0" + "@webpack-cli/serve" "^1.7.0" + colorette "^2.0.14" + commander "^7.0.0" + cross-spawn "^7.0.3" + fastest-levenshtein "^1.0.12" + import-local "^3.0.2" + interpret "^2.2.0" + rechoir "^0.7.0" + webpack-merge "^5.7.3" + +webpack-merge@^4.1.5: + version "4.2.2" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.2.2.tgz#a27c52ea783d1398afd2087f547d7b9d2f43634d" + integrity sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g== + dependencies: + lodash "^4.17.15" + +webpack-merge@^5.7.3: + version "5.10.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.10.0.tgz#a3ad5d773241e9c682803abf628d4cd62b8a4177" + integrity sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA== + dependencies: + clone-deep "^4.0.1" + flat "^5.0.2" + wildcard "^2.0.0" + +webpack-sources@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + +webpack@5.89.0: + version "5.89.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.89.0.tgz#56b8bf9a34356e93a6625770006490bf3a7f32dc" + integrity sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw== + dependencies: + "@types/eslint-scope" "^3.7.3" + "@types/estree" "^1.0.0" + "@webassemblyjs/ast" "^1.11.5" + "@webassemblyjs/wasm-edit" "^1.11.5" + "@webassemblyjs/wasm-parser" "^1.11.5" + acorn "^8.7.1" + acorn-import-assertions "^1.9.0" + browserslist "^4.14.5" + chrome-trace-event "^1.0.2" + enhanced-resolve "^5.15.0" + es-module-lexer "^1.2.1" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.9" + json-parse-even-better-errors "^2.3.1" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.2.0" + tapable "^2.1.1" + terser-webpack-plugin "^5.3.7" + watchpack "^2.4.0" + webpack-sources "^3.2.3" + +which@^1.2.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wildcard@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" + integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== + +workerpool@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" + integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +ws@~8.11.0: + version "8.11.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.11.0.tgz#6a0d36b8edfd9f96d8b25683db2f8d7de6e8e143" + integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yargs-parser@20.2.4: + version "20.2.4" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-unparser@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@16.2.0, yargs@^16.1.1: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/kotlin/settings.gradle.kts b/kotlin/settings.gradle.kts new file mode 100644 index 00000000000..481134aa1f2 --- /dev/null +++ b/kotlin/settings.gradle.kts @@ -0,0 +1,27 @@ +@file:Suppress("UnstableApiUsage") + +rootProject.name = "WalletCoreKotlin" + +pluginManagement { + repositories { + google() + mavenCentral() + } +} + +dependencyResolutionManagement { + // Uncomment after https://youtrack.jetbrains.com/issue/KT-55620/ + // repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +includeBuild( + "build-logic", +) + +include( + ":wallet-core-kotlin" +) diff --git a/kotlin/wallet-core-kotlin/.gitignore b/kotlin/wallet-core-kotlin/.gitignore new file mode 100644 index 00000000000..a9e76bfd475 --- /dev/null +++ b/kotlin/wallet-core-kotlin/.gitignore @@ -0,0 +1,2 @@ +/src/**/generated/ +/src/**/proto/ diff --git a/kotlin/wallet-core-kotlin/build.gradle.kts b/kotlin/wallet-core-kotlin/build.gradle.kts new file mode 100644 index 00000000000..63d879ca7c3 --- /dev/null +++ b/kotlin/wallet-core-kotlin/build.gradle.kts @@ -0,0 +1,147 @@ +@file:Suppress("UnstableApiUsage", "OPT_IN_USAGE") + +import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackOutput + +plugins { + kotlin("multiplatform") + id("com.android.library") + id("convention.maven-publish") + id("convention.proto-generation") +} + +kotlin { + targetHierarchy.default() + + android { + publishLibraryVariants = listOf("release") + } + + jvm { + testRuns.named("test") { + executionTask.configure { + useJUnitPlatform() + } + } + } + + val nativeTargets = + listOf( + iosArm64(), + iosSimulatorArm64(), + iosX64(), + ) + + js { + browser { + webpackTask { + output.libraryTarget = KotlinWebpackOutput.Target.COMMONJS2 + } + } + useCommonJs() + } + + sourceSets { + all { + languageSettings { + optIn("kotlin.js.ExperimentalJsExport") + } + } + + val commonMain by getting { + kotlin.srcDirs( + projectDir.resolve("src/commonMain/generated"), + projectDir.resolve("src/commonMain/proto"), + ) + + dependencies { + api(libs.wire.runtime) + } + } + + getByName("commonTest") { + dependencies { + implementation(kotlin("test")) + } + } + + val androidMain by getting + val jvmMain by getting + create("commonAndroidJvmMain") { + kotlin.srcDir(projectDir.resolve("src/commonAndroidJvmMain/generated")) + + dependsOn(commonMain) + androidMain.dependsOn(this) + jvmMain.dependsOn(this) + } + + getByName("iosMain") { + kotlin.srcDir(projectDir.resolve("src/iosMain/generated")) + } + + getByName("jsMain") { + kotlin.srcDir(projectDir.resolve("src/jsMain/generated")) + + dependencies { + implementation(npm(name = "webpack", version = "5.89.0")) + } + } + } + + nativeTargets.forEach { nativeTarget -> + nativeTarget.apply { + val main by compilations.getting + main.cinterops.create("WalletCore") { + packageName = "com.trustwallet.core" + headers(rootDir.parentFile.resolve("include/TrustWalletCore").listFiles()!!) + } + } + } +} + +android { + namespace = "com.trustwallet.core" + compileSdk = libs.versions.android.sdk.compile.get().toInt() + buildToolsVersion = libs.versions.android.sdk.tools.get() + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + defaultConfig { + minSdk = libs.versions.android.sdk.min.get().toInt() + ndkVersion = libs.versions.android.ndk.get() + + consumerProguardFiles += projectDir.resolve("consumer-rules.pro") + + externalNativeBuild { + cmake { + arguments += listOf("-DCMAKE_BUILD_TYPE=Release", "-DKOTLIN=True", "-DTW_UNITY_BUILD=ON") + } + } + } + + buildFeatures { + aidl = false + compose = false + buildConfig = false + prefab = false + renderScript = false + resValues = false + shaders = false + viewBinding = false + } + + androidComponents { + beforeVariants { + it.enable = it.name == "release" + } + } + + externalNativeBuild { + cmake { + version = libs.versions.android.cmake.get() + path = rootDir.parentFile.resolve("CMakeLists.txt") + } + } +} diff --git a/kotlin/wallet-core-kotlin/consumer-rules.pro b/kotlin/wallet-core-kotlin/consumer-rules.pro new file mode 100644 index 00000000000..877985aff56 --- /dev/null +++ b/kotlin/wallet-core-kotlin/consumer-rules.pro @@ -0,0 +1,15 @@ +-keepclassmembers class com.trustwallet.core.* { + # Usage example: (*env)->GetFieldID(env, thisClass, "nativeHandle", "J"); + private long nativeHandle; + # Usage example: (*env)->GetStaticMethodID(env, class, "createFromNative", "(J)Lcom/trustwallet/core/Account;"); + private static ** createFromNative(long); +} + +-keepclassmembers enum com.trustwallet.core.* { + # Usage example: (*env)->GetFieldID(env, thisClass, "value", "I"); + private int value; + # Usage example: (*env)->GetMethodID(env, coinClass, "value", "()I"); + public int value(); + # Usage example: (*env)->GetStaticMethodID(env, class, "createFromValue", "(I)Lcom/trustwallet/core/CoinType;"); + public static ** createFromValue(int); +} diff --git a/kotlin/wallet-core-kotlin/src/androidUnitTest/kotlin/com/trustwallet/core/LibLoader.kt b/kotlin/wallet-core-kotlin/src/androidUnitTest/kotlin/com/trustwallet/core/LibLoader.kt new file mode 100644 index 00000000000..1d4f9311712 --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/androidUnitTest/kotlin/com/trustwallet/core/LibLoader.kt @@ -0,0 +1,7 @@ +package com.trustwallet.core + +actual object LibLoader { + actual fun loadLibrary() { + throw NotImplementedError() + } +} diff --git a/kotlin/wallet-core-kotlin/src/commonAndroidJvmMain/kotlin/com/trustwallet/core/AnySigner.kt b/kotlin/wallet-core-kotlin/src/commonAndroidJvmMain/kotlin/com/trustwallet/core/AnySigner.kt new file mode 100644 index 00000000000..e6b348433c4 --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/commonAndroidJvmMain/kotlin/com/trustwallet/core/AnySigner.kt @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core + +actual object AnySigner { + + @JvmStatic + actual external fun sign(input: ByteArray, coin: CoinType): ByteArray + + @JvmStatic + actual external fun supportsJson(coin: CoinType): Boolean + + @JvmStatic + actual external fun signJson(json: String, key: ByteArray, coin: CoinType): String + + @JvmStatic + actual external fun plan(input: ByteArray, coin: CoinType): ByteArray +} diff --git a/kotlin/wallet-core-kotlin/src/commonMain/kotlin/com/trustwallet/core/AnySigner.kt b/kotlin/wallet-core-kotlin/src/commonMain/kotlin/com/trustwallet/core/AnySigner.kt new file mode 100644 index 00000000000..576aa1d32cb --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/commonMain/kotlin/com/trustwallet/core/AnySigner.kt @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core + +import com.squareup.wire.Message +import com.squareup.wire.ProtoAdapter + +expect object AnySigner { + + fun sign(input: ByteArray, coin: CoinType): ByteArray + + fun supportsJson(coin: CoinType): Boolean + + fun signJson(json: String, key: ByteArray, coin: CoinType): String + + fun plan(input: ByteArray, coin: CoinType): ByteArray +} + +fun > AnySigner.sign(input: Message<*, *>, coin: CoinType, adapter: ProtoAdapter): T = + adapter.decode(sign(input.encode(), coin)) + +fun > AnySigner.plan(input: Message<*, *>, coin: CoinType, adapter: ProtoAdapter): T = + adapter.decode(plan(input.encode(), coin)) diff --git a/kotlin/wallet-core-kotlin/src/commonTest/kotlin/com/trustwallet/core/LibLoader.kt b/kotlin/wallet-core-kotlin/src/commonTest/kotlin/com/trustwallet/core/LibLoader.kt new file mode 100644 index 00000000000..5d78d0dc298 --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/commonTest/kotlin/com/trustwallet/core/LibLoader.kt @@ -0,0 +1,5 @@ +package com.trustwallet.core + +expect object LibLoader { + fun loadLibrary() +} diff --git a/kotlin/wallet-core-kotlin/src/commonTest/kotlin/com/trustwallet/core/test/CoinAddressDerivationTests.kt b/kotlin/wallet-core-kotlin/src/commonTest/kotlin/com/trustwallet/core/test/CoinAddressDerivationTests.kt new file mode 100644 index 00000000000..959fd4821eb --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/commonTest/kotlin/com/trustwallet/core/test/CoinAddressDerivationTests.kt @@ -0,0 +1,152 @@ +package com.trustwallet.core.test + +import com.trustwallet.core.CoinType +import com.trustwallet.core.CoinType.* +import com.trustwallet.core.HDWallet +import com.trustwallet.core.LibLoader +import kotlin.test.Test +import kotlin.test.assertEquals + +class CoinAddressDerivationTests { + + init { + LibLoader.loadLibrary() + } + + @Test + fun testDeriveAddressesFromPhrase() { + val wallet = HDWallet("shoot island position soft burden budget tooth cruel issue economy destroy above", "") + + CoinType.values().forEach { coin -> + val address = wallet.getAddressForCoin(coin) + val expectedAddress = getExpectedAddress(coin) + + assertEquals(expectedAddress, address, "Coin = $coin") + } + } + + private fun getExpectedAddress(coin: CoinType): String = when (coin) { + Binance -> "bnb12vtaxl9952zm6rwf7v8jerq74pvaf77fcmvzhw" + TBinance -> "tbnb12vtaxl9952zm6rwf7v8jerq74pvaf77fkw9xhl" + Bitcoin -> "bc1quvuarfksewfeuevuc6tn0kfyptgjvwsvrprk9d" + BitcoinDiamond -> "1KaRW9xPPtCTZ9FdaTHduCPck4YvSeEWNn" + BitcoinCash -> "bitcoincash:qpzl3jxkzgvfd9flnd26leud5duv795fnv7vuaha70" + BitcoinGold -> "btg1qwz9sed0k4neu6ycrudzkca6cnqe3zweq35hvtg" + Callisto -> "0x3E6FFC80745E6669135a76F4A7ce6BCF02436e04" + Dash -> "XqHiz8EXYbTAtBEYs4pWTHh7ipEDQcNQeT" + DigiByte -> "dgb1qtjgmerfqwdffyf8ghcrkgy52cghsqptynmyswu" + + Ethereum, SmartChain, Polygon, Optimism, Zksync, Arbitrum, ArbitrumNova, ECOChain, AvalancheCChain, XDai, + Fantom, Celo, CronosChain, SmartBitcoinCash, KuCoinCommunityChain, Boba, Metis, + Aurora, Evmos, Moonriver, Moonbeam, KavaEvm, Kaia, Meter, OKXChain, PolygonzkEVM, Scroll, + ConfluxeSpace, AcalaEVM, OpBNB, Neon, Base, Linea, Greenfield, Mantle, ZenEON, MantaPacific, + ZetaEVM, Merlin, Lightlink, Blast, BounceBit, ZkLinkNova, + -> "0x8f348F300873Fd5DA36950B2aC75a26584584feE" + + Ronin -> "ronin:8f348F300873Fd5DA36950B2aC75a26584584feE" + EthereumClassic -> "0x078bA3228F3E6C08bEEac9A005de0b7e7089aD1c" + GoChain -> "0x5940ce4A14210d4Ccd0ac206CE92F21828016aC2" + Groestlcoin -> "grs1qexwmshts5pdpeqglkl39zyl6693tmfwp0cue4j" + ICON -> "hx18b380b53c23dc4ee9f6666bc20d1be02f3fe106" + Litecoin -> "ltc1qhd8fxxp2dx3vsmpac43z6ev0kllm4n53t5sk0u" + Ontology -> "AHKTnybvnWo3TeY8uvNXekvYxMrXogUjeT" + POANetwork -> "0xe8a3e8bE17E172B6926130eAfB521e9D2849aca9" + XRP -> "rPwE3gChNKtZ1mhH3Ko8YFGqKmGRWLWXV3" + Tezos -> "tz1acnY9VbMagps26Kj3RfoGRWD9nYG5qaRX" + ThunderCore -> "0x4b92b3ED6d8b24575Bf5ce4C6a86ED261DA0C8d7" + Viction -> "0xC74b6D8897cBa9A4b659d43fEF73C9cA852cE424" + Tron -> "TQ5NMqJjhpQGK7YJbESKtNCo86PJ89ujio" + VeChain -> "0x1a553275dF34195eAf23942CB7328AcF9d48c160" + Wanchain -> "0xD5ca90b928279FE5D06144136a25DeD90127aC15" + Komodo -> "RCWJLXE5CSXydxdSnwcghzPgkFswERegyb" + Zcash -> "t1YYnByMzdGhQv3W3rnjHMrJs6HH4Y231gy" + Zen -> "znUmzvod1f4P9LYsBhNxjqCDQvNSStAmYEX" + Firo -> "aEd5XFChyXobvEics2ppAqgK3Bgusjxtik" + Nimiq -> "NQ76 7AVR EHDA N05U X7SY XB14 XJU7 8ERV GM6H" + Stellar -> "GA3H6I4C5XUBYGVB66KXR27JV5KS3APSTKRUWOIXZ5MVWZKVTLXWKZ2P" + Aion -> "0xa0629f34c9ea4757ad0b275628d4d02e3db6c9009ba2ceeba76a5b55fb2ca42e" + Nano -> "nano_39gsbcishxn3n7wd17ono4otq5wazwzusqgqigztx73wbrh5jwbdbshfnumc" + Nebulas -> "n1ZVgEidtdseYv9ogmGz69Cz4mbqmHYSNqJ" + NEAR -> "0c91f6106ff835c0195d5388565a2d69e25038a7e23d26198f85caf6594117ec" + Theta, ThetaFuel -> "0x0d1fa20c218Fec2f2C55d52aB267940485fa5DA4" + Cosmos -> "cosmos142j9u5eaduzd7faumygud6ruhdwme98qsy2ekn" + Decred -> "DsidJiDGceqHTyqiejABy1ZQ3FX4SiWZkYG" + Dogecoin -> "DJRFZNg8jkUtjcpo2zJd92FUAzwRjitw6f" + Kin -> "GBL3MT2ICHHM5OJ2QJ44CAHGDK6MLPINVXBKOKLHGBWQDVRWTWQ7U2EA" + Viacoin -> "via1qnmsgjd6cvfprnszdgmyg9kewtjfgqflz67wwhc" + Verge -> "DPb3Xz4vjB6QGLKDmrbprrtv4XzNqkADc2" + Qtum -> "QhceuaTdeCZtcxmVc6yyEDEJ7Riu5gWFoF" + NULS -> "NULSd6HgU8MoRnNjBgvJpa9tqvGxYdv5ne4en" + EOS -> "EOS6hs8sRvGSzuQtq223zwJipMzqTJpXUVjyvHPvPwBSZWWrJTJkg" + WAX -> "EOS6hs8sRvGSzuQtq223zwJipMzqTJpXUVjyvHPvPwBSZWWrJTJkg" + IoTeX -> "io1qw9cccecw09q7p5kzyqtuhfhvah2mhfrc84jfk" + IoTeXEVM -> "0x038B8C633873Ca0f06961100BE5d37676EADDD23" + Zilliqa -> "zil1mk6pqphhkmaguhalq6n3cq0h38ltcehg0rfmv6" + Zelcash -> "t1UKbRPzL4WN8Rs8aZ8RNiWoD2ftCMHKGUf" + Ravencoin -> "RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS" + Waves -> "3P63vkaHhyE9pPv9EfsjwGKqmZYcCRHys4n" + Aeternity -> "ak_QDHJSfvHG9sDHBobaWt2TAGhuhipYjEqZEH34bWugpJfJc3GN" + Terra, TerraV2 -> "terra1rh402g98t7sly8trzqw5cyracntlep6qe3smug" + Monacoin -> "M9xFZzZdZhCDxpx42cM8bQHnLwaeX1aNja" + FIO -> "FIO7MN1LuSfFgrbVHmrt9cVa2FYAs857Ppr9dzvEXoD1miKSxm3n3" + Harmony -> "one12fk20wmvgypdkn59n4hq8e3aa5899xfx4vsu09" + Solana -> "2bUBiBNZyD29gP1oV6de7nxowMLoDBtopMMTGgMvjG5m" + Algorand -> "JTJWO524JXIHVPGBDWFLJE7XUIA32ECOZOBLF2QP3V5TQBT3NKZSCG67BQ" + Acala -> "25GGezx3LWFQj6HZpYzoWoVzLsHojGtybef3vthC9nd19ms3" + Kusama -> "G9xV2EatmrjRC1FLPexc3ddqNRRzCsAdURU8RFiAAJX6ppY" + Polkadot -> "13nN6BGAoJwd7Nw1XxeBCx5YcBXuYnL94Mh7i3xBprqVSsFk" + Pivx -> "D81AqC8zKma3Cht4TbVuh4jyVVyLkZULCm" + Kava -> "kava1drpa0x9ptz0fql3frv562rcrhj2nstuz3pas87" + Cardano -> "addr1qyr8jjfnypp95eq74aqzn7ss687ehxclgj7mu6gratmg3mul2040vt35dypp042awzsjk5xm3zr3zm5qh7454uwdv08s84ray2" + NEO -> "AT6w7PJvwPcSqHvtbNBY2aHPDv12eW5Uuf" + Filecoin -> "f1zzykebxldfcakj5wdb5n3n7priul522fnmjzori" + MultiversX -> "erd1jfcy8aeru6vlx4fe6h3pc3vlpe2cnnur5zetxdhp879yagq7vqvs8na4f8" + BandChain -> "band1624hqgend0s3d94z68fyka2y5jak6vd7u0l50r" + SmartChainLegacy -> "0x49784f90176D8D9d4A3feCDE7C1373dAAb5b13b8" + Oasis -> "oasis1qzcpavvmuw280dk0kd4lxjhtpf0u3ll27yf7sqps" + THORChain -> "thor1c8jd7ad9pcw4k3wkuqlkz4auv95mldr2kyhc65" + IOST -> "4av8w81EyzUgHonsVWqfs15WM4Vrpgox4BYYQWhNQDVu" + Syscoin -> "sys1qkl640se3mwpt666e3lyywnwh09e9jquvx9x8qj" + Stratis -> "strax1q0caanaw4nkf6fzwnzq2p7yum680e57pdg05zkm" + Bluzelle -> "bluzelle1xccvees6ev4wm2r49rc6ptulsdxa8x8jfpmund" + CryptoOrg -> "cro16fdf785ejm00jf9a24d23pzqzjh2h05klxjwu8" + Osmosis -> "osmo142j9u5eaduzd7faumygud6ruhdwme98qclefqp" + ECash -> "ecash:qpelrdn7a0hcucjlf9ascz3lkxv7r3rffgzn6x5377" + NativeEvmos -> "evmos13u6g7vqgw074mgmf2ze2cadzvkz9snlwstd20d" + Nervos -> "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdtyq04tvp02wectaumxn0664yw2jd53lqk4mxg3" + Everscale -> "0:0c39661089f86ec5926ea7d4ee4223d634ba4ed6dcc2e80c7b6a8e6d59f79b04" + TON -> "UQDgEMqToTacHic7SnvnPFmvceG5auFkCcAw0mSCvzvKUaT4" + Aptos -> "0x7968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30" + Nebl -> "NgDVaXAwNgBwb88xLiFKomfBmPkEh9F2d7" + Sui -> "0xada112cfb90b44ba889cc5d39ac2bf46281e4a91f7919c693bcd9b8323e81ed2" + Hedera -> "0.0.302a300506032b657003210049eba62f64d0d941045595d9433e65d84ecc46bcdb1421de55e05fcf2d8357d5" + Secret -> "secret1f69sk5033zcdr2p2yf3xjehn7xvgdeq09d2llh" + NativeInjective -> "inj13u6g7vqgw074mgmf2ze2cadzvkz9snlwcrtq8a" + Agoric -> "agoric18zvvgk6j3eq5wd7mqxccgt20gz2w94cy88aek5" + Stargaze -> "stars142j9u5eaduzd7faumygud6ruhdwme98qycayaz" + Juno -> "juno142j9u5eaduzd7faumygud6ruhdwme98qxkfz30" + Stride -> "stride142j9u5eaduzd7faumygud6ruhdwme98qn029zl" + Axelar -> "axelar142j9u5eaduzd7faumygud6ruhdwme98q52u3aj" + Crescent -> "cre142j9u5eaduzd7faumygud6ruhdwme98q5veur7" + Kujira -> "kujira142j9u5eaduzd7faumygud6ruhdwme98qpvgpme" + NativeCanto -> "canto13u6g7vqgw074mgmf2ze2cadzvkz9snlwqua5pd" + Comdex -> "comdex142j9u5eaduzd7faumygud6ruhdwme98qhtgm0y" + Neutron -> "neutron142j9u5eaduzd7faumygud6ruhdwme98q5mrmv5" + Sommelier -> "somm142j9u5eaduzd7faumygud6ruhdwme98quc948e" + FetchAI -> "fetch142j9u5eaduzd7faumygud6ruhdwme98qrera5y" + Mars -> "mars142j9u5eaduzd7faumygud6ruhdwme98qdenqrg" + Umee -> "umee142j9u5eaduzd7faumygud6ruhdwme98qzjhxjp" + Coreum -> "core1rawf376jz2lnchgc4wzf4h9c77neg3zldc7xa8" + Quasar -> "quasar142j9u5eaduzd7faumygud6ruhdwme98q78symk" + Persistence -> "persistence142j9u5eaduzd7faumygud6ruhdwme98q7gv2ch" + Akash -> "akash142j9u5eaduzd7faumygud6ruhdwme98qal870f" + Noble -> "noble142j9u5eaduzd7faumygud6ruhdwme98qc8l3wa" + Rootstock -> "0xA2D7065F94F838a3aB9C04D67B312056846424Df" + Sei -> "sei142j9u5eaduzd7faumygud6ruhdwme98qagm0sj" + InternetComputer -> "6f8e568160a3c8362789848dc0fa52891964473c045cc25208a305fb35b7c4ab" + Tia -> "celestia142j9u5eaduzd7faumygud6ruhdwme98qpwmfv7" + NativeZetaChain -> "zeta13u6g7vqgw074mgmf2ze2cadzvkz9snlwywj304" + Dydx -> "dydx142j9u5eaduzd7faumygud6ruhdwme98qeayaky" + Pactus -> "pc1r7ys2g5a4xc2qtm0t4q987m4mvs57w5g0v4pvzg" + } +} diff --git a/kotlin/wallet-core-kotlin/src/iosMain/kotlin/com/trustwallet/core/AnySigner.kt b/kotlin/wallet-core-kotlin/src/iosMain/kotlin/com/trustwallet/core/AnySigner.kt new file mode 100644 index 00000000000..6de0b110bea --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/iosMain/kotlin/com/trustwallet/core/AnySigner.kt @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core + +actual object AnySigner { + + actual fun sign(input: ByteArray, coin: CoinType): ByteArray = + TWAnySignerSign(input.toTwData(), coin.value)!!.readTwBytes()!! + + actual fun supportsJson(coin: CoinType): Boolean = + TWAnySignerSupportsJSON(coin.value) + + actual fun signJson(json: String, key: ByteArray, coin: CoinType): String = + TWAnySignerSignJSON(json.toTwString(), key.toTwData(), coin.value).fromTwString()!! + + actual fun plan(input: ByteArray, coin: CoinType): ByteArray = + TWAnySignerPlan(input.toTwData(), coin.value)?.readTwBytes()!! +} diff --git a/kotlin/wallet-core-kotlin/src/iosMain/kotlin/com/trustwallet/core/ByteArrayExt.kt b/kotlin/wallet-core-kotlin/src/iosMain/kotlin/com/trustwallet/core/ByteArrayExt.kt new file mode 100644 index 00000000000..ec5923272a1 --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/iosMain/kotlin/com/trustwallet/core/ByteArrayExt.kt @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core + +import kotlinx.cinterop.COpaquePointer +import kotlinx.cinterop.readBytes +import kotlinx.cinterop.toCValues + +internal fun COpaquePointer?.readTwBytes(): ByteArray? = + TWDataBytes(this)?.readBytes(TWDataSize(this).toInt()) + +@OptIn(ExperimentalUnsignedTypes::class) +internal fun ByteArray?.toTwData(): COpaquePointer? = + TWDataCreateWithBytes(this?.toUByteArray()?.toCValues(), this?.size?.toULong() ?: 0u) diff --git a/kotlin/wallet-core-kotlin/src/iosMain/kotlin/com/trustwallet/core/StringExt.kt b/kotlin/wallet-core-kotlin/src/iosMain/kotlin/com/trustwallet/core/StringExt.kt new file mode 100644 index 00000000000..2eb7fdd311e --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/iosMain/kotlin/com/trustwallet/core/StringExt.kt @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core + +import kotlinx.cinterop.COpaquePointer +import kotlinx.cinterop.CValuesRef +import kotlinx.cinterop.toKString + +internal fun String?.toTwString(): COpaquePointer? = + this?.let { TWStringCreateWithUTF8Bytes(it) } + +internal fun CValuesRef<*>?.fromTwString(): String? = + this?.let { TWStringUTF8Bytes(it)?.toKString() } diff --git a/kotlin/wallet-core-kotlin/src/iosTest/kotlin/com/trustwallet/core/LibLoader.kt b/kotlin/wallet-core-kotlin/src/iosTest/kotlin/com/trustwallet/core/LibLoader.kt new file mode 100644 index 00000000000..1d4f9311712 --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/iosTest/kotlin/com/trustwallet/core/LibLoader.kt @@ -0,0 +1,7 @@ +package com.trustwallet.core + +actual object LibLoader { + actual fun loadLibrary() { + throw NotImplementedError() + } +} diff --git a/kotlin/wallet-core-kotlin/src/jsMain/kotlin/WalletCore.kt b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/WalletCore.kt new file mode 100644 index 00000000000..a454889ea72 --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/WalletCore.kt @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +import com.trustwallet.core.* +import kotlin.js.Promise + +@JsExport +@JsName("WalletCoreKotlin") +object WalletCore { + + lateinit var Instance: JsWalletCore + private set + + fun init(): Promise = + if (::Instance.isInitialized) { + Promise.resolve(Instance) + } else { + WalletCoreExports.initWasm() + .then { walletCore -> + Instance = walletCore + walletCore + } + } +} + +@JsModule("@trustwallet/wallet-core") +@JsNonModule +private external object WalletCoreExports { + fun initWasm(): Promise +} diff --git a/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/AnySigner.kt b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/AnySigner.kt new file mode 100644 index 00000000000..d62bf4f81c3 --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/AnySigner.kt @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core + +import WalletCore + +actual object AnySigner { + + actual fun sign(input: ByteArray, coin: CoinType): ByteArray = + WalletCore.Instance.AnySigner.sign(input.asUInt8Array(), coin.jsValue).asByteArray() + + actual fun supportsJson(coin: CoinType): Boolean = + WalletCore.Instance.AnySigner.supportsJSON(coin.jsValue) + + actual fun signJson(json: String, key: ByteArray, coin: CoinType): String = + TODO() + + actual fun plan(input: ByteArray, coin: CoinType): ByteArray = + WalletCore.Instance.AnySigner.plan(input.asUInt8Array(), coin.jsValue).asByteArray() +} diff --git a/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/ByteArray.kt b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/ByteArray.kt new file mode 100644 index 00000000000..9163d5bdca2 --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/ByteArray.kt @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core + +import org.khronos.webgl.Int8Array +import org.khronos.webgl.Uint8Array + +internal typealias UInt8Array = Uint8Array + +fun Int8Array.asByteArray(): ByteArray = + unsafeCast() + +fun Uint8Array.asByteArray(): ByteArray = + Int8Array(buffer, byteOffset, length).asByteArray() + +fun ByteArray.asInt8Array(): Int8Array = + unsafeCast() + +fun ByteArray.asUInt8Array(): Uint8Array = + asInt8Array().let { Uint8Array(it.buffer, it.byteOffset, it.length) } diff --git a/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/JsAnySigner.kt b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/JsAnySigner.kt new file mode 100644 index 00000000000..75be5fbd8d7 --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/JsAnySigner.kt @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core + +@JsModule("@trustwallet/wallet-core") +@JsName("AnySigner") +external class JsAnySigner { + companion object { + fun sign(data: UInt8Array, coin: JsCoinType): UInt8Array + fun plan(data: UInt8Array, coin: JsCoinType): UInt8Array + fun supportsJSON(coin: JsCoinType): Boolean + } +} + +inline val JsWalletCore.AnySigner: JsAnySigner.Companion + get() = asDynamic().AnySigner.unsafeCast() diff --git a/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/JsWalletCore.kt b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/JsWalletCore.kt new file mode 100644 index 00000000000..0865e64e531 --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/JsWalletCore.kt @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +@file:Suppress("PropertyName") + +package com.trustwallet.core + +@JsModule("@trustwallet/wallet-core") +@JsName("WalletCore") +external interface JsWalletCore diff --git a/kotlin/wallet-core-kotlin/src/jsTest/kotlin/com/trustwallet/core/LibLoader.kt b/kotlin/wallet-core-kotlin/src/jsTest/kotlin/com/trustwallet/core/LibLoader.kt new file mode 100644 index 00000000000..1d4f9311712 --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/jsTest/kotlin/com/trustwallet/core/LibLoader.kt @@ -0,0 +1,7 @@ +package com.trustwallet.core + +actual object LibLoader { + actual fun loadLibrary() { + throw NotImplementedError() + } +} diff --git a/kotlin/wallet-core-kotlin/src/jvmMain/kotlin/com/trustwallet/core/WalletCoreLibLoader.kt b/kotlin/wallet-core-kotlin/src/jvmMain/kotlin/com/trustwallet/core/WalletCoreLibLoader.kt new file mode 100644 index 00000000000..23c20a24897 --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/jvmMain/kotlin/com/trustwallet/core/WalletCoreLibLoader.kt @@ -0,0 +1,60 @@ +package com.trustwallet.core + +import com.trustwallet.core.WalletCoreLibLoader.Linux64Path +import com.trustwallet.core.WalletCoreLibLoader.MacArm64Path +import java.io.File +import java.util.concurrent.atomic.AtomicBoolean + +/** + * Simple helper class that extracts proper native library for current OS/arch from .jar to temporary file and loads it. + * You can do the same by yourself, just use path constants: [MacArm64Path], [Linux64Path] + */ +object WalletCoreLibLoader { + + const val MacArm64Path = "/jni/macos-arm64/libTrustWalletCore.dylib" + const val Linux64Path = "/jni/linux-x86_64/libTrustWalletCore.so" + + private val isLoaded = AtomicBoolean(false) + + @JvmStatic + fun loadLibrary() { + if (isLoaded.compareAndSet(false, true)) { + val resLibPath = getLibResourcePath() + val resLibStream = WalletCoreLibLoader::class.java.getResourceAsStream(resLibPath) + ?: error("File not found: $resLibPath") + + val fileOut = File.createTempFile("libTrustWalletCore", null) + fileOut.deleteOnExit() + + resLibStream.copyTo(fileOut.outputStream()) + + @Suppress("UnsafeDynamicallyLoadedCode") + System.load(fileOut.absolutePath) + } + } + + private fun getLibResourcePath(): String { + val osNameOriginal = System.getProperty("os.name").lowercase() + val osName = osNameOriginal.lowercase() + val archOriginal = System.getProperty("os.arch").lowercase() + val arch = archOriginal.lowercase() + + return when { + osName.startsWith("mac") -> { + when (arch) { + "aarch64" -> MacArm64Path + else -> error("Arch is not supported: $archOriginal") + } + } + + osName.startsWith("linux") -> { + when (arch) { + "amd64", "x86_64" -> Linux64Path + else -> error("Arch is not supported: $archOriginal") + } + } + + else -> error("OS is not supported: $osNameOriginal") + } + } +} diff --git a/kotlin/wallet-core-kotlin/src/jvmMain/resources/jni/linux-x86_64/.gitignore b/kotlin/wallet-core-kotlin/src/jvmMain/resources/jni/linux-x86_64/.gitignore new file mode 100644 index 00000000000..6519c51f274 --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/jvmMain/resources/jni/linux-x86_64/.gitignore @@ -0,0 +1 @@ +libTrustWalletCore.so diff --git a/kotlin/wallet-core-kotlin/src/jvmMain/resources/jni/macos-arm64/.gitignore b/kotlin/wallet-core-kotlin/src/jvmMain/resources/jni/macos-arm64/.gitignore new file mode 100644 index 00000000000..9162c6ec1f1 --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/jvmMain/resources/jni/macos-arm64/.gitignore @@ -0,0 +1 @@ +libTrustWalletCore.dylib diff --git a/kotlin/wallet-core-kotlin/src/jvmTest/kotlin/com/trustwallet/core/LibLoader.kt b/kotlin/wallet-core-kotlin/src/jvmTest/kotlin/com/trustwallet/core/LibLoader.kt new file mode 100644 index 00000000000..0c153abd9e7 --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/jvmTest/kotlin/com/trustwallet/core/LibLoader.kt @@ -0,0 +1,7 @@ +package com.trustwallet.core + +actual object LibLoader { + actual fun loadLibrary() { + WalletCoreLibLoader.loadLibrary() + } +} diff --git a/kotlin/wallet-core-kotlin/src/nativeInterop/cinterop/WalletCore.def b/kotlin/wallet-core-kotlin/src/nativeInterop/cinterop/WalletCore.def new file mode 100644 index 00000000000..e69de29bb2d diff --git a/protobuf-plugin/CMakeLists.txt b/protobuf-plugin/CMakeLists.txt index 57b7ac59d83..237789be7be 100644 --- a/protobuf-plugin/CMakeLists.txt +++ b/protobuf-plugin/CMakeLists.txt @@ -1,33 +1,26 @@ -# Copyright © 2017-2022 Trust Wallet. +# SPDX-License-Identifier: Apache-2.0 # -# This file is part of Trust. The full Trust copyright notice, including -# terms governing use, modification, and redistribution, is contained in the -# file LICENSE at the root of the source code distribution tree. +# Copyright © 2017 Trust Wallet. -cmake_minimum_required(VERSION 3.2 FATAL_ERROR) +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) project(TrustWalletCoreProtobufPlugin) set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14" CACHE STRING "Minimum OS X deployment version" FORCE) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) -if ("$ENV{PREFIX}" STREQUAL "") +if("$ENV{PREFIX}" STREQUAL "") set(PREFIX "${CMAKE_SOURCE_DIR}/../build/local") else() set(PREFIX "$ENV{PREFIX}") endif() -include_directories(${PREFIX}/include) -link_directories(${PREFIX}/lib) +find_package(Protobuf CONFIG REQUIRED PATH ${PREFIX}/lib/pkgconfig) -find_package(Protobuf REQUIRED PATH ${PREFIX}/lib/pkgconfig) -include_directories(${Protobuf_INCLUDE_DIRS}) -include_directories(${CMAKE_CURRENT_BINARY_DIR}) +add_executable(protoc-gen-c-typedef c_typedef.cc) +target_link_libraries(protoc-gen-c-typedef protobuf::libprotobuf protobuf::libprotoc) -add_executable(protoc-gen-c-typedef c_typedef.cc ${PROTO_SRCS} ${PROTO_HDRS}) -target_link_libraries(protoc-gen-c-typedef protobuf -lprotoc -pthread) - -add_executable(protoc-gen-swift-typealias swift_typealias.cc ${PROTO_SRCS} ${PROTO_HDRS}) -target_link_libraries(protoc-gen-swift-typealias protobuf -lprotoc -pthread) +add_executable(protoc-gen-swift-typealias swift_typealias.cc) +target_link_libraries(protoc-gen-swift-typealias protobuf::libprotobuf protobuf::libprotoc) install(TARGETS protoc-gen-c-typedef protoc-gen-swift-typealias DESTINATION bin) diff --git a/protobuf-plugin/c_typedef.cc b/protobuf-plugin/c_typedef.cc index 9cd48a5e798..1352898cb73 100644 --- a/protobuf-plugin/c_typedef.cc +++ b/protobuf-plugin/c_typedef.cc @@ -14,16 +14,14 @@ class Generator : public compiler::CodeGenerator { return "TW" + proto_file.substr(0, index) + "Proto.h"; } - bool Generate(const FileDescriptor* file, const std::string& parameter, compiler::GeneratorContext* generator_context, string* error) const { + bool Generate(const FileDescriptor* file, const std::string& parameter, compiler::GeneratorContext* generator_context, std::string* error) const { std::unique_ptr output(generator_context->Open(GetOutputFilename(file->name()))); io::Printer printer(output.get(), '$'); printer.Print( - "// Copyright © 2017-2020 Trust Wallet.\n" + "// SPDX-License-Identifier: Apache-2.0\n" "//\n" - "// This file is part of Trust. The full Trust copyright notice, including\n" - "// terms governing use, modification, and redistribution, is contained in the\n" - "// file LICENSE at the root of the source code distribution tree.\n" + "// Copyright © 2017 Trust Wallet.\n" "//\n" "// This is a GENERATED FILE, changes made here WILL BE LOST.\n" "\n" diff --git a/protobuf-plugin/swift_typealias.cc b/protobuf-plugin/swift_typealias.cc index 57a169dea03..3d0983c2ca3 100644 --- a/protobuf-plugin/swift_typealias.cc +++ b/protobuf-plugin/swift_typealias.cc @@ -16,16 +16,14 @@ class Generator : public compiler::CodeGenerator { return proto_file.substr(0, index) + "+Proto.swift"; } - bool Generate(const FileDescriptor* file, const std::string& parameter, compiler::GeneratorContext* generator_context, string* error) const { + bool Generate(const FileDescriptor* file, const std::string& parameter, compiler::GeneratorContext* generator_context, std::string* error) const { std::unique_ptr output(generator_context->Open(GetOutputFilename(file->name()))); io::Printer printer(output.get(), '$'); printer.Print( - "// Copyright © 2017-2020 Trust Wallet.\n" + "// SPDX-License-Identifier: Apache-2.0\n" "//\n" - "// This file is part of Trust. The full Trust copyright notice, including\n" - "// terms governing use, modification, and redistribution, is contained in the\n" - "// file LICENSE at the root of the source code distribution tree.\n" + "// Copyright © 2017 Trust Wallet.\n" "\n" ); diff --git a/registry.json b/registry.json index 537498c91ac..d88798aff9c 100644 --- a/registry.json +++ b/registry.json @@ -18,6 +18,18 @@ "path": "m/44'/0'/0'/0/0", "xpub": "xpub", "xprv": "xprv" + }, + { + "name": "testnet", + "path": "m/84'/1'/0'/0/0", + "xpub": "zpub", + "xprv": "zprv" + }, + { + "name": "taproot", + "path": "m/86'/0'/0'/0/0", + "xpub": "zpub", + "xprv": "zprv" } ], "curve": "secp256k1", @@ -28,9 +40,9 @@ "publicKeyHasher": "sha256ripemd", "base58Hasher": "sha256d", "explorer": { - "url": "https://blockchair.com", - "txPath": "/bitcoin/transaction/", - "accountPath": "/bitcoin/address/", + "url": "https://mempool.space", + "txPath": "/tx/", + "accountPath": "/address/", "sampleTx": "0607f62530b68cfcc91c57a1702841dd399a899d0eecda8e31ecca3f52f01df2", "sampleAccount": "17A16QmavnUfCW11DAApiJxp7ARnxN5pGX" }, @@ -309,6 +321,161 @@ "documentation": "https://github.com/trezor/blockbook/blob/master/docs/api.md" } }, + { + "id": "syscoin", + "name": "Syscoin", + "coinId": 57, + "symbol": "SYS", + "decimals": 8, + "blockchain": "Bitcoin", + "derivation": [ + { + "path": "m/84'/57'/0'/0/0", + "xpub": "zpub", + "xprv": "zprv" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "p2pkhPrefix": 63, + "p2shPrefix": 5, + "hrp": "sys", + "publicKeyHasher": "sha256ripemd", + "base58Hasher": "sha256d", + "explorer": { + "url": "https://sys1.bcfn.ca", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "19e043f76f6ffc960f5fe93ecec37bc37a58ae7525d7e9cd6ed40f71f0da60eb", + "sampleAccount": "sys1qh3gvhnzq2ch7w8g04x8zksr2mz7r90x7ksmu40" + }, + "info": { + "url": "https://syscoin.org", + "source": "https://github.com/syscoin", + "rpc": "https://sys1.bcfn.ca", + "documentation": "https://docs.syscoin.org" + } + }, + { + "id": "base", + "name": "Base", + "coinId": 8453, + "symbol": "ETH", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/60'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "8453", + "addressHasher": "keccak256", + "explorer": { + "url": "https://basescan.org", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "0x4acb15506b7696a2dfac4258f3f86392b4b2b717a3f316a8aa78509b2c3b6ab4", + "sampleAccount": "0xb8ff877ed78ba520ece21b1de7843a8a57ca47cb" + }, + "info": { + "url": "https://base.mirror.xyz/", + "source": "https://github.com/base-org", + "rpc": "https://mainnet.base.org", + "documentation": "https://docs.base.org/" + } + }, + { + "id": "linea", + "name": "Linea", + "coinId": 59144, + "symbol": "ETH", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/60'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "59144", + "addressHasher": "keccak256", + "explorer": { + "url": "https://lineascan.build", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "0x0c7086f96865f4fcad58d7f3449db7baab9fce2625bcb79e7ea26676aa0d3420", + "sampleAccount": "0xbf71018f716ca6c64b0b12622f87a26b3b86100f" + }, + "info": { + "url": "https://linea.build", + "source": "https://github.com/LineaLabs", + "rpc": "https://rpc.linea.build", + "documentation": "https://docs.linea.build" + } + }, + { + "id": "mantle", + "name": "Mantle", + "coinId": 5000, + "symbol": "MNT", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/60'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "5000", + "addressHasher": "keccak256", + "explorer": { + "url": "https://explorer.mantle.xyz", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "0xfae996ea23f1ff9909ac04d26ae6e52ab600a84163fab9e0e893483c685629dd", + "sampleAccount": "0xA295EEFd401C8BE1457F266d3e73cdD015e5CFbb" + }, + "info": { + "url": "https://www.mantle.xyz", + "source": "https://github.com/mantlenetworkio", + "rpc": "https://rpc.mantle.xyz", + "documentation": "https://docs.mantle.xyz/network/introduction/overview" + } + }, + { + "id": "zeneon", + "name": "Zen EON", + "coinId": 7332, + "symbol": "ZEN", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/60'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "7332", + "addressHasher": "keccak256", + "explorer": { + "url": "https://eon-explorer.horizenlabs.io", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "0xb462e3dac8eef21957d3b6cff3c184d083434367a726dd871e98a774f4d037a5", + "sampleAccount": "0x09bCfC348101B1179BCF3837aC996cF09357215f" + }, + "info": { + "url": "https://eon.horizen.io", + "source": "https://github.com/HorizenOfficial/eon", + "rpc": "https://eon-rpc.horizenlabs.io/ethv1", + "documentation": "https://eon.horizen.io/docs" + } + }, { "id": "ethereum", "name": "Ethereum", @@ -358,7 +525,9 @@ "explorer": { "url": "https://blockscout.com/etc/mainnet", "txPath": "/tx/", - "accountPath": "/address/" + "accountPath": "/address/", + "sampleTx": "0x66004165d3901819dc22e568931591d2e4287bda54995f4ce2701a12016f5997", + "sampleAccount": "0x9eab4b0fc468a7f5d46228bf5a76cb52370d068d" }, "info": { "url": "https://ethereumclassic.org", @@ -394,1529 +563,3427 @@ } }, { - "id": "cosmos", - "name": "Cosmos", - "displayName": "Cosmos Hub", - "coinId": 118, - "symbol": "ATOM", + "id": "verge", + "name": "Verge", + "coinId": 77, + "symbol": "XVG", "decimals": 6, - "chainId": "cosmoshub-4", - "blockchain": "Cosmos", + "blockchain": "Verge", "derivation": [ { - "path": "m/44'/118'/0'/0/0" + "path": "m/84'/77'/0'/0/0", + "xpub": "zpub", + "xprv": "zprv" } ], "curve": "secp256k1", "publicKeyType": "secp256k1", - "hrp": "cosmos", - "addressHasher": "sha256ripemd", + "p2pkhPrefix": 30, + "p2shPrefix": 33, + "hrp": "vg", + "publicKeyHasher": "sha256ripemd", + "base58Hasher": "sha256d", "explorer": { - "url": "https://mintscan.io/cosmos", - "txPath": "/txs/", - "accountPath": "/account/" + "url": "https://verge-blockchain.info", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "8c99979a2b25a46659bff35b238aab1c3158f736f215d99526429c7c96203581", + "sampleAccount": "DFre88gd87bAZQdnS7dbBLwT6GWiGFMQB6" }, "info": { - "url": "https://cosmos.network", - "source": "https://github.com/cosmos/cosmos-sdk", - "rpc": "https://stargate.cosmos.network", - "documentation": "https://cosmos.network/rpc" + "url": "https://vergecurrency.com", + "source": "https://github.com/vergecurrency/verge", + "rpc": "", + "documentation": "https://github.com/trezor/blockbook/blob/master/docs/api.md" } }, { - "id": "zcash", - "name": "Zcash", - "coinId": 133, - "symbol": "ZEC", + "id": "pivx", + "name": "Pivx", + "coinId": 119, + "symbol": "PIVX", "decimals": 8, - "blockchain": "Zcash", + "blockchain": "Bitcoin", "derivation": [ { - "path": "m/44'/133'/0'/0/0", + "path": "m/44'/119'/0'/0/0", "xpub": "xpub", "xprv": "xprv" } ], "curve": "secp256k1", "publicKeyType": "secp256k1", - "staticPrefix": 28, - "p2pkhPrefix": 184, - "p2shPrefix": 189, + "p2pkhPrefix": 30, + "p2shPrefix": 13, "publicKeyHasher": "sha256ripemd", "base58Hasher": "sha256d", "explorer": { - "url": "https://blockchair.com/zcash", + "url": "https://pivx.ccore.online", "txPath": "/transaction/", "accountPath": "/address/" }, "info": { - "url": "https://z.cash", + "url": "https://pivx.org", "source": "https://github.com/trezor/blockbook", "rpc": "", "documentation": "https://github.com/trezor/blockbook/blob/master/docs/api.md" } }, { - "id": "firo", - "name": "Firo", - "coinId": 136, - "symbol": "FIRO", + "id": "zen", + "name": "Zen", + "coinId": 121, + "symbol": "ZEN", "decimals": 8, - "blockchain": "Bitcoin", + "blockchain": "Zen", "derivation": [ { - "path": "m/44'/136'/0'/0/0", + "path": "m/44'/121'/0'/0/0", "xpub": "xpub", "xprv": "xprv" } ], "curve": "secp256k1", "publicKeyType": "secp256k1", - "p2pkhPrefix": 82, - "p2shPrefix": 7, + "staticPrefix": 32, + "p2pkhPrefix": 137, + "p2shPrefix": 150, "publicKeyHasher": "sha256ripemd", "base58Hasher": "sha256d", "explorer": { - "url": "https://explorer.firo.org", + "url": "https://explorer.horizen.io", "txPath": "/tx/", - "accountPath": "/address/" + "accountPath": "/address/", + "sampleTx": "b7f548640766fb024247accf4e01bec37d88d49c4900357edc84d49a09ff4430", + "sampleAccount": "znRchPtvEyJJUwGbCALqyjwHJb1Gx6z4H4j" }, "info": { - "url": "https://firo.org/", - "source": "https://github.com/firoorg/firo", + "url": "https://www.horizen.io", + "source": "https://github.com/trezor/blockbook", "rpc": "", "documentation": "https://github.com/trezor/blockbook/blob/master/docs/api.md" } }, { - "id": "ripple", - "name": "XRP", - "coinId": 144, - "symbol": "XRP", - "decimals": 6, - "blockchain": "Ripple", + "id": "aptos", + "name": "Aptos", + "displayName": "Aptos", + "coinId": 637, + "symbol": "APT", + "decimals": 8, + "chainId": "1", + "blockchain": "Aptos", "derivation": [ { - "path": "m/44'/144'/0'/0/0" + "path": "m/44'/637'/0'/0'/0'" } ], - "curve": "secp256k1", - "publicKeyType": "secp256k1", + "curve": "ed25519", + "publicKeyType": "ed25519", "explorer": { - "url": "https://bithomp.com", - "txPath": "/explorer/", - "accountPath": "/explorer/", - "sampleTx": "E26AB8F3372D2FC02DEC1FD5674ADAB762D684BFFDBBDF5D674E9D7CF4A47054", - "sampleAccount": "rfkH7EuS1XcSkB9pocy1R6T8F4CsNYixYU" + "url": "https://explorer.aptoslabs.com", + "txPath": "/txn/", + "accountPath": "/account/", + "sampleTx": "0xedc88058e27f6c065fd6607e262cb2a83a65f74301df90c61923014c59f9d465", + "sampleAccount": "0x60ad80e8cdadb81399e8a738014bc9ec865cef842f7c2cf7d84fbf7e40d065" }, "info": { - "url": "https://ripple.com/xrp", - "source": "https://github.com/ripple/rippled", - "rpc": "https://s2.ripple.com:51234", - "documentation": "https://xrpl.org/rippled-api.html" + "url": "https://aptoslabs.com/", + "source": "https://github.com/aptos-labs/aptos-core", + "rpc": "https://fullnode.mainnet.aptoslabs.com/v1", + "documentation": "https://fullnode.mainnet.aptoslabs.com/v1/spec#/" } }, { - "id": "bitcoincash", - "name": "Bitcoin Cash", - "coinId": 145, - "symbol": "BCH", - "decimals": 8, - "blockchain": "Bitcoin", + "id": "sui", + "name": "Sui", + "coinId": 784, + "symbol": "SUI", + "decimals": 9, + "blockchain": "Sui", "derivation": [ { - "path": "m/44'/145'/0'/0/0", - "xpub": "xpub", - "xprv": "xprv" + "path": "m/44'/784'/0'/0'/0'" } ], - "curve": "secp256k1", - "publicKeyType": "secp256k1", - "p2pkhPrefix": 0, - "p2shPrefix": 5, - "hrp": "bitcoincash", - "publicKeyHasher": "sha256ripemd", - "base58Hasher": "sha256d", + "curve": "ed25519", + "publicKeyType": "ed25519", "explorer": { - "url": "https://blockchair.com", - "txPath": "/bitcoin-cash/transaction/", - "accountPath": "/bitcoin-cash/address/" + "url": "https://explorer.sui.io/", + "txPath": "/txblock/", + "accountPath": "/address/", + "sampleTx": "5i8fbSL6r8yw2xcKmXxwkzHu3wpiyMLsyf2htCvDH8Ao", + "sampleAccount": "0x259ff8074ab425cbb489f236e18e08f03f1a7856bdf7c7a2877bd64f738b5015" }, "info": { - "url": "https://bitcoincash.org", - "source": "https://github.com/trezor/blockbook", - "rpc": "", - "documentation": "https://github.com/trezor/blockbook/blob/master/docs/api.md" + "url": "https://sui.io/", + "source": "https://github.com/MystenLabs/sui", + "rpc": "https://fullnode.testnet.sui.io", + "documentation": "https://docs.sui.io/" } }, { - "id": "stellar", - "name": "Stellar", - "coinId": 148, - "symbol": "XLM", - "decimals": 7, - "blockchain": "Stellar", + "id": "cosmos", + "name": "Cosmos", + "displayName": "Cosmos Hub", + "coinId": 118, + "symbol": "ATOM", + "decimals": 6, + "chainId": "cosmoshub-4", + "blockchain": "Cosmos", "derivation": [ { - "path": "m/44'/148'/0'" + "path": "m/44'/118'/0'/0/0" } ], - "curve": "ed25519", - "publicKeyType": "ed25519", + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "hrp": "cosmos", + "addressHasher": "sha256ripemd", "explorer": { - "url": "https://blockchair.com/stellar", - "txPath": "/transaction/", - "accountPath": "/account/" + "url": "https://mintscan.io/cosmos", + "txPath": "/txs/", + "accountPath": "/account/", + "sampleTx": "541FA06FB37AC1BF61922143783DD76FECA361830F9876D0342536EE8A87A790", + "sampleAccount": "cosmos1gu6y2a0ffteesyeyeesk23082c6998xyzmt9mz" }, "info": { - "url": "https://stellar.org", - "source": "https://github.com/stellar/go", - "rpc": "https://horizon.stellar.org", - "documentation": "https://www.stellar.org/developers/horizon/reference" + "url": "https://cosmos.network", + "source": "https://github.com/cosmos/cosmos-sdk", + "rpc": "https://stargate.cosmos.network", + "documentation": "https://cosmos.network/rpc" } }, { - "id": "bitcoingold", - "name": "Bitcoin Gold", - "coinId": 156, - "symbol": "BTG", - "decimals": 8, - "blockchain": "Bitcoin", - "derivation": [ + "id": "stargaze", + "name": "Stargaze", + "displayName": "Stargaze", + "coinId": 20000118, + "symbol": "STARS", + "decimals": 6, + "chainId": "stargaze-1", + "blockchain": "Cosmos", + "derivation": [ { - "path": "m/84'/156'/0'/0/0", - "xpub": "zpub", - "xprv": "zprv" + "path": "m/44'/118'/0'/0/0" } ], "curve": "secp256k1", "publicKeyType": "secp256k1", - "p2pkhPrefix": 38, - "p2shPrefix": 23, - "hrp": "btg", - "publicKeyHasher": "sha256ripemd", - "base58Hasher": "sha256d", + "hrp": "stars", + "addressHasher": "sha256ripemd", "explorer": { - "url": "https://explorer.bitcoingold.org/insight", - "txPath": "/tx/", - "accountPath": "/address/" + "url": "https://www.mintscan.io/stargaze", + "txPath": "/txs/", + "accountPath": "/account/" }, "info": { - "url": "https://bitcoingold.org", - "source": "https://github.com/trezor/blockbook", - "rpc": "", - "documentation": "https://github.com/trezor/blockbook/blob/master/docs/api.md" + "url": "https://www.stargaze.zone/", + "source": "https://github.com/public-awesome/stargaze", + "rpc": "https://stargaze-rpc.polkachu.com/", + "documentation": "https://docs.stargaze.zone/guides/readme" } }, { - "id": "nano", - "name": "Nano", - "coinId": 165, - "symbol": "XNO", - "decimals": 30, - "blockchain": "Nano", + "id": "juno", + "name": "Juno", + "displayName": "Juno", + "coinId": 30000118, + "symbol": "JUNO", + "decimals": 6, + "chainId": "juno-1", + "blockchain": "Cosmos", "derivation": [ { - "path": "m/44'/165'/0'" + "path": "m/44'/118'/0'/0/0" } ], - "curve": "ed25519Blake2bNano", - "publicKeyType": "ed25519Blake2b", - "url": "https://nano.org", + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "hrp": "juno", + "addressHasher": "sha256ripemd", "explorer": { - "url": "https://nanocrawler.cc", - "txPath": "/explorer/block/", - "accountPath": "/explorer/account/", - "sampleTx": "C264DB7BF40738F0CEFF19B606746CB925B713E4B8699A055699E0DC8ABBC70F", - "sampleAccount": "nano_1wpj616kwhe1y38y1mspd8aub8i334cwybqco511iyuxm55zx8d67ptf1tsf" + "url": "https://www.mintscan.io/juno", + "txPath": "/txs/", + "accountPath": "/account/" }, "info": { - "url": "https://nano.org", - "source": "https://github.com/nanocurrency/nano-node", - "rpc": "", - "documentation": "https://docs.nano.org/commands/rpc-protocol/" + "url": "https://www.junonetwork.io/", + "source": "https://github.com/CosmosContracts/juno", + "rpc": "https://juno-rpc.polkachu.com", + "documentation": "https://docs.junonetwork.io/juno/readme" } }, { - "id": "ravencoin", - "name": "Ravencoin", - "coinId": 175, - "symbol": "RVN", - "decimals": 8, - "blockchain": "Bitcoin", + "id": "stride", + "name": "Stride", + "displayName": "Stride", + "coinId": 40000118, + "symbol": "STRD", + "decimals": 6, + "chainId": "stride-1", + "blockchain": "Cosmos", "derivation": [ { - "path": "m/44'/175'/0'/0/0", - "xpub": "xpub", - "xprv": "xprv" + "path": "m/44'/118'/0'/0/0" } ], "curve": "secp256k1", "publicKeyType": "secp256k1", - "p2pkhPrefix": 60, - "p2shPrefix": 122, - "publicKeyHasher": "sha256ripemd", - "base58Hasher": "sha256d", + "hrp": "stride", + "addressHasher": "sha256ripemd", "explorer": { - "url": "https://ravencoin.network", - "txPath": "/tx/", - "accountPath": "/address/" + "url": "https://www.mintscan.io/stride", + "txPath": "/txs/", + "accountPath": "/account/" }, "info": { - "url": "https://ravencoin.org", - "source": "https://github.com/trezor/blockbook", - "rpc": "", - "documentation": "https://github.com/trezor/blockbook/blob/master/docs/api.md" + "url": "https://stride.zone/", + "source": "https://github.com/Stride-Labs/stride", + "rpc": "https://stride-rpc.polkachu.com/", + "documentation": "https://docs.stride.zone/docs" } }, { - "id": "poa", - "name": "POA Network", - "coinId": 178, - "symbol": "POA", - "decimals": 18, - "blockchain": "Ethereum", + "id": "axelar", + "name": "Axelar", + "displayName": "Axelar", + "coinId": 50000118, + "symbol": "AXL", + "decimals": 6, + "chainId": "axelar-dojo-1", + "blockchain": "Cosmos", "derivation": [ { - "path": "m/44'/178'/0'/0/0" + "path": "m/44'/118'/0'/0/0" } ], "curve": "secp256k1", - "publicKeyType": "secp256k1Extended", - "chainId": "99", - "addressHasher": "keccak256", + "publicKeyType": "secp256k1", + "hrp": "axelar", + "addressHasher": "sha256ripemd", "explorer": { - "url": "https://blockscout.com", - "txPath": "/poa/core/tx/", - "accountPath": "/poa/core/address/" + "url": "https://www.mintscan.io/axelar", + "txPath": "/txs/", + "accountPath": "/account/" }, "info": { - "url": "https://poa.network", - "source": "https://github.com/poanetwork/parity-ethereum", - "rpc": "https://core.poa.network", - "documentation": "https://eth.wiki/json-rpc/API" + "url": "https://axelar.network/", + "source": "https://github.com/axelarnetwork/axelar-core", + "rpc": "https://axelar-rpc.polkachu.com", + "documentation": "https://docs.axelar.dev/" } }, { - "id": "eos", - "name": "EOS", - "coinId": 194, - "symbol": "EOS", - "decimals": 4, - "blockchain": "EOS", + "id": "crescent", + "name": "Crescent", + "displayName": "Crescent", + "coinId": 60000118, + "symbol": "CRE", + "decimals": 6, + "chainId": "crescent-1", + "blockchain": "Cosmos", "derivation": [ { - "path": "m/44'/194'/0'/0/0" + "path": "m/44'/118'/0'/0/0" } ], "curve": "secp256k1", "publicKeyType": "secp256k1", + "hrp": "cre", + "addressHasher": "sha256ripemd", "explorer": { - "url": "https://bloks.io", - "txPath": "/transaction/", + "url": "https://www.mintscan.io/crescent", + "txPath": "/txs/", "accountPath": "/account/" }, "info": { - "url": "http://eos.io", - "source": "https://github.com/eosio/eos", - "rpc": "", - "documentation": "https://developers.eos.io/eosio-nodeos/reference" + "url": "https://crescent.network/", + "source": "https://github.com/crescent-network/crescent", + "rpc": "https://crescent-rpc.polkachu.com", + "documentation": "https://docs.crescent.network/introduction/what-is-crescent" } }, { - "id": "tron", - "name": "Tron", - "coinId": 195, - "symbol": "TRX", + "id": "kujira", + "name": "Kujira", + "displayName": "Kujira", + "coinId": 70000118, + "symbol": "KUJI", "decimals": 6, - "blockchain": "Tron", + "chainId": "kaiyo-1", + "blockchain": "Cosmos", "derivation": [ { - "path": "m/44'/195'/0'/0/0" + "path": "m/44'/118'/0'/0/0" } ], "curve": "secp256k1", - "publicKeyType": "secp256k1Extended", + "publicKeyType": "secp256k1", + "hrp": "kujira", + "addressHasher": "sha256ripemd", "explorer": { - "url": "https://tronscan.org", - "txPath": "/#/transaction/", - "accountPath": "/#/address/" + "url": "https://www.mintscan.io/kujira", + "txPath": "/txs/", + "accountPath": "/account/" }, "info": { - "url": "https://tron.network", - "source": "https://github.com/tronprotocol/java-tron", - "rpc": "https://api.trongrid.io", - "documentation": "https://developers.tron.network/docs/tron-wallet-rpc-api" + "url": "https://kujira.app/", + "source": "https://github.com/Team-Kujira/core", + "rpc": "https://kujira-rpc.polkachu.com", + "documentation": "https://docs.kujira.app/introduction/readme" } }, { - "id": "fio", - "name": "FIO", - "coinId": 235, - "symbol": "FIO", - "decimals": 9, - "blockchain": "FIO", + "id": "comdex", + "name": "Comdex", + "displayName": "Comdex", + "coinId": 80000118, + "symbol": "CMDX", + "decimals": 6, + "chainId": "comdex-1", + "blockchain": "Cosmos", "derivation": [ { - "path": "m/44'/235'/0'/0/0" + "path": "m/44'/118'/0'/0/0" } ], "curve": "secp256k1", "publicKeyType": "secp256k1", - "url": "https://fioprotocol.io/", + "hrp": "comdex", + "addressHasher": "sha256ripemd", "explorer": { - "url": "https://explorer.fioprotocol.io", - "txPath": "/transaction/", - "accountPath": "/account/" + "url": "https://www.mintscan.io/comdex", + "txPath": "/txs/", + "accountPath": "/account/", + "sampleTx": "04C790D09A40EE958DBDD385B679B5EB60C10F9BC1389CC8F896DC9193A5ED6C", + "sampleAccount": "comdex1jz7av7cq45gh5hhrugtak7lkps2ga5v0u64nz6" }, "info": { - "url": "https://fioprotocol.io", - "source": "https://github.com/fioprotocol/fio", - "rpc": "https://mainnet.fioprotocol.io", - "documentation": "https://developers.fioprotocol.io" + "url": "https://comdex.one/", + "documentation": "https://docs.comdex.one/" } }, { - "id": "nimiq", - "name": "Nimiq", - "coinId": 242, - "symbol": "NIM", - "decimals": 5, - "blockchain": "Nimiq", + "id": "neutron", + "name": "Neutron", + "displayName": "Neutron", + "coinId": 90000118, + "symbol": "NTRN", + "decimals": 6, + "chainId": "neutron-1", + "blockchain": "Cosmos", "derivation": [ { - "path": "m/44'/242'/0'/0'" + "path": "m/44'/118'/0'/0/0" } ], - "curve": "ed25519", - "publicKeyType": "ed25519", + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "hrp": "neutron", + "addressHasher": "sha256ripemd", "explorer": { - "url": "https://nimiq.watch", - "txPath": "/#", - "accountPath": "/#" + "url": "https://www.mintscan.io/neutron", + "txPath": "/txs/", + "accountPath": "/account/", + "sampleTx": "E18BA087009A05EB6A15A22FE30BA99379B909F74A74120E6F92B9882C45F0D7", + "sampleAccount": "neutron1pm4af8pcurxssdxztqw9rexx5f8zfq7uzqfmy8" }, "info": { - "url": "https://nimiq.com", - "source": "https://github.com/nimiq/core-rs", - "rpc": "", - "documentation": "https://github.com/nimiq/core-js/wiki/JSON-RPC-API" + "url": "https://neutron.org/", + "documentation": "https://docs.neutron.org/" } }, { - "id": "algorand", - "name": "Algorand", - "coinId": 283, - "symbol": "ALGO", + "id": "sommelier", + "name": "Sommelier", + "displayName": "Sommelier", + "coinId": 11000118, + "symbol": "SOMM", "decimals": 6, - "blockchain": "Algorand", + "chainId": "sommelier-3", + "blockchain": "Cosmos", "derivation": [ { - "path": "m/44'/283'/0'/0'/0'" + "path": "m/44'/118'/0'/0/0" } ], - "curve": "ed25519", - "publicKeyType": "ed25519", + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "hrp": "somm", + "addressHasher": "sha256ripemd", "explorer": { - "url": "https://algoexplorer.io", - "txPath": "/tx/", - "accountPath": "/address/", - "sampleTx": "CR7POXFTYDLC7TV3IXHA7AZKWABUJC52BACLHJQNXAKZJGRPQY3A", - "sampleAccount": "J4AEINCSSLDA7LNBNWM4ZXFCTLTOZT5LG3F5BLMFPJYGFWVCMU37EZI2AM" + "url": "https://www.mintscan.io/sommelier", + "txPath": "/txs/", + "accountPath": "/account/", + "sampleTx": "E73A9E5E534777DDADF7F69A5CB41972894B862D1763FA4081FE913D8D3A5E80", + "sampleAccount": "somm10d5wmqvezwtj20u5hg3wuvwucce2nhsy0tzqgn" }, "info": { - "url": "https://www.algorand.com/", - "source": "https://github.com/algorand/go-algorand", - "rpc": "https://indexer.algorand.network", - "documentation": "https://developer.algorand.org/docs/algod-rest-paths" + "url": "https://www.sommelier.finance/" } }, { - "id": "iotex", - "name": "IoTeX", - "coinId": 304, - "symbol": "IOTX", - "decimals": 18, - "blockchain": "IoTeX", + "id": "fetchai", + "name": "FetchAI", + "displayName": "Fetch AI", + "coinId": 12000118, + "symbol": "FET", + "decimals": 6, + "chainId": "fetchhub-4", + "blockchain": "Cosmos", "derivation": [ { - "path": "m/44'/304'/0'/0/0" + "path": "m/44'/118'/0'/0/0" } ], "curve": "secp256k1", - "publicKeyType": "secp256k1Extended", - "hrp": "io", + "publicKeyType": "secp256k1", + "hrp": "fetch", + "addressHasher": "sha256ripemd", "explorer": { - "url": "https://iotexscan.io", - "txPath": "/action/", - "accountPath": "/address/" + "url": "https://www.mintscan.io/fetchai", + "txPath": "/txs/", + "accountPath": "/account/", + "sampleTx": "7EB4F6C26809BA047F81CEFD0889775AC8522B7B8AF559B436083BE7039C5EA6", + "sampleAccount": "fetch1t3qet68dr0qkmrjtq89lrx837qa2t05265qy6s" }, "info": { - "url": "https://iotex.io", - "source": "https://github.com/iotexproject/iotex-core", - "rpc": "", - "documentation": "https://docs.iotex.io/#api" + "url": "https://fetch.ai/", + "documentation": "https://docs.fetch.ai/" } }, { - "id": "nervos", - "name": "Nervos", - "coinId": 309, - "symbol": "CKB", - "decimals": 8, - "blockchain": "Nervos", + "id": "mars", + "name": "Mars", + "displayName": "Mars Hub", + "coinId": 13000118, + "symbol": "MARS", + "decimals": 6, + "chainId": "mars-1", + "blockchain": "Cosmos", "derivation": [ { - "path": "m/44'/309'/0'/0/0" + "path": "m/44'/118'/0'/0/0" } ], "curve": "secp256k1", "publicKeyType": "secp256k1", - "hrp": "ckb", + "hrp": "mars", + "addressHasher": "sha256ripemd", "explorer": { - "url": "https://explorer.nervos.org", - "txPath": "/transaction/", - "accountPath": "/address/" + "url": "https://www.mintscan.io/mars-protocol", + "txPath": "/txs/", + "accountPath": "/account/", + "sampleTx": "C12120760C71189A678739E0F1FD4EFAF2C29EA660B57A359AC728F89FAA7528", + "sampleAccount": "mars1nnjy6nct405pzfaqjm3dsyw0pf0kyw72vhw4pr" }, "info": { - "url": "https://nervos.org", - "source": "https://github.com/nervosnetwork/ckb", - "rpc": "https://mainnet.ckb.dev/rpc", - "documentation": "https://github.com/nervosnetwork/rfcs" + "url": "https://marsprotocol.io/", + "documentation": "https://docs.marsprotocol.io/" } }, { - "id": "zilliqa", - "name": "Zilliqa", - "coinId": 313, - "symbol": "ZIL", - "decimals": 12, - "blockchain": "Zilliqa", + "id": "umee", + "name": "Umee", + "displayName": "Umee", + "coinId": 14000118, + "symbol": "UMEE", + "decimals": 6, + "chainId": "umee-1", + "blockchain": "Cosmos", "derivation": [ { - "path": "m/44'/313'/0'/0/0" + "path": "m/44'/118'/0'/0/0" } ], "curve": "secp256k1", "publicKeyType": "secp256k1", - "hrp": "zil", + "hrp": "umee", + "addressHasher": "sha256ripemd", "explorer": { - "url": "https://viewblock.io", - "txPath": "/zilliqa/tx/", - "accountPath": "/zilliqa/address/" + "url": "https://www.mintscan.io/umee", + "txPath": "/txs/", + "accountPath": "/account/", + "sampleTx": "65B4B52C5F324F2287540847A114F645D89D544D99F793879FB3DBFF2CFEFC84", + "sampleAccount": "umee16934q0qf4akw8qruy5y8v748rvtxxjckgsecq4" }, "info": { - "url": "https://zilliqa.com", - "source": "https://github.com/Zilliqa/Zilliqa", - "rpc": "https://api.zilliqa.com", - "documentation": "https://apidocs.zilliqa.com" + "url": "https://umee.cc/", + "documentation": "https://umeeversity.umee.cc/developers/" } }, { - "id": "terra", - "name": "Terra", - "displayName": "Terra Classic", - "coinId": 330, - "symbol": "LUNC", + "id": "noble", + "name": "Noble", + "displayName": "Noble", + "coinId": 18000118, + "symbol": "USDC", "decimals": 6, + "chainId": "noble-1", "blockchain": "Cosmos", - "chainId": "columbus-5", "derivation": [ { - "path": "m/44'/330'/0'/0/0" + "path": "m/44'/118'/0'/0/0" } ], "curve": "secp256k1", "publicKeyType": "secp256k1", - "hrp": "terra", + "hrp": "noble", "addressHasher": "sha256ripemd", "explorer": { - "url": "https://finder.terra.money/classic", - "txPath": "/tx/", - "accountPath": "/address/" + "url": "https://www.mintscan.io/noble", + "txPath": "/txs/", + "accountPath": "/account/", + "sampleTx": "EA231079975A058FEC28EF372B445763918C098DE033E868E2E035F3F98C59C7", + "sampleAccount": "noble1y2egevq0nyzm7w6a9kpxkw86eqytcvxpwsp6d9" }, "info": { - "url": "https://terra.money", - "source": "https://github.com/terra-project/core", - "rpc": "https://columbus-fcd.terra.dev", - "documentation": "https://docs.terra.money" + "url": "https://nobleassets.xyz/" } }, { - "id": "terrav2", - "name": "TerraV2", - "displayName": "Terra", - "coinId": 10000330, - "symbol": "LUNA", + "id": "sei", + "name": "Sei", + "displayName": "Sei", + "coinId": 19000118, + "symbol": "SEI", "decimals": 6, "blockchain": "Cosmos", + "chainId": "pacific-1", "derivation": [ { - "path": "m/44'/330'/0'/0/0" + "path": "m/44'/118'/0'/0/0" } ], "curve": "secp256k1", "publicKeyType": "secp256k1", - "hrp": "terra", - "chainId": "phoenix-1", + "hrp": "sei", "addressHasher": "sha256ripemd", "explorer": { - "url": "https://finder.terra.money/mainnet", - "txPath": "/tx/", - "accountPath": "/address/" + "url": "https://www.mintscan.io/sei", + "txPath": "/txs/", + "accountPath": "/account/", + "sampleTx": "4A2114EE45317439690F3BEA9C8B6CFA11D42CF978F9487754902D372EEB488C", + "sampleAccount": "sei155hqv2rsypqzq0zpjn72frsxx4l6tcmplw63m2" }, "info": { - "url": "https://terra.money", - "source": "https://github.com/terra-project/core", - "rpc": "https://phoenix-lcd.terra.dev", - "documentation": "https://docs.terra.money" + "url": "https://sei.io/", + "documentation": "https://docs.sei.io/" } }, { - "id": "polkadot", - "name": "Polkadot", - "coinId": 354, - "symbol": "DOT", - "decimals": 10, - "blockchain": "Polkadot", + "id": "tia", + "name": "Tia", + "displayName": "Celestia", + "coinId": 21000118, + "symbol": "TIA", + "decimals": 6, + "blockchain": "Cosmos", + "chainId": "celestia", "derivation": [ { - "path": "m/44'/354'/0'/0'/0'" + "path": "m/44'/118'/0'/0/0" } ], - "curve": "ed25519", - "publicKeyType": "ed25519", - "addressHasher": "keccak256", + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "hrp": "celestia", + "addressHasher": "sha256ripemd", "explorer": { - "url": "https://polkadot.subscan.io", - "txPath": "/extrinsic/", - "accountPath": "/account/" + "url": "https://www.mintscan.io/celestia", + "txPath": "/txs/", + "accountPath": "/account/", + "sampleTx": "FF370C65D8D67B8236F9D3A8D2B1256337C60C1965092CADD1FA970288FCE99B", + "sampleAccount": "celestia1tt4tv4jrs4twdtzwywxd8u65duxgk8y73wvfu2" }, "info": { - "url": "https://polkadot.network/", - "source": "https://github.com/paritytech/polkadot", - "rpc": "", - "documentation": "https://polkadot.js.org/api/substrate/rpc.html" + "url": "https://celestia.org/", + "documentation": "https://docs.celestia.org/" } }, { - "id": "everscale", - "name": "Everscale", - "coinId": 396, - "symbol": "EVER", - "decimals": 9, - "blockchain": "Everscale", + "id": "coreum", + "name": "Coreum", + "displayName": "Coreum", + "coinId": 10000990, + "symbol": "CORE", + "decimals": 6, + "chainId": "coreum-mainnet-1", + "blockchain": "Cosmos", "derivation": [ { - "path": "m/44'/396'/0'/0/0" + "path": "m/44'/990'/0'/0/0" } ], - "curve": "ed25519", - "publicKeyType": "ed25519", + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "hrp": "core", + "addressHasher": "sha256ripemd", "explorer": { - "url": "https://everscan.io", - "txPath": "/transactions/", - "accountPath": "/accounts/", - "sampleTx": "781238b2b0d15cd4cd2e2a0a142753750cd5e1b2c8b506fcede75a90e02f1268", - "sampleAccount": "0:d2bf59964a05dee84a0dd1ddc0ad83ba44d49719cf843d689dc8b726d0fb59d8" + "url": "https://www.mintscan.io/coreum", + "txPath": "/txs/", + "accountPath": "/account/", + "sampleTx": "32A4AE2AE6AAE31E75EDDADE0AB9F1499ABD5AD8D3F261ADEF2805CD46FF74E7", + "sampleAccount": "core1zmwdnfpwuymwn0fkwnj2aaje34npd5sqgjxq9v" }, "info": { - "url": "https://everscale.network/", - "source": "https://github.com/tonlabs/evernode-ds", - "rpc": "https://evercloud.dev", - "documentation": "https://docs.everos.dev/evernode-platform/products/evercloud/get-started" + "url": "https://www.coreum.com/", + "documentation": "https://www.coreum.com/developers" } }, { - "id": "near", - "name": "NEAR", - "coinId": 397, - "symbol": "NEAR", - "decimals": 24, - "blockchain": "NEAR", + "id": "quasar", + "name": "Quasar", + "displayName": "Quasar", + "coinId": 15000118, + "symbol": "QSR", + "decimals": 6, + "chainId": "quasar-1", + "blockchain": "Cosmos", "derivation": [ { - "path": "m/44'/397'/0'" + "path": "m/44'/118'/0'/0/0" } ], - "curve": "ed25519", - "publicKeyType": "ed25519", + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "hrp": "quasar", + "addressHasher": "sha256ripemd", "explorer": { - "url": "https://explorer.near.org", - "txPath": "/transactions/", - "accountPath": "/accounts/" + "url": "https://www.mintscan.io/quasar", + "txPath": "/txs/", + "accountPath": "/account/", + "sampleTx": "2898B89C98FE1E8CF1E05A37E4EE5EE5ED83FD957B0CAEE53DE39FC82BF1A033", + "sampleAccount": "quasar1cqu6w425slheul3jsmyt6q0ec0rs0w0ugkst3k" }, "info": { - "url": "https://nearprotocol.com", - "source": "https://github.com/nearprotocol/nearcore", - "rpc": "https://rpc.nearprotocol.com", - "documentation": "https://docs.nearprotocol.com" + "url": "https://www.quasar.fi/", + "documentation": "https://docs.quasar.fi/" } }, { - "id": "aion", - "name": "Aion", - "coinId": 425, - "symbol": "AION", - "decimals": 18, - "blockchain": "Aion", + "id": "persistence", + "name": "Persistence", + "displayName": "Persistence", + "coinId": 16000118, + "symbol": "XPRT", + "decimals": 6, + "chainId": "core-1", + "blockchain": "Cosmos", "derivation": [ { - "path": "m/44'/425'/0'/0'/0'" + "path": "m/44'/118'/0'/0/0" } ], - "curve": "ed25519", - "publicKeyType": "ed25519", + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "hrp": "persistence", + "addressHasher": "sha256ripemd", "explorer": { - "url": "https://mainnet.aion.network", - "txPath": "/#/transaction/", - "accountPath": "/#/account/" + "url": "https://www.mintscan.io/persistence", + "txPath": "/txs/", + "accountPath": "/account/", + "sampleTx": "BBD9DEE03A8D7538D8E7398217467F4A2B5690D15773E8A6442E6AEEEFA21E64", + "sampleAccount": "persistence10ys69560pqr6zmqam80g8s0smtjw6p3ugzmy3u" }, "info": { - "url": "https://aion.network", - "source": "https://github.com/aionnetwork/aion", - "rpc": "", - "documentation": "https://github.com/aionnetwork/aion/wiki/JSON-RPC-API-Docs" + "url": "https://persistence.one/", + "documentation": "https://docs.persistence.one/" } }, { - "id": "kusama", - "name": "Kusama", - "coinId": 434, - "symbol": "KSM", - "decimals": 12, - "blockchain": "Kusama", + "id": "akash", + "name": "Akash", + "displayName": "Akash", + "coinId": 17000118, + "symbol": "AKT", + "decimals": 6, + "chainId": "akashnet-2", + "blockchain": "Cosmos", "derivation": [ { - "path": "m/44'/434'/0'/0'/0'" + "path": "m/44'/118'/0'/0/0" } ], - "curve": "ed25519", - "publicKeyType": "ed25519", - "addressHasher": "keccak256", + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "hrp": "akash", + "addressHasher": "sha256ripemd", "explorer": { - "url": "https://kusama.subscan.io", - "txPath": "/extrinsic/", + "url": "https://www.mintscan.io/akash", + "txPath": "/txs/", "accountPath": "/account/", - "sampleTx": "0xcbe0c2e2851c1245bedaae4d52f06eaa6b4784b786bea2f0bff11af7715973dd", - "sampleAccount": "DbCNECPna3k6MXFWWNZa5jGsuWycqEE6zcUxZYkxhVofrFk" + "sampleTx": "C0083856344425908D5333D4325E3E0DE9D697BA568C6D99C34303819F615D25", + "sampleAccount": "akash1f4nskxfw8ufhwnajh7xwt0wmdtxm02vwta6krg" }, "info": { - "url": "https://kusama.network", - "source": "https://github.com/paritytech/polkadot", - "rpc": "wss://kusama-rpc.polkadot.io/", - "documentation": "https://polkadot.js.org/api/substrate/rpc.html" + "url": "https://akash.network/", + "documentation": "https://docs.akash.network/" } }, { - "id": "aeternity", - "name": "Aeternity", - "coinId": 457, - "symbol": "AE", - "decimals": 18, - "blockchain": "Aeternity", + "id": "zcash", + "name": "Zcash", + "coinId": 133, + "symbol": "ZEC", + "decimals": 8, + "blockchain": "Zcash", "derivation": [ { - "path": "m/44'/457'/0'/0'/0'" + "path": "m/44'/133'/0'/0/0", + "xpub": "xpub", + "xprv": "xprv" } ], - "curve": "ed25519", - "publicKeyType": "ed25519", + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "staticPrefix": 28, + "p2pkhPrefix": 184, + "p2shPrefix": 189, + "publicKeyHasher": "sha256ripemd", + "base58Hasher": "sha256d", "explorer": { - "url": "https://explorer.aepps.com", - "txPath": "/transactions/", - "accountPath": "/account/transactions/" + "url": "https://blockchair.com/zcash", + "txPath": "/transaction/", + "accountPath": "/address/", + "sampleTx": "f2438a93039faf08d39bd3df1f7b5f19a2c29ffe8753127e2956ab4461adab35", + "sampleAccount": "t1Yfrf1dssDLmaMBsq2LFKWPbS5vH3nGpa2" }, "info": { - "url": "https://aeternity.com", - "source": "https://github.com/aeternity/aeternity", - "rpc": "https://sdk-mainnet.aepps.com", - "documentation": "http://aeternity.com/api-docs/" + "url": "https://z.cash", + "source": "https://github.com/trezor/blockbook", + "rpc": "", + "documentation": "https://github.com/trezor/blockbook/blob/master/docs/api.md" } }, { - "id": "kava", - "name": "Kava", - "coinId": 459, - "symbol": "KAVA", - "decimals": 6, - "blockchain": "Cosmos", - "chainId": "kava_2222-10", + "id": "firo", + "name": "Firo", + "coinId": 136, + "symbol": "FIRO", + "decimals": 8, + "blockchain": "Bitcoin", "derivation": [ { - "path": "m/44'/459'/0'/0/0" + "path": "m/44'/136'/0'/0/0", + "xpub": "xpub", + "xprv": "xprv" } ], "curve": "secp256k1", "publicKeyType": "secp256k1", - "hrp": "kava", - "addressHasher": "sha256ripemd", + "p2pkhPrefix": 82, + "p2shPrefix": 7, + "publicKeyHasher": "sha256ripemd", + "base58Hasher": "sha256d", "explorer": { - "url": "https://mintscan.io/kava", - "txPath": "/txs/", - "accountPath": "/account/", - "sampleTx": "2988DF83FCBFAA38179D583A96734CBD071541D6768221BB23111BC8136D5E6A", - "sampleAccount": "kava1jf9aaj9myrzsnmpdr7twecnaftzmku2mdpy2a7" + "url": "https://explorer.firo.org", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "09a60d58b3d17519a42a8eca60750c33b710ca8f3ca71994192e05c248a2a111", + "sampleAccount": "a8ULhhDgfdSiXJhSZVdhb8EuDc6R3ogsaM" }, "info": { - "url": "https://kava.io", - "source": "https://github.com/kava-labs/kava", - "rpc": "https://data.kava.io", - "documentation": "https://rpc.kava.io" + "url": "https://firo.org/", + "source": "https://github.com/firoorg/firo", + "rpc": "", + "documentation": "https://github.com/trezor/blockbook/blob/master/docs/api.md" } }, { - "id": "filecoin", - "name": "Filecoin", - "coinId": 461, - "symbol": "FIL", - "decimals": 18, - "blockchain": "Filecoin", + "id": "komodo", + "name": "Komodo", + "coinId": 141, + "symbol": "KMD", + "decimals": 8, + "blockchain": "Zcash", "derivation": [ { - "path": "m/44'/461'/0'/0/0" + "path": "m/44'/141'/0'/0/0", + "xpub": "xpub", + "xprv": "xprv" } ], "curve": "secp256k1", - "publicKeyType": "secp256k1Extended", + "publicKeyType": "secp256k1", + "p2pkhPrefix": 60, + "p2shPrefix": 85, + "publicKeyHasher": "sha256ripemd", + "base58Hasher": "sha256d", "explorer": { - "url": "https://filfox.info/en", - "txPath": "/message/", + "url": "https://kmdexplorer.io/", + "txPath": "/tx/", "accountPath": "/address/", - "sampleTx": "bafy2bzacedsgjcd6xfhrrymmfrqubb44otlyhvgqkgsh533d5j5hwniiqespm", - "sampleAccount": "f1abjxfbp274xpdqcpuaykwkfb43omjotacm2p3za" + "sampleTx": "f53bd1a5c0f5dc4b60ba9a1882742ea96faa996e1b870795812a29604dd7829e", + "sampleAccount": "RWvfkt8UjbPWXgeZEcgYmKw2vA1bbAx5t2" }, "info": { - "url": "https://filecoin.io/", - "source": "https://github.com/filecoin-project/lotus", + "url": "https://komodoplatform.com", + "source": "https://github.com/KomodoPlatform/komodo", "rpc": "", - "documentation": "https://docs.lotu.sh" + "documentation": "https://developers.komodoplatform.com" } }, { - "id": "bluzelle", - "name": "Bluzelle", - "coinId": 483, - "symbol": "BLZ", + "id": "ripple", + "name": "XRP", + "coinId": 144, + "symbol": "XRP", "decimals": 6, - "blockchain": "Cosmos", + "blockchain": "Ripple", "derivation": [ { - "path": "m/44'/483'/0'/0/0" + "path": "m/44'/144'/0'/0/0" } ], "curve": "secp256k1", "publicKeyType": "secp256k1", - "hrp": "bluzelle", - "addressHasher": "sha256ripemd", "explorer": { - "url": "https://bigdipper.net.bluzelle.com", - "txPath": "/transactions/", - "accountPath": "/account/", - "sampleTx": "AC026E0EC6E33A77D5EA6B9CEF9810699BC2AD8C5582E007E7857457C6D3B819", - "sampleAccount": "bluzelle1q9cryfal7u3jvnq6er5ufety20xtzw6ycx2te9" + "url": "https://bithomp.com", + "txPath": "/explorer/", + "accountPath": "/explorer/", + "sampleTx": "E26AB8F3372D2FC02DEC1FD5674ADAB762D684BFFDBBDF5D674E9D7CF4A47054", + "sampleAccount": "rfkH7EuS1XcSkB9pocy1R6T8F4CsNYixYU" }, "info": { - "url": "https://bluzelle.com", - "source": "https://github.com/bluzelle", - "rpc": "https://bluzelle.github.io/api/", - "documentation": "https://docs.bluzelle.com/developers/" + "url": "https://ripple.com/xrp", + "source": "https://github.com/ripple/rippled", + "rpc": "https://s2.ripple.com:51234", + "documentation": "https://xrpl.org/rippled-api.html" } }, { - "id": "band", - "name": "BandChain", - "symbol": "BAND", - "coinId": 494, - "decimals": 6, - "blockchain": "Cosmos", - "chainId": "laozi-mainnet", + "id": "bitcoincash", + "name": "Bitcoin Cash", + "coinId": 145, + "symbol": "BCH", + "decimals": 8, + "blockchain": "BitcoinCash", "derivation": [ { - "path": "m/44'/494'/0'/0/0" + "path": "m/44'/145'/0'/0/0", + "xpub": "xpub", + "xprv": "xprv" } ], "curve": "secp256k1", "publicKeyType": "secp256k1", - "hrp": "band", - "addressHasher": "sha256ripemd", + "p2pkhPrefix": 0, + "p2shPrefix": 5, + "hrp": "bitcoincash", + "publicKeyHasher": "sha256ripemd", + "base58Hasher": "sha256d", "explorer": { - "url": "https://scan-wenchang-testnet2.bandchain.org/", - "txPath": "/tx/", - "accountPath": "/account/", - "sampleTx": "473264551D3063A9EC64EC251C61BE92DDDFCF6CC46D026D1E574D83D5447173", - "sampleAccount": "band12nmsm9khdsv0tywge43q3zwj8kkj3hvup9rltp" + "url": "https://blockchair.com", + "txPath": "/bitcoin-cash/transaction/", + "accountPath": "/bitcoin-cash/address/" }, "info": { - "url": "https://bandprotocol.com/", - "source": "https://github.com/bandprotocol/bandchain", - "rpc": "https://api-wt2-lb.bandchain.org", - "documentation": "https://docs.bandchain.org/" + "url": "https://bitcoincash.org", + "source": "https://github.com/trezor/blockbook", + "rpc": "", + "documentation": "https://github.com/trezor/blockbook/blob/master/docs/api.md" } }, { - "id": "theta", - "name": "Theta", - "coinId": 500, - "symbol": "THETA", - "decimals": 18, - "blockchain": "Theta", + "id": "stellar", + "name": "Stellar", + "coinId": 148, + "symbol": "XLM", + "decimals": 7, + "blockchain": "Stellar", "derivation": [ { - "path": "m/44'/500'/0'/0/0" + "path": "m/44'/148'/0'" } ], - "curve": "secp256k1", - "publicKeyType": "secp256k1Extended", + "curve": "ed25519", + "publicKeyType": "ed25519", "explorer": { - "url": "https://explorer.thetatoken.org", - "txPath": "/txs/", - "accountPath": "/account/" + "url": "https://blockchair.com/stellar", + "txPath": "/transaction/", + "accountPath": "/account/", + "sampleTx": "8a7ff7261e8b3f31af7f6ed257c2e9fe7c47afcd9b1ce1be1bfc1bc5f6a3ad9e", + "sampleAccount": "GCILJZQ3CKBKBUJWW4TAM6Q37LJA5MQX6GMSFSQN75BPLWIZ33OPRG52" }, "info": { - "url": "https://www.thetatoken.org", - "source": "https://github.com/thetatoken/theta-protocol-ledger", - "rpc": "", - "documentation": "https://github.com/thetatoken/theta-mainnet-integration-guide/blob/master/docs/api.md#api-reference" + "url": "https://stellar.org", + "source": "https://github.com/stellar/go", + "rpc": "https://horizon.stellar.org", + "documentation": "https://www.stellar.org/developers/horizon/reference" } }, { - "id": "solana", - "name": "Solana", - "coinId": 501, - "symbol": "SOL", - "decimals": 9, - "blockchain": "Solana", + "id": "bitcoingold", + "name": "Bitcoin Gold", + "coinId": 156, + "symbol": "BTG", + "decimals": 8, + "blockchain": "Bitcoin", "derivation": [ { - "path": "m/44'/501'/0'" - }, - { - "name": "solana", - "path": "m/44'/501'/0'/0'" + "path": "m/84'/156'/0'/0/0", + "xpub": "zpub", + "xprv": "zprv" } ], - "curve": "ed25519", - "publicKeyType": "ed25519", + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "p2pkhPrefix": 38, + "p2shPrefix": 23, + "hrp": "btg", + "publicKeyHasher": "sha256ripemd", + "base58Hasher": "sha256d", "explorer": { - "url": "https://solscan.io", + "url": "https://explorer.bitcoingold.org/insight", "txPath": "/tx/", - "accountPath": "/account/", - "sampleTx": "5LmxrEKGchhMuYfw6Qut6CbsvE9pVfb8YvwZKvWssSesDVjHioBCmWKSJQh1WhvcM6CpemhpHNmEMA2a36rzwTa8", - "sampleAccount": "Bxp8yhH9zNwxyE4UqxP7a7hgJ5xTZfxNNft7YJJ2VRjT" + "accountPath": "/address/", + "sampleTx": "2f807d7734de35d2236a1b3d8704eb12954f5f82ea66987949b10e94d9999b23", + "sampleAccount": "GJjz2Du9BoJQ3CPcoyVTHUJZSj62i1693U" }, "info": { - "url": "https://solana.com", - "source": "https://github.com/solana-labs/solana", - "rpc": "https://api.mainnet-beta.solana.com", - "documentation": "https://docs.solana.com" + "url": "https://bitcoingold.org", + "source": "https://github.com/trezor/blockbook", + "rpc": "", + "documentation": "https://github.com/trezor/blockbook/blob/master/docs/api.md" } }, { - "id": "elrond", - "name": "Elrond", - "coinId": 508, - "symbol": "eGLD", - "decimals": 18, - "blockchain": "ElrondNetwork", + "id": "nano", + "name": "Nano", + "coinId": 165, + "symbol": "XNO", + "decimals": 30, + "blockchain": "Nano", "derivation": [ { - "path": "m/44'/508'/0'/0'/0'" + "path": "m/44'/165'/0'" } ], - "curve": "ed25519", - "publicKeyType": "ed25519", - "hrp": "erd", + "curve": "ed25519Blake2bNano", + "publicKeyType": "ed25519Blake2b", + "url": "https://nano.org", "explorer": { - "url": "https://explorer.elrond.com", - "txPath": "/transactions/", - "accountPath": "/address/" + "url": "https://www.nanolooker.com", + "txPath": "/block/", + "accountPath": "/account/", + "sampleTx": "C264DB7BF40738F0CEFF19B606746CB925B713E4B8699A055699E0DC8ABBC70F", + "sampleAccount": "nano_1wpj616kwhe1y38y1mspd8aub8i334cwybqco511iyuxm55zx8d67ptf1tsf" }, "info": { - "url": "https://elrond.com/", - "source": "https://github.com/ElrondNetwork/elrond-go", - "rpc": "https://api.elrond.com", - "documentation": "https://docs.elrond.com" + "url": "https://nano.org", + "source": "https://github.com/nanocurrency/nano-node", + "rpc": "", + "documentation": "https://docs.nano.org/commands/rpc-protocol/" } }, { - "id": "binance", - "name": "Binance", - "displayName": "BNB Beacon Chain", - "coinId": 714, - "symbol": "BNB", + "id": "ravencoin", + "name": "Ravencoin", + "coinId": 175, + "symbol": "RVN", "decimals": 8, - "blockchain": "Binance", + "blockchain": "Bitcoin", "derivation": [ { - "path": "m/44'/714'/0'/0/0" + "path": "m/44'/175'/0'/0/0", + "xpub": "xpub", + "xprv": "xprv" } ], "curve": "secp256k1", "publicKeyType": "secp256k1", - "hrp": "bnb", - "chainId": "Binance-Chain-Tigris", + "p2pkhPrefix": 60, + "p2shPrefix": 122, + "publicKeyHasher": "sha256ripemd", + "base58Hasher": "sha256d", "explorer": { - "url": "https://explorer.binance.org", + "url": "https://blockbook.ravencoin.org", "txPath": "/tx/", - "accountPath": "/address/", - "sampleTx": "A93625C9F9ABEA1A8E31585B30BBB16C34FAE0D172EB5B6B2F834AF077BF06BB", - "sampleAccount": "bnb1u7jm0cll5h3224y0tapwn6gf6pr49ytewx4gsz" + "accountPath": "/address/" }, "info": { - "url": "https://binance.org", - "source": "https://github.com/binance-chain/node-binary", - "rpc": "https://dex.binance.org", - "documentation": "https://docs.binance.org/api-reference/dex-api/paths.html" + "url": "https://ravencoin.org", + "source": "https://github.com/trezor/blockbook", + "rpc": "", + "documentation": "https://github.com/trezor/blockbook/blob/master/docs/api.md" } }, { - "id": "vechain", - "name": "VeChain", - "coinId": 818, - "symbol": "VET", + "id": "poa", + "name": "POA Network", + "coinId": 178, + "symbol": "POA", "decimals": 18, - "blockchain": "Vechain", + "blockchain": "Ethereum", "derivation": [ { - "path": "m/44'/818'/0'/0/0" + "path": "m/44'/178'/0'/0/0" } ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", - "chainId": "74", + "chainId": "99", + "addressHasher": "keccak256", "explorer": { - "url": "https://explore.vechain.org", - "txPath": "/transactions/", - "accountPath": "/accounts/" + "url": "https://blockscout.com", + "txPath": "/poa/core/tx/", + "accountPath": "/poa/core/address/" }, "info": { - "url": "https://vechain.org", - "source": "https://github.com/vechain/thor", - "rpc": "", - "documentation": "https://doc.vechainworld.io/docs" + "url": "https://poa.network", + "source": "https://github.com/poanetwork/parity-ethereum", + "rpc": "https://core.poa.network", + "documentation": "https://eth.wiki/json-rpc/API" } }, { - "id": "callisto", - "name": "Callisto", - "coinId": 820, - "symbol": "CLO", - "decimals": 18, - "blockchain": "Ethereum", + "id": "eos", + "name": "EOS", + "coinId": 194, + "symbol": "EOS", + "decimals": 4, + "blockchain": "EOS", "derivation": [ { - "path": "m/44'/820'/0'/0/0" + "path": "m/44'/194'/0'/0/0" } ], "curve": "secp256k1", - "publicKeyType": "secp256k1Extended", - "chainId": "820", - "addressHasher": "keccak256", + "publicKeyType": "secp256k1", "explorer": { - "url": "https://explorer.callisto.network", - "txPath": "/tx/", - "accountPath": "/addr/" + "url": "https://bloks.io", + "txPath": "/transaction/", + "accountPath": "/account/" }, "info": { - "url": "https://callisto.network", - "source": "https://github.com/EthereumCommonwealth/go-callisto", - "rpc": "https://clo-geth.0xinfra.com", - "documentation": "https://eth.wiki/json-rpc/API" + "url": "http://eos.io", + "source": "https://github.com/eosio/eos", + "rpc": "", + "documentation": "https://developers.eos.io/eosio-nodeos/reference" } }, { - "id": "neo", - "name": "NEO", - "coinId": 888, - "symbol": "NEO", - "decimals": 8, - "blockchain": "NEO", + "id": "wax", + "name": "WAX", + "coinId": 14001, + "symbol": "WAXP", + "decimals": 4, + "blockchain": "EOS", "derivation": [ { - "path": "m/44'/888'/0'/0/0" + "path": "m/44'/194'/0'/0/0" } ], - "curve": "nist256p1", - "publicKeyType": "nist256p1", + "curve": "secp256k1", + "publicKeyType": "secp256k1", "explorer": { - "url": "https://neoscan.io", + "url": "https://wax.bloks.io", "txPath": "/transaction/", - "accountPath": "/address/", - "sampleTx": "e0ddf7c81c732df26180aca0c36d5868ad009fdbbe6e7a56ebafc14bba41cd53", - "sampleAccount": "AcxuqWhTureEQGeJgbmtSWNAtssjMLU7pb" + "accountPath": "/account/" }, "info": { - "url": "https://neo.org", - "source": "https://github.com/neo-project/neo", - "rpc": "http://seed1.ngd.network:10332", - "documentation": "https://neo.org/eco" + "url": "http://wax.io", + "source": "https://github.com/worldwide-asset-exchange/wax-blockchain", + "rpc": "https://wax.blacklusion.io", + "documentation": "https://https://developer.wax.io" } }, { - "id": "tomochain", - "name": "TomoChain", - "coinId": 889, - "symbol": "TOMO", - "decimals": 18, - "blockchain": "Ethereum", + "id": "tron", + "name": "Tron", + "coinId": 195, + "symbol": "TRX", + "decimals": 6, + "blockchain": "Tron", "derivation": [ { - "path": "m/44'/889'/0'/0/0" + "path": "m/44'/195'/0'/0/0" } ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", - "chainId": "88", - "addressHasher": "keccak256", "explorer": { - "url": "https://tomoscan.io", - "txPath": "/tx/", - "accountPath": "/address/" + "url": "https://tronscan.org", + "txPath": "/#/transaction/", + "accountPath": "/#/address/" }, "info": { - "url": "https://tomochain.com", - "source": "https://github.com/tomochain/tomochain", - "rpc": "https://rpc.tomochain.com", - "documentation": "https://eth.wiki/json-rpc/API" + "url": "https://tron.network", + "source": "https://github.com/tronprotocol/java-tron", + "rpc": "https://api.trongrid.io", + "documentation": "https://developers.tron.network/docs/tron-wallet-rpc-api" } }, { - "id": "thundertoken", - "name": "Thunder Token", - "coinId": 1001, - "symbol": "TT", - "decimals": 18, - "blockchain": "Ethereum", + "id": "fio", + "name": "FIO", + "coinId": 235, + "symbol": "FIO", + "decimals": 9, + "blockchain": "FIO", "derivation": [ { - "path": "m/44'/1001'/0'/0/0" + "path": "m/44'/235'/0'/0/0" } ], "curve": "secp256k1", - "publicKeyType": "secp256k1Extended", - "chainId": "108", - "addressHasher": "keccak256", + "publicKeyType": "secp256k1", + "url": "https://fioprotocol.io/", "explorer": { - "url": "https://scan.thundercore.com", - "txPath": "/transactions/", - "accountPath": "/address/" + "url": "https://explorer.fioprotocol.io", + "txPath": "/transaction/", + "accountPath": "/account/", + "sampleTx": "930d1d3cf8988b39b5f64b64e9d61314a3e05a155d9e3505bdf863aab1adddf3", + "sampleAccount": "f5axfpgffiqz" }, "info": { - "url": "https://thundercore.com", - "source": "https://github.com/thundercore/pala", - "rpc": "https://mainnet-rpc.thundercore.com", - "documentation": "https://eth.wiki/json-rpc/API" + "url": "https://fioprotocol.io", + "source": "https://github.com/fioprotocol/fio", + "rpc": "https://mainnet.fioprotocol.io", + "documentation": "https://developers.fioprotocol.io" } }, { - "id": "harmony", - "name": "Harmony", - "coinId": 1023, - "symbol": "ONE", - "decimals": 18, - "blockchain": "Harmony", + "id": "nimiq", + "name": "Nimiq", + "coinId": 242, + "symbol": "NIM", + "decimals": 5, + "blockchain": "Nimiq", "derivation": [ { - "path": "m/44'/1023'/0'/0/0" + "path": "m/44'/242'/0'/0'" } ], - "curve": "secp256k1", - "publicKeyType": "secp256k1Extended", - "hrp": "one", + "curve": "ed25519", + "publicKeyType": "ed25519", "explorer": { - "url": "https://explorer.harmony.one", - "txPath": "/#/tx/", - "accountPath": "/#/address/" + "url": "https://nimiq.watch", + "txPath": "/#", + "accountPath": "/#" }, "info": { - "url": "https://harmony.one", - "source": "https://github.com/harmony-one/go-sdk", + "url": "https://nimiq.com", + "source": "https://github.com/nimiq/core-rs", "rpc": "", - "documentation": "https://docs.harmony.one/home/harmony-networks/harmony-network-overview/mainnet" + "documentation": "https://github.com/nimiq/core-js/wiki/JSON-RPC-API" } }, { - "id": "oasis", - "name": "Oasis", - "coinId": 474, - "symbol": "ROSE", - "decimals": 9, - "blockchain": "OasisNetwork", + "id": "algorand", + "name": "Algorand", + "coinId": 283, + "symbol": "ALGO", + "decimals": 6, + "blockchain": "Algorand", "derivation": [ { - "path": "m/44'/474'/0'" + "path": "m/44'/283'/0'/0'/0'" } ], "curve": "ed25519", "publicKeyType": "ed25519", - "hrp": "oasis", "explorer": { - "url": "https://oasisscan.com", - "txPath": "/transactions/", - "accountPath": "/accounts/detail/", - "sampleTx": "0b9bd4983f1c88a1c71bf33562b6ba02b3064e01697d15a0de4bfe1922ec74b8", - "sampleAccount": "oasis1qrx376dmwuckmruzn9vq64n49clw72lywctvxdf4" + "url": "https://app.dappflow.org/explorer", + "txPath": "/transaction/", + "accountPath": "/account/", + "sampleTx": "CR7POXFTYDLC7TV3IXHA7AZKWABUJC52BACLHJQNXAKZJGRPQY3A", + "sampleAccount": "J4AEINCSSLDA7LNBNWM4ZXFCTLTOZT5LG3F5BLMFPJYGFWVCMU37EZI2AM" }, "info": { - "url": "https://oasisprotocol.org/", - "source": "https://github.com/oasisprotocol/oasis-core", - "rpc": "https://rosetta.oasis.dev/api/v1", - "documentation": "https://docs.oasis.dev/oasis-core/" + "url": "https://www.algorand.com/", + "source": "https://github.com/algorand/go-algorand", + "rpc": "https://indexer.algorand.network", + "documentation": "https://developer.algorand.org/docs/algod-rest-paths" } }, { - "id": "ontology", - "name": "Ontology", - "coinId": 1024, - "symbol": "ONT", - "decimals": 0, - "blockchain": "Ontology", + "id": "iotex", + "name": "IoTeX", + "coinId": 304, + "symbol": "IOTX", + "decimals": 18, + "blockchain": "IoTeX", "derivation": [ { - "path": "m/44'/1024'/0'/0/0" + "path": "m/44'/304'/0'/0/0" } ], - "curve": "nist256p1", - "publicKeyType": "nist256p1", + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "hrp": "io", "explorer": { - "url": "https://explorer.ont.io", - "txPath": "/transaction/", + "url": "https://iotexscan.io", + "txPath": "/action/", "accountPath": "/address/" }, "info": { - "url": "https://ont.io", - "source": "https://github.com/ontio/ontology", - "rpc": "http://dappnode1.ont.io:20336", - "documentation": "https://github.com/ontio/ontology/blob/master/docs/specifications/rpc_api.md" + "url": "https://iotex.io", + "source": "https://github.com/iotexproject/iotex-core", + "rpc": "", + "documentation": "https://docs.iotex.io/#api" } }, { - "id": "tezos", - "name": "Tezos", - "coinId": 1729, - "symbol": "XTZ", - "decimals": 6, - "blockchain": "Tezos", + "id": "iotexevm", + "name": "IoTeX EVM", + "displayName": "IoTeX EVM", + "coinId": 10004689, + "symbol": "IOTX", + "decimals": 18, + "blockchain": "Ethereum", "derivation": [ { - "path": "m/44'/1729'/0'/0'" + "path": "m/44'/304'/0'/0/0" } ], - "curve": "ed25519", - "publicKeyType": "ed25519", + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "4689", + "addressHasher": "keccak256", "explorer": { - "url": "https://tzstats.com", - "txPath": "/", - "accountPath": "/" + "url": "https://iotexscan.io", + "txPath": "/tx/", + "accountPath": "/address/" }, "info": { - "url": "https://tezos.com", - "source": "https://gitlab.com/tezos/tezos", - "rpc": "https://rpc.tulip.tools/mainnet", - "documentation": "https://tezos.gitlab.io/tezos/api/rpc.html" + "url": "https://iotex.io/", + "documentation": "https://iotex.io/developers" } }, { - "id": "cardano", - "name": "Cardano", - "coinId": 1815, - "symbol": "ADA", - "decimals": 6, - "blockchain": "Cardano", + "id": "nervos", + "name": "Nervos", + "coinId": 309, + "symbol": "CKB", + "decimals": 8, + "blockchain": "Nervos", "derivation": [ { - "path": "m/1852'/1815'/0'/0/0" + "path": "m/44'/309'/0'/0/0" } ], - "curve": "ed25519ExtendedCardano", - "publicKeyType": "ed25519Cardano", - "hrp": "addr", + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "hrp": "ckb", "explorer": { - "url": "https://cardanoscan.io", + "url": "https://explorer.nervos.org", "txPath": "/transaction/", - "accountPath": "/address/", - "sampleTx": "b7a6c5cadab0f64bdc89c77ee4a351463aba5c33f2cef6bbd6542a74a90a3af3", - "sampleAccount": "addr1s3xuxwfetyfe7q9u3rfn6je9stlvcgmj8rezd87qjjegdtxm3y3f2mgtn87mrny9r77gm09h6ecslh3gmarrvrp9n4yzmdnecfxyu59jz29g8j" + "accountPath": "/address/" }, "info": { - "url": "https://www.cardano.org", - "source": "https://github.com/input-output-hk/cardano-sl", - "rpc": "", - "documentation": "https://cardanodocs.com/introduction/" + "url": "https://nervos.org", + "source": "https://github.com/nervosnetwork/ckb", + "rpc": "https://mainnet.ckb.dev/rpc", + "documentation": "https://github.com/nervosnetwork/rfcs" } }, { - "id": "kin", - "name": "Kin", - "coinId": 2017, - "symbol": "KIN", - "decimals": 5, - "blockchain": "Stellar", - "derivation": [ + "id": "zilliqa", + "name": "Zilliqa", + "coinId": 313, + "symbol": "ZIL", + "decimals": 12, + "blockchain": "Zilliqa", + "derivation": [ + { + "path": "m/44'/313'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "hrp": "zil", + "explorer": { + "url": "https://viewblock.io", + "txPath": "/zilliqa/tx/", + "accountPath": "/zilliqa/address/" + }, + "info": { + "url": "https://zilliqa.com", + "source": "https://github.com/Zilliqa/Zilliqa", + "rpc": "https://api.zilliqa.com", + "documentation": "https://apidocs.zilliqa.com" + } + }, + { + "id": "terra", + "name": "Terra", + "displayName": "Terra Classic", + "coinId": 330, + "symbol": "LUNC", + "decimals": 6, + "blockchain": "Cosmos", + "chainId": "columbus-5", + "derivation": [ + { + "path": "m/44'/330'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "hrp": "terra", + "addressHasher": "sha256ripemd", + "explorer": { + "url": "https://finder.terra.money/classic", + "txPath": "/tx/", + "accountPath": "/address/" + }, + "info": { + "url": "https://terra.money", + "source": "https://github.com/terra-project/core", + "rpc": "https://columbus-fcd.terra.dev", + "documentation": "https://docs.terra.money" + } + }, + { + "id": "terrav2", + "name": "TerraV2", + "displayName": "Terra", + "coinId": 10000330, + "symbol": "LUNA", + "decimals": 6, + "blockchain": "Cosmos", + "derivation": [ + { + "path": "m/44'/330'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "hrp": "terra", + "chainId": "phoenix-1", + "addressHasher": "sha256ripemd", + "explorer": { + "url": "https://finder.terra.money/mainnet", + "txPath": "/tx/", + "accountPath": "/address/" + }, + "info": { + "url": "https://terra.money", + "source": "https://github.com/terra-project/core", + "rpc": "https://phoenix-lcd.terra.dev", + "documentation": "https://docs.terra.money" + } + }, + { + "id": "polkadot", + "name": "Polkadot", + "coinId": 354, + "symbol": "DOT", + "decimals": 10, + "blockchain": "Polkadot", + "derivation": [ + { + "path": "m/44'/354'/0'/0'/0'" + } + ], + "curve": "ed25519", + "publicKeyType": "ed25519", + "addressHasher": "keccak256", + "ss58Prefix": 0, + "explorer": { + "url": "https://polkadot.subscan.io", + "txPath": "/extrinsic/", + "accountPath": "/account/", + "sampleTx": "0xb96f97d8ee508f420e606e1a6dcc74b88844713ddec2bd7cf4e3aa6b1d6beef4", + "sampleAccount": "13hJFqnkqQbmgnGQteGntjMjTdmTBRE8Z93JqxsrpgT7Yjd2" + }, + "info": { + "url": "https://polkadot.network/", + "source": "https://github.com/paritytech/polkadot", + "rpc": "", + "documentation": "https://polkadot.js.org/api/substrate/rpc.html" + } + }, + { + "id": "everscale", + "name": "Everscale", + "coinId": 396, + "symbol": "EVER", + "decimals": 9, + "blockchain": "Everscale", + "derivation": [ + { + "path": "m/44'/396'/0'/0/0" + } + ], + "curve": "ed25519", + "publicKeyType": "ed25519", + "explorer": { + "url": "https://everscan.io", + "txPath": "/transactions/", + "accountPath": "/accounts/", + "sampleTx": "781238b2b0d15cd4cd2e2a0a142753750cd5e1b2c8b506fcede75a90e02f1268", + "sampleAccount": "0:d2bf59964a05dee84a0dd1ddc0ad83ba44d49719cf843d689dc8b726d0fb59d8" + }, + "info": { + "url": "https://everscale.network/", + "source": "https://github.com/tonlabs/evernode-ds", + "rpc": "https://evercloud.dev", + "documentation": "https://docs.everos.dev/evernode-platform/products/evercloud/get-started" + } + }, + { + "id": "near", + "name": "NEAR", + "coinId": 397, + "symbol": "NEAR", + "decimals": 24, + "blockchain": "NEAR", + "derivation": [ + { + "path": "m/44'/397'/0'" + } + ], + "curve": "ed25519", + "publicKeyType": "ed25519", + "explorer": { + "url": "https://nearblocks.io", + "txPath": "/txns/", + "accountPath": "/address/", + "sampleTx": "FPQAMaVnvFHNwNBJWnTttXfdJhp5FvMGGDJEesB8gvbL", + "sampleAccount": "test-trust.vlad.near" + }, + "info": { + "url": "https://nearprotocol.com", + "source": "https://github.com/nearprotocol/nearcore", + "rpc": "https://rpc.nearprotocol.com", + "documentation": "https://docs.nearprotocol.com" + } + }, + { + "id": "aion", + "name": "Aion", + "coinId": 425, + "symbol": "AION", + "decimals": 18, + "blockchain": "Aion", + "derivation": [ + { + "path": "m/44'/425'/0'/0'/0'" + } + ], + "curve": "ed25519", + "publicKeyType": "ed25519", + "explorer": { + "url": "https://mainnet.aion.network", + "txPath": "/#/transaction/", + "accountPath": "/#/account/" + }, + "info": { + "url": "https://aion.network", + "source": "https://github.com/aionnetwork/aion", + "rpc": "", + "documentation": "https://github.com/aionnetwork/aion/wiki/JSON-RPC-API-Docs" + } + }, + { + "id": "kusama", + "name": "Kusama", + "coinId": 434, + "symbol": "KSM", + "decimals": 12, + "blockchain": "Kusama", + "derivation": [ + { + "path": "m/44'/434'/0'/0'/0'" + } + ], + "curve": "ed25519", + "publicKeyType": "ed25519", + "addressHasher": "keccak256", + "ss58Prefix": 2, + "explorer": { + "url": "https://kusama.subscan.io", + "txPath": "/extrinsic/", + "accountPath": "/account/", + "sampleTx": "0xcbe0c2e2851c1245bedaae4d52f06eaa6b4784b786bea2f0bff11af7715973dd", + "sampleAccount": "DbCNECPna3k6MXFWWNZa5jGsuWycqEE6zcUxZYkxhVofrFk" + }, + "info": { + "url": "https://kusama.network", + "source": "https://github.com/paritytech/polkadot", + "rpc": "wss://kusama-rpc.polkadot.io/", + "documentation": "https://polkadot.js.org/api/substrate/rpc.html" + } + }, + { + "id": "acala", + "name": "Acala", + "coinId": 787, + "symbol": "ACA", + "decimals": 12, + "blockchain": "Polkadot", + "derivation": [ + { + "path": "m/44'/787'/0'/0'/0'" + } + ], + "curve": "ed25519", + "publicKeyType": "ed25519", + "addressHasher": "keccak256", + "ss58Prefix": 10, + "explorer": { + "url": "https://acala.subscan.io", + "txPath": "/extrinsic/", + "accountPath": "/account/", + "sampleTx": "0xf3d58aafb1208bc09d10ba74bbf1c7811dc55a9149c1505256b6fb5603f5047f", + "sampleAccount": "26JqMKx4HJJcmb1kXo24HYYobiK2jURGCq6zuEzFBK3hQ9Ti" + }, + "info": { + "url": "https://acala.network", + "source": "https://github.com/AcalaNetwork/Acala", + "rpc": "wss://acala-rpc.dwellir.com", + "documentation": "https://polkadot.js.org/api/substrate/rpc.html" + } + }, + { + "id": "acalaevm", + "name": "Acala EVM", + "coinId": 10000787, + "slip44": 60, + "symbol": "ACA", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/60'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "787", + "addressHasher": "keccak256", + "explorer": { + "url": "https://blockscout.acala.network", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "0x4b0b151dd71ed8ef3174da18565790bf14f0a903a13e4f3266c7848bc8841593", + "sampleAccount": "0x9d1d97aDFcd324Bbd603D3872BD78e04098510b1" + }, + "info": { + "url": "https://acala.network", + "source": "https://github.com/AcalaNetwork/Acala", + "rpc": "https://eth-rpc-acala.aca-api.network", + "documentation": "https://polkadot.js.org/api/substrate/rpc.html" + } + }, + { + "id": "aeternity", + "name": "Aeternity", + "coinId": 457, + "symbol": "AE", + "decimals": 18, + "blockchain": "Aeternity", + "derivation": [ + { + "path": "m/44'/457'/0'/0'/0'" + } + ], + "curve": "ed25519", + "publicKeyType": "ed25519", + "explorer": { + "url": "https://explorer.aepps.com", + "txPath": "/transactions/", + "accountPath": "/account/transactions/" + }, + "info": { + "url": "https://aeternity.com", + "source": "https://github.com/aeternity/aeternity", + "rpc": "https://sdk-mainnet.aepps.com", + "documentation": "http://aeternity.com/api-docs/" + } + }, + { + "id": "kava", + "name": "Kava", + "coinId": 459, + "symbol": "KAVA", + "decimals": 6, + "blockchain": "Cosmos", + "chainId": "kava_2222-10", + "derivation": [ + { + "path": "m/44'/459'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "hrp": "kava", + "addressHasher": "sha256ripemd", + "explorer": { + "url": "https://mintscan.io/kava", + "txPath": "/txs/", + "accountPath": "/account/", + "sampleTx": "2988DF83FCBFAA38179D583A96734CBD071541D6768221BB23111BC8136D5E6A", + "sampleAccount": "kava1xd39avn2f008jmvua0eupg39zsp2xn3wf802vn" + }, + "info": { + "url": "https://kava.io", + "source": "https://github.com/kava-labs/kava", + "rpc": "https://data.kava.io", + "documentation": "https://rpc.kava.io" + } + }, + { + "id": "filecoin", + "name": "Filecoin", + "coinId": 461, + "symbol": "FIL", + "decimals": 18, + "blockchain": "Filecoin", + "derivation": [ + { + "path": "m/44'/461'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "explorer": { + "url": "https://filfox.info/en", + "txPath": "/message/", + "accountPath": "/address/", + "sampleTx": "bafy2bzacedsgjcd6xfhrrymmfrqubb44otlyhvgqkgsh533d5j5hwniiqespm", + "sampleAccount": "f1abjxfbp274xpdqcpuaykwkfb43omjotacm2p3za" + }, + "info": { + "url": "https://filecoin.io/", + "source": "https://github.com/filecoin-project/lotus", + "rpc": "", + "documentation": "https://docs.lotu.sh" + } + }, + { + "id": "bluzelle", + "name": "Bluzelle", + "coinId": 483, + "symbol": "BLZ", + "decimals": 6, + "blockchain": "Cosmos", + "derivation": [ + { + "path": "m/44'/483'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "hrp": "bluzelle", + "addressHasher": "sha256ripemd", + "explorer": { + "url": "https://bigdipper.net.bluzelle.com", + "txPath": "/transactions/", + "accountPath": "/account/", + "sampleTx": "AC026E0EC6E33A77D5EA6B9CEF9810699BC2AD8C5582E007E7857457C6D3B819", + "sampleAccount": "bluzelle1q9cryfal7u3jvnq6er5ufety20xtzw6ycx2te9" + }, + "info": { + "url": "https://bluzelle.com", + "source": "https://github.com/bluzelle", + "rpc": "https://bluzelle.github.io/api/", + "documentation": "https://docs.bluzelle.com/developers/" + } + }, + { + "id": "band", + "name": "BandChain", + "symbol": "BAND", + "coinId": 494, + "decimals": 6, + "blockchain": "Cosmos", + "chainId": "laozi-mainnet", + "derivation": [ + { + "path": "m/44'/494'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "hrp": "band", + "addressHasher": "sha256ripemd", + "explorer": { + "url": "https://www.mintscan.io/band", + "txPath": "/tx/", + "accountPath": "/account/", + "sampleTx": "74AF38C2183B06EB6274DA4AAC0D2334E6E283643D436852F5E088AEA2CD0B17", + "sampleAccount": "band16gpgu994g2gdrzvwp9047le3pcq9wz6mcgtd4w" + }, + "info": { + "url": "https://bandprotocol.com/", + "source": "https://github.com/bandprotocol/bandchain", + "rpc": "https://api-wt2-lb.bandchain.org", + "documentation": "https://docs.bandchain.org/" + } + }, + { + "id": "theta", + "name": "Theta", + "coinId": 500, + "symbol": "THETA", + "decimals": 18, + "blockchain": "Theta", + "derivation": [ + { + "path": "m/44'/500'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "explorer": { + "url": "https://explorer.thetatoken.org", + "txPath": "/txs/", + "accountPath": "/account/" + }, + "info": { + "url": "https://www.thetatoken.org", + "source": "https://github.com/thetatoken/theta-protocol-ledger", + "rpc": "", + "documentation": "https://github.com/thetatoken/theta-mainnet-integration-guide/blob/master/docs/api.md#api-reference" + } + }, + { + "id": "tfuelevm", + "name": "Theta Fuel", + "coinId": 361, + "symbol": "TFUEL", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/500'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "361", + "addressHasher": "keccak256", + "explorer": { + "url": "https://explorer.thetatoken.org", + "txPath": "/tx/", + "accountPath": "/account/", + "sampleTx": "0xdb1c1c4e06289a4fc71b98ced218242d4f4a54a09987791a6a53a5260c053555", + "sampleAccount": "0xa144e6a98b967e585b214bfa7f6692af81987e5b" + }, + "info": { + "url": "https://www.thetatoken.org", + "source": "https://github.com/thetatoken/theta-protocol-ledger", + "rpc": "https://eth-rpc-api.thetatoken.org/rpc", + "documentation": "https://github.com/thetatoken/theta-mainnet-integration-guide/blob/master/docs/api.md#api-reference" + } + }, + { + "id": "solana", + "name": "Solana", + "coinId": 501, + "symbol": "SOL", + "decimals": 9, + "blockchain": "Solana", + "derivation": [ + { + "path": "m/44'/501'/0'" + }, + { + "name": "solana", + "path": "m/44'/501'/0'/0'" + } + ], + "curve": "ed25519", + "publicKeyType": "ed25519", + "explorer": { + "url": "https://solscan.io", + "txPath": "/tx/", + "accountPath": "/account/", + "sampleTx": "5LmxrEKGchhMuYfw6Qut6CbsvE9pVfb8YvwZKvWssSesDVjHioBCmWKSJQh1WhvcM6CpemhpHNmEMA2a36rzwTa8", + "sampleAccount": "Bxp8yhH9zNwxyE4UqxP7a7hgJ5xTZfxNNft7YJJ2VRjT" + }, + "info": { + "url": "https://solana.com", + "source": "https://github.com/solana-labs/solana", + "rpc": "https://api.mainnet-beta.solana.com", + "documentation": "https://docs.solana.com" + } + }, + { + "id": "elrond", + "name": "MultiversX", + "coinId": 508, + "symbol": "eGLD", + "decimals": 18, + "blockchain": "MultiversX", + "derivation": [ + { + "path": "m/44'/508'/0'/0'/0'" + } + ], + "curve": "ed25519", + "publicKeyType": "ed25519", + "hrp": "erd", + "explorer": { + "url": "https://explorer.multiversx.com", + "txPath": "/transactions/", + "accountPath": "/accounts/" + }, + "info": { + "url": "https://multiversx.com/", + "source": "https://github.com/multiversx/mx-chain-go", + "rpc": "https://api.multiversx.com", + "documentation": "https://docs.multiversx.com" + } + }, + { + "id": "binance", + "name": "Binance", + "displayName": "BNB Beacon Chain", + "coinId": 714, + "symbol": "BNB", + "decimals": 8, + "blockchain": "Binance", + "derivation": [ + { + "path": "m/44'/714'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "addressHasher": "sha256ripemd", + "hrp": "bnb", + "chainId": "Binance-Chain-Tigris", + "explorer": { + "url": "https://explorer.binance.org", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "A93625C9F9ABEA1A8E31585B30BBB16C34FAE0D172EB5B6B2F834AF077BF06BB", + "sampleAccount": "bnb1u7jm0cll5h3224y0tapwn6gf6pr49ytewx4gsz" + }, + "info": { + "url": "https://www.bnbchain.org", + "source": "https://github.com/bnb-chain/node-binary", + "rpc": "https://dex.binance.org", + "documentation": "https://docs.bnbchain.org/docs/beaconchain/develop/api-reference/dex-api/paths" + } + }, + { + "id": "tbinance", + "name": "TBinance", + "displayName": "TBNB", + "coinId": 30000714, + "slip44": 714, + "symbol": "BNB", + "decimals": 8, + "blockchain": "Binance", + "derivation": [ + { + "path": "m/44'/714'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "addressHasher": "sha256ripemd", + "hrp": "tbnb", + "explorer": { + "url": "https://testnet-explorer.binance.org", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "92E9DA1B6D603667E2DE83C0AC0C1D9E6D65405AD642DA794421C64A82A078D0", + "sampleAccount": "tbnb1c2cxgv3cklswxlvqr9anm6mlp6536qnd36txgr" + }, + "info": { + "url": "https://www.bnbchain.org", + "source": "https://github.com/bnb-chain/node-binary", + "rpc": "https://testnet-dex.binance.org", + "documentation": "https://docs.bnbchain.org/docs/beaconchain/develop/api-reference/dex-api/paths-testnet" + } + }, + { + "id": "vechain", + "name": "VeChain", + "coinId": 818, + "symbol": "VET", + "decimals": 18, + "blockchain": "Vechain", + "derivation": [ + { + "path": "m/44'/818'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "74", + "explorer": { + "url": "https://explore.vechain.org", + "txPath": "/transactions/", + "accountPath": "/accounts/", + "sampleTx": "0xa424053be0063555aee73a595ca69968c2e4d90d36f280753e503b92b11a655d", + "sampleAccount": "0x8a0a035a33173601bfbec8b6ae7c4a6557a55103" + }, + "info": { + "url": "https://vechain.org", + "source": "https://github.com/vechain/thor", + "rpc": "", + "documentation": "https://doc.vechainworld.io/docs" + } + }, + { + "id": "callisto", + "name": "Callisto", + "coinId": 820, + "symbol": "CLO", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/820'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "820", + "addressHasher": "keccak256", + "explorer": { + "url": "https://explorer.callisto.network", + "txPath": "/tx/", + "accountPath": "/addr/" + }, + "info": { + "url": "https://callisto.network", + "source": "https://github.com/EthereumCommonwealth/go-callisto", + "rpc": "https://clo-geth.0xinfra.com", + "documentation": "https://eth.wiki/json-rpc/API" + } + }, + { + "id": "neo", + "name": "NEO", + "coinId": 888, + "symbol": "NEO", + "decimals": 8, + "blockchain": "NEO", + "derivation": [ + { + "path": "m/44'/888'/0'/0/0" + } + ], + "curve": "nist256p1", + "publicKeyType": "nist256p1", + "explorer": { + "url": "https://neoscan.io", + "txPath": "/transaction/", + "accountPath": "/address/", + "sampleTx": "e0ddf7c81c732df26180aca0c36d5868ad009fdbbe6e7a56ebafc14bba41cd53", + "sampleAccount": "AcxuqWhTureEQGeJgbmtSWNAtssjMLU7pb" + }, + "info": { + "url": "https://neo.org", + "source": "https://github.com/neo-project/neo", + "rpc": "http://seed1.ngd.network:10332", + "documentation": "https://neo.org/eco" + } + }, + { + "id": "viction", + "name": "Viction", + "coinId": 889, + "symbol": "VIC", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/889'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "88", + "addressHasher": "keccak256", + "explorer": { + "url": "https://www.vicscan.xyz", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "0x35a8d3ab06c94d5b7d27221b7c9a24ba3f1710dd0fcfd75c5d59b3a885fd709b", + "sampleAccount": "0x86cCbD9bfb371c355202086882bC644A7D0b024B" + }, + "info": { + "url": "https://www.viction.xyz/", + "source": "https://github.com/BuildOnViction/tomochain", + "rpc": "https://rpc.tomochain.com", + "documentation": "https://eth.wiki/json-rpc/API" + } + }, + { + "id": "bitcoindiamond", + "name": "Bitcoin Diamond", + "coinId": 999, + "symbol": "BCD", + "decimals": 7, + "blockchain": "BitcoinDiamond", + "derivation": [ + { + "path": "m/84'/999'/0'/0/0", + "xpub": "zpub", + "xprv": "zprv" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "p2pkhPrefix": 0, + "p2shPrefix": 5, + "hrp": "bcd", + "publicKeyHasher": "sha256ripemd", + "base58Hasher": "sha256d", + "explorer": { + "url": "http://explorer.btcd.io/#", + "txPath": "/tx?tx=", + "accountPath": "/address?address=", + "sampleTx": "ec564fe8993ba77f3f5c8b7f6ebb4cbc08e564a54612d6f4584cd1017cf723d4", + "sampleAccount": "1HNTyntGXNhy4WxNzWfffPqp7LHb8bGJ9R" + }, + "info": { + "url": "https://www.bitcoindiamond.org", + "source": "https://github.com/trezor/blockbook", + "rpc": "", + "documentation": "https://github.com/trezor/blockbook/blob/master/docs/api.md" + } + }, + { + "id": "thundertoken", + "name": "ThunderCore", + "coinId": 1001, + "symbol": "TT", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/1001'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "108", + "addressHasher": "keccak256", + "explorer": { + "url": "https://scan.thundercore.com", + "txPath": "/transactions/", + "accountPath": "/address/" + }, + "info": { + "url": "https://thundercore.com", + "source": "https://github.com/thundercore/pala", + "rpc": "https://mainnet-rpc.thundercore.com", + "documentation": "https://eth.wiki/json-rpc/API" + } + }, + { + "id": "harmony", + "name": "Harmony", + "coinId": 1023, + "symbol": "ONE", + "decimals": 18, + "blockchain": "Harmony", + "derivation": [ + { + "path": "m/44'/1023'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "hrp": "one", + "explorer": { + "url": "https://explorer.harmony.one", + "txPath": "/#/tx/", + "accountPath": "/#/address/" + }, + "info": { + "url": "https://harmony.one", + "source": "https://github.com/harmony-one/go-sdk", + "rpc": "", + "documentation": "https://docs.harmony.one/home/harmony-networks/harmony-network-overview/mainnet" + } + }, + { + "id": "oasis", + "name": "Oasis", + "coinId": 474, + "symbol": "ROSE", + "decimals": 9, + "blockchain": "OasisNetwork", + "derivation": [ + { + "path": "m/44'/474'/0'" + } + ], + "curve": "ed25519", + "publicKeyType": "ed25519", + "hrp": "oasis", + "explorer": { + "url": "https://oasisscan.com", + "txPath": "/transactions/", + "accountPath": "/accounts/detail/", + "sampleTx": "73dc977fdd8596d4a57e6feb891b21f5da3652d26815dc94f15f7420c298e29e", + "sampleAccount": "oasis1qrx376dmwuckmruzn9vq64n49clw72lywctvxdf4" + }, + "info": { + "url": "https://oasisprotocol.org/", + "source": "https://github.com/oasisprotocol/oasis-core", + "rpc": "https://rosetta.oasis.dev/api/v1", + "documentation": "https://docs.oasis.dev/oasis-core/" + } + }, + { + "id": "ontology", + "name": "Ontology", + "coinId": 1024, + "symbol": "ONT", + "decimals": 0, + "blockchain": "Ontology", + "derivation": [ + { + "path": "m/44'/1024'/0'/0/0" + } + ], + "curve": "nist256p1", + "publicKeyType": "nist256p1", + "explorer": { + "url": "https://explorer.ont.io", + "txPath": "/transaction/", + "accountPath": "/address/" + }, + "info": { + "url": "https://ont.io", + "source": "https://github.com/ontio/ontology", + "rpc": "http://dappnode1.ont.io:20336", + "documentation": "https://github.com/ontio/ontology/blob/master/docs/specifications/rpc_api.md" + } + }, + { + "id": "tezos", + "name": "Tezos", + "coinId": 1729, + "symbol": "XTZ", + "decimals": 6, + "blockchain": "Tezos", + "derivation": [ + { + "path": "m/44'/1729'/0'/0'" + } + ], + "curve": "ed25519", + "publicKeyType": "ed25519", + "explorer": { + "url": "https://tzstats.com", + "txPath": "/", + "accountPath": "/", + "sampleTx": "onk3Z6V4StyfiXTPSHwZFvTKVAaws37cHmZacmULPr3VbVHpKrg", + "sampleAccount": "tz1SiPXX4MYGNJNDsRc7n8hkvUqFzg8xqF9m" + }, + "info": { + "url": "https://tezos.com", + "source": "https://gitlab.com/tezos/tezos", + "rpc": "https://rpc.tulip.tools/mainnet", + "documentation": "https://tezos.gitlab.io/tezos/api/rpc.html" + } + }, + { + "id": "cardano", + "name": "Cardano", + "coinId": 1815, + "symbol": "ADA", + "decimals": 6, + "blockchain": "Cardano", + "derivation": [ + { + "path": "m/1852'/1815'/0'/0/0" + } + ], + "curve": "ed25519ExtendedCardano", + "publicKeyType": "ed25519Cardano", + "hrp": "addr", + "explorer": { + "url": "https://cardanoscan.io", + "txPath": "/transaction/", + "accountPath": "/address/", + "sampleTx": "b7a6c5cadab0f64bdc89c77ee4a351463aba5c33f2cef6bbd6542a74a90a3af3", + "sampleAccount": "DdzFFzCqrhstpwKc8WMvPwwBb5oabcTW9zc5ykA37wJR4tYQucvsR9dXb2kEGNXkFJz2PtrpzfRiZkx8R1iNo8NYqdsukVmv7EAybFwC" + }, + "info": { + "url": "https://www.cardano.org", + "source": "https://github.com/input-output-hk/cardano-sl", + "rpc": "", + "documentation": "https://cardanodocs.com/introduction/" + } + }, + { + "id": "kin", + "name": "Kin", + "coinId": 2017, + "symbol": "KIN", + "decimals": 5, + "blockchain": "Stellar", + "derivation": [ + { + "path": "m/44'/2017'/0'" + } + ], + "curve": "ed25519", + "publicKeyType": "ed25519", + "explorer": { + "url": "https://www.kin.org", + "txPath": "/blockchainInfoPage/?&dataType=public&header=Transaction&id=", + "accountPath": "/blockchainAccount/?&dataType=public&header=accountID&id=" + }, + "info": { + "url": "https://www.kin.org", + "source": "https://github.com/kinecosystem/go", + "rpc": "https://horizon.kinfederation.com", + "documentation": "https://www.stellar.org/developers/horizon/reference" + }, + "deprecated": true + }, + { + "id": "qtum", + "name": "Qtum", + "coinId": 2301, + "symbol": "QTUM", + "decimals": 8, + "blockchain": "Bitcoin", + "derivation": [ + { + "path": "m/44'/2301'/0'/0/0", + "xpub": "xpub", + "xprv": "xprv" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "p2pkhPrefix": 58, + "p2shPrefix": 50, + "hrp": "qc", + "publicKeyHasher": "sha256ripemd", + "base58Hasher": "sha256d", + "explorer": { + "url": "https://qtum.info", + "txPath": "/tx/", + "accountPath": "/address/" + }, + "info": { + "url": "https://qtum.org", + "source": "https://github.com/trezor/blockbook", + "rpc": "", + "documentation": "https://github.com/trezor/blockbook/blob/master/docs/api.md" + } + }, + { + "id": "nebulas", + "name": "Nebulas", + "coinId": 2718, + "symbol": "NAS", + "decimals": 18, + "blockchain": "Nebulas", + "derivation": [ + { + "path": "m/44'/2718'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "explorer": { + "url": "https://explorer.nebulas.io", + "txPath": "/#/tx/", + "accountPath": "/#/address/" + }, + "info": { + "url": "https://nebulas.io", + "source": "https://github.com/nebulasio/go-nebulas", + "rpc": "https://mainnet.nebulas.io", + "documentation": "https://wiki.nebulas.io/en/latest/dapp-development/rpc/rpc.html" + } + }, + { + "id": "gochain", + "name": "GoChain", + "coinId": 6060, + "symbol": "GO", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/6060'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "60", + "addressHasher": "keccak256", + "explorer": { + "url": "https://explorer.gochain.io", + "txPath": "/tx/", + "accountPath": "/addr/" + }, + "info": { + "url": "https://gochain.io", + "source": "https://github.com/gochain-io/gochain", + "rpc": "https://rpc.gochain.io", + "documentation": "https://eth.wiki/json-rpc/API" + } + }, + { + "id": "nuls", + "name": "NULS", + "coinId": 8964, + "symbol": "NULS", + "decimals": 8, + "blockchain": "NULS", + "derivation": [ + { + "path": "m/44'/8964'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "explorer": { + "url": "https://nulscan.io", + "txPath": "/transaction/info?hash=", + "accountPath": "/address/info?address=", + "sampleTx": "303e0e42c28acc37ba952a1effd43daa1caec79928054f7abefb21c32e6fdc02", + "sampleAccount": "NULSd6HgdSjUZy7jKMZfvQ5QU6Z97oufGTGcF" + }, + "info": { + "url": "https://nuls.io", + "source": "https://github.com/nuls-io/nuls-v2", + "rpc": "https://public1.nuls.io/", + "documentation": "https://docs.nuls.io/" + } + }, + { + "id": "zelcash", + "name": "Zelcash", + "displayName": "Flux", + "coinId": 19167, + "symbol": "FLUX", + "decimals": 8, + "blockchain": "Zcash", + "derivation": [ + { + "path": "m/44'/19167'/0'/0/0", + "xpub": "xpub", + "xprv": "xprv" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "staticPrefix": 28, + "p2pkhPrefix": 184, + "p2shPrefix": 189, + "publicKeyHasher": "sha256ripemd", + "base58Hasher": "sha256d", + "explorer": { + "url": "https://explorer.runonflux.io", + "txPath": "/tx/", + "accountPath": "/address/" + }, + "info": { + "url": "https://runonflux.io", + "source": "https://github.com/trezor/blockbook", + "rpc": "https://blockbook.runonflux.io", + "documentation": "https://github.com/trezor/blockbook/blob/master/docs/api.md" + } + }, + { + "id": "wanchain", + "name": "Wanchain", + "coinId": 5718350, + "symbol": "WAN", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/5718350'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "888", + "addressHasher": "keccak256", + "explorer": { + "url": "https://www.wanscan.org", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "0x180ea96a3218b82b9b35d796823266d8a425c182507adfe5eeffc96e6a14d856", + "sampleAccount": "0x69B492D57bb777e97aa7044D0575228434e2E8B1" + }, + "info": { + "url": "https://wanchain.org", + "source": "https://github.com/wanchain/go-wanchain", + "rpc": "", + "documentation": "https://eth.wiki/json-rpc/API" + } + }, + { + "id": "waves", + "name": "Waves", + "coinId": 5741564, + "symbol": "WAVES", + "decimals": 8, + "blockchain": "Waves", + "derivation": [ + { + "path": "m/44'/5741564'/0'/0'/0'" + } + ], + "curve": "ed25519", + "publicKeyType": "curve25519", + "explorer": { + "url": "https://wavesexplorer.com", + "txPath": "/tx/", + "accountPath": "/address/" + }, + "info": { + "url": "https://wavesplatform.com", + "source": "https://github.com/wavesplatform/Waves", + "rpc": "https://nodes.wavesnodes.com", + "documentation": "https://nodes.wavesnodes.com/api-docs/index.html" + } + }, + { + "id": "bsc", + "name": "Smart Chain Legacy", + "coinId": 10000714, + "slip44": 714, + "symbol": "BNB", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/714'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "56", + "addressHasher": "keccak256", + "explorer": { + "url": "https://bscscan.com", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "0xb9ae2e808fe8e57171f303ad8f6e3fd17d949b0bfc7b4db6e8e30a71cc517d7e", + "sampleAccount": "0x35552c16704d214347f29Fa77f77DA6d75d7C752" + }, + "info": { + "url": "https://www.binance.org/en/smartChain", + "source": "https://github.com/binance-chain/bsc", + "rpc": "https://data-seed-prebsc-1-s1.binance.org:8545", + "documentation": "https://eth.wiki/json-rpc/API" + }, + "deprecated": true, + "testFolderName": "Binance" + }, + { + "id": "smartchain", + "name": "Smart Chain", + "displayName": "BNB Smart Chain", + "coinId": 20000714, + "slip44": 714, + "symbol": "BNB", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/60'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "56", + "addressHasher": "keccak256", + "explorer": { + "url": "https://bscscan.com", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "0xb9ae2e808fe8e57171f303ad8f6e3fd17d949b0bfc7b4db6e8e30a71cc517d7e", + "sampleAccount": "0x35552c16704d214347f29Fa77f77DA6d75d7C752" + }, + "info": { + "url": "https://www.binance.org/en/smartChain", + "source": "https://github.com/binance-chain/bsc", + "rpc": "https://bsc-dataseed1.binance.org", + "documentation": "https://eth.wiki/json-rpc/API" + }, + "testFolderName": "Binance" + }, + { + "id": "polygon", + "name": "Polygon", + "coinId": 966, + "symbol": "POL", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/60'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "137", + "addressHasher": "keccak256", + "explorer": { + "url": "https://polygonscan.com", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "0xe26ed1470d5bf99a53d687843e7acdf7e4ba6620af93b4d672e714de90476e8e", + "sampleAccount": "0x720E1fa107A1Df39Db4E78A3633121ac36Bec132" + }, + "info": { + "url": "https://polygon.technology", + "source": "https://github.com/maticnetwork", + "rpc": "https://polygon-rpc.com", + "documentation": "https://docs.polygon.technology" + } + }, + { + "id": "rootstock", + "name": "Rootstock", + "coinId": 137, + "symbol": "RBTC", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/137'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "30", + "addressHasher": "keccak256", + "explorer": { + "url": "https://explorer.rsk.co", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "0xeb8fa0488a655f8dc975153bffd066800bcaae5f21cf372356365b2a1d6d2288", + "sampleAccount": "0x4e5dabc28e4a0f5e5b19fcb56b28c5a1989352c1" + }, + "info": { + "url": "https://rootstock.io", + "source": "https://github.com/rsksmart/rskj", + "rpc": "https://public-node.rsk.co", + "documentation": "https://dev.rootstock.io" + } + }, + { + "id": "thorchain", + "name": "THORChain", + "coinId": 931, + "symbol": "RUNE", + "decimals": 8, + "blockchain": "Thorchain", + "derivation": [ + { + "path": "m/44'/931'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "hrp": "thor", + "addressHasher": "sha256ripemd", + "chainId": "thorchain-mainnet-v1", + "explorer": { + "url": "https://viewblock.io/thorchain", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "ADF0899E58C177E2391F22D04E9C5E1C35BB0F75B42B363A0761687907FD9476", + "sampleAccount": "thor196yf4pq80hjrmz7nnh0ar0ypqg02r0w4dq4mzu" + }, + "info": { + "url": "https://thorchain.org", + "source": "https://gitlab.com/thorchain/thornode", + "rpc": "https://seed.thorchain.info", + "documentation": "https://docs.thorchain.org" + } + }, + { + "id": "optimism", + "name": "Optimism", + "displayName": "OP Mainnet", + "coinId": 10000070, + "slip44": 60, + "symbol": "ETH", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/60'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "10", + "addressHasher": "keccak256", + "explorer": { + "url": "https://optimistic.etherscan.io", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "0x6fd99288be9bf71eb002bb31da10a4fb0fbbb3c45ae73693b212f49c9db7df8f", + "sampleAccount": "0x1f932361e31d206b4f6b2478123a9d0f8c761031" + }, + "info": { + "url": "https://optimism.io/", + "source": "https://github.com/ethereum-optimism/optimism", + "rpc": "https://mainnet.optimism.io", + "documentation": "https://eth.wiki/json-rpc/API" + } + }, + { + "id": "polygonzkevm", + "name": "Polygon zkEVM", + "displayName": "Polygon zkEVM", + "coinId": 10001101, + "slip44": 60, + "symbol": "ETH", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/60'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "1101", + "addressHasher": "keccak256", + "explorer": { + "url": "https://zkevm.polygonscan.com", + "txPath": "/tx/", + "accountPath": "/address/" + }, + "info": { + "url": "https://www.polygon.technology/", + "source": "https://github.com/0xpolygonhermez", + "rpc": "https://zkevm-rpc.com", + "documentation": "https://wiki.polygon.technology/docs/zkEVM/introduction/" + } + }, + { + "id": "zksync", + "name": "Zksync", + "displayName": "zkSync Era", + "coinId": 10000324, + "slip44": 60, + "symbol": "ETH", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/60'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "324", + "addressHasher": "keccak256", + "explorer": { + "url": "https://explorer.zksync.io", + "txPath": "/tx/", + "accountPath": "/address/" + }, + "info": { + "url": "https://portal.zksync.io/", + "source": "https://github.com/matter-labs/zksync", + "rpc": "https://zksync2-mainnet.zksync.io", + "documentation": "https://era.zksync.io/docs" + } + }, + { + "id": "scroll", + "name": "Scroll", + "displayName": "Scroll", + "coinId": 534352, + "slip44": 60, + "symbol": "ETH", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/60'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "534352", + "addressHasher": "keccak256", + "explorer": { + "url": "https://scrollscan.com", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "0xa2062a4530b194a438bb9f9e87cdce59f70775a52e8336892364445847c43ca2", + "sampleAccount": "0xf9062b8a30e0d7722960e305049fa50b86ba6253" + }, + "info": { + "url": "https://scroll.io", + "source": "https://github.com/scroll-tech", + "rpc": "https://rpc.scroll.io", + "documentation": "https://guide.scroll.io" + } + }, + { + "id": "arbitrum", + "name": "Arbitrum", + "coinId": 10042221, + "slip44": 60, + "symbol": "ETH", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/60'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "42161", + "addressHasher": "keccak256", + "explorer": { + "url": "https://arbiscan.io", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "0xa1e319be22c08155e5904aa211fb87df5f4ade48de79c6578b1cf3dfda9e498c", + "sampleAccount": "0xecf9ffa7f51e1194f89c25ad8c484f6bfd04e1ac" + }, + "info": { + "url": "https://arbitrum.io", + "source": "https://github.com/OffchainLabs/arbitrum", + "rpc": "https://arb1.arbitrum.io/rpc", + "documentation": "https://docs.arbitrum.io/" + } + }, + { + "id": "arbitrumnova", + "name": "Arbitrum Nova", + "coinId": 10042170, + "slip44": 60, + "symbol": "ETH", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/60'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "42170", + "addressHasher": "keccak256", + "explorer": { + "url": "https://nova.arbiscan.io", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "0xfdfee13848c2d21813c82c53afc9925f31770564c3117477960a81055702c1be", + "sampleAccount": "0x0d0707963952f2fba59dd06f2b425ace40b492fe" + }, + "info": { + "url": "https://nova.arbitrum.io", + "source": "https://github.com/OffchainLabs/arbitrum", + "rpc": "https://nova.arbitrum.io/rpc", + "documentation": "https://docs.arbitrum.io/" + } + }, + { + "id": "heco", + "name": "ECO Chain", + "displayName": "Huobi ECO Chain", + "coinId": 10000553, + "slip44": 553, + "symbol": "HT", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/60'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "128", + "addressHasher": "keccak256", + "explorer": { + "url": "https://hecoinfo.com", + "txPath": "/tx/", + "accountPath": "/address/" + }, + "info": { + "url": "https://www.hecochain.com/en-us", + "source": "https://github.com/HuobiGroup/huobi-eco-chain", + "rpc": "https://http-mainnet-node.huobichain.com", + "documentation": "https://eth.wiki/json-rpc/API" + }, + "testFolderName": "ECO" + }, + { + "id": "avalanchec", + "name": "Avalanche C-Chain", + "coinId": 10009000, + "symbol": "AVAX", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/60'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "43114", + "addressHasher": "keccak256", + "explorer": { + "url": "https://snowtrace.io", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "0x9243890b844219accefd8798271052f5a056453ec18984a56e81c92921330d54", + "sampleAccount": "0xa664325f36Ec33E66323fe2620AF3f2294b2Ef3A" + }, + "info": { + "url": "https://www.avalabs.org/", + "client": "https://github.com/ava-labs/avalanchego", + "clientPublic": "https://api.avax.network/ext/bc/C/rpc", + "clientDocs": "https://docs.avax.network/" + }, + "testFolderName": "Avalanche" + }, + { + "id": "xdai", + "name": "xDai", + "displayName": "Gnosis Chain", + "coinId": 10000100, + "symbol": "xDAI", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/60'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "100", + "addressHasher": "keccak256", + "explorer": { + "url": "https://blockscout.com/xdai/mainnet", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "0x936798a1ef607c9e856d7861b15999c770c06f0887c4fc1f6acbf3bef09899c1", + "sampleAccount": "0x12d61a95CF55e18D267C2F1AA67d8e42ae1368f8" + }, + "info": { + "url": "https://www.xdaichain.com", + "client": "https://github.com/openethereum/openethereum", + "clientPublic": "https://rpc.gnosischain.com", + "clientDocs": "https://eth.wiki/json-rpc/API" + } + }, + { + "id": "fantom", + "name": "Fantom", + "coinId": 10000250, + "symbol": "FTM", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ { - "path": "m/44'/2017'/0'" + "path": "m/44'/60'/0'/0/0" } ], - "curve": "ed25519", - "publicKeyType": "ed25519", + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "250", + "addressHasher": "keccak256", "explorer": { - "url": "https://www.kin.org", - "txPath": "/blockchainInfoPage/?&dataType=public&header=Transaction&id=", - "accountPath": "/blockchainAccount/?&dataType=public&header=accountID&id=" + "url": "https://ftmscan.com", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "0xb0a741d882291951de1fac72e90b9baf886ddb0c9c87658a0c206490dfaa5202", + "sampleAccount": "0x9474feb9917b87da6f0d830ba66ee0035835c0d3" }, "info": { - "url": "https://www.kin.org", - "source": "https://github.com/kinecosystem/go", - "rpc": "https://horizon.kinfederation.com", - "documentation": "https://www.stellar.org/developers/horizon/reference" - }, - "deprecated": true + "url": "https://fantom.foundation", + "client": "https://github.com/openethereum/openethereum", + "clientPublic": "https://rpc.ftm.tools", + "clientDocs": "https://eth.wiki/json-rpc/API" + } }, { - "id": "qtum", - "name": "Qtum", - "coinId": 2301, - "symbol": "QTUM", + "id": "cryptoorg", + "name": "CryptoOrg", + "displayName": "Crypto.org", + "coinId": 394, + "symbol": "CRO", "decimals": 8, - "blockchain": "Bitcoin", + "blockchain": "Cosmos", "derivation": [ { - "path": "m/44'/2301'/0'/0/0", + "path": "m/44'/394'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "hrp": "cro", + "chainId": "crypto-org-chain-mainnet-1", + "addressHasher": "sha256ripemd", + "explorer": { + "url": "https://crypto.org/explorer", + "txPath": "/tx/", + "accountPath": "/account/", + "sampleTx": "D87D2EB46B21466886EE149C1DEA3AE6C2E019C7D8C24FA1533A95439DDCE1E2", + "sampleAccount": "cro10wrflcdc4pys9vvgqm98yg7yv5ltj7d3xehent" + }, + "info": { + "url": "https://crypto.org/", + "client": "https://github.com/crypto-org-chain/chain-main", + "clientPublic": "https://mainnet.crypto.org:1317/", + "clientDocs": "https://crypto.org/docs/resources/chain-integration.html#api-documentation" + } + }, + { + "id": "celo", + "name": "Celo", + "coinId": 52752, + "symbol": "CELO", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/60'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "42220", + "addressHasher": "keccak256", + "explorer": { + "url": "https://explorer.celo.org", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "0xaf41ee58afe633dc7b179c15693cca40fe0372c1d7c70351620105d59d326693", + "sampleAccount": "0xFBFf95e2Fa7e4Ff3aeA34eFB05fB60F9968a6aaD" + }, + "info": { + "url": "https://celo.org", + "client": "https://github.com/celo-org/celo-blockchain", + "clientPublic": "https://forno.celo.org", + "clientDocs": "https://eth.wiki/json-rpc/API" + } + }, + { + "id": "ronin", + "name": "Ronin", + "coinId": 10002020, + "slip44": 60, + "symbol": "RON", + "decimals": 18, + "blockchain": "Ronin", + "derivation": [ + { + "path": "m/44'/60'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "2020", + "addressHasher": "keccak256", + "explorer": { + "url": "https://explorer.roninchain.com", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "0xc09835aaf9c1cacea8ce322865583c791d3a4dfbd9a3b72f79539db88d3697ab", + "sampleAccount": "0xdc05ecd5fbdb64058d94f3182d66f44342b9adcb" + }, + "info": { + "url": "https://whitepaper.axieinfinity.com/technology/ronin-ethereum-sidechain", + "client": "https://github.com/axieinfinity/ronin-smart-contracts", + "clientPublic": "https://api.roninchain.com/rpc", + "clientDocs": "https://eth.wiki/json-rpc/API" + } + }, + { + "id": "secret", + "name": "Secret", + "displayName": "Secret", + "coinId": 529, + "symbol": "SCRT", + "decimals": 6, + "blockchain": "Cosmos", + "derivation": [ + { + "path": "m/44'/529'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "hrp": "secret", + "chainId": "secret-4", + "addressHasher": "sha256ripemd", + "explorer": { + "url": "https://mintscan.io/secret", + "txPath": "/txs/", + "accountPath": "/account/", + "sampleTx": "026B4886B1D9CE836A99755DDE99D4F8A7748D27B1CE9D298A763B1CFFF62C00", + "sampleAccount": "secret167m3s89ddurjpyr82vsluvvj0t8ylzn95trrqy" + }, + "info": { + "url": "https://scrt.network/", + "source": "https://github.com/scrtlabs/SecretNetwork", + "rpc": "https://scrt-rpc.blockpane.com/", + "documentation": "https://docs.scrt.network/" + } + }, + { + "id": "osmosis", + "name": "Osmosis", + "displayName": "Osmosis", + "coinId": 10000118, + "symbol": "OSMO", + "decimals": 6, + "blockchain": "Cosmos", + "derivation": [ + { + "path": "m/44'/118'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "hrp": "osmo", + "chainId": "osmosis-1", + "addressHasher": "sha256ripemd", + "explorer": { + "url": "https://mintscan.io/osmosis", + "txPath": "/txs/", + "accountPath": "/account/", + "sampleTx": "5A6E50A6F2927E4B8C87BB094D5FBF15F1287429A09111806FC44B3CD86CACA8", + "sampleAccount": "osmo1mky69cn8ektwy0845vec9upsdphktxt0en97f5" + }, + "info": { + "url": "https://osmosis.zone/", + "client": "https://github.com/osmosis-labs/osmosis", + "clientPublic": "https://rpc-osmosis.keplr.app/", + "clientDocs": "" + } + }, + { + "id": "ecash", + "name": "eCash", + "coinId": 899, + "symbol": "XEC", + "decimals": 2, + "blockchain": "BitcoinCash", + "derivation": [ + { + "path": "m/44'/899'/0'/0/0", "xpub": "xpub", "xprv": "xprv" } ], "curve": "secp256k1", "publicKeyType": "secp256k1", - "p2pkhPrefix": 58, - "p2shPrefix": 50, - "hrp": "qc", + "p2pkhPrefix": 0, + "p2shPrefix": 5, + "hrp": "ecash", "publicKeyHasher": "sha256ripemd", "base58Hasher": "sha256d", "explorer": { - "url": "https://qtum.info", + "url": "https://explorer.bitcoinabc.org", "txPath": "/tx/", - "accountPath": "/address/" + "accountPath": "/address/", + "sampleTx": "6bc767e69cfacffd954c9e5acd178d3140bf00d094b92c6f6052b517500c553b", + "sampleAccount": "ecash:pqnqv9lt7e5vjyp0w88zf2af0l92l8rxdg2jj94l5j" }, "info": { - "url": "https://qtum.org", + "url": "https://e.cash", "source": "https://github.com/trezor/blockbook", - "rpc": "", + "rpc": "https://blockbook.fabien.cash:9197", "documentation": "https://github.com/trezor/blockbook/blob/master/docs/api.md" } }, { - "id": "nebulas", - "name": "Nebulas", - "coinId": 2718, - "symbol": "NAS", + "id": "iost", + "name": "IOST", + "coinId": 291, + "symbol": "IOST", + "decimals": 2, + "blockchain": "IOST", + "derivation": [ + { + "path": "m/44'/899'/0'/0/0", + "xpub": "xpub", + "xprv": "xprv" + } + ], + "curve": "ed25519", + "publicKeyType": "ed25519", + "p2pkhPrefix": 0, + "p2shPrefix": 5, + "publicKeyHasher": "sha256ripemd", + "base58Hasher": "sha256d", + "explorer": { + "url": "https://explorer.iost.io", + "txPath": "/tx/", + "accountPath": "/account/", + "sampleTx": "7dKQzgTkPBNrZqrQ2Bqhqq132CHGPKANFDtzRsjHRCqx", + "sampleAccount": "4av8w81EyzUgHonsVWqfs15WM4Vrpgox4BYYQWhNQDVu" + }, + "info": { + "url": "https://iost.io", + "source": "https://github.com/iost-official/go-iost", + "rpc": "", + "documentation": "https://developers.iost.io/docs/en/6-reference/API.html" + } + }, + { + "id": "cronos", + "name": "Cronos Chain", + "coinId": 10000025, + "symbol": "CRO", "decimals": 18, - "blockchain": "Nebulas", + "blockchain": "Ethereum", "derivation": [ { - "path": "m/44'/2718'/0'/0/0" + "path": "m/44'/60'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "25", + "addressHasher": "keccak256", + "explorer": { + "url": "https://cronoscan.com", + "txPath": "/tx/", + "accountPath": "/address/" + }, + "info": { + "url": "https://cronos.org", + "client": "https://github.com/crypto-org-chain/cronos", + "clientPublic": "https://evm-cronos.crypto.org", + "clientDocs": "https://eth.wiki/json-rpc/API" + }, + "testFolderName": "Cronos" + }, + { + "id": "kavaevm", + "name": "KavaEvm", + "coinId": 10002222, + "symbol": "KAVA", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/60'/0'/0/0" } ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", + "chainId": "2222", + "addressHasher": "keccak256", "explorer": { - "url": "https://explorer.nebulas.io", - "txPath": "/#/tx/", - "accountPath": "/#/address/" + "url": "https://explorer.kava.io", + "txPath": "/tx/", + "accountPath": "/address/" }, "info": { - "url": "https://nebulas.io", - "source": "https://github.com/nebulasio/go-nebulas", - "rpc": "https://mainnet.nebulas.io", - "documentation": "https://wiki.nebulas.io/en/latest/dapp-development/rpc/rpc.html" + "url": "https://www.kava.io/", + "client": "https://github.com/Kava-Labs/kava", + "documentation": "https://docs.kava.io/docs/ethereum/overview/", + "rpc": "https://evm.kava.io" } }, { - "id": "gochain", - "name": "GoChain", - "coinId": 6060, - "symbol": "GO", + "id": "smartbch", + "name": "Smart Bitcoin Cash", + "coinId": 10000145, + "symbol": "BCH", "decimals": 18, "blockchain": "Ethereum", "derivation": [ { - "path": "m/44'/6060'/0'/0/0" + "path": "m/44'/60'/0'/0/0" } ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", - "chainId": "60", + "chainId": "10000", "addressHasher": "keccak256", "explorer": { - "url": "https://explorer.gochain.io", + "url": "https://www.smartscan.cash", "txPath": "/tx/", - "accountPath": "/addr/" + "accountPath": "/address/", + "sampleTx": "0x6413466b455b17d03c7a8ce2d7f99fec34bcd338628bdd2d0580a21e3197a4d9", + "sampleAccount": "0xFeEc227410E1DF9f3b4e6e2E284DC83051ae468F" }, "info": { - "url": "https://gochain.io", - "source": "https://github.com/gochain-io/gochain", - "rpc": "https://rpc.gochain.io", - "documentation": "https://eth.wiki/json-rpc/API" - } + "url": "https://smartbch.org/", + "source": "https://github.com/smartbch/smartbch", + "rpc": "https://smartbch.fountainhead.cash/mainnet", + "documentation": "https://github.com/smartbch/docs/blob/main/developers-guide/jsonrpc.md" + }, + "testFolderName": "Bitcoin" }, { - "id": "nuls", - "name": "NULS", - "coinId": 8964, - "symbol": "NULS", - "decimals": 8, - "blockchain": "NULS", + "id": "kcc", + "name": "KuCoin Community Chain", + "coinId": 10000321, + "symbol": "KCS", + "decimals": 18, + "blockchain": "Ethereum", "derivation": [ { - "path": "m/44'/8964'/0'/0/0" + "path": "m/44'/60'/0'/0/0" } ], "curve": "secp256k1", - "publicKeyType": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "321", + "addressHasher": "keccak256", "explorer": { - "url": "https://nulscan.io", - "txPath": "/transaction/info?hash=", - "accountPath": "/address/info?address=" + "url": "https://explorer.kcc.io/en", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "0x2f0d79cd289a02f3181b68b9583a64c3809fe7387810b274275985c29d02c80d", + "sampleAccount": "0x4446fc4eb47f2f6586f9faab68b3498f86c07521" }, "info": { - "url": "https://nuls.io", - "source": "https://github.com/nuls-io/nuls-v2", - "rpc": "https://public1.nuls.io/", - "documentation": "https://docs.nuls.io/" - } + "url": "https://www.kcc.io/", + "source": "https://github.com/kcc-community/kcc", + "rpc": "https://rpc-mainnet.kcc.network", + "documentation": "https://docs.kcc.io/#/en-us/" + }, + "testFolderName": "KuCoinCommunityChain" }, { - "id": "zelcash", - "name": "Zelcash", - "displayName": "Flux", - "coinId": 19167, - "symbol": "FLUX", - "decimals": 8, - "blockchain": "Zcash", + "id": "boba", + "name": "Boba", + "coinId": 10000288, + "symbol": "BOBAETH", + "decimals": 18, + "blockchain": "Ethereum", "derivation": [ { - "path": "m/44'/19167'/0'/0/0", - "xpub": "xpub", - "xprv": "xprv" + "path": "m/44'/60'/0'/0/0" } ], "curve": "secp256k1", - "publicKeyType": "secp256k1", - "staticPrefix": 28, - "p2pkhPrefix": 184, - "p2shPrefix": 189, - "publicKeyHasher": "sha256ripemd", - "base58Hasher": "sha256d", + "publicKeyType": "secp256k1Extended", + "chainId": "288", + "addressHasher": "keccak256", "explorer": { - "url": "https://explorer.runonflux.io", + "url": "https://blockexplorer.boba.network", "txPath": "/tx/", - "accountPath": "/address/" + "accountPath": "/address/", + "sampleTx": "0x31533707c3feb3b10f7deeea387ff8893f229253e65ca6b14d2400bf95b5d103", + "sampleAccount": "0x4F96F50eDB37a19216d87693E5dB241e31bD3735" }, "info": { - "url": "https://runonflux.io", - "source": "https://github.com/trezor/blockbook", - "rpc": "https://blockbook.runonflux.io", - "documentation": "https://github.com/trezor/blockbook/blob/master/docs/api.md" + "url": "https://boba.network/", + "source": "https://github.com/bobanetwork/boba", + "rpc": "https://mainnet.boba.network", + "documentation": "https://docs.boba.network/" } }, { - "id": "wanchain", - "name": "Wanchain", - "coinId": 5718350, - "symbol": "WAN", + "id": "metis", + "name": "Metis", + "coinId": 10001088, + "symbol": "METIS", "decimals": 18, "blockchain": "Ethereum", "derivation": [ { - "path": "m/44'/5718350'/0'/0/0" + "path": "m/44'/60'/0'/0/0" } ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", - "chainId": "888", + "chainId": "1088", "addressHasher": "keccak256", "explorer": { - "url": "https://www.wanscan.org", + "url": "https://andromeda-explorer.metis.io", "txPath": "/tx/", "accountPath": "/address/", - "sampleTx": "0x180ea96a3218b82b9b35d796823266d8a425c182507adfe5eeffc96e6a14d856", - "sampleAccount": "0xc6D3DBf8dF90BA3f957A9634677805eee0e43bBe" + "sampleTx": "0x422f2ebbede32d4434ad0cf0ae55d44a84e14d3d5725a760133255b42676d8ce", + "sampleAccount": "0xBe9E8Ec25866B21bA34e97b9393BCabBcB4A5C86" }, "info": { - "url": "https://wanchain.org", - "source": "https://github.com/wanchain/go-wanchain", - "rpc": "", - "documentation": "https://eth.wiki/json-rpc/API" + "url": "https://www.metis.io/", + "source": "https://github.com/MetisProtocol/mvm", + "rpc": "https://andromeda.metis.io/?owner=1088", + "documentation": "https://docs.metis.io/" } }, { - "id": "waves", - "name": "Waves", - "coinId": 5741564, - "symbol": "WAVES", - "decimals": 8, - "blockchain": "Waves", + "id": "aurora", + "name": "Aurora", + "coinId": 1323161554, + "symbol": "ETH", + "decimals": 18, + "blockchain": "Ethereum", "derivation": [ { - "path": "m/44'/5741564'/0'/0'/0'" + "path": "m/44'/60'/0'/0/0" } ], - "curve": "ed25519", - "publicKeyType": "curve25519", + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "1313161554", + "addressHasher": "keccak256", "explorer": { - "url": "https://wavesexplorer.com", + "url": "https://aurorascan.dev", "txPath": "/tx/", - "accountPath": "/address/" + "accountPath": "/address/", + "sampleTx": "0x99deebdb70f8027037abb3d3d0f3c7523daee857d85e9056d2671593ff2f2f28", + "sampleAccount": "0x8707cdE20dd43E3dB1F74c28fcd509ef38B0bA51" }, "info": { - "url": "https://wavesplatform.com", - "source": "https://github.com/wavesplatform/Waves", - "rpc": "https://nodes.wavesnodes.com", - "documentation": "https://nodes.wavesnodes.com/api-docs/index.html" + "url": "https://aurora.dev/", + "source": "https://github.com/aurora-is-near/aurora-engine", + "rpc": "https://mainnet.aurora.dev/", + "documentation": "https://doc.aurora.dev/" } }, { - "id": "bsc", - "name": "Smart Chain Legacy", - "coinId": 10000714, - "slip44": 714, - "symbol": "BNB", + "id": "evmos", + "name": "Evmos", + "coinId": 10009001, + "symbol": "EVMOS", "decimals": 18, "blockchain": "Ethereum", "derivation": [ { - "path": "m/44'/714'/0'/0/0" + "path": "m/44'/60'/0'/0/0" } ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", - "chainId": "56", + "chainId": "9001", "addressHasher": "keccak256", "explorer": { - "url": "https://bscscan.com", + "url": "https://evm.evmos.org", "txPath": "/tx/", "accountPath": "/address/", - "sampleTx": "0xb9ae2e808fe8e57171f303ad8f6e3fd17d949b0bfc7b4db6e8e30a71cc517d7e", - "sampleAccount": "0x35552c16704d214347f29Fa77f77DA6d75d7C752" + "sampleTx": "0x24af42cf4977a96d62e3a82c3cd9b519c3e7c53dd83398b88f0cb435d867b422", + "sampleAccount": "0x30627903124Aa1e71384bc52e1cb96E4AB3252b6" }, "info": { - "url": "https://www.binance.org/en/smartChain", - "source": "https://github.com/binance-chain/bsc", - "rpc": "https://data-seed-prebsc-1-s1.binance.org:8545", - "documentation": "https://eth.wiki/json-rpc/API" - }, - "deprecated": true, - "testFolderName" : "Binance" + "url": "https://evmos.org/", + "source": "https://github.com/tharsis/evmos", + "rpc": "https://eth.bd.evmos.org:8545", + "documentation": "https://docs.evmos.org/" + } }, { - "id": "smartchain", - "name": "Smart Chain", - "displayName": "BNB Smart Chain", - "coinId": 20000714, - "slip44": 714, - "symbol": "BNB", + "id": "nativeevmos", + "name": "NativeEvmos", + "displayName": "Native Evmos", + "coinId": 20009001, + "symbol": "EVMOS", "decimals": 18, - "blockchain": "Ethereum", + "blockchain": "NativeEvmos", + "chainId": "evmos_9001-2", "derivation": [ { "path": "m/44'/60'/0'/0/0" @@ -1924,28 +3991,27 @@ ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", - "chainId": "56", + "hrp": "evmos", "addressHasher": "keccak256", "explorer": { - "url": "https://bscscan.com", - "txPath": "/tx/", - "accountPath": "/address/", - "sampleTx": "0xb9ae2e808fe8e57171f303ad8f6e3fd17d949b0bfc7b4db6e8e30a71cc517d7e", - "sampleAccount": "0x35552c16704d214347f29Fa77f77DA6d75d7C752" + "url": "https://mintscan.io/evmos", + "txPath": "/txs/", + "accountPath": "/account/", + "sampleTx": "A16C211C83AD1E684DE46F694FAAC17D8465C864BD7385A81EC062CDE0638811", + "sampleAccount": "evmos17xpfvakm2amg962yls6f84z3kell8c5ljcjw34" }, "info": { - "url": "https://www.binance.org/en/smartChain", - "source": "https://github.com/binance-chain/bsc", - "rpc": "https://bsc-dataseed1.binance.org", - "documentation": "https://eth.wiki/json-rpc/API" - }, - "testFolderName" : "Binance" + "url": "https://evmos.org/", + "client": "https://github.com/tharsis/evmos", + "clientPublic": "https://rest.bd.evmos.org:1317", + "clientDocs": "" + } }, { - "id": "polygon", - "name": "Polygon", - "coinId": 966, - "symbol": "MATIC", + "id": "moonriver", + "name": "Moonriver", + "coinId": 10001285, + "symbol": "MOVR", "decimals": 18, "blockchain": "Ethereum", "derivation": [ @@ -1955,59 +4021,52 @@ ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", - "chainId": "137", - "addressHasher": "keccak256", + "chainId": "1285", "explorer": { - "url": "https://polygonscan.com", + "url": "https://moonriver.moonscan.io", "txPath": "/tx/", "accountPath": "/address/", - "sampleTx": "0xe26ed1470d5bf99a53d687843e7acdf7e4ba6620af93b4d672e714de90476e8e", - "sampleAccount": "0x720E1fa107A1Df39Db4E78A3633121ac36Bec132" + "sampleTx": "0x2e2daa3943ba65d9bbb910a4f6765aa6a466a0ef8935090547ca9d30e201e032", + "sampleAccount": "0x899831D937937d011305E73EE782cce0455DF15a" }, "info": { - "url": "https://polygon.technology", - "source": "https://github.com/maticnetwork/contracts", - "rpc": "https://polygon-rpc.com", - "documentation": "https://eth.wiki/json-rpc/API" + "url": "https://moonbeam.network/networks/moonriver", + "rpc": "https://moonriver.public.blastapi.io" } }, { - "id": "thorchain", - "name": "THORChain", - "coinId": 931, - "symbol": "RUNE", - "decimals": 8, - "blockchain": "Thorchain", + "id": "moonbeam", + "name": "Moonbeam", + "coinId": 10001284, + "symbol": "GLMR", + "decimals": 18, + "blockchain": "Ethereum", "derivation": [ { - "path": "m/44'/931'/0'/0/0" + "path": "m/44'/60'/0'/0/0" } ], "curve": "secp256k1", - "publicKeyType": "secp256k1", - "hrp": "thor", - "chainId": "thorchain-mainnet-v1", + "publicKeyType": "secp256k1Extended", + "chainId": "1284", "explorer": { - "url": "https://viewblock.io/thorchain", + "url": "https://moonscan.io", "txPath": "/tx/", "accountPath": "/address/", - "sampleTx": "ADF0899E58C177E2391F22D04E9C5E1C35BB0F75B42B363A0761687907FD9476", - "sampleAccount": "thor196yf4pq80hjrmz7nnh0ar0ypqg02r0w4dq4mzu" + "sampleTx": "0xb22a146c933e6e51affbfa5f712a266b5f5e92ae453cd2f252bcc3c36ff035a6", + "sampleAccount": "0x201bb4f276C765dF7225e5A4153E17edD23a67eC" }, "info": { - "url": "https://thorchain.org", - "source": "https://gitlab.com/thorchain/thornode", - "rpc": "https://seed.thorchain.info", - "documentation": "https://docs.thorchain.org" + "url": "https://moonbeam.network", + "rpc": "https://rpc.api.moonbeam.network", + "documentation": "https://docs.moonbeam.network" } }, { - "id": "optimism", - "name": "Optimism", - "displayName": "Optimistic Ethereum", - "coinId": 10000070, - "slip44": 60, - "symbol": "ETH", + "id": "kaia", + "name": "Kaia", + "coinId": 10008217, + "symbol": "KLAY", "decimals": 18, "blockchain": "Ethereum", "derivation": [ @@ -2017,26 +4076,26 @@ ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", - "chainId": "10", - "addressHasher": "keccak256", + "chainId": "8217", "explorer": { - "url": "https://optimistic.etherscan.io", + "url": "https://kaiascan.io", "txPath": "/tx/", - "accountPath": "/address/" + "accountPath": "/account/", + "sampleTx": "0x93ea92687845fe7bb6cacd69c76a16a2a3c2bbb85a8a93ff0e032d0098d583d7", + "sampleAccount": "0x2ad9656bf5b82caf10847b431012e28e301e83ba" }, "info": { - "url": "https://optimism.io/", - "source": "https://github.com/ethereum-optimism/optimism", - "rpc": "https://mainnet.optimism.io", - "documentation": "https://eth.wiki/json-rpc/API" + "url": "https://kaia.io", + "rpc": "https://public-en.node.kaia.io", + "documentation": "https://docs.kaia.io" } }, { - "id": "arbitrum", - "name": "Arbitrum", - "coinId": 10042221, - "slip44": 60, - "symbol": "ETH", + "id": "meter", + "name": "Meter", + "coinId": 18000, + "chainId": "82", + "symbol": "MTR", "decimals": 18, "blockchain": "Ethereum", "derivation": [ @@ -2046,27 +4105,26 @@ ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", - "chainId": "42161", - "addressHasher": "keccak256", "explorer": { - "url": "https://arbiscan.io", + "url": "https://scan.meter.io", "txPath": "/tx/", - "accountPath": "/address/" + "accountPath": "/address/", + "sampleTx": "0x8ea268d5dbb40217c763b800a75fc063cf28b56f40f2bc69dc043f5c4bbdc144", + "sampleAccount": "0xe5a273954d24eddf9ae9ea4cef2347d584cfa3dd" }, "info": { - "url": "https://arbitrum.io", - "source": "https://github.com/OffchainLabs/arbitrum", - "rpc": "https://node.offchainlabs.com:8547", - "documentation": "https://developer.offchainlabs.com" + "url": "https://meter.io/", + "source": "https://github.com/meterio/meter-pov", + "rpc": "https://rpc.meter.io", + "documentation": "https://docs.meter.io/" } }, { - "id": "heco", - "name": "ECO Chain", - "displayName": "Huobi ECO Chain", - "coinId": 10000553, - "slip44": 553, - "symbol": "HT", + "id": "okc", + "name": "OKX Chain", + "coinId": 996, + "chainId": "66", + "symbol": "OKT", "decimals": 18, "blockchain": "Ethereum", "derivation": [ @@ -2076,26 +4134,27 @@ ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", - "chainId": "128", "addressHasher": "keccak256", "explorer": { - "url": "https://hecoinfo.com", + "url": "https://www.oklink.com/oktc", "txPath": "/tx/", - "accountPath": "/address/" + "accountPath": "/address/", + "sampleTx": "0x46C3A947E8248570FBD28E4FE456CC8F80DFD90716533878FB67857B95FA3D37", + "sampleAccount": "0x074faafd0b20fad2efa115b8ed7e75993e580b85" }, "info": { - "url": "https://www.hecochain.com/en-us", - "source": "https://github.com/HuobiGroup/huobi-eco-chain", - "rpc": "https://http-mainnet-node.huobichain.com", - "documentation": "https://eth.wiki/json-rpc/API" - }, - "testFolderName" : "ECO" + "url": "https://www.okx.com/okc", + "source": "https://github.com/okex/exchain", + "rpc": "https://exchainrpc.okex.org", + "documentation": "https://okc-docs.readthedocs.io/en/latest" + } }, { - "id": "avalanchec", - "name": "Avalanche C-Chain", - "coinId": 10009000, - "symbol": "AVAX", + "id": "cfxevm", + "name": "Conflux eSpace", + "coinId": 1030, + "chainId": "1030", + "symbol": "CFX", "decimals": 18, "blockchain": "Ethereum", "derivation": [ @@ -2105,59 +4164,58 @@ ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", - "chainId": "43114", "addressHasher": "keccak256", "explorer": { - "url": "https://snowtrace.io", + "url": "https://evm.confluxscan.net", "txPath": "/tx/", "accountPath": "/address/", - "sampleTx": "0x9243890b844219accefd8798271052f5a056453ec18984a56e81c92921330d54", - "sampleAccount": "0xa664325f36Ec33E66323fe2620AF3f2294b2Ef3A" + "sampleTx": "0x920efefb3213b2d6a3b84149cb50b61a813d085443a20e1b0eab74120e41ff72", + "sampleAccount": "0x337a087daef75c72871de592fbbba570829a936a" }, "info": { - "url": "https://www.avalabs.org/", - "client": "https://github.com/ava-labs/avalanchego", - "clientPublic": "https://api.avax.network/ext/bc/C/rpc", - "clientDocs": "https://docs.avax.network/" - }, - "testFolderName" : "Avalanche" + "url": "https://confluxnetwork.org", + "source": "https://github.com/conflux-chain", + "rpc": "https://evm.confluxrpc.com", + "documentation": "https://doc.confluxnetwork.org/docs/espace" + } }, { - "id": "xdai", - "name": "xDai", - "displayName": "Gnosis Chain", - "coinId": 10000100, - "symbol": "xDAI", + "id": "greenfield", + "name": "Greenfield", + "displayName": "BNB Greenfield", + "coinId": 5600, + "symbol": "BNB", "decimals": 18, - "blockchain": "Ethereum", + "chainId": "1017", + "blockchain": "Greenfield", "derivation": [ { "path": "m/44'/60'/0'/0/0" } ], "curve": "secp256k1", - "publicKeyType": "secp256k1Extended", - "chainId": "100", + "publicKeyType": "secp256k1", "addressHasher": "keccak256", "explorer": { - "url": "https://blockscout.com/xdai/mainnet", + "url": "https://greenfieldscan.com", "txPath": "/tx/", - "accountPath": "/address/", - "sampleTx": "0x936798a1ef607c9e856d7861b15999c770c06f0887c4fc1f6acbf3bef09899c1", - "sampleAccount": "0x12d61a95CF55e18D267C2F1AA67d8e42ae1368f8" + "accountPath": "/account/", + "sampleTx": "0x150eac42070957115fd538b1f348fadd78d710fb641c248120efcf35d1e7e4f3", + "sampleAccount": "0xcf0f6b88ed72653b00fdebbffc90b98072cb3285" }, "info": { - "url": "https://www.xdaichain.com", - "client": "https://github.com/openethereum/openethereum", - "clientPublic": "https://rpc.gnosischain.com", - "clientDocs": "https://eth.wiki/json-rpc/API" + "url": "https://greenfield.bnbchain.org", + "source": "https://github.com/bnb-chain/greenfield", + "rpc": "https://gnfd-testnet-fullnode-tendermint-us.bnbchain.org", + "documentation": "https://docs.bnbchain.org/greenfield-docs" } }, { - "id": "fantom", - "name": "Fantom", - "coinId": 10000250, - "symbol": "FTM", + "id": "opbnb", + "name": "OpBNB", + "coinId": 204, + "chainId": "204", + "symbol": "BNB", "decimals": 18, "blockchain": "Ethereum", "derivation": [ @@ -2167,187 +4225,189 @@ ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", - "chainId": "250", "addressHasher": "keccak256", "explorer": { - "url": "https://ftmscan.com", + "url": "https://opbnbscan.com", "txPath": "/tx/", "accountPath": "/address/", - "sampleTx": "0xb0a741d882291951de1fac72e90b9baf886ddb0c9c87658a0c206490dfaa5202", - "sampleAccount": "0x9474feb9917b87da6f0d830ba66ee0035835c0d3" + "sampleTx": "0x788ea8fb4a82dae957f1d3b18af3cd0bbde55a276e66bd17af8c869f24c03a0f", + "sampleAccount": "0x4eaf936c172b5e5511959167e8ab4f7031113ca3" }, "info": { - "url": "https://fantom.foundation", - "client": "https://github.com/openethereum/openethereum", - "clientPublic": "https://rpc.ftm.tools", - "clientDocs": "https://eth.wiki/json-rpc/API" + "url": "https://opbnb.bnbchain.org/en", + "source": "https://github.com/bnb-chain/opbnb", + "rpc": "https://opbnb-mainnet-rpc.bnbchain.org", + "documentation": "https://docs.bnbchain.org/opbnb-docs" } }, { - "id": "cryptoorg", - "name": "CryptoOrg", - "displayName": "Crypto.org", - "coinId": 394, - "symbol": "CRO", + "id": "stratis", + "name": "Stratis", + "coinId": 105105, + "symbol": "STRAX", "decimals": 8, - "blockchain": "Cosmos", + "blockchain": "Bitcoin", "derivation": [ { - "path": "m/44'/394'/0'/0/0" + "name": "segwit", + "path": "m/44'/105105'/0'/0/0", + "xpub": "xpub", + "xprv": "xprv" } ], "curve": "secp256k1", "publicKeyType": "secp256k1", - "hrp": "cro", - "chainId": "crypto-org-chain-mainnet-1", - "addressHasher": "sha256ripemd", + "hrp": "strax", + "p2pkhPrefix": 75, + "p2shPrefix": 140, + "publicKeyHasher": "sha256ripemd", + "base58Hasher": "sha256d", "explorer": { - "url": "https://crypto.org/explorer", - "txPath": "/tx/", - "accountPath": "/account/", - "sampleTx": "D87D2EB46B21466886EE149C1DEA3AE6C2E019C7D8C24FA1533A95439DDCE1E2", - "sampleAccount": "cro10wrflcdc4pys9vvgqm98yg7yv5ltj7d3xehent" + "url": "https://explorer.rutanio.com/strax/explorer", + "txPath": "/transaction/", + "accountPath": "/address/", + "sampleTx": "3923df87e83859dec8b87a414cbb1529113788c512a4d0c283e1394c274f0bfb", + "sampleAccount": "XWqnSWzQA5kDAS727UTYtXkdcbKc8mEvyN" }, "info": { - "url": "https://crypto.org/", - "client": "https://github.com/crypto-org-chain/chain-main", - "clientPublic": "https://mainnet.crypto.org:1317/", - "clientDocs": "https://crypto.org/docs/resources/chain-integration.html#api-documentation" + "url": "https://www.stratisplatform.com/", + "source": "https://github.com/stratisproject", + "rpc": "", + "documentation": "https://academy.stratisplatform.com/index.html" } }, { - "id": "celo", - "name": "Celo", - "coinId": 52752, - "symbol": "CELO", - "decimals": 18, - "blockchain": "Ethereum", + "id": "Nebl", + "name": "Nebl", + "coinId": 146, + "symbol": "NEBL", + "decimals": 8, + "blockchain": "Verge", "derivation": [ { - "path": "m/44'/60'/0'/0/0" + "path": "m/44'/146'/0'/0/0", + "xpub": "xpub", + "xprv": "xprv" } ], "curve": "secp256k1", - "publicKeyType": "secp256k1Extended", - "chainId": "42220", - "addressHasher": "keccak256", + "publicKeyType": "secp256k1", + "p2pkhPrefix": 53, + "p2shPrefix": 112, + "publicKeyHasher": "sha256ripemd", + "base58Hasher": "sha256d", "explorer": { - "url": "https://explorer.celo.org", + "url": "https://explorer.nebl.io", "txPath": "/tx/", "accountPath": "/address/", - "sampleTx": "0xaf41ee58afe633dc7b179c15693cca40fe0372c1d7c70351620105d59d326693", - "sampleAccount": "0xFBFf95e2Fa7e4Ff3aeA34eFB05fB60F9968a6aaD" + "sampleTx": "1e56c745ab87d702c98eddc6bc2475b2eb292ed4af92d170b2362c8a089272a4", + "sampleAccount": "NboLGGKWtK5eXzaah5GVpXju9jCcoMi4cc" }, "info": { - "url": "https://celo.org", - "client": "https://github.com/celo-org/celo-blockchain", - "clientPublic": "https://forno.celo.org", - "clientDocs": "https://eth.wiki/json-rpc/API" + "url": "https://nebl.io", + "source": "https://github.com/NeblioTeam", + "rpc": "", + "documentation": "https://github.com/NeblioTeam" } }, { - "id": "ronin", - "name": "Ronin", - "coinId": 10002020, - "slip44": 60, - "symbol": "RON", - "decimals": 18, - "blockchain": "Ronin", + "id": "hedera", + "name": "Hedera", + "coinId": 3030, + "symbol": "HBAR", + "decimals": 8, + "blockchain": "Hedera", "derivation": [ { - "path": "m/44'/60'/0'/0/0" + "path": "m/44'/3030'/0'/0'/0" } ], - "curve": "secp256k1", - "publicKeyType": "secp256k1Extended", - "chainId": "2020", - "addressHasher": "keccak256", + "curve": "ed25519", + "publicKeyType": "ed25519", "explorer": { - "url": "https://explorer.roninchain.com", - "txPath": "/tx/", - "accountPath": "/address/", - "sampleTx": "0xc09835aaf9c1cacea8ce322865583c791d3a4dfbd9a3b72f79539db88d3697ab", - "sampleAccount": "0xdc05ecd5fbdb64058d94f3182d66f44342b9adcb" + "url": "https://hashscan.io/mainnet", + "txPath": "/transaction/", + "accountPath": "/account/", + "sampleTx": "0.0.19790-1666769504-858851231", + "sampleAccount": "0.0.19790" }, "info": { - "url": "https://whitepaper.axieinfinity.com/technology/ronin-ethereum-sidechain", - "client": "https://github.com/axieinfinity/ronin-smart-contracts", - "clientPublic": "https://api.roninchain.com/rpc", - "clientDocs": "https://eth.wiki/json-rpc/API" + "url": "https://hedera.com/", + "source": "https://github.com/hashgraph", + "documentation": "https://docs.hedera.com" } }, { - "id": "osmosis", - "name": "Osmosis", - "displayName": "Osmosis", - "coinId": 10000118, - "symbol": "OSMO", + "id": "agoric", + "name": "Agoric", + "coinId": 564, + "symbol": "BLD", "decimals": 6, "blockchain": "Cosmos", "derivation": [ { - "path": "m/44'/118'/0'/0/0" + "path": "m/44'/564'/0'/0/0" } ], "curve": "secp256k1", "publicKeyType": "secp256k1", - "hrp": "osmo", - "chainId": "osmosis-1", + "hrp": "agoric", + "chainId": "agoric-3", "addressHasher": "sha256ripemd", "explorer": { - "url": "https://mintscan.io/osmosis", - "txPath": "/txs/", - "accountPath": "/account/", - "sampleTx": "5A6E50A6F2927E4B8C87BB094D5FBF15F1287429A09111806FC44B3CD86CACA8", - "sampleAccount": "osmo1mky69cn8ektwy0845vec9upsdphktxt0en97f5" - }, - "info": { - "url": "https://osmosis.zone/", - "client": "https://github.com/osmosis-labs/osmosis", - "clientPublic": "https://rpc-osmosis.keplr.app/", - "clientDocs": "" + "url": "https://atomscan.com/agoric", + "txPath": "/transactions/", + "accountPath": "/accounts/", + "sampleTx": "576224B1A0F3D56BA23C5350C2A0E3CEA86F40005B828793E5ACBC2F4813152E", + "sampleAccount": "agoric1cqvwa8jr6pmt45jndanc8lqmdsxjkhw0yertc0" + }, + "info": { + "url": "https://agoric.com", + "source": "https://github.com/Agoric/agoric-sdk", + "rpc": "https://agoric-rpc.polkachu.com", + "documentation": "https://docs.agoric.com" } }, { - "id": "ecash", - "name": "eCash", - "coinId": 899, - "symbol": "XEC", - "decimals": 2, - "blockchain": "Bitcoin", + "id": "dydx", + "name": "Dydx", + "displayName": "dYdX", + "coinId": 22000118, + "symbol": "DYDX", + "decimals": 18, + "blockchain": "Cosmos", "derivation": [ { - "path": "m/44'/899'/0'/0/0", - "xpub": "xpub", - "xprv": "xprv" + "path": "m/44'/118'/0'/0/0" } ], "curve": "secp256k1", "publicKeyType": "secp256k1", - "p2pkhPrefix": 0, - "p2shPrefix": 5, - "hrp": "ecash", - "publicKeyHasher": "sha256ripemd", - "base58Hasher": "sha256d", + "hrp": "dydx", + "chainId": "dydx-mainnet-1", + "addressHasher": "sha256ripemd", "explorer": { - "url": "https://explorer.bitcoinabc.org", + "url": "https://www.mintscan.io/dydx", "txPath": "/tx/", - "accountPath": "/address/" + "accountPath": "/address/", + "sampleTx": "F236222E4F7C92FA84711FD6451ED22DD56CBDFA319BFDAFB99A21E4E9B9EC2F", + "sampleAccount": "dydx1adl7usw7z2dnysyn7wvrghu0u0q6gr7jqs4gtt" }, "info": { - "url": "https://e.cash", - "source": "https://github.com/trezor/blockbook", - "rpc": "https://blockbook.fabien.cash:9197", - "documentation": "https://github.com/trezor/blockbook/blob/master/docs/api.md" + "url": "https://dydx.exchange", + "source": "https://github.com/dydxprotocol", + "rpc": "https://dydx-dao-api.polkachu.com", + "documentation": "https://docs.dydx.exchange" } }, { - "id": "cronos", - "name": "Cronos Chain", - "coinId": 10000025, - "symbol": "CRO", + "id": "nativeinjective", + "name": "NativeInjective", + "displayName": "Native Injective", + "coinId": 10000060, + "symbol": "INJ", "decimals": 18, - "blockchain": "Ethereum", + "blockchain": "NativeInjective", "derivation": [ { "path": "m/44'/60'/0'/0/0" @@ -2355,28 +4415,30 @@ ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", - "chainId": "25", + "hrp": "inj", "addressHasher": "keccak256", + "chainId": "injective-1", "explorer": { - "url": "https://cronoscan.com", - "txPath": "/tx/", - "accountPath": "/address/" + "url": "https://www.mintscan.io/injective", + "txPath": "/txs/", + "accountPath": "/account/", + "sampleTx": "C5F6A4FF9DF1AE9FF543D2CEBD8E3E9B04290B2445F9D91D7707EDBF4B7EE16B", + "sampleAccount": "inj1xmpkmxr4as00em23tc2zgmuyy2gr4h3wgcl6vd" }, "info": { - "url": "https://cronos.org", - "client": "https://github.com/crypto-org-chain/cronos", - "clientPublic": "https://evm-cronos.crypto.org", - "clientDocs": "https://eth.wiki/json-rpc/API" - }, - "testFolderName" : "Cronos" + "url": "https://injective.com", + "documentation": "https://docs.injective.network" + } }, { - "id": "kavaevm", - "name": "KavaEvm", - "coinId": 10002222, - "symbol": "KAVA", + "id": "nativecanto", + "name": "NativeCanto", + "displayName": "NativeCanto", + "coinId": 10007700, + "symbol": "CANTO", "decimals": 18, - "blockchain": "Ethereum", + "blockchain": "Cosmos", + "chainId": "canto_7700-1", "derivation": [ { "path": "m/44'/60'/0'/0/0" @@ -2384,27 +4446,29 @@ ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", - "chainId": "2222", + "hrp": "canto", "addressHasher": "keccak256", "explorer": { - "url": "https://explorer.kava.io", - "txPath": "/tx/", - "accountPath": "/address/" + "url": "https://mintscan.io/canto", + "txPath": "/txs/", + "accountPath": "/account/", + "sampleTx": "7A7830270097AA9AC8B819EFBB8E0B56579F20ECB7615ECD37E19ABEEFB8DB83", + "sampleAccount": "canto17xpfvakm2amg962yls6f84z3kell8c5lz0zsl4" }, "info": { - "url": "https://www.kava.io/", - "client": "https://github.com/Kava-Labs/kava", - "documentation": "https://docs.kava.io/docs/ethereum/overview/", - "rpc": "https://evm.kava.io" + "url": "https://canto.io/", + "documentation": "https://docs.canto.io/" } }, { - "id": "smartbch", - "name": "Smart Bitcoin Cash", - "coinId": 10000145, - "symbol": "BCH", + "id": "zetachain", + "name": "NativeZetaChain", + "displayName": "NativeZetaChain", + "coinId": 10007000, + "symbol": "ZETA", "decimals": 18, - "blockchain": "Ethereum", + "blockchain": "Cosmos", + "chainId": "zetachain_7000-1", "derivation": [ { "path": "m/44'/60'/0'/0/0" @@ -2412,28 +4476,25 @@ ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", - "chainId": "10000", + "hrp": "zeta", "addressHasher": "keccak256", "explorer": { - "url": "https://www.smartscan.cash", - "txPath": "/tx/", + "url": "https://explorer.zetachain.com", + "txPath": "/cosmos/tx/", "accountPath": "/address/", - "sampleTx": "0x6413466b455b17d03c7a8ce2d7f99fec34bcd338628bdd2d0580a21e3197a4d9", - "sampleAccount": "0xFeEc227410E1DF9f3b4e6e2E284DC83051ae468F" + "sampleTx": "2DBB071DDD47985F4470A21E5943CE95D371AE4BDE2267E201D3553FB2BDCFDE", + "sampleAccount": "zeta14py36sx57ud82t9yrks9z6hdsrpn5x6kmxs0ne" }, "info": { - "url": "https://smartbch.org/", - "source": "https://github.com/smartbch/smartbch", - "rpc": "https://smartbch.fountainhead.cash/mainnet", - "documentation": "https://github.com/smartbch/docs/blob/main/developers-guide/jsonrpc.md" - }, - "testFolderName" : "Bitcoin" + "url": "https://www.zetachain.com/", + "documentation": "https://www.zetachain.com/docs/" + } }, { - "id": "kcc", - "name": "KuCoin Community Chain", - "coinId": 10000321, - "symbol": "KCS", + "id": "zetaevm", + "name": "Zeta EVM", + "coinId": 20007000, + "symbol": "ZETA", "decimals": 18, "blockchain": "Ethereum", "derivation": [ @@ -2443,58 +4504,53 @@ ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", - "chainId": "321", + "chainId": "7000", "addressHasher": "keccak256", "explorer": { - "url": "https://explorer.kcc.io/en", - "txPath": "/tx/", + "url": "https://explorer.zetachain.com", + "txPath": "/evm/tx/", "accountPath": "/address/", - "sampleTx": "0x2f0d79cd289a02f3181b68b9583a64c3809fe7387810b274275985c29d02c80d", - "sampleAccount": "0x4446fc4eb47f2f6586f9faab68b3498f86c07521" + "sampleTx": "0x04cb1201857de29af97b755e51c888454fb96c1f3bb3c1329bb94d5353d5c19e", + "sampleAccount": "0x85539A58F9c88DdDccBaBBfc660968323Fd1e167" }, "info": { - "url": "https://www.kcc.io/", - "source": "https://github.com/kcc-community/kcc", - "rpc": "https://rpc-mainnet.kcc.network", - "documentation": "https://docs.kcc.io/#/en-us/" - }, - "testFolderName" : "KuCoinCommunityChain" + "url": "https://www.zetachain.com/", + "documentation": "https://www.zetachain.com/docs/" + } }, { - "id": "boba", - "name": "Boba", - "coinId": 10000288, - "symbol": "BOBAETH", - "decimals": 18, - "blockchain": "Ethereum", + "id": "ton", + "name": "TON", + "coinId": 607, + "symbol": "TON", + "decimals": 9, + "blockchain": "TheOpenNetwork", "derivation": [ { - "path": "m/44'/60'/0'/0/0" + "path": "m/44'/607'/0'" } ], - "curve": "secp256k1", - "publicKeyType": "secp256k1Extended", - "chainId": "288", - "addressHasher": "keccak256", + "curve": "ed25519", + "publicKeyType": "ed25519", "explorer": { - "url": "https://blockexplorer.boba.network", - "txPath": "/tx/", - "accountPath": "/address/", - "sampleTx": "0x31533707c3feb3b10f7deeea387ff8893f229253e65ca6b14d2400bf95b5d103", - "sampleAccount": "0x4F96F50eDB37a19216d87693E5dB241e31bD3735" + "url": "https://tonviewer.com", + "txPath": "/transaction/", + "accountPath": "/", + "sampleTx": "fJXfn0EVhV09HFuEgUHu4Cchb24nUQtIMwSzmzk2tLs=", + "sampleAccount": "EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N" }, "info": { - "url": "https://boba.network/", - "source": "https://github.com/bobanetwork/boba", - "rpc": "https://mainnet.boba.network", - "documentation": "https://docs.boba.network/" + "url": "https://ton.org", + "source": "https://github.com/ton-blockchain", + "rpc": "https://toncenter.com/api/v2/jsonRPC", + "documentation": "https://ton.org/docs" } }, { - "id": "metis", - "name": "Metis", - "coinId": 10001088, - "symbol": "METIS", + "id": "neon", + "name": "Neon", + "coinId": 245022934, + "symbol": "NEON", "decimals": 18, "blockchain": "Ethereum", "derivation": [ @@ -2504,57 +4560,57 @@ ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", - "chainId": "1088", + "chainId": "245022934", "addressHasher": "keccak256", "explorer": { - "url": "https://andromeda-explorer.metis.io", + "url": "https://neonscan.org", "txPath": "/tx/", "accountPath": "/address/", - "sampleTx": "0x422f2ebbede32d4434ad0cf0ae55d44a84e14d3d5725a760133255b42676d8ce", - "sampleAccount": "0xBe9E8Ec25866B21bA34e97b9393BCabBcB4A5C86" + "sampleTx": "0x77d86af2c6f02f14ef13ca52bf54864d92fcc4b32d8e884e225061c006738ed6", + "sampleAccount": "0xfa4a8650e7bebb918859c280a86f9661bed29877" }, "info": { - "url": "https://www.metis.io/", - "source": "https://github.com/MetisProtocol/mvm", - "rpc": "https://andromeda.metis.io/?owner=1088", - "documentation": "https://docs.metis.io/" + "url": "https://neonevm.org", + "source": "https://github.com/neonevm/neon-evm", + "rpc": "https://neon-proxy-mainnet.solana.p2p.org/", + "documentation": "https://docs.neonfoundation.io/docs/quick_start" } }, { - "id": "aurora", - "name": "Aurora", - "coinId": 1323161554, - "symbol": "ETH", - "decimals": 18, - "blockchain": "Ethereum", + "id": "internet_computer", + "name": "Internet Computer", + "coinId": 223, + "symbol": "ICP", + "decimals": 8, + "blockchain": "InternetComputer", "derivation": [ { - "path": "m/44'/60'/0'/0/0" + "path": "m/44'/223'/0'/0/0", + "xpub": "xpub", + "xpriv": "xpriv" } ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", - "chainId": "1313161554", - "addressHasher": "keccak256", "explorer": { - "url": "https://aurorascan.dev", - "txPath": "/tx/", - "accountPath": "/address/", - "sampleTx": "0x99deebdb70f8027037abb3d3d0f3c7523daee857d85e9056d2671593ff2f2f28", - "sampleAccount": "0x8707cdE20dd43E3dB1F74c28fcd509ef38B0bA51" + "url": "https://dashboard.internetcomputer.org", + "txPath": "/transaction/", + "accountPath": "/account/", + "sampleTx": "9e32c54975adf84a1d98f19df41bbc34a752a899c32cc9c0000200b2c4308f85", + "sampleAccount": "529ea51c22e8d66e8302eabd9297b100fdb369109822248bb86939a671fbc55b" }, "info": { - "url": "https://aurora.dev/", - "source": "https://github.com/aurora-is-near/aurora-engine", - "rpc": "https://mainnet.aurora.dev/", - "documentation": "https://doc.aurora.dev/" + "url": "https://internetcomputer.org", + "source": "https://github.com/dfinity/ic", + "rpc": "", + "documentation": "https://internetcomputer.org/docs" } }, { - "id": "evmos", - "name": "Evmos", - "coinId": 10009001, - "symbol": "EVMOS", + "id": "manta", + "name": "Manta Pacific", + "coinId": 169, + "symbol": "ETH", "decimals": 18, "blockchain": "Ethereum", "derivation": [ @@ -2564,31 +4620,29 @@ ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", - "chainId": "9001", + "chainId": "169", "addressHasher": "keccak256", "explorer": { - "url": "https://evm.evmos.org", + "url": "https://pacific-explorer.manta.network", "txPath": "/tx/", "accountPath": "/address/", - "sampleTx": "0x24af42cf4977a96d62e3a82c3cd9b519c3e7c53dd83398b88f0cb435d867b422", - "sampleAccount": "0x30627903124Aa1e71384bc52e1cb96E4AB3252b6" + "sampleTx": "0x2bbd5d85b0ed05d1416e30ce1197a6f0c27d10ce02593a2719e2baf486d2e8c2", + "sampleAccount": "0xF122a1aC569a36a5Cf6d0F828A22254c8A9afF84" }, "info": { - "url": "https://evmos.org/", - "source": "https://github.com/tharsis/evmos", - "rpc": "https://eth.bd.evmos.org:8545", - "documentation": "https://docs.evmos.org/" + "url": "https://pacific.manta.network", + "source": "https://github.com/manta-network", + "rpc": "https://pacific-rpc.manta.network/http", + "documentation": "https://docs.manta.network/docs/Introduction" } }, { - "id": "nativeevmos", - "name": "NativeEvmos", - "displayName": "Native Evmos", - "coinId": 20009001, - "symbol": "EVMOS", + "id": "merlin", + "name": "Merlin", + "coinId": 4200, + "symbol": "BTC", "decimals": 18, - "blockchain": "Cosmos", - "chainId": "evmos_9001-2", + "blockchain": "Ethereum", "derivation": [ { "path": "m/44'/60'/0'/0/0" @@ -2596,27 +4650,28 @@ ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", - "hrp": "evmos", + "chainId": "4200", "addressHasher": "keccak256", "explorer": { - "url": "https://mintscan.io/evmos", - "txPath": "/txs/", - "accountPath": "/account/", - "sampleTx": "A16C211C83AD1E684DE46F694FAAC17D8465C864BD7385A81EC062CDE0638811", - "sampleAccount": "evmos17xpfvakm2amg962yls6f84z3kell8c5ljcjw34" + "url": "https://scan.merlinchain.io", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "0xca6f2891959b669237738dd0bc2c1051d966778c9de90b94165032ce58364212", + "sampleAccount": "0xf7e017b3f61bD3410A3b03D7DAD7699FD6780584" }, "info": { - "url": "https://evmos.org/", - "client": "https://github.com/tharsis/evmos", - "clientPublic": "https://rest.bd.evmos.org:1317", - "clientDocs": "" + "url": "https://merlinchain.io", + "source": "https://merlinchain.io", + "rpc": "https://rpc.merlinchain.io", + "documentation": "https://docs.merlinchain.io/merlin-docs" } }, { - "id": "moonriver", - "name": "Moonriver", - "coinId": 10001285, - "symbol": "MOVR", + "id": "lightlink", + "name": "Lightlink", + "displayName": "Lightlink Phoenix", + "coinId": 1890, + "symbol": "ETH", "decimals": 18, "blockchain": "Ethereum", "derivation": [ @@ -2626,24 +4681,27 @@ ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", - "chainId": "1285", + "chainId": "1890", + "addressHasher": "keccak256", "explorer": { - "url": "https://moonriver.moonscan.io", + "url": "https://phoenix.lightlink.io", "txPath": "/tx/", "accountPath": "/address/", - "sampleTx": "0x2e2daa3943ba65d9bbb910a4f6765aa6a466a0ef8935090547ca9d30e201e032", - "sampleAccount": "0x899831D937937d011305E73EE782cce0455DF15a" + "sampleTx": "0xc65f82445aefc883fd4ffe09149c8ce48f61b670c0734528a49d4a8bd8309bb0", + "sampleAccount": "0x4566ED6c7a7fFc90E2C7cfF7eB9156262afD2fDe" }, "info": { - "url": "https://moonbeam.network/networks/moonriver", - "rpc": "https://moonriver.public.blastapi.io" + "url": "https://lightlink.io", + "source": "https://github.com/lightlink-network", + "rpc": "https://endpoints.omniatech.io/v1/lightlink/phoenix/public", + "documentation": "https://docs.lightlink.io/lightlink-protocol" } }, { - "id": "moonbeam", - "name": "Moonbeam", - "coinId": 10001284, - "symbol": "GLMR", + "id": "blast", + "name": "Blast", + "coinId": 81457, + "symbol": "ETH", "decimals": 18, "blockchain": "Ethereum", "derivation": [ @@ -2653,25 +4711,27 @@ ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", - "chainId": "1284", + "chainId": "81457", + "addressHasher": "keccak256", "explorer": { - "url": "https://moonscan.io", + "url": "https://blastscan.io", "txPath": "/tx/", "accountPath": "/address/", - "sampleTx": "0xb22a146c933e6e51affbfa5f712a266b5f5e92ae453cd2f252bcc3c36ff035a6", - "sampleAccount": "0x201bb4f276C765dF7225e5A4153E17edD23a67eC" + "sampleTx": "0x511fc00e8329343b9e953bf1f75e9b0a7b3cc2eb3a8f049d5be41adf4fbd6cac", + "sampleAccount": "0x0d11f2f0ff55c4fcfc3ff86bdc8e78ffa7df99fd" }, "info": { - "url": "https://moonbeam.network", - "rpc": "https://rpc.api.moonbeam.network", - "documentation": "https://docs.moonbeam.network" + "url": "https://blast.io", + "source": "https://github.com/blast-io", + "rpc": "https://rpc.blast.io", + "documentation": "https://docs.blast.io" } }, { - "id": "klaytn", - "name": "Klaytn", - "coinId": 10008217, - "symbol": "KLAY", + "id": "bouncebit", + "name": "BounceBit", + "coinId": 6001, + "symbol": "BB", "decimals": 18, "blockchain": "Ethereum", "derivation": [ @@ -2681,26 +4741,28 @@ ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", - "chainId": "8217", + "chainId": "6001", + "addressHasher": "keccak256", "explorer": { - "url": "https://scope.klaytn.com", + "url": "https://bbscan.io", "txPath": "/tx/", - "accountPath": "/account/", - "sampleTx": "0x93ea92687845fe7bb6cacd69c76a16a2a3c2bbb85a8a93ff0e032d0098d583d7", - "sampleAccount": "0x2ad9656bf5b82caf10847b431012e28e301e83ba" + "accountPath": "/address/", + "sampleTx": "0x52558f4143d058d942e3b73414090266ae3ffce1fe8c25fe86896e2c8e5ef932", + "sampleAccount": "0xf4aa7349a9ccca4609943955b5ddc7bd9278c223" }, "info": { - "url": "https://klaytn.foundation", - "rpc": "https://public-node-api.klaytnapi.com/v1/cypress", - "documentation": "https://docs.klaytn.foundation" + "url": "https://bouncebit.io", + "source": "https://github.com/BounceBit-Labs", + "rpc": "https://fullnode-mainnet.bouncebitapi.com", + "documentation": "https://docs.bouncebit.io" } }, { - "id": "meter", - "name": "Meter", - "coinId": 18000, - "chainId": "82", - "symbol": "MTR", + "id": "zklinknova", + "name": "ZkLinkNova", + "displayName": "zkLink Nova Mainnet", + "coinId": 810180, + "symbol": "ETH", "decimals": 18, "blockchain": "Ethereum", "derivation": [ @@ -2710,48 +4772,47 @@ ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", + "chainId": "810180", + "addressHasher": "keccak256", "explorer": { - "url": "https://scan.meter.io", + "url": "https://explorer.zklink.io", "txPath": "/tx/", "accountPath": "/address/", - "sampleTx": "0x8ea268d5dbb40217c763b800a75fc063cf28b56f40f2bc69dc043f5c4bbdc144", - "sampleAccount": "0xe5a273954d24eddf9ae9ea4cef2347d584cfa3dd" + "sampleTx": "0xeb5eb8710369c89115a83f3e744c15c9d388030cfce2fd3a653dbd18f2947400", + "sampleAccount": "0xF95115BaD9a4585B3C5e2bfB50579f17163A45aA" }, "info": { - "url": "https://meter.io/", - "source": "https://github.com/meterio/meter-pov", - "rpc": "https://rpc.meter.io", - "documentation": "https://docs.meter.io/" + "url": "https://zklink.io", + "source": "https://github.com/zkLinkProtocol", + "rpc": "https://rpc.zklink.io", + "documentation": "https://docs.zklink.io" } }, { - "id": "okc", - "name": "OKX Chain", - "coinId": 996, - "chainId": "66", - "symbol": "OKT", - "decimals": 18, - "blockchain": "Ethereum", + "id": "pactus", + "name": "Pactus", + "coinId": 21888, + "symbol": "PAC", + "decimals": 9, + "blockchain": "Pactus", "derivation": [ { - "path": "m/44'/60'/0'/0/0" + "path": "m/44'/21888'/3'/0'" } ], - "curve": "secp256k1", - "publicKeyType": "secp256k1Extended", - "addressHasher": "keccak256", + "curve": "ed25519", + "publicKeyType": "ed25519", + "hrp": "pc", "explorer": { - "url": "https://www.oklink.com/en/okc", - "txPath": "/tx/", - "accountPath": "/address/", - "sampleTx": "0x46C3A947E8248570FBD28E4FE456CC8F80DFD90716533878FB67857B95FA3D37", - "sampleAccount": "0x074faafd0b20fad2efa115b8ed7e75993e580b85" + "url": "https://pacviewer.com", + "txPath": "/transaction/", + "accountPath": "/address/" }, "info": { - "url": "https://www.okx.com/okc", - "source": "https://github.com/okex/exchain", - "rpc": "https://exchainrpc.okex.org", - "documentation": "https://okc-docs.readthedocs.io/en/latest" + "url": "https://pactus.org", + "source": "https://github.com/pactus-project/pactus", + "rpc": "https://docs.pactus.org/api/http", + "documentation": "https://docs.pactus.org" } } ] diff --git a/rust/.gitignore b/rust/.gitignore new file mode 100644 index 00000000000..bca6f9b85aa --- /dev/null +++ b/rust/.gitignore @@ -0,0 +1,7 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# These are backup files generated by rustfmt +**/*.rs.bk diff --git a/rust/Cargo.lock b/rust/Cargo.lock new file mode 100644 index 00000000000..e12cf3ea375 --- /dev/null +++ b/rust/Cargo.lock @@ -0,0 +1,2467 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "arbitrary" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db55d72333851e17d572bec876e390cd3b11eb1ef53ae821dd9f3b653d2b4569" + +[[package]] +name = "arbitrary" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e" +dependencies = [ + "derive_arbitrary", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest 0.10.6", + "itertools", + "num-bigint", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.107", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.107", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-std", + "digest 0.10.6", + "num-bigint", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bcs" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b6598a2f5d564fb7855dc6b06fd1c38cff5a72bd8b863a4d021938497b440a" +dependencies = [ + "serde", + "thiserror", +] + +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + +[[package]] +name = "bigdecimal" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aaf33151a6429fe9211d1b276eafdf70cdff28b071e76c0b0e1503221ea3744" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitcoin" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e99ff7289b20a7385f66a0feda78af2fc119d28fb56aea8886a9cd0a4abdd75" +dependencies = [ + "bech32", + "bitcoin-private", + "bitcoin_hashes", + "hex_lit", + "secp256k1", +] + +[[package]] +name = "bitcoin-private" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" + +[[package]] +name = "bitcoin_hashes" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d7066118b13d4b20b23645932dfb3a81ce7e29f95726c2036fa33cd7b092501" +dependencies = [ + "bitcoin-private", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitreader" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd859c9d97f7c468252795b35aeccc412bdbb1e90ee6969c4fa6328272eaeff" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "bitstream-io" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcde5f311c85b8ca30c2e4198d4326bc342c76541590106f5fa4a50946ea499" + +[[package]] +name = "bitvec" +version = "0.20.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7774144344a4faa177370406a7ff5f1da24303817368584c6206c8303eb07848" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake-hash" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94d1988118c887f61418940e322d574e8a2dd67165f1f1556eaae22e4019c6af" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "ppv-lite86", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.6", +] + +[[package]] +name = "blake2b-ref" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "294d17c72e0ba59fad763caa112368d0672083779cdebbb97164f4bb4c1e339a" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +dependencies = [ + "generic-array", +] + +[[package]] +name = "borsh" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f58b559fd6448c6e2fd0adb5720cd98a2506594cafa4737ff98c396f3e82f667" +dependencies = [ + "borsh-derive", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aadb5b6ccbd078890f6d7003694e33816e6b784358f18e15e7e6d9f065a57cd" +dependencies = [ + "once_cell", + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.37", + "syn_derive", +] + +[[package]] +name = "bs58" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" + +[[package]] +name = "bumpalo" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "ciborium" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" + +[[package]] +name = "ciborium-ll" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", + "zeroize", +] + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "const-oid" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c2538c4e68e52548bacb3e83ac549f903d44f011ac9d5abb5e132e67d0808f7" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core", + "typenum", +] + +[[package]] +name = "crypto_box" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16182b4f39a82ec8a6851155cc4c0cda3065bb1db33651726a29e1951de0f009" +dependencies = [ + "aead", + "crypto_secretbox", + "curve25519-dalek", + "salsa20", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto_secretbox" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d6cf87adf719ddf43a805e92c6870a531aedda35ff640442cbaf8674e141e1" +dependencies = [ + "aead", + "cipher", + "generic-array", + "poly1305", + "salsa20", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.6", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + +[[package]] +name = "data-encoding" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" + +[[package]] +name = "der" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b10af9f9f9f2134a42d3f8aa74658660f2e0234b0eb81bd171df8aa32779ed" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derivation-path" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0" + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.107", +] + +[[package]] +name = "derive_arbitrary" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cdeb9ec472d588e539a818b2dee436825730da08ad0017c4b1a17676bdc8b7" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.107", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer 0.10.3", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "ecdsa" +version = "0.16.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a48e5d537b8a30c0b023116d981b16334be1485af7ca68db3a2b7024cbc957fd" +dependencies = [ + "der", + "digest 0.10.6", + "elliptic-curve", + "rfc6979", + "signature", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "elliptic-curve" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75c71eaa367f2e5d556414a8eea812bc62985c879748d6403edabd9cb03f16e7" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.6", + "ff", + "generic-array", + "group", + "hkdf", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "equivalent" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" + +[[package]] +name = "ethnum" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8ff382b2fa527fb7fb06eeebfc5bbb3f17e3cc6b9d70b006c41daa8824adac" + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1676f435fc1dadde4d03e43f5d62b259e1ce5f40bd4ffb21db2b42ebe59c1382" + +[[package]] +name = "fixed-hash" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" +dependencies = [ + "arbitrary 0.4.7", + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "funty" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "groestl" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343cfc165f92a988fd60292f7a0bfde4352a5a0beff9fbec29251ca4e9676e4d" +dependencies = [ + "digest 0.10.6", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex_lit" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" + +[[package]] +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.6", +] + +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + +[[package]] +name = "impl-codec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "161ebdfec3c8e3b52bf61c4f3550a1eea4f9579d10dc1b936f3171ebdcd6c443" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-serde" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.107", +] + +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "js-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "k256" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", + "signature", +] + +[[package]] +name = "keccak" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "move-core-types" +version = "0.0.4" +source = "git+https://github.com/move-language/move?rev=ea70797099baea64f05194a918cebd69ed02b285#ea70797099baea64f05194a918cebd69ed02b285" +dependencies = [ + "anyhow", + "bcs", + "ethnum", + "hex", + "num", + "once_cell", + "primitive-types", + "rand", + "ref-cast", + "serde", + "serde_bytes", + "uint", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "parity-scale-codec" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.107", +] + +[[package]] +name = "paste" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" + +[[package]] +name = "pb-rs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "354a34df9c65b596152598001c0fe3393379ec2db03ae30b9985659422e2607e" +dependencies = [ + "clap", + "env_logger", + "log", + "nom", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "primeorder" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8d3875361e28f7753baefef104386e7aa47642c93023356d97fdef4003bfb5" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "primitive-types" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-serde", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.11", +] + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit 0.21.1", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quick-protobuf" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d6da84cc204722a989e01ba2f6e1e276e190f22263d0cb6ce8526fcdb0d2e1f" +dependencies = [ + "byteorder", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "ref-cast" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c78fb8c9293bcd48ef6fce7b4ca950ceaf21210de6e105a883ee280c0f7b9ed" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f9c0c92af03644e4806106281fe2e068ac5bc0ae74a707266d06ea27bccee5f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.107", +] + +[[package]] +name = "regex" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.6", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + +[[package]] +name = "sec1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48518a2b5775ba8ca5b46596aae011caa431e6ce7e4a67ead66d92f08884220e" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +dependencies = [ + "bitcoin_hashes", + "rand", + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +dependencies = [ + "cc", +] + +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" + +[[package]] +name = "serde" +version = "1.0.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + +[[package]] +name = "serde_json" +version = "1.0.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + +[[package]] +name = "sha1" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.6", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.6", +] + +[[package]] +name = "sha3" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" +dependencies = [ + "digest 0.10.6", + "keccak", +] + +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +dependencies = [ + "digest 0.10.6", + "rand_core", +] + +[[package]] +name = "spki" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a5be806ab6f127c3da44b7378837ebf01dadca8510a0e572460216b228bd0e" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "starknet-crypto" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693e6362f150f9276e429a910481fb7f3bcb8d6aa643743f587cfece0b374874" +dependencies = [ + "crypto-bigint", + "hex", + "hmac", + "num-bigint", + "num-integer", + "num-traits", + "rfc6979", + "sha2", + "starknet-crypto-codegen", + "starknet-curve", + "starknet-ff", + "zeroize", +] + +[[package]] +name = "starknet-crypto-codegen" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6dc88f1f470d9de1001ffbb90d2344c9dd1a615f5467daf0574e2975dfd9ebd" +dependencies = [ + "starknet-curve", + "starknet-ff", + "syn 2.0.37", +] + +[[package]] +name = "starknet-curve" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "252610baff59e4c4332ce3569f7469c5d3f9b415a2240d698fb238b2b4fc0942" +dependencies = [ + "starknet-ff", +] + +[[package]] +name = "starknet-ff" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcdf692e13247ec111718e219caaa44ea1a687e9c36bf6083e1cd1b98374a2ad" +dependencies = [ + "ark-ff", + "bigdecimal", + "crypto-bigint", + "getrandom", + "hex", + "serde", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.37", +] + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.37", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "thiserror" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.107", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" + +[[package]] +name = "toml_edit" +version = "0.19.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow 0.4.7", +] + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "tw_any_coin" +version = "0.1.0" +dependencies = [ + "tw_coin_entry", + "tw_coin_registry", + "tw_encoding", + "tw_hash", + "tw_keypair", + "tw_memory", + "tw_misc", + "tw_proto", +] + +[[package]] +name = "tw_aptos" +version = "0.1.0" +dependencies = [ + "move-core-types", + "serde", + "serde_bytes", + "serde_json", + "tw_coin_entry", + "tw_encoding", + "tw_hash", + "tw_keypair", + "tw_memory", + "tw_number", + "tw_proto", +] + +[[package]] +name = "tw_base58_address" +version = "0.1.0" +dependencies = [ + "serde", + "tw_coin_entry", + "tw_encoding", + "tw_hash", +] + +[[package]] +name = "tw_bech32_address" +version = "0.1.0" +dependencies = [ + "serde", + "tw_coin_entry", + "tw_encoding", + "tw_hash", + "tw_keypair", + "tw_memory", +] + +[[package]] +name = "tw_binance" +version = "0.1.0" +dependencies = [ + "quick-protobuf", + "serde", + "serde_json", + "serde_repr", + "strum_macros", + "tw_bech32_address", + "tw_coin_entry", + "tw_cosmos_sdk", + "tw_encoding", + "tw_evm", + "tw_hash", + "tw_keypair", + "tw_memory", + "tw_misc", + "tw_proto", +] + +[[package]] +name = "tw_bitcoin" +version = "0.1.0" +dependencies = [ + "bitcoin", + "secp256k1", + "serde", + "serde_json", + "tw_base58_address", + "tw_bech32_address", + "tw_coin_entry", + "tw_encoding", + "tw_hash", + "tw_keypair", + "tw_memory", + "tw_misc", + "tw_proto", + "tw_utxo", +] + +[[package]] +name = "tw_bitcoincash" +version = "0.1.0" +dependencies = [ + "tw_bitcoin", + "tw_coin_entry", + "tw_encoding", + "tw_hash", + "tw_keypair", + "tw_memory", + "tw_misc", + "tw_proto", + "tw_utxo", +] + +[[package]] +name = "tw_coin_entry" +version = "0.1.0" +dependencies = [ + "derivation-path", + "serde", + "serde_json", + "tw_encoding", + "tw_hash", + "tw_keypair", + "tw_memory", + "tw_misc", + "tw_number", + "tw_proto", +] + +[[package]] +name = "tw_coin_registry" +version = "0.1.0" +dependencies = [ + "itertools", + "lazy_static", + "serde", + "serde_json", + "strum", + "strum_macros", + "tw_aptos", + "tw_binance", + "tw_bitcoin", + "tw_bitcoincash", + "tw_coin_entry", + "tw_cosmos", + "tw_ethereum", + "tw_evm", + "tw_greenfield", + "tw_hash", + "tw_internet_computer", + "tw_keypair", + "tw_memory", + "tw_misc", + "tw_native_evmos", + "tw_native_injective", + "tw_pactus", + "tw_ronin", + "tw_solana", + "tw_sui", + "tw_thorchain", + "tw_ton", + "tw_utxo", +] + +[[package]] +name = "tw_cosmos" +version = "0.1.0" +dependencies = [ + "tw_coin_entry", + "tw_cosmos_sdk", + "tw_keypair", + "tw_proto", +] + +[[package]] +name = "tw_cosmos_sdk" +version = "0.1.0" +dependencies = [ + "pb-rs", + "quick-protobuf", + "serde", + "serde_json", + "tw_bech32_address", + "tw_coin_entry", + "tw_cosmos_sdk", + "tw_encoding", + "tw_hash", + "tw_keypair", + "tw_memory", + "tw_misc", + "tw_number", + "tw_proto", +] + +[[package]] +name = "tw_encoding" +version = "0.1.0" +dependencies = [ + "arbitrary 1.3.0", + "bcs", + "bech32", + "bs58", + "ciborium", + "data-encoding", + "hex", + "serde", + "serde_bytes", + "tw_memory", +] + +[[package]] +name = "tw_ethereum" +version = "0.1.0" +dependencies = [ + "tw_coin_entry", + "tw_encoding", + "tw_evm", + "tw_keypair", + "tw_number", + "tw_proto", +] + +[[package]] +name = "tw_evm" +version = "0.1.0" +dependencies = [ + "itertools", + "lazy_static", + "rlp", + "serde", + "serde_json", + "tw_coin_entry", + "tw_encoding", + "tw_hash", + "tw_keypair", + "tw_memory", + "tw_misc", + "tw_number", + "tw_proto", +] + +[[package]] +name = "tw_greenfield" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", + "tw_coin_entry", + "tw_cosmos_sdk", + "tw_encoding", + "tw_evm", + "tw_hash", + "tw_keypair", + "tw_memory", + "tw_misc", + "tw_number", + "tw_proto", +] + +[[package]] +name = "tw_hash" +version = "0.1.0" +dependencies = [ + "arbitrary 1.3.0", + "blake-hash", + "blake2b-ref", + "digest 0.10.6", + "groestl", + "hmac", + "ripemd", + "serde", + "serde_json", + "sha1", + "sha2", + "sha3", + "tw_encoding", + "tw_memory", + "zeroize", +] + +[[package]] +name = "tw_internet_computer" +version = "0.1.0" +dependencies = [ + "pb-rs", + "quick-protobuf", + "serde", + "tw_coin_entry", + "tw_encoding", + "tw_hash", + "tw_keypair", + "tw_memory", + "tw_proto", +] + +[[package]] +name = "tw_keypair" +version = "0.1.0" +dependencies = [ + "arbitrary 1.3.0", + "bitcoin", + "blake2", + "crypto_box", + "curve25519-dalek", + "der", + "digest 0.10.6", + "ecdsa", + "k256", + "lazy_static", + "p256", + "pkcs8", + "rand_core", + "rfc6979", + "secp256k1", + "serde", + "serde_json", + "sha2", + "starknet-crypto", + "starknet-ff", + "tw_encoding", + "tw_hash", + "tw_keypair", + "tw_memory", + "tw_misc", + "zeroize", +] + +[[package]] +name = "tw_memory" +version = "0.1.0" + +[[package]] +name = "tw_misc" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", + "zeroize", +] + +[[package]] +name = "tw_native_evmos" +version = "0.1.0" +dependencies = [ + "tw_coin_entry", + "tw_cosmos_sdk", + "tw_hash", + "tw_keypair", + "tw_memory", + "tw_proto", +] + +[[package]] +name = "tw_native_injective" +version = "0.1.0" +dependencies = [ + "tw_coin_entry", + "tw_cosmos_sdk", + "tw_hash", + "tw_keypair", + "tw_memory", + "tw_proto", +] + +[[package]] +name = "tw_number" +version = "0.1.0" +dependencies = [ + "arbitrary 1.3.0", + "lazy_static", + "primitive-types", + "serde", + "tw_encoding", + "tw_hash", + "tw_memory", +] + +[[package]] +name = "tw_pactus" +version = "0.1.0" +dependencies = [ + "bech32", + "byteorder", + "tw_coin_entry", + "tw_encoding", + "tw_hash", + "tw_keypair", + "tw_memory", + "tw_proto", +] + +[[package]] +name = "tw_proto" +version = "0.1.0" +dependencies = [ + "arbitrary 1.3.0", + "pb-rs", + "quick-protobuf", +] + +[[package]] +name = "tw_ronin" +version = "0.1.0" +dependencies = [ + "tw_coin_entry", + "tw_encoding", + "tw_evm", + "tw_keypair", + "tw_memory", + "tw_number", + "tw_proto", +] + +[[package]] +name = "tw_solana" +version = "0.1.0" +dependencies = [ + "bincode", + "borsh", + "lazy_static", + "serde", + "serde_json", + "tw_coin_entry", + "tw_encoding", + "tw_hash", + "tw_keypair", + "tw_memory", + "tw_proto", +] + +[[package]] +name = "tw_sui" +version = "0.1.0" +dependencies = [ + "indexmap", + "move-core-types", + "serde", + "serde_repr", + "tw_coin_entry", + "tw_encoding", + "tw_hash", + "tw_keypair", + "tw_memory", + "tw_proto", +] + +[[package]] +name = "tw_tests" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", + "tw_any_coin", + "tw_coin_entry", + "tw_coin_registry", + "tw_cosmos_sdk", + "tw_encoding", + "tw_hash", + "tw_keypair", + "tw_memory", + "tw_misc", + "tw_number", + "tw_proto", + "tw_solana", + "tw_ton", + "tw_ton_sdk", + "tw_utxo", + "wallet-core-rs", +] + +[[package]] +name = "tw_thorchain" +version = "0.1.0" +dependencies = [ + "tw_coin_entry", + "tw_cosmos_sdk", + "tw_keypair", + "tw_memory", + "tw_proto", +] + +[[package]] +name = "tw_ton" +version = "0.1.0" +dependencies = [ + "lazy_static", + "tw_coin_entry", + "tw_encoding", + "tw_hash", + "tw_keypair", + "tw_memory", + "tw_misc", + "tw_number", + "tw_proto", + "tw_ton_sdk", +] + +[[package]] +name = "tw_ton_sdk" +version = "0.1.0" +dependencies = [ + "bitreader", + "bitstream-io", + "crc", + "lazy_static", + "num-bigint", + "serde", + "serde_json", + "tw_coin_entry", + "tw_encoding", + "tw_hash", + "tw_keypair", + "tw_memory", + "tw_number", +] + +[[package]] +name = "tw_utxo" +version = "0.1.0" +dependencies = [ + "bech32", + "bitcoin", + "byteorder", + "itertools", + "secp256k1", + "strum_macros", + "tw_base58_address", + "tw_bech32_address", + "tw_coin_entry", + "tw_encoding", + "tw_hash", + "tw_keypair", + "tw_memory", + "tw_misc", + "tw_proto", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "arbitrary 1.3.0", + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "uuid" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +dependencies = [ + "getrandom", +] + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wallet-core-rs" +version = "0.1.0" +dependencies = [ + "bitreader", + "tw_any_coin", + "tw_bitcoin", + "tw_coin_registry", + "tw_encoding", + "tw_ethereum", + "tw_hash", + "tw_keypair", + "tw_memory", + "tw_misc", + "tw_number", + "tw_proto", + "tw_solana", + "tw_ton", + "uuid", +] + +[[package]] +name = "wallet_core_bin" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", + "tw_coin_registry", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 1.0.107", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.107", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "winnow" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] diff --git a/rust/Cargo.toml b/rust/Cargo.toml new file mode 100644 index 00000000000..692beec2692 --- /dev/null +++ b/rust/Cargo.toml @@ -0,0 +1,54 @@ +[workspace] +members = [ + "chains/tw_aptos", + "chains/tw_binance", + "chains/tw_bitcoin", + "chains/tw_bitcoincash", + "chains/tw_cosmos", + "chains/tw_ethereum", + "chains/tw_greenfield", + "chains/tw_internet_computer", + "chains/tw_native_evmos", + "chains/tw_native_injective", + "chains/tw_pactus", + "chains/tw_ronin", + "chains/tw_solana", + "chains/tw_sui", + "chains/tw_thorchain", + "chains/tw_ton", + "frameworks/tw_ton_sdk", + "frameworks/tw_utxo", + "tw_any_coin", + "tw_base58_address", + "tw_bech32_address", + "tw_coin_entry", + "tw_coin_registry", + "tw_cosmos_sdk", + "tw_encoding", + "tw_evm", + "tw_hash", + "tw_keypair", + "tw_memory", + "tw_misc", + "tw_number", + "tw_proto", + "tw_tests", + "wallet_core_bin", + "wallet_core_rs", +] + +[profile.release] +strip = true +codegen-units = 1 +panic = "abort" + +[profile.wasm-test] +inherits = "release" +# Fixes an incredibly slow compilation of `curve25519-dalek` package. +opt-level = 1 +debug = true +debug-assertions = true +overflow-checks = true + +[profile.release.package.curve25519-dalek] +opt-level = 2 diff --git a/rust/chains/tw_aptos/Cargo.toml b/rust/chains/tw_aptos/Cargo.toml new file mode 100644 index 00000000000..d78b0e3c644 --- /dev/null +++ b/rust/chains/tw_aptos/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "tw_aptos" +version = "0.1.0" +edition = "2021" + +[dependencies] +serde_json = "1.0" +tw_coin_entry = { path = "../../tw_coin_entry" } +tw_encoding = { path = "../../tw_encoding" } +tw_keypair = { path = "../../tw_keypair" } +tw_proto = { path = "../../tw_proto" } +tw_number = { path = "../../tw_number" } +tw_hash = { path = "../../tw_hash" } +tw_memory = { path = "../../tw_memory" } +move-core-types = { git = "https://github.com/move-language/move", rev = "ea70797099baea64f05194a918cebd69ed02b285", features = ["address32"] } +serde = { version = "1.0", features = ["derive"] } +serde_bytes = "0.11.12" + +[dev-dependencies] +tw_coin_entry = { path = "../../tw_coin_entry", features = ["test-utils"] } +tw_encoding = { path = "../../tw_encoding" } +tw_number = { path = "../../tw_number", features = ["helpers"] } diff --git a/rust/chains/tw_aptos/fuzz/.gitignore b/rust/chains/tw_aptos/fuzz/.gitignore new file mode 100644 index 00000000000..5c404b9583f --- /dev/null +++ b/rust/chains/tw_aptos/fuzz/.gitignore @@ -0,0 +1,5 @@ +target +corpus +artifacts +coverage +Cargo.lock diff --git a/rust/chains/tw_aptos/fuzz/Cargo.toml b/rust/chains/tw_aptos/fuzz/Cargo.toml new file mode 100644 index 00000000000..721a84b3ab9 --- /dev/null +++ b/rust/chains/tw_aptos/fuzz/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "tw_aptos-fuzz" +version = "0.0.0" +publish = false +edition = "2021" + +[package.metadata] +cargo-fuzz = true + +[dependencies] +libfuzzer-sys = "0.4" +tw_proto = { path = "../../tw_proto", features = ["fuzz"] } + +[dependencies.tw_aptos] +path = ".." + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[profile.release] +debug = 1 + +[[bin]] +name = "sign" +path = "fuzz_targets/sign.rs" +test = false +doc = false diff --git a/rust/chains/tw_aptos/fuzz/fuzz_targets/sign.rs b/rust/chains/tw_aptos/fuzz/fuzz_targets/sign.rs new file mode 100644 index 00000000000..5d55e467d14 --- /dev/null +++ b/rust/chains/tw_aptos/fuzz/fuzz_targets/sign.rs @@ -0,0 +1,9 @@ +#![no_main] + +use libfuzzer_sys::fuzz_target; +use tw_aptos::signer::Signer; +use tw_proto::Aptos::Proto; + +fuzz_target!(|input: Proto::SigningInput<'_>| { + let _ = Signer::sign_proto(input); +}); diff --git a/rust/chains/tw_aptos/src/address.rs b/rust/chains/tw_aptos/src/address.rs new file mode 100644 index 00000000000..3915750c625 --- /dev/null +++ b/rust/chains/tw_aptos/src/address.rs @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use move_core_types::account_address::{AccountAddress, AccountAddressParseError}; +use std::fmt::{Display, Formatter}; +use std::str::FromStr; +use tw_coin_entry::coin_entry::CoinAddress; +use tw_coin_entry::error::prelude::*; +use tw_hash::sha3::sha3_256; +use tw_keypair::ed25519; +use tw_memory::Data; + +#[repr(u8)] +pub enum Scheme { + Ed25519 = 0, +} + +#[derive(Clone)] +pub struct Address { + addr: AccountAddress, +} + +impl Address { + pub const LENGTH: usize = AccountAddress::LENGTH; + + /// Initializes an address with a `ed25519` public key. + pub fn with_ed25519_pubkey( + pubkey: &ed25519::sha512::PublicKey, + ) -> Result { + let mut to_hash = pubkey.as_slice().to_vec(); + to_hash.push(Scheme::Ed25519 as u8); + let hashed = sha3_256(to_hash.as_slice()); + let addr = AccountAddress::from_bytes(hashed).map_err(from_account_error)?; + Ok(Address { addr }) + } + + pub fn inner(&self) -> AccountAddress { + self.addr + } +} + +impl Display for Address { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.addr.to_hex_literal()) + } +} + +impl CoinAddress for Address { + #[inline] + fn data(&self) -> Data { + self.addr.to_vec() + } +} + +#[inline] +pub fn from_account_error(_err: AccountAddressParseError) -> AddressError { + AddressError::InvalidInput +} + +impl FromStr for Address { + type Err = AddressError; + + // https://github.com/aptos-labs/aptos-core/blob/261019cbdafe1c514c60c2b74357ea2c77d25e67/types/src/account_address.rs#L44 + fn from_str(s: &str) -> Result { + const NUM_CHARS: usize = AccountAddress::LENGTH * 2; + let mut has_0x = false; + let mut working = s.trim(); + + // Checks if it has a 0x at the beginning, which is okay + if working.starts_with("0x") { + has_0x = true; + working = &working[2..]; + } + + if working.len() > NUM_CHARS || (!has_0x && working.len() < NUM_CHARS) { + return Err(AddressError::InvalidInput); + } + + if !working.chars().all(|c| char::is_ascii_hexdigit(&c)) { + return Err(AddressError::InvalidInput); + } + + let addr = if has_0x { + AccountAddress::from_hex_literal(s.trim()) + } else { + AccountAddress::from_str(s.trim()) + } + .map_err(from_account_error)?; + + Ok(Address { addr }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use tw_keypair::ed25519::sha512::PrivateKey; + + #[test] + fn test_from_public_key() { + let private = PrivateKey::try_from( + "afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5", + ) + .unwrap(); + let public = private.public(); + let addr = Address::with_ed25519_pubkey(&public); + assert_eq!( + addr.as_ref().unwrap().to_string(), + "0x9006fa46f038224e8004bdda97f2e7a60c2c3d135bce7cb15541e5c0aae907a4" + ); + assert_eq!(addr.unwrap().data().len(), Address::LENGTH); + } + + #[test] + fn test_from_account_error() { + assert_eq!( + from_account_error(AccountAddressParseError {}), + AddressError::InvalidInput + ); + } +} diff --git a/rust/chains/tw_aptos/src/aptos_move_packages.rs b/rust/chains/tw_aptos/src/aptos_move_packages.rs new file mode 100644 index 00000000000..e90e6bf2a4b --- /dev/null +++ b/rust/chains/tw_aptos/src/aptos_move_packages.rs @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::transaction_payload::{EntryFunction, TransactionPayload}; +use move_core_types::account_address::AccountAddress; +use move_core_types::ident_str; +use move_core_types::language_storage::{ModuleId, TypeTag}; +use serde_json::json; +use tw_coin_entry::error::prelude::*; +use tw_encoding::bcs; + +pub fn aptos_account_transfer( + to: AccountAddress, + amount: u64, +) -> SigningResult { + Ok(TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("aptos_account").to_owned(), + ), + ident_str!("transfer").to_owned(), + vec![], + vec![bcs::encode(&to)?, bcs::encode(&amount)?], + json!([to.to_hex_literal(), amount.to_string()]), + ))) +} + +pub fn aptos_account_create_account(auth_key: AccountAddress) -> SigningResult { + Ok(TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("aptos_account").to_owned(), + ), + ident_str!("create_account").to_owned(), + vec![], + vec![bcs::encode(&auth_key)?], + json!([auth_key.to_hex_literal()]), + ))) +} + +pub fn coin_transfer( + coin_type: TypeTag, + to: AccountAddress, + amount: u64, +) -> SigningResult { + Ok(TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("coin").to_owned(), + ), + ident_str!("transfer").to_owned(), + vec![coin_type], + vec![bcs::encode(&to)?, bcs::encode(&amount)?], + json!([to.to_hex_literal(), amount.to_string()]), + ))) +} + +pub fn aptos_account_transfer_coins( + coin_type: TypeTag, + to: AccountAddress, + amount: u64, +) -> SigningResult { + Ok(TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("aptos_account").to_owned(), + ), + ident_str!("transfer_coins").to_owned(), + vec![coin_type], + vec![bcs::encode(&to)?, bcs::encode(&amount)?], + json!([to.to_hex_literal(), amount.to_string()]), + ))) +} + +pub fn token_transfers_offer_script( + receiver: AccountAddress, + creator: AccountAddress, + collection: Vec, + name: Vec, + property_version: u64, + amount: u64, +) -> SigningResult { + Ok(TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, + ]), + ident_str!("token_transfers").to_owned(), + ), + ident_str!("offer_script").to_owned(), + vec![], + vec![ + bcs::encode(&receiver)?, + bcs::encode(&creator)?, + bcs::encode(&collection)?, + bcs::encode(&name)?, + bcs::encode(&property_version)?, + bcs::encode(&amount)?, + ], + json!([ + receiver.to_hex_literal(), + creator.to_hex_literal(), + String::from_utf8_lossy(&collection), + String::from_utf8_lossy(&name), + property_version.to_string(), + amount.to_string() + ]), + ))) +} + +pub fn token_transfers_cancel_offer_script( + receiver: AccountAddress, + creator: AccountAddress, + collection: Vec, + name: Vec, + property_version: u64, +) -> SigningResult { + Ok(TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, + ]), + ident_str!("token_transfers").to_owned(), + ), + ident_str!("cancel_offer_script").to_owned(), + vec![], + vec![ + bcs::encode(&receiver)?, + bcs::encode(&creator)?, + bcs::encode(&collection)?, + bcs::encode(&name)?, + bcs::encode(&property_version)?, + ], + json!([ + receiver.to_hex_literal(), + creator.to_hex_literal(), + String::from_utf8_lossy(&collection), + String::from_utf8_lossy(&name), + property_version.to_string() + ]), + ))) +} + +pub fn token_transfers_claim_script( + sender: AccountAddress, + creator: AccountAddress, + collection: Vec, + name: Vec, + property_version: u64, +) -> SigningResult { + Ok(TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, + ]), + ident_str!("token_transfers").to_owned(), + ), + ident_str!("claim_script").to_owned(), + vec![], + vec![ + bcs::encode(&sender)?, + bcs::encode(&creator)?, + bcs::encode(&collection)?, + bcs::encode(&name)?, + bcs::encode(&property_version)?, + ], + json!([ + sender.to_hex_literal(), + creator.to_hex_literal(), + String::from_utf8_lossy(&collection), + String::from_utf8_lossy(&name), + property_version.to_string() + ]), + ))) +} + +pub fn managed_coin_register(coin_type: TypeTag) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, + ]), + ident_str!("managed_coin").to_owned(), + ), + ident_str!("register").to_owned(), + vec![coin_type], + vec![], + json!([]), + )) +} diff --git a/rust/chains/tw_aptos/src/compiler.rs b/rust/chains/tw_aptos/src/compiler.rs new file mode 100644 index 00000000000..53b9df11bd4 --- /dev/null +++ b/rust/chains/tw_aptos/src/compiler.rs @@ -0,0 +1,76 @@ +use crate::address::Address; +use crate::transaction_builder; +use std::str::FromStr; +use tw_coin_entry::coin_entry::{PublicKeyBytes, SignatureBytes}; +use tw_coin_entry::error::prelude::*; +use tw_coin_entry::signing_output_error; +use tw_proto::Aptos::Proto; +use tw_proto::TxCompiler::Proto as CompilerProto; + +pub struct Compiler; + +impl Compiler { + #[inline] + pub fn preimage_hashes( + input: Proto::SigningInput<'_>, + ) -> CompilerProto::PreSigningOutput<'static> { + Self::preimage_hashes_impl(input) + .unwrap_or_else(|e| signing_output_error!(CompilerProto::PreSigningOutput, e)) + } + + fn preimage_hashes_impl( + input: Proto::SigningInput<'_>, + ) -> SigningResult> { + let builder = transaction_builder::TransactionFactory::new_from_protobuf(input.clone())?; + let sender = Address::from_str(&input.sender) + .into_tw() + .context("Invalid sender address")?; + let signed_tx = builder + .sender(sender.inner()) + .sequence_number(input.sequence_number as u64) + .build()? + .pre_image()?; + Ok(CompilerProto::PreSigningOutput { + data: signed_tx.into(), + ..CompilerProto::PreSigningOutput::default() + }) + } + + #[inline] + pub fn compile( + input: Proto::SigningInput<'_>, + signatures: Vec, + public_keys: Vec, + ) -> Proto::SigningOutput<'static> { + Self::compile_impl(input, signatures, public_keys) + .unwrap_or_else(|e| signing_output_error!(Proto::SigningOutput, e)) + } + + fn compile_impl( + input: Proto::SigningInput<'_>, + signatures: Vec, + public_keys: Vec, + ) -> SigningResult> { + let builder = transaction_builder::TransactionFactory::new_from_protobuf(input.clone())?; + let sender = Address::from_str(&input.sender)?; + let signature = signatures + .first() + .or_tw_err(SigningErrorType::Error_signatures_count)?; + let public_key = public_keys + .first() + .or_tw_err(SigningErrorType::Error_signatures_count)?; + + let signed_tx = builder + .sender(sender.inner()) + .sequence_number(input.sequence_number as u64) + .build()? + .compile(signature.to_vec(), public_key.to_vec())?; + Ok(Proto::SigningOutput { + raw_txn: signed_tx.raw_txn_bytes().clone().into(), + encoded: signed_tx.encoded().clone().into(), + authenticator: Some((*signed_tx.authenticator()).clone().into()), + json: signed_tx.to_json().to_string().into(), + ..Proto::SigningOutput::default() + }) + } +} diff --git a/rust/chains/tw_aptos/src/constants.rs b/rust/chains/tw_aptos/src/constants.rs new file mode 100644 index 00000000000..714c1a2f782 --- /dev/null +++ b/rust/chains/tw_aptos/src/constants.rs @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +pub const GAS_UNIT_PRICE: u64 = 100; +pub const MAX_GAS_AMOUNT: u64 = 100_000_000; +pub const APTOS_SALT: &[u8] = b"APTOS::RawTransaction"; diff --git a/rust/chains/tw_aptos/src/entry.rs b/rust/chains/tw_aptos/src/entry.rs new file mode 100644 index 00000000000..e2ef01a6e2f --- /dev/null +++ b/rust/chains/tw_aptos/src/entry.rs @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::address::Address; +use crate::compiler::Compiler; +use crate::modules::transaction_util::AptosTransactionUtil; +use crate::signer::Signer; +use std::str::FromStr; +use tw_coin_entry::coin_context::CoinContext; +use tw_coin_entry::coin_entry::{CoinEntry, PublicKeyBytes, SignatureBytes}; +use tw_coin_entry::derivation::Derivation; +use tw_coin_entry::error::prelude::*; +use tw_coin_entry::modules::json_signer::NoJsonSigner; +use tw_coin_entry::modules::message_signer::NoMessageSigner; +use tw_coin_entry::modules::plan_builder::NoPlanBuilder; +use tw_coin_entry::modules::transaction_decoder::NoTransactionDecoder; +use tw_coin_entry::modules::wallet_connector::NoWalletConnector; +use tw_coin_entry::prefix::NoPrefix; +use tw_keypair::tw::PublicKey; +use tw_proto::Aptos::Proto; +use tw_proto::TxCompiler::Proto as CompilerProto; + +pub struct AptosEntry; + +impl CoinEntry for AptosEntry { + type AddressPrefix = NoPrefix; + type Address = Address; + type SigningInput<'a> = Proto::SigningInput<'a>; + type SigningOutput = Proto::SigningOutput<'static>; + type PreSigningOutput = CompilerProto::PreSigningOutput<'static>; + + // Optional modules: + type JsonSigner = NoJsonSigner; + type PlanBuilder = NoPlanBuilder; + type MessageSigner = NoMessageSigner; + type WalletConnector = NoWalletConnector; + type TransactionDecoder = NoTransactionDecoder; + type TransactionUtil = AptosTransactionUtil; + + #[inline] + fn parse_address( + &self, + _coin: &dyn CoinContext, + address: &str, + _prefix: Option, + ) -> AddressResult { + Address::from_str(address) + } + + #[inline] + fn parse_address_unchecked(&self, address: &str) -> AddressResult { + Address::from_str(address) + } + + fn derive_address( + &self, + _coin: &dyn CoinContext, + public_key: PublicKey, + _derivation: Derivation, + _prefix: Option, + ) -> AddressResult { + let public_key = public_key + .to_ed25519() + .ok_or(AddressError::PublicKeyTypeMismatch)?; + Address::with_ed25519_pubkey(public_key) + } + + #[inline] + fn sign(&self, _coin: &dyn CoinContext, input: Self::SigningInput<'_>) -> Self::SigningOutput { + Signer::sign_proto(input) + } + + #[inline] + fn preimage_hashes( + &self, + _coin: &dyn CoinContext, + input: Self::SigningInput<'_>, + ) -> Self::PreSigningOutput { + Compiler::preimage_hashes(input) + } + + #[inline] + fn compile( + &self, + _coin: &dyn CoinContext, + input: Self::SigningInput<'_>, + signatures: Vec, + public_keys: Vec, + ) -> Self::SigningOutput { + Compiler::compile(input, signatures, public_keys) + } + + #[inline] + fn json_signer(&self) -> Option { + None + } + + #[inline] + fn message_signer(&self) -> Option { + None + } + + #[inline] + fn transaction_util(&self) -> Option { + Some(AptosTransactionUtil) + } +} diff --git a/rust/chains/tw_aptos/src/lib.rs b/rust/chains/tw_aptos/src/lib.rs new file mode 100644 index 00000000000..5388e03f4e7 --- /dev/null +++ b/rust/chains/tw_aptos/src/lib.rs @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +pub mod address; +pub mod aptos_move_packages; +pub mod constants; +pub mod entry; +mod serde_helper; + +pub mod nft; + +pub mod compiler; +pub mod liquid_staking; +pub mod modules; +pub mod signer; +pub mod transaction; +pub mod transaction_builder; +pub mod transaction_payload; diff --git a/rust/chains/tw_aptos/src/liquid_staking.rs b/rust/chains/tw_aptos/src/liquid_staking.rs new file mode 100644 index 00000000000..2ce311e4350 --- /dev/null +++ b/rust/chains/tw_aptos/src/liquid_staking.rs @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::address::from_account_error; +use crate::transaction_payload::{EntryFunction, TransactionPayload}; +use move_core_types::{account_address::AccountAddress, ident_str, language_storage::ModuleId}; +use serde_json::json; +use std::str::FromStr; +use tw_coin_entry::error::prelude::*; +use tw_encoding::bcs; +use tw_proto::{ + Aptos::Proto::mod_LiquidStaking::OneOfliquid_stake_transaction_payload, + Aptos::Proto::{LiquidStaking, TortugaClaim, TortugaStake, TortugaUnstake}, +}; + +pub fn tortuga_stake( + smart_contract_address: AccountAddress, + amount: u64, +) -> SigningResult { + Ok(TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + smart_contract_address, + ident_str!("stake_router").to_owned(), + ), + ident_str!("stake").to_owned(), + vec![], + vec![bcs::encode(&amount)?], + json!([amount.to_string()]), + ))) +} + +pub fn tortuga_unstake( + smart_contract_address: AccountAddress, + amount: u64, +) -> SigningResult { + Ok(TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + smart_contract_address, + ident_str!("stake_router").to_owned(), + ), + ident_str!("unstake").to_owned(), + vec![], + vec![bcs::encode(&amount)?], + json!([amount.to_string()]), + ))) +} + +pub fn tortuga_claim( + smart_contract_address: AccountAddress, + idx: u64, +) -> SigningResult { + Ok(TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + smart_contract_address, + ident_str!("stake_router").to_owned(), + ), + ident_str!("claim").to_owned(), + vec![], + vec![bcs::encode(&idx)?], + json!([idx.to_string()]), + ))) +} + +pub struct Stake { + pub amount: u64, + pub smart_contract_address: AccountAddress, +} + +pub struct Unstake { + pub amount: u64, + pub smart_contract_address: AccountAddress, +} + +pub struct Claim { + pub idx: u64, + pub smart_contract_address: AccountAddress, +} + +pub enum LiquidStakingOperation { + Stake(Stake), + Unstake(Unstake), + Claim(Claim), +} + +impl TryFrom> for LiquidStakingOperation { + type Error = SigningError; + + fn try_from(value: LiquidStaking) -> SigningResult { + match value.liquid_stake_transaction_payload { + OneOfliquid_stake_transaction_payload::stake(stake_msg) => { + let smart_contract_address = + AccountAddress::from_str(&value.smart_contract_address) + .map_err(from_account_error) + .into_tw() + .context("Invalid Smart Contract address")?; + Ok(LiquidStakingOperation::Stake(Stake { + amount: stake_msg.amount, + smart_contract_address, + })) + }, + OneOfliquid_stake_transaction_payload::unstake(unstake_msg) => { + let smart_contract_address = + AccountAddress::from_str(&value.smart_contract_address) + .map_err(from_account_error) + .into_tw() + .context("Invalid Smart Contract address")?; + Ok(LiquidStakingOperation::Unstake(Unstake { + amount: unstake_msg.amount, + smart_contract_address, + })) + }, + OneOfliquid_stake_transaction_payload::claim(claim) => { + let smart_contract_address = + AccountAddress::from_str(&value.smart_contract_address) + .map_err(from_account_error) + .into_tw() + .context("Invalid Smart Contract address")?; + Ok(LiquidStakingOperation::Claim(Claim { + idx: claim.idx, + smart_contract_address, + })) + }, + OneOfliquid_stake_transaction_payload::None => { + SigningError::err(SigningErrorType::Error_invalid_params) + }, + } + } +} + +impl From for LiquidStaking<'_> { + fn from(value: LiquidStakingOperation) -> Self { + match value { + LiquidStakingOperation::Stake(stake) => LiquidStaking { + smart_contract_address: stake.smart_contract_address.to_hex_literal().into(), + liquid_stake_transaction_payload: OneOfliquid_stake_transaction_payload::stake( + TortugaStake { + amount: stake.amount, + }, + ), + }, + LiquidStakingOperation::Unstake(unstake) => LiquidStaking { + smart_contract_address: unstake.smart_contract_address.to_hex_literal().into(), + liquid_stake_transaction_payload: OneOfliquid_stake_transaction_payload::unstake( + TortugaUnstake { + amount: unstake.amount, + }, + ), + }, + LiquidStakingOperation::Claim(claim) => LiquidStaking { + smart_contract_address: claim.smart_contract_address.to_hex_literal().into(), + liquid_stake_transaction_payload: OneOfliquid_stake_transaction_payload::claim( + TortugaClaim { idx: claim.idx }, + ), + }, + } + } +} diff --git a/rust/chains/tw_aptos/src/modules/mod.rs b/rust/chains/tw_aptos/src/modules/mod.rs new file mode 100644 index 00000000000..c083bb0102e --- /dev/null +++ b/rust/chains/tw_aptos/src/modules/mod.rs @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +pub mod transaction_util; diff --git a/rust/chains/tw_aptos/src/modules/transaction_util.rs b/rust/chains/tw_aptos/src/modules/transaction_util.rs new file mode 100644 index 00000000000..6b7034477f8 --- /dev/null +++ b/rust/chains/tw_aptos/src/modules/transaction_util.rs @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use tw_coin_entry::coin_context::CoinContext; +use tw_coin_entry::error::prelude::*; +use tw_coin_entry::modules::transaction_util::TransactionUtil; +use tw_encoding::hex; +use tw_hash::sha3::sha3_256; + +pub struct AptosTransactionUtil; + +impl TransactionUtil for AptosTransactionUtil { + fn calc_tx_hash(&self, coin: &dyn CoinContext, encoded_tx: &str) -> SigningResult { + Self::calc_tx_hash_impl(coin, encoded_tx) + } +} + +impl AptosTransactionUtil { + fn calc_tx_hash_impl(_coin: &dyn CoinContext, encoded_tx: &str) -> SigningResult { + let txn_bytes = hex::decode(encoded_tx).map_err(|_| SigningErrorType::Error_input_parse)?; + + // See: https://github.com/aptos-labs/aptos-ts-sdk/blob/f54cac824a41e41dea09c7a6916858a8604dc901/src/api/transaction.ts#L118 + let prefix = sha3_256("APTOS::Transaction".as_bytes()); + + let mut hash_message = Vec::new(); + hash_message.extend_from_slice(&prefix); + // 0 is the index of the enum `Transaction`, see: https://github.com/aptos-labs/aptos-core/blob/6a130c1cca274a5cfdb4a65b441cd5fe61b6c15b/types/src/transaction/mod.rs#L1939 + hash_message.push(0); + hash_message.extend_from_slice(&txn_bytes); + + let tx_hash = sha3_256(&hash_message); + Ok(hex::encode(tx_hash, true)) + } +} diff --git a/rust/chains/tw_aptos/src/nft.rs b/rust/chains/tw_aptos/src/nft.rs new file mode 100644 index 00000000000..172308b4ee2 --- /dev/null +++ b/rust/chains/tw_aptos/src/nft.rs @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::address::from_account_error; +use move_core_types::account_address::AccountAddress; +use std::str::FromStr; +use tw_coin_entry::error::prelude::*; +use tw_proto::Aptos::Proto::mod_NftMessage::OneOfnft_transaction_payload; +use tw_proto::Aptos::Proto::{CancelOfferNftMessage, ClaimNftMessage, NftMessage, OfferNftMessage}; + +pub struct Offer { + pub receiver: AccountAddress, + pub creator: AccountAddress, + pub collection: Vec, + pub name: Vec, + pub property_version: u64, + pub amount: u64, +} + +pub struct Claim { + pub sender: AccountAddress, + pub creator: AccountAddress, + pub collection: Vec, + pub name: Vec, + pub property_version: u64, +} + +pub enum NftOperation { + Claim(Claim), + Offer(Offer), + Cancel(Offer), +} + +impl TryFrom> for NftOperation { + type Error = SigningError; + + fn try_from(value: NftMessage) -> SigningResult { + match value.nft_transaction_payload { + OneOfnft_transaction_payload::offer_nft(msg) => { + Ok(NftOperation::Offer(Offer::try_from(msg)?)) + }, + OneOfnft_transaction_payload::cancel_offer_nft(msg) => { + Ok(NftOperation::Cancel(Offer::try_from(msg)?)) + }, + OneOfnft_transaction_payload::claim_nft(msg) => { + Ok(NftOperation::Claim(Claim::try_from(msg)?)) + }, + OneOfnft_transaction_payload::None => { + SigningError::err(SigningErrorType::Error_invalid_params) + .context("No transaction payload provided") + }, + } + } +} + +impl From for NftMessage<'_> { + fn from(value: NftOperation) -> Self { + match value { + NftOperation::Claim(claim) => NftMessage { + nft_transaction_payload: OneOfnft_transaction_payload::claim_nft(claim.into()), + }, + NftOperation::Offer(offer) => NftMessage { + nft_transaction_payload: OneOfnft_transaction_payload::offer_nft(offer.into()), + }, + NftOperation::Cancel(cancel) => NftMessage { + nft_transaction_payload: OneOfnft_transaction_payload::cancel_offer_nft( + cancel.into(), + ), + }, + } + } +} + +impl TryFrom> for Offer { + type Error = SigningError; + + fn try_from(value: OfferNftMessage) -> SigningResult { + Ok(Offer { + receiver: AccountAddress::from_str(&value.receiver).map_err(from_account_error)?, + creator: AccountAddress::from_str(&value.creator).map_err(from_account_error)?, + collection: value.collectionName.as_bytes().to_vec(), + name: value.name.as_bytes().to_vec(), + property_version: value.property_version, + amount: value.amount, + }) + } +} + +impl From for OfferNftMessage<'_> { + fn from(value: Offer) -> Self { + OfferNftMessage { + receiver: value.receiver.to_hex_literal().into(), + creator: value.creator.to_hex_literal().into(), + collectionName: String::from_utf8_lossy(value.collection.as_slice()) + .to_string() + .into(), + name: String::from_utf8_lossy(&value.name).to_string().into(), + property_version: value.property_version, + amount: value.amount, + } + } +} + +impl TryFrom> for Offer { + type Error = SigningError; + + fn try_from(value: CancelOfferNftMessage) -> SigningResult { + Ok(Offer { + receiver: AccountAddress::from_str(&value.receiver) + .map_err(from_account_error) + .into_tw() + .context("Invalid receiver address")?, + creator: AccountAddress::from_str(&value.creator) + .map_err(from_account_error) + .into_tw() + .context("Invalid creator address")?, + collection: value.collectionName.as_bytes().to_vec(), + name: value.name.as_bytes().to_vec(), + property_version: value.property_version, + amount: 0, + }) + } +} + +impl From for CancelOfferNftMessage<'_> { + fn from(value: Offer) -> Self { + CancelOfferNftMessage { + receiver: value.receiver.to_hex_literal().into(), + creator: value.creator.to_hex_literal().into(), + collectionName: String::from_utf8_lossy(value.collection.as_slice()) + .to_string() + .into(), + name: String::from_utf8_lossy(value.name.as_slice()) + .to_string() + .into(), + property_version: value.property_version, + } + } +} + +impl TryFrom> for Claim { + type Error = SigningError; + + fn try_from(value: ClaimNftMessage) -> SigningResult { + Ok(Claim { + sender: AccountAddress::from_str(&value.sender) + .map_err(from_account_error) + .into_tw() + .context("Invalid sender address")?, + creator: AccountAddress::from_str(&value.creator) + .map_err(from_account_error) + .into_tw() + .context("Invalid creator address")?, + collection: value.collectionName.as_bytes().to_vec(), + name: value.name.as_bytes().to_vec(), + property_version: value.property_version, + }) + } +} + +impl From for ClaimNftMessage<'_> { + fn from(value: Claim) -> Self { + ClaimNftMessage { + sender: value.sender.to_hex_literal().into(), + creator: value.creator.to_hex_literal().into(), + collectionName: String::from_utf8_lossy(value.collection.as_slice()) + .to_string() + .into(), + name: String::from_utf8_lossy(value.name.as_slice()) + .to_string() + .into(), + property_version: value.property_version, + } + } +} diff --git a/rust/chains/tw_aptos/src/serde_helper/mod.rs b/rust/chains/tw_aptos/src/serde_helper/mod.rs new file mode 100644 index 00000000000..876f018225e --- /dev/null +++ b/rust/chains/tw_aptos/src/serde_helper/mod.rs @@ -0,0 +1,5 @@ +// Copyright © Aptos Foundation +// Parts of the project are originally copyright © Meta Platforms, Inc. +// SPDX-License-Identifier: Apache-2.0 + +pub mod vec_bytes; diff --git a/rust/chains/tw_aptos/src/serde_helper/vec_bytes.rs b/rust/chains/tw_aptos/src/serde_helper/vec_bytes.rs new file mode 100644 index 00000000000..f57311d19dd --- /dev/null +++ b/rust/chains/tw_aptos/src/serde_helper/vec_bytes.rs @@ -0,0 +1,30 @@ +// Copyright © Aptos Foundation +// Parts of the project are originally copyright © Meta Platforms, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use serde::{ + de::Deserializer, + ser::{SerializeSeq, Serializer}, + Deserialize, +}; + +pub fn serialize(data: &[Vec], serializer: S) -> Result +where + S: Serializer, +{ + let mut seq = serializer.serialize_seq(Some(data.len()))?; + for e in data { + seq.serialize_element(serde_bytes::Bytes::new(e.as_slice()))?; + } + seq.end() +} + +pub fn deserialize<'de, D>(deserializer: D) -> Result>, D::Error> +where + D: Deserializer<'de>, +{ + Ok(>::deserialize(deserializer)? + .into_iter() + .map(serde_bytes::ByteBuf::into_vec) + .collect()) +} diff --git a/rust/chains/tw_aptos/src/signer.rs b/rust/chains/tw_aptos/src/signer.rs new file mode 100644 index 00000000000..8937e821081 --- /dev/null +++ b/rust/chains/tw_aptos/src/signer.rs @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::address::Address; +use crate::transaction_builder; +use std::str::FromStr; +use tw_coin_entry::error::prelude::*; +use tw_coin_entry::signing_output_error; +use tw_keypair::ed25519; +use tw_proto::Aptos::Proto; + +pub struct Signer; + +impl Signer { + #[inline] + pub fn sign_proto(input: Proto::SigningInput<'_>) -> Proto::SigningOutput<'static> { + Self::sign_proto_impl(input) + .unwrap_or_else(|e| signing_output_error!(Proto::SigningOutput, e)) + } + + fn sign_proto_impl( + input: Proto::SigningInput<'_>, + ) -> SigningResult> { + let key_pair = ed25519::sha512::KeyPair::try_from(input.private_key.as_ref())?; + let builder = transaction_builder::TransactionFactory::new_from_protobuf(input.clone())?; + let sender = Address::from_str(&input.sender) + .into_tw() + .context("Invalid sender address")?; + let signed_tx = builder + .sender(sender.inner()) + .sequence_number(input.sequence_number as u64) + .build()? + .sign(key_pair)?; + Ok(Proto::SigningOutput { + raw_txn: signed_tx.raw_txn_bytes().clone().into(), + encoded: signed_tx.encoded().clone().into(), + authenticator: Some((*signed_tx.authenticator()).clone().into()), + json: signed_tx.to_json().to_string().into(), + ..Proto::SigningOutput::default() + }) + } +} diff --git a/rust/chains/tw_aptos/src/transaction.rs b/rust/chains/tw_aptos/src/transaction.rs new file mode 100644 index 00000000000..f4ca4a2c151 --- /dev/null +++ b/rust/chains/tw_aptos/src/transaction.rs @@ -0,0 +1,221 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::constants::APTOS_SALT; +use crate::transaction_payload::TransactionPayload; +use move_core_types::account_address::AccountAddress; +use serde::Serialize; +use serde_json::{json, Value}; +use std::borrow::Cow; +use tw_coin_entry::error::prelude::*; +use tw_encoding::hex::encode; +use tw_encoding::{bcs, EncodingResult}; +use tw_keypair::ed25519::sha512::KeyPair; +use tw_keypair::traits::{KeyPairTrait, SigningKeyTrait}; +use tw_memory::Data; +use tw_proto::Aptos::Proto; + +#[derive(Clone, Serialize)] +pub enum TransactionAuthenticator { + /// Single Ed25519 signature + Ed25519 { + public_key: Vec, + signature: Vec, + }, +} + +impl From for Proto::TransactionAuthenticator<'_> { + fn from(from: TransactionAuthenticator) -> Self { + Proto::TransactionAuthenticator { + signature: Cow::from(from.get_signature()), + public_key: Cow::from(from.get_public_key()), + } + } +} + +impl TransactionAuthenticator { + pub fn get_signature(&self) -> Vec { + match self { + TransactionAuthenticator::Ed25519 { + public_key: _public_key, + signature, + } => signature.clone(), + } + } + + pub fn get_public_key(&self) -> Vec { + match self { + TransactionAuthenticator::Ed25519 { + public_key, + signature: _signature, + } => public_key.clone(), + } + } + + pub fn to_json(&self) -> Value { + match self { + TransactionAuthenticator::Ed25519 { + public_key, + signature, + } => { + json!({"public_key": encode(public_key, true), + "signature": encode(signature, true), + "type": "ed25519_signature"}) + }, + } + } +} + +/// RawTransaction is the portion of a transaction that a client signs. +#[derive(Clone, Serialize)] +pub struct RawTransaction { + /// Sender's address. + sender: AccountAddress, + + /// Sequence number of this transaction. This must match the sequence number + /// stored in the sender's account at the time the transaction executes. + sequence_number: u64, + + /// The transaction payload, e.g., a script to execute. + payload: TransactionPayload, + + /// Maximal total gas to spend for this transaction. + max_gas_amount: u64, + + /// Price to be paid per gas unit. + gas_unit_price: u64, + + /// Expiration timestamp for this transaction, represented + /// as seconds from the Unix Epoch. If the current blockchain timestamp + /// is greater than or equal to this time, then the transaction has + /// expired and will be discarded. This can be set to a large value far + /// in the future to indicate that a transaction does not expire. + expiration_timestamp_secs: u64, + + /// Chain ID of the Aptos network this transaction is intended for. + chain_id: u8, +} + +impl RawTransaction { + /// Create a new `RawTransaction` with a payload. + /// + /// It can be either to publish a module, to execute a script, or to issue a writeset + /// transaction. + pub fn new( + sender: AccountAddress, + sequence_number: u64, + payload: TransactionPayload, + max_gas_amount: u64, + gas_unit_price: u64, + expiration_timestamp_secs: u64, + chain_id: u8, + ) -> Self { + RawTransaction { + sender, + sequence_number, + payload, + max_gas_amount, + gas_unit_price, + expiration_timestamp_secs, + chain_id, + } + } + + /// Create a new `RawTransaction` with an entry function + fn serialize(&self) -> EncodingResult { + bcs::encode(&self) + } + + fn msg_to_sign(&self) -> SigningResult { + let serialized = self + .serialize() + .into_tw() + .context("Error serializing RawTransaction")?; + let mut preimage = tw_hash::sha3::sha3_256(APTOS_SALT); + preimage.extend_from_slice(serialized.as_slice()); + Ok(preimage) + } + + pub fn pre_image(&self) -> SigningResult> { + self.msg_to_sign() + } + + pub fn compile( + &self, + signature: Vec, + public_key: Vec, + ) -> SigningResult { + let serialized = self.serialize()?; + let auth = TransactionAuthenticator::Ed25519 { + public_key, + signature, + }; + let mut encoded = serialized.clone(); + encoded.extend_from_slice(bcs::encode(&auth)?.as_slice()); + Ok(SignedTransaction { + raw_txn: self.clone(), + authenticator: auth, + raw_txn_bytes: serialized.to_vec(), + encoded, + }) + } + + pub fn sign(self, key_pair: KeyPair) -> SigningResult { + let to_sign = self.pre_image()?; + let signature = key_pair.private().sign(to_sign)?.to_bytes().into_vec(); + let pubkey = key_pair.public().as_slice().to_vec(); + self.compile(signature, pubkey) + } + + pub fn to_json(&self) -> Value { + json!({ + "expiration_timestamp_secs": self.expiration_timestamp_secs.to_string(), + "gas_unit_price": self.gas_unit_price.to_string(), + "max_gas_amount": self.max_gas_amount.to_string(), + "payload": self.payload.to_json(), + "sender": self.sender.to_hex_literal(), + "sequence_number": self.sequence_number.to_string() + }) + } +} + +/// A transaction that has been signed. +/// +/// A `SignedTransaction` is a single transaction that can be atomically executed. Clients submit +/// these to validator nodes, and the validator and executor submits these to the VM. +/// +#[derive(Clone, Serialize)] +pub struct SignedTransaction { + /// The raw transaction + raw_txn: RawTransaction, + + /// Public key and signature to authenticate + authenticator: TransactionAuthenticator, + + #[serde(skip_serializing)] + /// Raw txs bytes + raw_txn_bytes: Vec, + + #[serde(skip_serializing)] + /// Encoded bytes to be broadcast + encoded: Vec, +} + +impl SignedTransaction { + pub fn authenticator(&self) -> &TransactionAuthenticator { + &self.authenticator + } + pub fn raw_txn_bytes(&self) -> &Vec { + &self.raw_txn_bytes + } + pub fn encoded(&self) -> &Vec { + &self.encoded + } + + pub fn to_json(&self) -> Value { + let mut json_value = self.raw_txn.to_json(); + json_value["signature"] = self.authenticator.to_json(); + json_value + } +} diff --git a/rust/chains/tw_aptos/src/transaction_builder.rs b/rust/chains/tw_aptos/src/transaction_builder.rs new file mode 100644 index 00000000000..deae84c8008 --- /dev/null +++ b/rust/chains/tw_aptos/src/transaction_builder.rs @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::address::from_account_error; +use crate::aptos_move_packages::{ + aptos_account_create_account, aptos_account_transfer, aptos_account_transfer_coins, + coin_transfer, managed_coin_register, token_transfers_cancel_offer_script, + token_transfers_claim_script, token_transfers_offer_script, +}; +use crate::constants::{GAS_UNIT_PRICE, MAX_GAS_AMOUNT}; +use crate::liquid_staking::{ + tortuga_claim, tortuga_stake, tortuga_unstake, LiquidStakingOperation, +}; +use crate::nft::NftOperation; +use crate::transaction::RawTransaction; +use crate::transaction_payload::{ + convert_proto_struct_tag_to_type_tag, EntryFunction, TransactionPayload, +}; +use move_core_types::account_address::AccountAddress; +use move_core_types::language_storage::TypeTag; +use serde_json::Value; +use std::str::FromStr; +use tw_coin_entry::error::prelude::*; +use tw_proto::Aptos::Proto::mod_SigningInput::OneOftransaction_payload; +use tw_proto::Aptos::Proto::SigningInput; + +pub struct TransactionBuilder { + sender: Option, + sequence_number: Option, + payload: TransactionPayload, + max_gas_amount: u64, + gas_unit_price: u64, + expiration_timestamp_secs: u64, + chain_id: u8, +} + +impl TransactionBuilder { + pub fn sender(mut self, sender: AccountAddress) -> Self { + self.sender = Some(sender); + self + } + + pub fn sequence_number(mut self, sequence_number: u64) -> Self { + self.sequence_number = Some(sequence_number); + self + } + + pub fn build(self) -> SigningResult { + let sender = self + .sender + .or_tw_err(SigningErrorType::Error_invalid_params) + .context("Invalid sender address")?; + let sequence_number = self + .sequence_number + .or_tw_err(SigningErrorType::Error_invalid_params) + .context("Invalid sequence number")?; + Ok(RawTransaction::new( + sender, + sequence_number, + self.payload, + self.max_gas_amount, + self.gas_unit_price, + self.expiration_timestamp_secs, + self.chain_id, + )) + } +} + +#[derive(Clone, Debug)] +pub struct TransactionFactory { + max_gas_amount: u64, + gas_unit_price: u64, + transaction_expiration_time: u64, + chain_id: u8, +} + +impl TransactionFactory { + pub fn new(chain_id: u8) -> Self { + Self { + max_gas_amount: MAX_GAS_AMOUNT, + gas_unit_price: GAS_UNIT_PRICE, + transaction_expiration_time: 30, + chain_id, + } + } + + pub fn new_from_protobuf(input: SigningInput) -> SigningResult { + let factory = TransactionFactory::new(input.chain_id as u8) + .with_gas_unit_price(input.gas_unit_price) + .with_max_gas_amount(input.max_gas_amount) + .with_transaction_expiration_time(input.expiration_timestamp_secs); + match input.transaction_payload { + OneOftransaction_payload::transfer(transfer) => factory + .implicitly_create_user_account_and_transfer( + AccountAddress::from_str(&transfer.to) + .map_err(from_account_error) + .into_tw() + .context("Invalid destination address")?, + transfer.amount, + ), + OneOftransaction_payload::token_transfer(token_transfer) => { + let func = token_transfer + .function + .or_tw_err(SigningErrorType::Error_invalid_params) + .context("'TokenTransferMessage::function' is not set")?; + factory.coins_transfer( + AccountAddress::from_str(&token_transfer.to) + .map_err(from_account_error) + .into_tw() + .context("Invalid destination address")?, + token_transfer.amount, + convert_proto_struct_tag_to_type_tag(func)?, + ) + }, + OneOftransaction_payload::create_account(create_account) => { + let address = AccountAddress::from_str(&create_account.auth_key) + .map_err(from_account_error) + .into_tw() + .context("Invalid 'auth_key' address")?; + factory.create_user_account(address) + }, + OneOftransaction_payload::nft_message(nft_message) => { + factory.nft_ops(NftOperation::try_from(nft_message)?) + }, + OneOftransaction_payload::register_token(register_token) => { + let function = register_token + .function + .or_tw_err(SigningErrorType::Error_invalid_params) + .context("'ManagedTokensRegisterMessage::function' is not set")?; + Ok(factory.register_token(convert_proto_struct_tag_to_type_tag(function)?)) + }, + OneOftransaction_payload::liquid_staking_message(msg) => { + factory.liquid_staking_ops(LiquidStakingOperation::try_from(msg)?) + }, + OneOftransaction_payload::token_transfer_coins(token_transfer_coins) => { + let func = token_transfer_coins + .function + .or_tw_err(SigningErrorType::Error_invalid_params) + .context("'TokenTransferCoinsMessage::function' is not set")?; + factory.implicitly_create_user_and_coins_transfer( + AccountAddress::from_str(&token_transfer_coins.to) + .map_err(from_account_error) + .into_tw() + .context("Invalid destination address")?, + token_transfer_coins.amount, + convert_proto_struct_tag_to_type_tag(func)?, + ) + }, + OneOftransaction_payload::None => { + let is_blind_sign = !input.any_encoded.is_empty(); + let v = serde_json::from_str::(&input.any_encoded) + .into_tw() + .context("Error decoding 'SigningInput::any_encoded' as JSON")?; + if is_blind_sign { + let entry_function = EntryFunction::try_from(v)?; + Ok(factory.payload(TransactionPayload::EntryFunction(entry_function))) + } else { + SigningError::err(SigningErrorType::Error_input_parse) + } + }, + } + } + + pub fn with_max_gas_amount(mut self, max_gas_amount: u64) -> Self { + self.max_gas_amount = max_gas_amount; + self + } + + pub fn with_gas_unit_price(mut self, gas_unit_price: u64) -> Self { + self.gas_unit_price = gas_unit_price; + self + } + + pub fn with_transaction_expiration_time(mut self, transaction_expiration_time: u64) -> Self { + self.transaction_expiration_time = transaction_expiration_time; + self + } + + pub fn payload(&self, payload: TransactionPayload) -> TransactionBuilder { + self.transaction_builder(payload) + } + + pub fn create_user_account(&self, to: AccountAddress) -> SigningResult { + Ok(self.payload(aptos_account_create_account(to)?)) + } + + pub fn register_token(&self, coin_type: TypeTag) -> TransactionBuilder { + self.payload(managed_coin_register(coin_type)) + } + + pub fn nft_ops(&self, operation: NftOperation) -> SigningResult { + match operation { + NftOperation::Claim(claim) => Ok(self.payload(token_transfers_claim_script( + claim.sender, + claim.creator, + claim.collection, + claim.name, + claim.property_version, + )?)), + NftOperation::Cancel(offer) => Ok(self.payload(token_transfers_cancel_offer_script( + offer.receiver, + offer.creator, + offer.collection, + offer.name, + offer.property_version, + )?)), + NftOperation::Offer(offer) => Ok(self.payload(token_transfers_offer_script( + offer.receiver, + offer.creator, + offer.collection, + offer.name, + offer.property_version, + offer.amount, + )?)), + } + } + + pub fn liquid_staking_ops( + &self, + operation: LiquidStakingOperation, + ) -> SigningResult { + match operation { + LiquidStakingOperation::Stake(stake) => { + Ok(self.payload(tortuga_stake(stake.smart_contract_address, stake.amount)?)) + }, + LiquidStakingOperation::Unstake(unstake) => Ok(self.payload(tortuga_unstake( + unstake.smart_contract_address, + unstake.amount, + )?)), + LiquidStakingOperation::Claim(claim) => { + Ok(self.payload(tortuga_claim(claim.smart_contract_address, claim.idx)?)) + }, + } + } + + pub fn implicitly_create_user_account_and_transfer( + &self, + to: AccountAddress, + amount: u64, + ) -> SigningResult { + Ok(self.payload(aptos_account_transfer(to, amount)?)) + } + + pub fn coins_transfer( + &self, + to: AccountAddress, + amount: u64, + coin_type: TypeTag, + ) -> SigningResult { + Ok(self.payload(coin_transfer(coin_type, to, amount)?)) + } + + pub fn implicitly_create_user_and_coins_transfer( + &self, + to: AccountAddress, + amount: u64, + coin_type: TypeTag, + ) -> SigningResult { + Ok(self.payload(aptos_account_transfer_coins(coin_type, to, amount)?)) + } + + fn transaction_builder(&self, payload: TransactionPayload) -> TransactionBuilder { + TransactionBuilder { + sender: None, + sequence_number: None, + payload, + max_gas_amount: self.max_gas_amount, + gas_unit_price: self.gas_unit_price, + expiration_timestamp_secs: self.expiration_timestamp(), + chain_id: self.chain_id, + } + } + + fn expiration_timestamp(&self) -> u64 { + self.transaction_expiration_time + } +} diff --git a/rust/chains/tw_aptos/src/transaction_payload.rs b/rust/chains/tw_aptos/src/transaction_payload.rs new file mode 100644 index 00000000000..d0105bc949d --- /dev/null +++ b/rust/chains/tw_aptos/src/transaction_payload.rs @@ -0,0 +1,276 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::serde_helper::vec_bytes; +use move_core_types::identifier::Identifier; +use move_core_types::language_storage::{ModuleId, StructTag, TypeTag}; +use move_core_types::parser::parse_transaction_argument; +use move_core_types::transaction_argument::TransactionArgument; +use serde::{Deserialize, Serialize}; +use serde_json::{json, Value}; +use std::default::Default; +use std::str::FromStr; +use tw_coin_entry::error::prelude::*; +use tw_encoding::{bcs, EncodingError, EncodingResult}; +use tw_memory::Data; +use tw_proto::Aptos; + +pub type EntryFunctionResult = Result; + +#[derive(Debug)] +pub enum EntryFunctionError { + MissingFunctionName, + InvalidFunctionName, + MissingArguments, + InvalidArguments, + EncodingError, + MissingTypeArguments, + InvalidTypeArguments, +} + +impl From for EntryFunctionError { + fn from(_error: EncodingError) -> Self { + EntryFunctionError::EncodingError + } +} + +impl From for SigningError { + fn from(e: EntryFunctionError) -> Self { + SigningError::new(SigningErrorType::Error_invalid_params) + .context(format!("Error decoding EntryFunction: {e:?}")) + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct EntryFunction { + module: ModuleId, + function: Identifier, + ty_args: Vec, + #[serde(with = "vec_bytes")] + args: Vec>, + #[serde(skip_serializing)] + json_args: Value, +} + +impl TryFrom for EntryFunction { + type Error = EntryFunctionError; + + fn try_from(value: Value) -> EntryFunctionResult { + let function_str = value["function"] + .as_str() + .ok_or(EntryFunctionError::MissingFunctionName)?; + let tag = StructTag::from_str(function_str) + .map_err(|_| EntryFunctionError::InvalidFunctionName)?; + + let args = value["arguments"] + .as_array() + .ok_or(EntryFunctionError::MissingArguments)? + .iter() + .map(|element| { + let arg_str = element.to_string(); + let arg = parse_transaction_argument( + arg_str.trim_start_matches('"').trim_end_matches('"'), + ) + .map_err(|_| EntryFunctionError::InvalidArguments)?; + serialize_argument(&arg).map_err(EntryFunctionError::from) + }) + .collect::>>()?; + + let ty_args = value["type_arguments"] + .as_array() + .ok_or(EntryFunctionError::MissingTypeArguments)? + .iter() + .map(|element| { + let ty_arg_str = element + .as_str() + .ok_or(EntryFunctionError::InvalidTypeArguments)?; + TypeTag::from_str(ty_arg_str).map_err(|_| EntryFunctionError::InvalidTypeArguments) + }) + .collect::>>()?; + + Ok(EntryFunction { + module: tag.module_id(), + function: tag.name, + ty_args, + args, + json_args: value["arguments"].clone(), + }) + } +} + +fn serialize_argument(arg: &TransactionArgument) -> EncodingResult { + match arg { + TransactionArgument::U8(v) => bcs::encode(v), + TransactionArgument::U16(v) => bcs::encode(v), + TransactionArgument::U32(v) => bcs::encode(v), + TransactionArgument::U64(v) => bcs::encode(v), + TransactionArgument::U128(v) => bcs::encode(v), + TransactionArgument::U256(v) => bcs::encode(v), + TransactionArgument::U8Vector(v) => bcs::encode(v), + TransactionArgument::Bool(v) => bcs::encode(v), + TransactionArgument::Address(v) => bcs::encode(v), + } +} + +pub fn convert_proto_struct_tag_to_type_tag( + struct_tag: Aptos::Proto::StructTag, +) -> SigningResult { + TypeTag::from_str(&format!( + "{}::{}::{}", + struct_tag.account_address, struct_tag.module, struct_tag.name + )) + .tw_err(|_| SigningErrorType::Error_invalid_params) +} + +pub fn convert_type_tag_to_struct_tag(type_tag: TypeTag) -> Aptos::Proto::StructTag<'static> { + if let TypeTag::Struct(st) = type_tag { + Aptos::Proto::StructTag { + account_address: st.address.to_hex_literal().into(), + module: st.module.to_string().into(), + name: st.name.to_string().into(), + } + } else { + Aptos::Proto::StructTag::default() + } +} + +impl EntryFunction { + fn to_json(&self) -> Value { + // Create a JSON array from the `ty_args` field by filtering and mapping + // the items that match `TypeTag::Struct` to their string representation. + let type_arguments: Value = self + .ty_args + .iter() + .map(|item| Some(json!(item.to_string()))) + .collect(); + + // Construct the final JSON value + json!({ + "type": "entry_function_payload", + "function": format!("{}::{}", self.module.short_str_lossless(), self.function.clone().into_string()), + "arguments": self.json_args, + "type_arguments": type_arguments + }) + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub enum TransactionPayload { + Script, + ModuleBundle, + /// A transaction that executes an existing entry function published on-chain. + EntryFunction(EntryFunction), +} + +impl TransactionPayload { + pub fn to_json(&self) -> Value { + match self { + TransactionPayload::Script => Value::default(), + TransactionPayload::ModuleBundle => Value::default(), + TransactionPayload::EntryFunction(entry) => entry.to_json(), + } + } +} + +impl EntryFunction { + pub fn new( + module: ModuleId, + function: Identifier, + ty_args: Vec, + args: Vec>, + json_args: Value, + ) -> Self { + EntryFunction { + module, + function, + ty_args, + args, + json_args, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::address::Address; + use move_core_types::account_address::AccountAddress; + use move_core_types::identifier::Identifier; + use move_core_types::language_storage::{ModuleId, TypeTag}; + use serde_json::{json, Value}; + use std::str::FromStr; + use tw_encoding::hex; + + #[test] + fn test_payload_from_json() { + let payload_value: Value = json!({ + "arguments": ["0xc95db29a67a848940829b3df6119b5e67b788ff0248676e4484c7c6f29c0f5e6"], + "function": "0xc23c3b70956ce8d88fb18ad9ed3b463fe873cb045db3f6d2e2fb15b9aab71d50::IFO::release", + "type": "entry_function_payload", + "type_arguments": [ + "0x48e0e3958d42b8d452c9199d4a221d0d1b15d14655787453dbe77208ced90517::coins::BUSD", + "0x48e0e3958d42b8d452c9199d4a221d0d1b15d14655787453dbe77208ced90517::coins::DAI", + "0x9936836587ca33240d3d3f91844651b16cb07802faf5e34514ed6f78580deb0a::uints::U1" + ] + }); + + let v = EntryFunction::try_from(payload_value.clone()).unwrap(); + assert_eq!(payload_value, v.to_json()); + + let tp = TransactionPayload::EntryFunction(v); + let serialized = bcs::encode(&tp).unwrap(); + assert_eq!(hex::encode(serialized, false), "02c23c3b70956ce8d88fb18ad9ed3b463fe873cb045db3f6d2e2fb15b9aab71d500349464f0772656c65617365030748e0e3958d42b8d452c9199d4a221d0d1b15d14655787453dbe77208ced9051705636f696e730442555344000748e0e3958d42b8d452c9199d4a221d0d1b15d14655787453dbe77208ced9051705636f696e730344414900079936836587ca33240d3d3f91844651b16cb07802faf5e34514ed6f78580deb0a0575696e7473025531000120c95db29a67a848940829b3df6119b5e67b788ff0248676e4484c7c6f29c0f5e6"); + } + + #[test] + fn test_payload_from_json_with_arg_non_str() { + let payload_value: Value = json!({ + "type":"entry_function_payload", + "function":"0xd11107bdf0d6d7040c6c0bfbdecb6545191fdf13e8d8d259952f53e1713f61b5::ditto_staking::stake_aptos", + "type_arguments":[], + "arguments": [1000000] + }); + + let v = EntryFunction::try_from(payload_value.clone()).unwrap(); + assert_eq!(payload_value, v.to_json()); + } + + #[test] + fn test_basic_payload() { + let addr = + Address::from_str("0xeeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b") + .unwrap() + .inner(); + let amount: i64 = 1000; + let args = vec![bcs::encode(&addr).unwrap(), bcs::encode(&amount).unwrap()]; + let module = ModuleId::new(AccountAddress::ONE, Identifier::from_str("coin").unwrap()); + let function = Identifier::from_str("transfer").unwrap(); + let type_tag = vec![TypeTag::from_str("0x1::aptos_coin::AptosCoin").unwrap()]; + let entry = EntryFunction::new( + module, + function, + type_tag, + args, + json!([addr.to_hex_literal(), amount.to_string()]), + ); + let tp = TransactionPayload::EntryFunction(entry); + let serialized = bcs::encode(&tp).unwrap(); + let expected_serialized = "02000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e000220eeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b08e803000000000000"; + assert_eq!(hex::encode(serialized, false), expected_serialized); + let payload_value: Value = json!({ + "function": "0x1::coin::transfer", + "type": "entry_function_payload", + "arguments": ["0xeeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b", "1000"], + "type_arguments": ["0x1::aptos_coin::AptosCoin"] + }); + assert_eq!(tp.to_json(), payload_value); + + // Rebuild a new EntryFunction object from the JSON above + let v = EntryFunction::try_from(payload_value.clone()).unwrap(); + let tp = TransactionPayload::EntryFunction(v); + // Serialize the new EntryFunction object and compare with the expected serialized value + let serialized = bcs::encode(&tp).unwrap(); + assert_eq!(hex::encode(serialized, false), expected_serialized); + } +} diff --git a/rust/chains/tw_aptos/tests/signer.rs b/rust/chains/tw_aptos/tests/signer.rs new file mode 100644 index 00000000000..e69c6894839 --- /dev/null +++ b/rust/chains/tw_aptos/tests/signer.rs @@ -0,0 +1,871 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use move_core_types::account_address::AccountAddress; +use move_core_types::language_storage::TypeTag; +use std::str::FromStr; +use tw_aptos::liquid_staking; +use tw_aptos::liquid_staking::{LiquidStakingOperation, Stake, Unstake}; +use tw_aptos::nft::{Claim, NftOperation, Offer}; +use tw_aptos::signer::Signer; +use tw_aptos::transaction_payload::convert_type_tag_to_struct_tag; +use tw_coin_entry::error::prelude::*; +use tw_encoding::hex; +use tw_proto::Aptos::Proto; +use tw_proto::Aptos::Proto::{SigningInput, SigningOutput}; + +pub struct AccountCreation { + to: String, +} + +pub struct Transfer { + to: String, + amount: u64, +} + +pub struct TokenTransfer { + transfer: Transfer, + tag: TypeTag, +} + +pub struct RegisterToken { + coin_type: TypeTag, +} + +pub enum OpsDetails { + RegisterToken(RegisterToken), + LiquidStakingOps(LiquidStakingOperation), + AccountCreation(AccountCreation), + Transfer(Transfer), + TokenTransfer(TokenTransfer), + ImplicitTokenTransfer(TokenTransfer), + NftOps(NftOperation), +} + +fn setup_proto_transaction<'a>( + sender: &'a str, + keypair_str: &'a str, + transaction_type: &'a str, + sequence_number: i64, + chain_id: u32, + max_gas_amount: u64, + timestamp: u64, + gas_unit_price: u64, + any_encoded: &'a str, + ops_details: Option, +) -> SigningInput<'a> { + let private = hex::decode(keypair_str).unwrap(); + + let payload: Proto::mod_SigningInput::OneOftransaction_payload = match transaction_type { + "transfer" => { + if let OpsDetails::Transfer(transfer) = ops_details.unwrap() { + Proto::mod_SigningInput::OneOftransaction_payload::transfer( + Proto::TransferMessage { + to: transfer.to.into(), + amount: transfer.amount, + }, + ) + } else { + panic!("Unsupported arguments") + } + }, + "create_account" => { + if let OpsDetails::AccountCreation(account) = ops_details.unwrap() { + Proto::mod_SigningInput::OneOftransaction_payload::create_account( + Proto::CreateAccountMessage { + auth_key: account.to.into(), + }, + ) + } else { + panic!("Unsupported arguments") + } + }, + "coin_transfer" => { + if let OpsDetails::TokenTransfer(token_transfer) = ops_details.unwrap() { + Proto::mod_SigningInput::OneOftransaction_payload::token_transfer( + Proto::TokenTransferMessage { + to: token_transfer.transfer.to.into(), + amount: token_transfer.transfer.amount, + function: Some(convert_type_tag_to_struct_tag(token_transfer.tag)), + }, + ) + } else { + panic!("Unsupported arguments") + } + }, + "implicit_coin_transfer" => { + if let OpsDetails::ImplicitTokenTransfer(token_transfer) = ops_details.unwrap() { + Proto::mod_SigningInput::OneOftransaction_payload::token_transfer_coins( + Proto::TokenTransferCoinsMessage { + to: token_transfer.transfer.to.into(), + amount: token_transfer.transfer.amount, + function: Some(convert_type_tag_to_struct_tag(token_transfer.tag)), + }, + ) + } else { + panic!("Unsupported arguments") + } + }, + "nft_ops" => { + if let OpsDetails::NftOps(nft) = ops_details.unwrap() { + Proto::mod_SigningInput::OneOftransaction_payload::nft_message(nft.into()) + } else { + panic!("Unsupported arguments") + } + }, + "register_token" => { + if let OpsDetails::RegisterToken(register_token) = ops_details.unwrap() { + Proto::mod_SigningInput::OneOftransaction_payload::register_token( + Proto::ManagedTokensRegisterMessage { + function: Some(convert_type_tag_to_struct_tag(register_token.coin_type)), + }, + ) + } else { + panic!("Unsupported arguments") + } + }, + "liquid_staking_ops" => { + if let OpsDetails::LiquidStakingOps(liquid_staking_ops) = ops_details.unwrap() { + Proto::mod_SigningInput::OneOftransaction_payload::liquid_staking_message( + liquid_staking_ops.into(), + ) + } else { + panic!("Unsupported arguments") + } + }, + "blind_sign_json" => Proto::mod_SigningInput::OneOftransaction_payload::None, + _ => Proto::mod_SigningInput::OneOftransaction_payload::None, + }; + + let input = SigningInput { + chain_id, + sender: sender.into(), + sequence_number, + max_gas_amount, + gas_unit_price, + expiration_timestamp_secs: timestamp, + private_key: private.into(), + any_encoded: any_encoded.into(), + transaction_payload: payload, + }; + + input +} + +fn test_tx_result( + output: SigningOutput, + expected_raw_txn_bytes_str: &str, + expected_signature_str: &str, + expected_encoded_txn_str: &str, + json_literal: &str, +) { + assert_eq!(output.error, SigningErrorType::OK); + assert!(output.error_message.is_empty()); + + assert_eq!( + hex::encode(output.raw_txn.to_vec(), false), + expected_raw_txn_bytes_str + ); + assert_eq!( + hex::encode(output.authenticator.unwrap().signature.to_vec(), false), + expected_signature_str + ); + assert_eq!( + hex::encode(output.encoded.to_vec(), false), + expected_encoded_txn_str + ); + + let json_value_expected: serde_json::Value = serde_json::from_str(json_literal).unwrap(); + let json_value: serde_json::Value = serde_json::from_str(output.json.as_ref()).unwrap(); + assert_eq!(json_value, json_value_expected); +} + +// Successfully broadcasted https://explorer.aptoslabs.com/txn/0xb4d62afd3862116e060dd6ad9848ccb50c2bc177799819f1d29c059ae2042467?network=devnet +#[test] +fn test_aptos_sign_transaction_transfer() { + let input = setup_proto_transaction( + "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", + "5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec", + "transfer", + 99, + 33, + 3296766, + 3664390082, + 100, + "", + Some(OpsDetails::Transfer(Transfer { + to: "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30".to_string(), + amount: 1000, + })), + ); + let output = Signer::sign_proto(input); + test_tx_result(output, + "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3063000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e74087472616e7366657200022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada0000000021", + "5707246db31e2335edc4316a7a656a11691d1d1647f6e864d1ab12f43428aaaf806cf02120d0b608cdd89c5c904af7b137432aacdd60cc53f9fad7bd33578e01", + "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3063000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e74087472616e7366657200022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada00000000210020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c405707246db31e2335edc4316a7a656a11691d1d1647f6e864d1ab12f43428aaaf806cf02120d0b608cdd89c5c904af7b137432aacdd60cc53f9fad7bd33578e01", + r#"{ + "expiration_timestamp_secs": "3664390082", + "gas_unit_price": "100", + "max_gas_amount": "3296766", + "payload": { + "arguments": ["0x7968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30","1000"], + "function": "0x1::aptos_account::transfer", + "type": "entry_function_payload", + "type_arguments": [] + }, + "sender": "0x7968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", + "sequence_number": "99", + "signature": { + "public_key": "0xea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c", + "signature": "0x5707246db31e2335edc4316a7a656a11691d1d1647f6e864d1ab12f43428aaaf806cf02120d0b608cdd89c5c904af7b137432aacdd60cc53f9fad7bd33578e01", + "type": "ed25519_signature" + } + }"#); +} + +// Successfully broadcasted: https://explorer.aptoslabs.com/txn/0x477141736de6b0936a6c3734e4d6fd018c7d21f1f28f99028ef0bc6881168602?network=Devnet +#[test] +fn test_aptos_sign_create_account() { + let input = setup_proto_transaction( + "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", // Sender's address + "5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec", // Keypair + "create_account", + 0, // Sequence number + 33, + 3296766, + 3664390082, + 100, + "", + Some(OpsDetails::AccountCreation(AccountCreation { + to: "0x3aa1672641a4e17b3d913b4c0301e805755a80b12756fc729c5878f12344d30e".to_string(), + })), + ); + let output = Signer::sign_proto(input); + test_tx_result(output, + "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3000000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e740e6372656174655f6163636f756e740001203aa1672641a4e17b3d913b4c0301e805755a80b12756fc729c5878f12344d30efe4d3200000000006400000000000000c2276ada0000000021", // Expected raw transaction bytes + "fcba3dfbec76721454ef414955f09f159660a13886b4edd8c579e3c779c29073afe7b25efa3fef9b21c2efb1cf16b4247fc0e5c8f63fdcd1c8d87f5d59f44501", // Expected signature + "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3000000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e740e6372656174655f6163636f756e740001203aa1672641a4e17b3d913b4c0301e805755a80b12756fc729c5878f12344d30efe4d3200000000006400000000000000c2276ada00000000210020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c40fcba3dfbec76721454ef414955f09f159660a13886b4edd8c579e3c779c29073afe7b25efa3fef9b21c2efb1cf16b4247fc0e5c8f63fdcd1c8d87f5d59f44501", // Expected encoded transaction + r#"{ + "expiration_timestamp_secs": "3664390082", + "gas_unit_price": "100", + "max_gas_amount": "3296766", + "payload": { + "arguments": ["0x3aa1672641a4e17b3d913b4c0301e805755a80b12756fc729c5878f12344d30e"], + "function": "0x1::aptos_account::create_account", + "type": "entry_function_payload", + "type_arguments": [] + }, + "sender": "0x7968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", + "sequence_number": "0", + "signature": { + "public_key": "0xea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c", + "signature": "0xfcba3dfbec76721454ef414955f09f159660a13886b4edd8c579e3c779c29073afe7b25efa3fef9b21c2efb1cf16b4247fc0e5c8f63fdcd1c8d87f5d59f44501", + "type": "ed25519_signature" + } + }"#); +} + +// Successfully broadcasted https://explorer.aptoslabs.com/txn/0xb5b383a5c7f99b2edb3bed9533f8169a89051b149d65876a82f4c0b9bf78a15b?network=Devnet +#[test] +fn test_aptos_sign_coin_transfer() { + let input = setup_proto_transaction( + "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", // Sender's address + "5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec", // Keypair + "coin_transfer", + 24, // Sequence number + 32, + 3296766, + 3664390082, + 100, + "", + Some(OpsDetails::TokenTransfer(TokenTransfer { + transfer: Transfer { + to: "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30" + .to_string(), + amount: 100000, + }, + tag: TypeTag::from_str( + "0x43417434fd869edee76cca2a4d2301e528a1551b1d719b75c350c3c97d15b8b9::coins::BTC", + ) + .unwrap(), + })), + ); + let output = Signer::sign_proto(input); + test_tx_result(output, + "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30180000000000000002000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010743417434fd869edee76cca2a4d2301e528a1551b1d719b75c350c3c97d15b8b905636f696e730342544300022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008a086010000000000fe4d3200000000006400000000000000c2276ada0000000020", // Expected raw transaction bytes + "7643ec8aae6198bd13ca6ea2962265859cba5a228e7d181131f6c022700dd02a7a04dc0345ad99a0289e5ab80b130b3864e6404079980bc226f1a13aee7d280a", // Expected signature + "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30180000000000000002000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010743417434fd869edee76cca2a4d2301e528a1551b1d719b75c350c3c97d15b8b905636f696e730342544300022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008a086010000000000fe4d3200000000006400000000000000c2276ada00000000200020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c407643ec8aae6198bd13ca6ea2962265859cba5a228e7d181131f6c022700dd02a7a04dc0345ad99a0289e5ab80b130b3864e6404079980bc226f1a13aee7d280a", // Expected encoded transaction + r#"{ + "expiration_timestamp_secs": "3664390082", + "gas_unit_price": "100", + "max_gas_amount": "3296766", + "payload": { + "arguments": ["0x7968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30","100000"], + "function": "0x1::coin::transfer", + "type": "entry_function_payload", + "type_arguments": ["0x43417434fd869edee76cca2a4d2301e528a1551b1d719b75c350c3c97d15b8b9::coins::BTC"] + }, + "sender": "0x7968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", + "sequence_number": "24", + "signature": { + "public_key": "0xea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c", + "signature": "0x7643ec8aae6198bd13ca6ea2962265859cba5a228e7d181131f6c022700dd02a7a04dc0345ad99a0289e5ab80b130b3864e6404079980bc226f1a13aee7d280a", + "type": "ed25519_signature" + } + }"#); +} + +// Successfully broadcasted https://explorer.aptoslabs.com/txn/0x197d40ea12e2bfc65a0a913b9f4ca3b0b0208fe0c1514d3d55cef3d5bcf25211?network=mainnet +#[test] +fn test_implicit_aptos_sign_coin_transfer() { + let input = setup_proto_transaction("0x1869b853768f0ba935d67f837a66b172dd39a60ca2315f8d4e0e669bbd35cf25", // Sender's address + "e7f56c77189e03699a75d8ec5c090e41f3d9d4783bc49c33df8a93d915e10de8", // Keypair + "implicit_coin_transfer", + 2, // Sequence number + 1, + 2000, + 3664390082, + 100, + "", + Some(OpsDetails::ImplicitTokenTransfer(TokenTransfer { transfer: Transfer { to: "0xb7c7d12080209e9dc14498c80200706e760363fb31782247e82cf57d1d6e5d6c".to_string(), amount: 10000 }, tag: TypeTag::from_str("0xe9c192ff55cffab3963c695cff6dbf9dad6aff2bb5ac19a6415cad26a81860d9::mee_coin::MeeCoin").unwrap() })), + ); + let output = Signer::sign_proto(input); + test_tx_result(output, + "1869b853768f0ba935d67f837a66b172dd39a60ca2315f8d4e0e669bbd35cf2502000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e740e7472616e736665725f636f696e730107e9c192ff55cffab3963c695cff6dbf9dad6aff2bb5ac19a6415cad26a81860d9086d65655f636f696e074d6565436f696e000220b7c7d12080209e9dc14498c80200706e760363fb31782247e82cf57d1d6e5d6c081027000000000000d0070000000000006400000000000000c2276ada0000000001", // Expected raw transaction bytes + "30ebd7e95cb464677f411868e2cbfcb22bc01cc63cded36c459dff45e6d2f1354ae4e090e7dfbb509851c0368b343e0e5ecaf6b08e7c1b94c186530b0f7dee0d", // Expected signature + "1869b853768f0ba935d67f837a66b172dd39a60ca2315f8d4e0e669bbd35cf2502000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e740e7472616e736665725f636f696e730107e9c192ff55cffab3963c695cff6dbf9dad6aff2bb5ac19a6415cad26a81860d9086d65655f636f696e074d6565436f696e000220b7c7d12080209e9dc14498c80200706e760363fb31782247e82cf57d1d6e5d6c081027000000000000d0070000000000006400000000000000c2276ada0000000001002062e7a6a486553b56a53e89dfae3f780693e537e5b0a7ed33290780e581ca83694030ebd7e95cb464677f411868e2cbfcb22bc01cc63cded36c459dff45e6d2f1354ae4e090e7dfbb509851c0368b343e0e5ecaf6b08e7c1b94c186530b0f7dee0d", // Expected encoded transaction + r#"{ + "expiration_timestamp_secs": "3664390082", + "gas_unit_price": "100", + "max_gas_amount": "2000", + "payload": { + "arguments": ["0xb7c7d12080209e9dc14498c80200706e760363fb31782247e82cf57d1d6e5d6c","10000"], + "function": "0x1::aptos_account::transfer_coins", + "type": "entry_function_payload", + "type_arguments": ["0xe9c192ff55cffab3963c695cff6dbf9dad6aff2bb5ac19a6415cad26a81860d9::mee_coin::MeeCoin"] + }, + "sender": "0x1869b853768f0ba935d67f837a66b172dd39a60ca2315f8d4e0e669bbd35cf25", + "sequence_number": "2", + "signature": { + "public_key": "0x62e7a6a486553b56a53e89dfae3f780693e537e5b0a7ed33290780e581ca8369", + "signature": "0x30ebd7e95cb464677f411868e2cbfcb22bc01cc63cded36c459dff45e6d2f1354ae4e090e7dfbb509851c0368b343e0e5ecaf6b08e7c1b94c186530b0f7dee0d", + "type": "ed25519_signature" + } + }"#); +} + +// Successfully broadcasted https://explorer.aptoslabs.com/txn/0x514e473618bd3cb89a2b110b7c473db9a2e10532f98eb42d02d86fb31c00525d?network=testnet +#[test] +fn test_aptos_nft_offer() { + let input = setup_proto_transaction( + "0x783135e8b00430253a22ba041d860c373d7a1501ccf7ac2d1ad37a8ed2775aee", // Sender's address + "7bebb6d543d17f6fe4e685cfab239fa37896edd594ff859f1df32f244fb707e2", // Keypair + "nft_ops", + 1, // Sequence number + 2, + 3296766, + 3664390082, + 100, + "", + Some(OpsDetails::NftOps(NftOperation::Offer(Offer { + receiver: AccountAddress::from_str( + "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", + ) + .unwrap(), + creator: AccountAddress::from_str( + "0x9125e4054d884fdc7296b66e12c0d63a7baa0d88c77e8e784987c0a967c670ac", + ) + .unwrap(), + collection: "Topaz Troopers".as_bytes().to_vec(), + name: "Topaz Trooper #20068".as_bytes().to_vec(), + property_version: 0, + amount: 1, + }))), + ); + let output = Signer::sign_proto(input); + test_tx_result(output, + "783135e8b00430253a22ba041d860c373d7a1501ccf7ac2d1ad37a8ed2775aee01000000000000000200000000000000000000000000000000000000000000000000000000000000030f746f6b656e5f7472616e73666572730c6f666665725f73637269707400062007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30209125e4054d884fdc7296b66e12c0d63a7baa0d88c77e8e784987c0a967c670ac0f0e546f70617a2054726f6f706572731514546f70617a2054726f6f70657220233230303638080000000000000000080100000000000000fe4d3200000000006400000000000000c2276ada0000000002", // Expected raw transaction bytes + "af5c7357a83c69e3f425beb23eaf232f8bb36dea3b7cad4a7ab8d735cee999c8ec5285005adf69dc85a6c34b042dd0308fe92b76dad5d6ac88c7b9259902c10f", // Expected signature + "783135e8b00430253a22ba041d860c373d7a1501ccf7ac2d1ad37a8ed2775aee01000000000000000200000000000000000000000000000000000000000000000000000000000000030f746f6b656e5f7472616e73666572730c6f666665725f73637269707400062007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30209125e4054d884fdc7296b66e12c0d63a7baa0d88c77e8e784987c0a967c670ac0f0e546f70617a2054726f6f706572731514546f70617a2054726f6f70657220233230303638080000000000000000080100000000000000fe4d3200000000006400000000000000c2276ada00000000020020d1d99b67e37b483161a0fa369c46f34a3be4863c20e20fc7cdc669c0826a411340af5c7357a83c69e3f425beb23eaf232f8bb36dea3b7cad4a7ab8d735cee999c8ec5285005adf69dc85a6c34b042dd0308fe92b76dad5d6ac88c7b9259902c10f", // Expected encoded transaction + r#"{ + "expiration_timestamp_secs": "3664390082", + "gas_unit_price": "100", + "max_gas_amount": "3296766", + "payload": { + "arguments": [ + "0x7968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", + "0x9125e4054d884fdc7296b66e12c0d63a7baa0d88c77e8e784987c0a967c670ac", + "Topaz Troopers", "Topaz Trooper #20068", "0", "1"], + "function": "0x3::token_transfers::offer_script", + "type": "entry_function_payload", + "type_arguments": [] + }, + "sender": "0x783135e8b00430253a22ba041d860c373d7a1501ccf7ac2d1ad37a8ed2775aee", + "sequence_number": "1", + "signature": { + "public_key": "0xd1d99b67e37b483161a0fa369c46f34a3be4863c20e20fc7cdc669c0826a4113", + "signature": "0xaf5c7357a83c69e3f425beb23eaf232f8bb36dea3b7cad4a7ab8d735cee999c8ec5285005adf69dc85a6c34b042dd0308fe92b76dad5d6ac88c7b9259902c10f", + "type": "ed25519_signature" + } + }"#); +} + +// Successfully broadcasted https://explorer.aptoslabs.com/txn/0x0b8c64e6847c368e4c6bd2cce0e9eab378971b0ef2e3bc40cbd292910a80201d?network=testnet +#[test] +fn test_aptos_cancel_nft_offer() { + let input = setup_proto_transaction( + "0x7968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", // Sender's address + "5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec", // Keypair + "nft_ops", + 21, // Sequence number + 2, + 3296766, + 3664390082, + 100, + "", + Some(OpsDetails::NftOps(NftOperation::Cancel(Offer { + receiver: AccountAddress::from_str( + "0x783135e8b00430253a22ba041d860c373d7a1501ccf7ac2d1ad37a8ed2775aee", + ) + .unwrap(), + creator: AccountAddress::from_str( + "0x9125e4054d884fdc7296b66e12c0d63a7baa0d88c77e8e784987c0a967c670ac", + ) + .unwrap(), + collection: "Topaz Troopers".as_bytes().to_vec(), + name: "Topaz Trooper #20068".as_bytes().to_vec(), + property_version: 0, + amount: 0, + }))), + ); + let output = Signer::sign_proto(input); + test_tx_result(output, + "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3015000000000000000200000000000000000000000000000000000000000000000000000000000000030f746f6b656e5f7472616e73666572731363616e63656c5f6f666665725f736372697074000520783135e8b00430253a22ba041d860c373d7a1501ccf7ac2d1ad37a8ed2775aee209125e4054d884fdc7296b66e12c0d63a7baa0d88c77e8e784987c0a967c670ac0f0e546f70617a2054726f6f706572731514546f70617a2054726f6f70657220233230303638080000000000000000fe4d3200000000006400000000000000c2276ada0000000002", // Expected raw transaction bytes + "826722d374e276f618123e77da3ac024c89a3f97db9e09e19aa8ed06c3cdfc57d4a21c7890137f9a7c0447cc303447ba10ca5b1908e889071e0a68f48c0f260a", // Expected signature + "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3015000000000000000200000000000000000000000000000000000000000000000000000000000000030f746f6b656e5f7472616e73666572731363616e63656c5f6f666665725f736372697074000520783135e8b00430253a22ba041d860c373d7a1501ccf7ac2d1ad37a8ed2775aee209125e4054d884fdc7296b66e12c0d63a7baa0d88c77e8e784987c0a967c670ac0f0e546f70617a2054726f6f706572731514546f70617a2054726f6f70657220233230303638080000000000000000fe4d3200000000006400000000000000c2276ada00000000020020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c40826722d374e276f618123e77da3ac024c89a3f97db9e09e19aa8ed06c3cdfc57d4a21c7890137f9a7c0447cc303447ba10ca5b1908e889071e0a68f48c0f260a", // Expected encoded transaction + r#"{ + "expiration_timestamp_secs": "3664390082", + "gas_unit_price": "100", + "max_gas_amount": "3296766", + "payload": { + "arguments": [ + "0x783135e8b00430253a22ba041d860c373d7a1501ccf7ac2d1ad37a8ed2775aee", + "0x9125e4054d884fdc7296b66e12c0d63a7baa0d88c77e8e784987c0a967c670ac", + "Topaz Troopers", "Topaz Trooper #20068", "0"], + "function": "0x3::token_transfers::cancel_offer_script", + "type": "entry_function_payload", + "type_arguments": [] + }, + "sender": "0x7968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", + "sequence_number": "21", + "signature": { + "public_key": "0xea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c", + "signature": "0x826722d374e276f618123e77da3ac024c89a3f97db9e09e19aa8ed06c3cdfc57d4a21c7890137f9a7c0447cc303447ba10ca5b1908e889071e0a68f48c0f260a", + "type": "ed25519_signature" + } + }"#); +} + +// Successfully broadcasted: https://explorer.aptoslabs.com/txn/0x60b51e15140ec0b7650334e948fb447ce3cb13ae63492260461ebfa9d02e85c4?network=testnet +#[test] +fn test_aptos_nft_claim() { + let input = setup_proto_transaction( + "0x7968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", // Sender's address + "5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec", // Keypair + "nft_ops", + 19, // Sequence number + 2, + 3296766, + 3664390082, + 100, + "", + Some(OpsDetails::NftOps(NftOperation::Claim(Claim { + sender: AccountAddress::from_str( + "0x783135e8b00430253a22ba041d860c373d7a1501ccf7ac2d1ad37a8ed2775aee", + ) + .unwrap(), + creator: AccountAddress::from_str( + "0x9125e4054d884fdc7296b66e12c0d63a7baa0d88c77e8e784987c0a967c670ac", + ) + .unwrap(), + collection: "Topaz Troopers".as_bytes().to_vec(), + name: "Topaz Trooper #20068".as_bytes().to_vec(), + property_version: 0, + }))), + ); + let output = Signer::sign_proto(input); + test_tx_result(output, + "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3013000000000000000200000000000000000000000000000000000000000000000000000000000000030f746f6b656e5f7472616e73666572730c636c61696d5f736372697074000520783135e8b00430253a22ba041d860c373d7a1501ccf7ac2d1ad37a8ed2775aee209125e4054d884fdc7296b66e12c0d63a7baa0d88c77e8e784987c0a967c670ac0f0e546f70617a2054726f6f706572731514546f70617a2054726f6f70657220233230303638080000000000000000fe4d3200000000006400000000000000c2276ada0000000002", // Expected raw transaction bytes + "ede1ffb5f8f663741c2ca9597af44af81c98f7a910261bb4125f758fd0c0ebbf5bacb34f1196ad45153177729eb6d478676b364ab747da17602713f65ca2dd0a", // Expected signature + "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3013000000000000000200000000000000000000000000000000000000000000000000000000000000030f746f6b656e5f7472616e73666572730c636c61696d5f736372697074000520783135e8b00430253a22ba041d860c373d7a1501ccf7ac2d1ad37a8ed2775aee209125e4054d884fdc7296b66e12c0d63a7baa0d88c77e8e784987c0a967c670ac0f0e546f70617a2054726f6f706572731514546f70617a2054726f6f70657220233230303638080000000000000000fe4d3200000000006400000000000000c2276ada00000000020020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c40ede1ffb5f8f663741c2ca9597af44af81c98f7a910261bb4125f758fd0c0ebbf5bacb34f1196ad45153177729eb6d478676b364ab747da17602713f65ca2dd0a", // Expected encoded transaction + r#"{ + "expiration_timestamp_secs": "3664390082", + "gas_unit_price": "100", + "max_gas_amount": "3296766", + "payload": { + "arguments": [ + "0x783135e8b00430253a22ba041d860c373d7a1501ccf7ac2d1ad37a8ed2775aee", + "0x9125e4054d884fdc7296b66e12c0d63a7baa0d88c77e8e784987c0a967c670ac", + "Topaz Troopers", "Topaz Trooper #20068", "0"], + "function": "0x3::token_transfers::claim_script", + "type": "entry_function_payload", + "type_arguments": [] + }, + "sender": "0x7968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", + "sequence_number": "19", + "signature": { + "public_key": "0xea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c", + "signature": "0xede1ffb5f8f663741c2ca9597af44af81c98f7a910261bb4125f758fd0c0ebbf5bacb34f1196ad45153177729eb6d478676b364ab747da17602713f65ca2dd0a", + "type": "ed25519_signature" + } + }"#); +} + +// Successfully broadcasted https://explorer.aptoslabs.com/txn/0xe591252daed785641bfbbcf72a5d17864568cf32e04c0cc9129f3a13834d0e8e?network=testnet +#[test] +fn test_aptos_register_token() { + let input = setup_proto_transaction("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", // Sender's address + "5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec", // Keypair + "register_token", + 23, // Sequence number + 2, + 2000000, + 3664390082, + 100, + "", + Some(OpsDetails::RegisterToken(RegisterToken { coin_type: TypeTag::from_str("0xe4497a32bf4a9fd5601b27661aa0b933a923191bf403bd08669ab2468d43b379::move_coin::MoveCoin").unwrap() })), + ); + let output = Signer::sign_proto(input); + test_tx_result(output, + "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3017000000000000000200000000000000000000000000000000000000000000000000000000000000010c6d616e616765645f636f696e0872656769737465720107e4497a32bf4a9fd5601b27661aa0b933a923191bf403bd08669ab2468d43b379096d6f76655f636f696e084d6f7665436f696e000080841e00000000006400000000000000c2276ada0000000002", // Expected raw transaction bytes + "e230b49f552fb85356dbec9df13f0dc56228eb7a9c29a8af3a99f4ae95b86c72bdcaa4ff1e9beb0bd81c298b967b9d97449856ec8bc672a08e2efef345c37100", // Expected signature + "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3017000000000000000200000000000000000000000000000000000000000000000000000000000000010c6d616e616765645f636f696e0872656769737465720107e4497a32bf4a9fd5601b27661aa0b933a923191bf403bd08669ab2468d43b379096d6f76655f636f696e084d6f7665436f696e000080841e00000000006400000000000000c2276ada00000000020020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c40e230b49f552fb85356dbec9df13f0dc56228eb7a9c29a8af3a99f4ae95b86c72bdcaa4ff1e9beb0bd81c298b967b9d97449856ec8bc672a08e2efef345c37100", // Expected encoded transaction + r#"{ + "expiration_timestamp_secs": "3664390082", + "gas_unit_price": "100", + "max_gas_amount": "2000000", + "payload": { + "arguments": [], + "function": "0x1::managed_coin::register", + "type": "entry_function_payload", + "type_arguments": ["0xe4497a32bf4a9fd5601b27661aa0b933a923191bf403bd08669ab2468d43b379::move_coin::MoveCoin"] + }, + "sender": "0x7968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", + "sequence_number": "23", + "signature": { + "public_key": "0xea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c", + "signature": "0xe230b49f552fb85356dbec9df13f0dc56228eb7a9c29a8af3a99f4ae95b86c72bdcaa4ff1e9beb0bd81c298b967b9d97449856ec8bc672a08e2efef345c37100", + "type": "ed25519_signature" + } + }"#); +} + +// Successfully broadcasted: https://explorer.aptoslabs.com/txn/0x25dca849cb4ebacbff223139f7ad5d24c37c225d9506b8b12a925de70429e685/userTxnOverview?network=mainnet +#[test] +fn test_aptos_tortuga_stake() { + let input = setup_proto_transaction( + "0xf3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc", // Sender's address + "786fc7ceca43b4c1da018fea5d96f35dfdf5605f220b1205ff29c5c6d9eccf05", // Keypair + "liquid_staking_ops", + 19, // Sequence number + 1, + 5554, + 1670240203, + 100, + "", + Some(OpsDetails::LiquidStakingOps(LiquidStakingOperation::Stake( + Stake { + amount: 100000000, + smart_contract_address: AccountAddress::from_str( + "0x8f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f", + ) + .unwrap(), + }, + ))), + ); + let output = Signer::sign_proto(input); + test_tx_result(output, + "f3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc1300000000000000028f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f0c7374616b655f726f75746572057374616b6500010800e1f50500000000b2150000000000006400000000000000cbd78d630000000001", // Expected raw transaction bytes + "22d3166c3003f9c24a35fd39c71eb27e0d2bb82541be610822165c9283f56fefe5a9d46421b9caf174995bd8f83141e60ea8cff521ecf4741fe19e6ae9a5680d", // Expected signature + "f3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc1300000000000000028f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f0c7374616b655f726f75746572057374616b6500010800e1f50500000000b2150000000000006400000000000000cbd78d630000000001002089e0211d7e19c7d3a8e2030fe16c936a690ca9b95569098c5d2bf1031ff44bc44022d3166c3003f9c24a35fd39c71eb27e0d2bb82541be610822165c9283f56fefe5a9d46421b9caf174995bd8f83141e60ea8cff521ecf4741fe19e6ae9a5680d", // Expected encoded transaction + r#"{ + "sender": "0xf3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc", + "sequence_number": "19", + "max_gas_amount": "5554", + "gas_unit_price": "100", + "expiration_timestamp_secs": "1670240203", + "payload": { + "function": "0x8f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f::stake_router::stake", + "type_arguments": [], + "arguments": [ + "100000000" + ], + "type": "entry_function_payload" + }, + "signature": { + "public_key": "0x89e0211d7e19c7d3a8e2030fe16c936a690ca9b95569098c5d2bf1031ff44bc4", + "signature": "0x22d3166c3003f9c24a35fd39c71eb27e0d2bb82541be610822165c9283f56fefe5a9d46421b9caf174995bd8f83141e60ea8cff521ecf4741fe19e6ae9a5680d", + "type": "ed25519_signature" + } + }"#); +} + +// Successfully broadcasted: https://explorer.aptoslabs.com/txn/0x92edb4f756fe86118e34a0e64746c70260ee02c2ae2cf402b3e39f6a282ce968?network=mainnet +#[test] +fn test_aptos_tortuga_unstake() { + let input = setup_proto_transaction( + "0xf3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc", // Sender's address + "786fc7ceca43b4c1da018fea5d96f35dfdf5605f220b1205ff29c5c6d9eccf05", // Keypair + "liquid_staking_ops", + 20, // Sequence number + 1, + 2371, + 1670304949, + 120, + "", + Some(OpsDetails::LiquidStakingOps( + LiquidStakingOperation::Unstake(Unstake { + amount: 99178100, + smart_contract_address: AccountAddress::from_str( + "0x8f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f", + ) + .unwrap(), + }), + )), + ); + let output = Signer::sign_proto(input); + test_tx_result(output, + "f3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc1400000000000000028f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f0c7374616b655f726f7574657207756e7374616b650001087456e9050000000043090000000000007800000000000000b5d48e630000000001", // Expected raw transaction bytes + "6994b917432ad70ae84d2ce1484e6aece589a68aad1b7c6e38c9697f2a012a083a3a755c5e010fd3d0f149a75dd8d257acbd09f10800e890074e5ad384314d0c", // Expected signature + "f3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc1400000000000000028f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f0c7374616b655f726f7574657207756e7374616b650001087456e9050000000043090000000000007800000000000000b5d48e630000000001002089e0211d7e19c7d3a8e2030fe16c936a690ca9b95569098c5d2bf1031ff44bc4406994b917432ad70ae84d2ce1484e6aece589a68aad1b7c6e38c9697f2a012a083a3a755c5e010fd3d0f149a75dd8d257acbd09f10800e890074e5ad384314d0c", // Expected encoded transaction + r#"{ + "sender": "0xf3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc", + "sequence_number": "20", + "max_gas_amount": "2371", + "gas_unit_price": "120", + "expiration_timestamp_secs": "1670304949", + "payload": { + "function": "0x8f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f::stake_router::unstake", + "type_arguments": [], + "arguments": [ + "99178100" + ], + "type": "entry_function_payload" + }, + "signature": { + "public_key": "0x89e0211d7e19c7d3a8e2030fe16c936a690ca9b95569098c5d2bf1031ff44bc4", + "signature": "0x6994b917432ad70ae84d2ce1484e6aece589a68aad1b7c6e38c9697f2a012a083a3a755c5e010fd3d0f149a75dd8d257acbd09f10800e890074e5ad384314d0c", + "type": "ed25519_signature" + } + }"#); +} + +// // Successfully broadcasted: https://explorer.aptoslabs.com/txn/0x9fc874de7a7d3e813d9a1658d896023de270a0096a5e258c196005656ace7d54?network=mainnet +#[test] +fn test_aptos_tortuga_claim() { + let input = setup_proto_transaction( + "0xf3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc", // Sender's address + "786fc7ceca43b4c1da018fea5d96f35dfdf5605f220b1205ff29c5c6d9eccf05", // Keypair + "liquid_staking_ops", + 28, // Sequence number + 1, + 10, + 1682066783, + 148, + "", + Some(OpsDetails::LiquidStakingOps(LiquidStakingOperation::Claim( + liquid_staking::Claim { + idx: 0, + smart_contract_address: AccountAddress::from_str( + "0x8f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f", + ) + .unwrap(), + }, + ))), + ); + let output = Signer::sign_proto(input); + test_tx_result(output, + "f3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc1c00000000000000028f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f0c7374616b655f726f7574657205636c61696d00010800000000000000000a0000000000000094000000000000005f4d42640000000001", // Expected raw transaction bytes + "c936584f89777e1fe2d5dd75cd8d9c514efc445810ba22f462b6fe7229c6ec7fc1c8b25d3e233eafaa8306433b3220235e563498ba647be38cac87ff618e3d03", // Expected signature + "f3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc1c00000000000000028f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f0c7374616b655f726f7574657205636c61696d00010800000000000000000a0000000000000094000000000000005f4d42640000000001002089e0211d7e19c7d3a8e2030fe16c936a690ca9b95569098c5d2bf1031ff44bc440c936584f89777e1fe2d5dd75cd8d9c514efc445810ba22f462b6fe7229c6ec7fc1c8b25d3e233eafaa8306433b3220235e563498ba647be38cac87ff618e3d03", // Expected encoded transaction + r#"{ + "sender": "0xf3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc", + "sequence_number": "28", + "max_gas_amount": "10", + "gas_unit_price": "148", + "expiration_timestamp_secs": "1682066783", + "payload": { + "function": "0x8f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f::stake_router::claim", + "type_arguments": [], + "arguments": [ + "0" + ], + "type": "entry_function_payload" + }, + "signature": { + "public_key": "0x89e0211d7e19c7d3a8e2030fe16c936a690ca9b95569098c5d2bf1031ff44bc4", + "signature": "0xc936584f89777e1fe2d5dd75cd8d9c514efc445810ba22f462b6fe7229c6ec7fc1c8b25d3e233eafaa8306433b3220235e563498ba647be38cac87ff618e3d03", + "type": "ed25519_signature" + } + }"#); +} + +// Successfully broadcasted: https://explorer.aptoslabs.com/txn/0x7efd69e7f9462774b932ce500ab51c0d0dcc004cf272e09f8ffd5804c2a84e33?network=mainnet +#[test] +fn test_aptos_blind_sign() { + let input = setup_proto_transaction( + "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", // Sender's address + "5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec", // Keypair + "blind_sign_json", + 42, // Sequence number + 1, + 100011, + 3664390082, + 100, + r#"{ + "function": "0x16fe2df00ea7dde4a63409201f7f4e536bde7bb7335526a35d05111e68aa322c::AnimeSwapPoolV1::swap_exact_coins_for_coins_3_pair_entry", + "type_arguments": [ + "0x1::aptos_coin::AptosCoin", + "0x881ac202b1f1e6ad4efcff7a1d0579411533f2502417a19211cfc49751ddb5f4::coin::MOJO", + "0xf22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa::asset::USDT", + "0xf22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa::asset::USDC" + ], + "arguments": [ + "1000000", + "49329" + ], + "type": "entry_function_payload" + }"#, + None, + ); + let output = Signer::sign_proto(input); + test_tx_result(output, + "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f302a000000000000000216fe2df00ea7dde4a63409201f7f4e536bde7bb7335526a35d05111e68aa322c0f416e696d6553776170506f6f6c563127737761705f65786163745f636f696e735f666f725f636f696e735f335f706169725f656e747279040700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e0007881ac202b1f1e6ad4efcff7a1d0579411533f2502417a19211cfc49751ddb5f404636f696e044d4f4a4f0007f22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa05617373657404555344540007f22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa056173736574045553444300020840420f000000000008b1c0000000000000ab860100000000006400000000000000c2276ada0000000001", // Expected raw transaction bytes + "42cd67406e85afd1e948e7ad7f5f484fb4c60d82b267c6b6b28a92301e228b983206d2b87cd5487cf9acfb0effbd183ab90123570eb2e047cb152d337152210b", // Expected signature + "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f302a000000000000000216fe2df00ea7dde4a63409201f7f4e536bde7bb7335526a35d05111e68aa322c0f416e696d6553776170506f6f6c563127737761705f65786163745f636f696e735f666f725f636f696e735f335f706169725f656e747279040700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e0007881ac202b1f1e6ad4efcff7a1d0579411533f2502417a19211cfc49751ddb5f404636f696e044d4f4a4f0007f22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa05617373657404555344540007f22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa056173736574045553444300020840420f000000000008b1c0000000000000ab860100000000006400000000000000c2276ada00000000010020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c4042cd67406e85afd1e948e7ad7f5f484fb4c60d82b267c6b6b28a92301e228b983206d2b87cd5487cf9acfb0effbd183ab90123570eb2e047cb152d337152210b", // Expected encoded transaction + r#"{ + "expiration_timestamp_secs": "3664390082", + "gas_unit_price": "100", + "max_gas_amount": "100011", + "payload": { + "function": "0x16fe2df00ea7dde4a63409201f7f4e536bde7bb7335526a35d05111e68aa322c::AnimeSwapPoolV1::swap_exact_coins_for_coins_3_pair_entry", + "type_arguments": [ + "0x1::aptos_coin::AptosCoin", + "0x881ac202b1f1e6ad4efcff7a1d0579411533f2502417a19211cfc49751ddb5f4::coin::MOJO", + "0xf22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa::asset::USDT", + "0xf22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa::asset::USDC" + ], + "arguments": [ + "1000000", + "49329" + ], + "type": "entry_function_payload" + }, + "sender": "0x7968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", + "sequence_number": "42", + "signature": { + "public_key": "0xea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c", + "signature": "0x42cd67406e85afd1e948e7ad7f5f484fb4c60d82b267c6b6b28a92301e228b983206d2b87cd5487cf9acfb0effbd183ab90123570eb2e047cb152d337152210b", + "type": "ed25519_signature" + } + }"#); +} + +// Successfully broadcasted: https://explorer.aptoslabs.com/txn/0x25dca849cb4ebacbff223139f7ad5d24c37c225d9506b8b12a925de70429e685/payload +#[test] +fn test_aptos_blind_sign_staking() { + let input = setup_proto_transaction( + "0xf3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc", // Sender's address + "5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec", // Keypair + "blind_sign_json", + 43, // Sequence number + 1, + 100011, + 3664390082, + 100, + r#"{ + "function": "0x8f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f::stake_router::stake", + "type_arguments": [], + "arguments": [ + "100000000" + ], + "type": "entry_function_payload" + }"#, + None, + ); + let output = Signer::sign_proto(input); + test_tx_result(output, + "f3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc2b00000000000000028f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f0c7374616b655f726f75746572057374616b6500010800e1f50500000000ab860100000000006400000000000000c2276ada0000000001", // Expected raw transaction bytes + "a41b7440a50f36e8491319508734acb55488abc6d88fbc9cb2b37ba23210f01f5d08c856cb7abf18c414cf9302ee144450bd99495a7e21e61f624764db91eb0b", // Expected signature + "f3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc2b00000000000000028f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f0c7374616b655f726f75746572057374616b6500010800e1f50500000000ab860100000000006400000000000000c2276ada00000000010020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c40a41b7440a50f36e8491319508734acb55488abc6d88fbc9cb2b37ba23210f01f5d08c856cb7abf18c414cf9302ee144450bd99495a7e21e61f624764db91eb0b", // Expected encoded transaction + r#"{ + "expiration_timestamp_secs": "3664390082", + "gas_unit_price": "100", + "max_gas_amount": "100011", + "payload": { + "function": "0x8f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f::stake_router::stake", + "type_arguments": [], + "arguments": [ + "100000000" + ], + "type": "entry_function_payload" + }, + "sender": "0xf3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc", + "sequence_number": "43", + "signature": { + "public_key": "0xea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c", + "signature": "0xa41b7440a50f36e8491319508734acb55488abc6d88fbc9cb2b37ba23210f01f5d08c856cb7abf18c414cf9302ee144450bd99495a7e21e61f624764db91eb0b", + "type": "ed25519_signature" + } + }"#); +} + +// Successfully broadcasted: https://explorer.aptoslabs.com/txn/0x92edb4f756fe86118e34a0e64746c70260ee02c2ae2cf402b3e39f6a282ce968/payload +#[test] +fn test_aptos_blind_sign_unstaking() { + let input = setup_proto_transaction( + "0xf3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc", // Sender's address + "5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec", // Keypair + "blind_sign_json", + 44, // Sequence number + 1, + 100011, + 3664390082, + 100, + r#"{ + "function": "0x8f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f::stake_router::unstake", + "type_arguments": [], + "arguments": [ + "99178100" + ], + "type": "entry_function_payload" + }"#, + None, + ); + let output = Signer::sign_proto(input); + test_tx_result(output, + "f3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc2c00000000000000028f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f0c7374616b655f726f7574657207756e7374616b650001087456e90500000000ab860100000000006400000000000000c2276ada0000000001", // Expected raw transaction bytes + "a58ad5e3331beb8c0212a18a1f932207cb664b78f5aad3cb1fe7435e0e0e053247ce49b38fd67b064bed34ed643eb6a03165d77c681d7d73ac3161ab984a960a", // Expected signature + "f3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc2c00000000000000028f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f0c7374616b655f726f7574657207756e7374616b650001087456e90500000000ab860100000000006400000000000000c2276ada00000000010020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c40a58ad5e3331beb8c0212a18a1f932207cb664b78f5aad3cb1fe7435e0e0e053247ce49b38fd67b064bed34ed643eb6a03165d77c681d7d73ac3161ab984a960a", // Expected encoded transaction + r#"{ + "expiration_timestamp_secs": "3664390082", + "gas_unit_price": "100", + "max_gas_amount": "100011", + "payload": { + "function": "0x8f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f::stake_router::unstake", + "type_arguments": [], + "arguments": [ + "99178100" + ], + "type": "entry_function_payload" + }, + "sender": "0xf3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc", + "sequence_number": "44", + "signature": { + "public_key": "0xea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c", + "signature": "0xa58ad5e3331beb8c0212a18a1f932207cb664b78f5aad3cb1fe7435e0e0e053247ce49b38fd67b064bed34ed643eb6a03165d77c681d7d73ac3161ab984a960a", + "type": "ed25519_signature" + } + }"#); +} diff --git a/rust/chains/tw_binance/Cargo.toml b/rust/chains/tw_binance/Cargo.toml new file mode 100644 index 00000000000..e5c9a10aa2c --- /dev/null +++ b/rust/chains/tw_binance/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "tw_binance" +version = "0.1.0" +edition = "2021" + +[dependencies] +quick-protobuf = "0.8.1" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +serde_repr = "0.1" +strum_macros = "0.25" +tw_bech32_address = { path = "../../tw_bech32_address" } +tw_coin_entry = { path = "../../tw_coin_entry" } +tw_cosmos_sdk = { path = "../../tw_cosmos_sdk" } +tw_encoding = { path = "../../tw_encoding" } +tw_evm = { path = "../../tw_evm" } +tw_hash = { path = "../../tw_hash" } +tw_keypair = { path = "../../tw_keypair" } +tw_memory = { path = "../../tw_memory" } +tw_misc = { path = "../../tw_misc", features = ["serde"] } +tw_proto = { path = "../../tw_proto" } diff --git a/rust/chains/tw_binance/fuzz/.gitignore b/rust/chains/tw_binance/fuzz/.gitignore new file mode 100644 index 00000000000..5c404b9583f --- /dev/null +++ b/rust/chains/tw_binance/fuzz/.gitignore @@ -0,0 +1,5 @@ +target +corpus +artifacts +coverage +Cargo.lock diff --git a/rust/chains/tw_binance/fuzz/Cargo.toml b/rust/chains/tw_binance/fuzz/Cargo.toml new file mode 100644 index 00000000000..179f9d77239 --- /dev/null +++ b/rust/chains/tw_binance/fuzz/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "tw_binance-fuzz" +version = "0.0.0" +publish = false +edition = "2021" + +[package.metadata] +cargo-fuzz = true + +[dependencies] +libfuzzer-sys = "0.4" +tw_any_coin = { path = "../../../tw_any_coin", features = ["test-utils"] } +tw_coin_registry = { path = "../../../tw_coin_registry" } +tw_proto = { path = "../../../tw_proto", features = ["fuzz"] } + +[dependencies.tw_binance] +path = ".." + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[profile.release] +debug = 1 + +[[bin]] +name = "sign" +path = "fuzz_targets/sign.rs" +test = false +doc = false diff --git a/rust/chains/tw_binance/fuzz/fuzz_targets/sign.rs b/rust/chains/tw_binance/fuzz/fuzz_targets/sign.rs new file mode 100644 index 00000000000..482fd1f5844 --- /dev/null +++ b/rust/chains/tw_binance/fuzz/fuzz_targets/sign.rs @@ -0,0 +1,11 @@ +#![no_main] + +use libfuzzer_sys::fuzz_target; +use tw_any_coin::test_utils::sign_utils::AnySignerHelper; +use tw_coin_registry::coin_type::CoinType; +use tw_proto::Binance::Proto; + +fuzz_target!(|input: Proto::SigningInput<'_>| { + let mut signer = AnySignerHelper::::default(); + let _ = signer.sign(CoinType::Binance, input); +}); diff --git a/rust/chains/tw_binance/src/address.rs b/rust/chains/tw_binance/src/address.rs new file mode 100644 index 00000000000..45b00e26bb4 --- /dev/null +++ b/rust/chains/tw_binance/src/address.rs @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use serde::{Deserialize, Serialize}; +use std::fmt; +use std::str::FromStr; +use tw_bech32_address::bech32_prefix::Bech32Prefix; +use tw_bech32_address::Bech32Address; +use tw_coin_entry::coin_context::CoinContext; +use tw_coin_entry::coin_entry::CoinAddress; +use tw_coin_entry::error::prelude::*; +use tw_cosmos_sdk::address::CosmosAddress; +use tw_keypair::tw::PublicKey; +use tw_memory::Data; + +/// The list of known BNB hrps. +const BNB_KNOWN_HRPS: [&str; 2] = [ + BinanceAddress::VALIDATOR_HRP, // BNB Validator HRP. + "bca", +]; + +#[derive(Deserialize, PartialEq, Serialize)] +pub struct BinanceAddress(Bech32Address); + +impl CoinAddress for BinanceAddress { + #[inline] + fn data(&self) -> Data { + self.0.data() + } +} + +impl CosmosAddress for BinanceAddress {} + +impl BinanceAddress { + pub const VALIDATOR_HRP: &'static str = "bva"; + + pub fn new_validator_addr(key_hash: Data) -> AddressResult { + Bech32Address::new(Self::VALIDATOR_HRP.to_string(), key_hash).map(BinanceAddress) + } + + /// Creates a Binance address with the only `prefix` + pub fn from_str_with_coin_and_prefix( + coin: &dyn CoinContext, + address_str: String, + prefix: Option, + ) -> AddressResult + where + Self: Sized, + { + let possible_hrps = match prefix { + Some(Bech32Prefix { hrp }) => vec![hrp], + None => { + let coin_hrp = coin.hrp().ok_or(AddressError::InvalidHrp)?; + let other_hrps = BNB_KNOWN_HRPS + .iter() + .map(|another_hrp| another_hrp.to_string()); + std::iter::once(coin_hrp).chain(other_hrps).collect() + }, + }; + Bech32Address::from_str_checked(possible_hrps, address_str).map(BinanceAddress) + } + + pub fn with_public_key_coin_context( + coin: &dyn CoinContext, + public_key: &PublicKey, + prefix: Option, + ) -> AddressResult { + Bech32Address::with_public_key_coin_context(coin, public_key, prefix).map(BinanceAddress) + } + + pub fn from_key_hash_with_coin( + coin: &dyn CoinContext, + key_hash: Data, + ) -> AddressResult { + Bech32Address::from_key_hash_with_coin(coin, key_hash).map(BinanceAddress) + } +} + +impl FromStr for BinanceAddress { + type Err = AddressError; + + fn from_str(s: &str) -> Result { + Bech32Address::from_str(s).map(BinanceAddress) + } +} + +impl fmt::Display for BinanceAddress { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} diff --git a/rust/chains/tw_binance/src/amino.rs b/rust/chains/tw_binance/src/amino.rs new file mode 100644 index 00000000000..6bcc017dd48 --- /dev/null +++ b/rust/chains/tw_binance/src/amino.rs @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use quick_protobuf::MessageWrite; +use tw_encoding::{EncodingError, EncodingResult}; +use tw_memory::Data; +use tw_proto::serialize; + +pub struct AminoEncoder { + /// The Amino content starts with a prefix. + content: Data, +} + +impl AminoEncoder { + pub fn new(prefix: &[u8]) -> AminoEncoder { + AminoEncoder { + content: prefix.to_vec(), + } + } + + pub fn extend_content(mut self, content: &[u8]) -> AminoEncoder { + self.content.extend_from_slice(content); + self + } + + pub fn extend_with_msg(mut self, msg: &M) -> EncodingResult { + let msg_data = serialize(msg).map_err(|_| EncodingError::Internal)?; + self.content.extend_from_slice(&msg_data); + Ok(self) + } + + pub fn encode(self) -> Data { + self.content + } + + pub fn encode_size_prefixed(self) -> EncodingResult { + const CONTENT_SIZE_CAPACITY: usize = 10; + + let content_len = self.content.len(); + let capacity = content_len + CONTENT_SIZE_CAPACITY; + + let mut buffer = Vec::with_capacity(capacity); + + Self::write_varint(&mut buffer, content_len as u64)?; + buffer.extend_from_slice(&self.content); + + Ok(buffer) + } + + /// This method takes `&mut Data` instead of `&mut [u8]` because the given `buffer` can be extended (become longer). + fn write_varint(buffer: &mut Data, num: u64) -> EncodingResult<()> { + let mut writer = quick_protobuf::Writer::new(buffer); + writer + .write_varint(num) + .map_err(|_| EncodingError::Internal) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use tw_encoding::hex::DecodeHex; + + struct TestInput { + prefix: &'static str, + content: &'static str, + content_size_prefixed: bool, + expected: &'static str, + } + + fn amino_encode_impl(input: TestInput) { + let prefix = input.prefix.decode_hex().unwrap(); + let content = input.content.decode_hex().unwrap(); + + let encoder = AminoEncoder::new(&prefix).extend_content(&content); + + let actual = if input.content_size_prefixed { + encoder + .encode_size_prefixed() + .expect("Error on Amino encoding with content size prefix") + } else { + encoder.encode() + }; + + let expected = input.expected.decode_hex().unwrap(); + assert_eq!(actual, expected); + } + + #[test] + fn test_amino_encode() { + let content_size_prefixed = false; + + amino_encode_impl(TestInput { + prefix: "0b0c0d0e", + content: "0102030405060708", + content_size_prefixed, + expected: "0b0c0d0e0102030405060708", + }); + amino_encode_impl(TestInput { + prefix: "0b0c0d0e", + content: "01020304050607080102030405060708010203040506070801020304050607080102030405060708", + content_size_prefixed, + expected: "0b0c0d0e01020304050607080102030405060708010203040506070801020304050607080102030405060708", + }); + } + + #[test] + fn test_amino_encode_with_content_size_prefix() { + let content_size_prefixed = true; + + amino_encode_impl(TestInput { + prefix: "0b0c0d0e", + content: "0102030405060708", + content_size_prefixed, + expected: "0c0b0c0d0e0102030405060708", + }); + amino_encode_impl(TestInput { + prefix: "0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e", + content: "0102030405060708", + content_size_prefixed, + expected: "dc020b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0b0c0d0e0f101112131415161718191a1b1c1d1e0102030405060708", + }); + } +} diff --git a/rust/chains/tw_binance/src/compiler.rs b/rust/chains/tw_binance/src/compiler.rs new file mode 100644 index 00000000000..400c37e36ec --- /dev/null +++ b/rust/chains/tw_binance/src/compiler.rs @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::context::BinanceContext; +use crate::modules::preimager::{JsonPreimager, JsonTxPreimage}; +use crate::modules::serializer::BinanceAminoSerializer; +use crate::modules::tx_builder::TxBuilder; +use crate::signature::BinanceSignature; +use crate::transaction::SignerInfo; +use tw_coin_entry::coin_context::CoinContext; +use tw_coin_entry::coin_entry::{PublicKeyBytes, SignatureBytes}; +use tw_coin_entry::common::compile_input::SingleSignaturePubkey; +use tw_coin_entry::error::prelude::*; +use tw_coin_entry::signing_output_error; +use tw_cosmos_sdk::modules::serializer::json_serializer::JsonSerializer; +use tw_cosmos_sdk::public_key::secp256k1::Secp256PublicKey; +use tw_cosmos_sdk::public_key::CosmosPublicKey; +use tw_misc::traits::ToBytesVec; +use tw_proto::Binance::Proto; +use tw_proto::TxCompiler::Proto as CompilerProto; + +pub struct BinanceCompiler; + +impl BinanceCompiler { + #[inline] + pub fn preimage_hashes( + coin: &dyn CoinContext, + input: Proto::SigningInput<'_>, + ) -> CompilerProto::PreSigningOutput<'static> { + Self::preimage_hashes_impl(coin, input) + .unwrap_or_else(|e| signing_output_error!(CompilerProto::PreSigningOutput, e)) + } + + fn preimage_hashes_impl( + coin: &dyn CoinContext, + input: Proto::SigningInput<'_>, + ) -> SigningResult> { + let unsigned_tx = TxBuilder::unsigned_tx_from_proto(coin, &input)?; + let JsonTxPreimage { + tx_hash, + encoded_tx, + } = JsonPreimager::preimage_hash(&unsigned_tx)?; + + Ok(CompilerProto::PreSigningOutput { + data_hash: tx_hash.to_vec().into(), + data: encoded_tx.as_bytes().to_vec().into(), + ..CompilerProto::PreSigningOutput::default() + }) + } + + #[inline] + pub fn compile( + coin: &dyn CoinContext, + input: Proto::SigningInput<'_>, + signatures: Vec, + public_keys: Vec, + ) -> Proto::SigningOutput<'static> { + Self::compile_impl(coin, input, signatures, public_keys) + .unwrap_or_else(|e| signing_output_error!(Proto::SigningOutput, e)) + } + + fn compile_impl( + coin: &dyn CoinContext, + input: Proto::SigningInput<'_>, + signatures: Vec, + public_keys: Vec, + ) -> SigningResult> { + let SingleSignaturePubkey { + signature, + public_key, + } = SingleSignaturePubkey::from_sign_pubkey_list(signatures, public_keys)?; + let signature = BinanceSignature::try_from(signature.as_slice())?; + let public_key_params = None; + let public_key = + Secp256PublicKey::from_bytes(coin, public_key.as_slice(), public_key_params)?; + + let signature_bytes = signature.to_vec(); + let signature_json = JsonSerializer::::serialize_signature( + &public_key, + signature_bytes.clone(), + ); + + let unsigned_tx = TxBuilder::unsigned_tx_from_proto(coin, &input)?; + let signed_tx = unsigned_tx.into_signed(SignerInfo { + public_key, + signature, + }); + + let encoded_tx = BinanceAminoSerializer::serialize_signed_tx(&signed_tx)?; + + let signature_json = + serde_json::to_string(&signature_json).tw_err(|_| SigningErrorType::Error_internal)?; + Ok(Proto::SigningOutput { + encoded: encoded_tx.into(), + signature: signature_bytes.into(), + signature_json: signature_json.into(), + ..Proto::SigningOutput::default() + }) + } +} diff --git a/rust/chains/tw_binance/src/context.rs b/rust/chains/tw_binance/src/context.rs new file mode 100644 index 00000000000..58952365b63 --- /dev/null +++ b/rust/chains/tw_binance/src/context.rs @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::address::BinanceAddress; +use tw_cosmos_sdk::context::CosmosContext; +use tw_cosmos_sdk::private_key::secp256k1::Secp256PrivateKey; +use tw_cosmos_sdk::public_key::secp256k1::Secp256PublicKey; +use tw_cosmos_sdk::signature::secp256k1::Secp256k1Signature; +use tw_hash::hasher::Hasher; + +pub struct BinanceContext; + +impl CosmosContext for BinanceContext { + type Address = BinanceAddress; + type PrivateKey = Secp256PrivateKey; + type PublicKey = Secp256PublicKey; + type Signature = Secp256k1Signature; + + /// Binance Beacon chain uses `sha256` hash. + fn default_tx_hasher() -> Hasher { + Hasher::Sha256 + } +} diff --git a/rust/chains/tw_binance/src/entry.rs b/rust/chains/tw_binance/src/entry.rs new file mode 100644 index 00000000000..6552c0e6bd0 --- /dev/null +++ b/rust/chains/tw_binance/src/entry.rs @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::address::BinanceAddress; +use crate::compiler::BinanceCompiler; +use crate::modules::wallet_connect::connector::BinanceWalletConnector; +use crate::signer::BinanceSigner; +use std::str::FromStr; +use tw_bech32_address::bech32_prefix::Bech32Prefix; +use tw_coin_entry::coin_context::CoinContext; +use tw_coin_entry::coin_entry::{CoinEntry, PublicKeyBytes, SignatureBytes}; +use tw_coin_entry::derivation::Derivation; +use tw_coin_entry::error::prelude::*; +use tw_coin_entry::modules::json_signer::NoJsonSigner; +use tw_coin_entry::modules::message_signer::NoMessageSigner; +use tw_coin_entry::modules::plan_builder::NoPlanBuilder; +use tw_coin_entry::modules::transaction_decoder::NoTransactionDecoder; +use tw_coin_entry::modules::transaction_util::NoTransactionUtil; +use tw_keypair::tw::PublicKey; +use tw_proto::Binance::Proto; +use tw_proto::TxCompiler::Proto as CompilerProto; + +pub struct BinanceEntry; + +impl CoinEntry for BinanceEntry { + type AddressPrefix = Bech32Prefix; + type Address = BinanceAddress; + type SigningInput<'a> = Proto::SigningInput<'a>; + type SigningOutput = Proto::SigningOutput<'static>; + type PreSigningOutput = CompilerProto::PreSigningOutput<'static>; + + // Optional modules: + type JsonSigner = NoJsonSigner; + type PlanBuilder = NoPlanBuilder; + type MessageSigner = NoMessageSigner; + type WalletConnector = BinanceWalletConnector; + type TransactionDecoder = NoTransactionDecoder; + type TransactionUtil = NoTransactionUtil; + + #[inline] + fn parse_address( + &self, + coin: &dyn CoinContext, + address: &str, + prefix: Option, + ) -> AddressResult { + BinanceAddress::from_str_with_coin_and_prefix(coin, address.to_string(), prefix) + } + + #[inline] + fn parse_address_unchecked(&self, address: &str) -> AddressResult { + BinanceAddress::from_str(address) + } + + #[inline] + fn derive_address( + &self, + coin: &dyn CoinContext, + public_key: PublicKey, + _derivation: Derivation, + prefix: Option, + ) -> AddressResult { + BinanceAddress::with_public_key_coin_context(coin, &public_key, prefix) + } + + #[inline] + fn sign(&self, coin: &dyn CoinContext, input: Self::SigningInput<'_>) -> Self::SigningOutput { + BinanceSigner::sign(coin, input) + } + + #[inline] + fn preimage_hashes( + &self, + coin: &dyn CoinContext, + input: Self::SigningInput<'_>, + ) -> Self::PreSigningOutput { + BinanceCompiler::preimage_hashes(coin, input) + } + + #[inline] + fn compile( + &self, + coin: &dyn CoinContext, + input: Self::SigningInput<'_>, + signatures: Vec, + public_keys: Vec, + ) -> Self::SigningOutput { + BinanceCompiler::compile(coin, input, signatures, public_keys) + } + + #[inline] + fn wallet_connector(&self) -> Option { + Some(BinanceWalletConnector) + } +} diff --git a/rust/chains/tw_binance/src/lib.rs b/rust/chains/tw_binance/src/lib.rs new file mode 100644 index 00000000000..6df844a203d --- /dev/null +++ b/rust/chains/tw_binance/src/lib.rs @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +pub mod address; +pub mod amino; +pub mod compiler; +pub mod context; +pub mod entry; +pub mod modules; +pub mod signature; +pub mod signer; +pub mod transaction; diff --git a/rust/chains/tw_binance/src/modules/mod.rs b/rust/chains/tw_binance/src/modules/mod.rs new file mode 100644 index 00000000000..943cd0f39ce --- /dev/null +++ b/rust/chains/tw_binance/src/modules/mod.rs @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +pub mod preimager; +pub mod serializer; +pub mod tx_builder; +pub mod wallet_connect; diff --git a/rust/chains/tw_binance/src/modules/preimager.rs b/rust/chains/tw_binance/src/modules/preimager.rs new file mode 100644 index 00000000000..45e2dacdf53 --- /dev/null +++ b/rust/chains/tw_binance/src/modules/preimager.rs @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::transaction::UnsignedTransaction; +use tw_coin_entry::error::prelude::*; +use tw_hash::{sha2, H256}; + +pub struct JsonTxPreimage { + pub encoded_tx: String, + pub tx_hash: H256, +} + +pub struct JsonPreimager; + +impl JsonPreimager { + pub fn preimage_hash(unsigned: &UnsignedTransaction) -> SigningResult { + let encoded_tx = + serde_json::to_string(unsigned).tw_err(|_| SigningErrorType::Error_internal)?; + let tx_hash = sha2::sha256(encoded_tx.as_bytes()); + let tx_hash = H256::try_from(tx_hash.as_slice()).expect("sha256 must return 32 bytes"); + Ok(JsonTxPreimage { + encoded_tx, + tx_hash, + }) + } +} diff --git a/rust/chains/tw_binance/src/modules/serializer.rs b/rust/chains/tw_binance/src/modules/serializer.rs new file mode 100644 index 00000000000..88ec0ad22f3 --- /dev/null +++ b/rust/chains/tw_binance/src/modules/serializer.rs @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::amino::AminoEncoder; +use crate::transaction::SignedTransaction; +use std::borrow::Cow; +use tw_coin_entry::error::prelude::*; +use tw_cosmos_sdk::public_key::CosmosPublicKey; +use tw_memory::Data; +use tw_misc::traits::ToBytesVec; +use tw_proto::serialize; +use tw_proto::Binance::Proto; + +/// cbindgen:ignore +pub const TRANSACTION_AMINO_PREFIX: [u8; 4] = [0xF0, 0x62, 0x5D, 0xEE]; +/// cbindgen:ignore +pub const PUBLIC_KEY_PREFIX: [u8; 4] = [0xEB, 0x5A, 0xE9, 0x87]; + +pub struct BinanceAminoSerializer; + +impl BinanceAminoSerializer { + pub fn serialize_signed_tx(tx: &SignedTransaction) -> SigningResult { + let msgs = tx + .unsigned + .msgs + .iter() + .map(|msg| msg.as_ref().to_amino_protobuf().map(Cow::from)) + .collect::>>()?; + + let signature = Self::serialize_signature(tx)?; + let tx = Proto::Transaction { + msgs, + signatures: vec![signature.into()], + memo: tx.unsigned.memo.clone().into(), + source: tx.unsigned.source, + data: tx.unsigned.data.clone().unwrap_or_default().into(), + }; + Ok(AminoEncoder::new(&TRANSACTION_AMINO_PREFIX) + .extend_with_msg(&tx)? + .encode_size_prefixed()?) + } + + pub fn serialize_public_key(public_key: Data) -> Data { + let public_key_len = public_key.len() as u8; + AminoEncoder::new(&PUBLIC_KEY_PREFIX) + // Push the length of the public key. + .extend_content(&[public_key_len]) + .extend_content(public_key.as_slice()) + .encode() + } + + pub fn serialize_signature(signed: &SignedTransaction) -> SigningResult { + let sign_msg = Proto::Signature { + pub_key: Self::serialize_public_key(signed.signer.public_key.to_bytes()).into(), + signature: signed.signer.signature.to_vec().into(), + account_number: signed.unsigned.account_number, + sequence: signed.unsigned.sequence, + }; + // There is no need to use Amino encoding here as the prefix is empty. + serialize(&sign_msg).tw_err(|_| SigningErrorType::Error_internal) + } +} diff --git a/rust/chains/tw_binance/src/modules/tx_builder.rs b/rust/chains/tw_binance/src/modules/tx_builder.rs new file mode 100644 index 00000000000..ce1340d63c0 --- /dev/null +++ b/rust/chains/tw_binance/src/modules/tx_builder.rs @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::transaction::message::{BinanceMessageEnum, TWBinanceProto}; +use crate::transaction::UnsignedTransaction; +use std::borrow::Cow; +use tw_coin_entry::coin_context::CoinContext; +use tw_coin_entry::error::prelude::*; +use tw_proto::Binance::Proto; + +pub struct TxBuilder; + +impl TxBuilder { + pub fn unsigned_tx_from_proto( + coin: &dyn CoinContext, + input: &Proto::SigningInput<'_>, + ) -> SigningResult { + let msg = BinanceMessageEnum::from_tw_proto(coin, &input.order_oneof)?; + Ok(UnsignedTransaction { + account_number: input.account_number, + chain_id: input.chain_id.to_string(), + data: None, + memo: input.memo.to_string(), + msgs: vec![msg], + sequence: input.sequence, + source: input.source, + }) + } + + pub fn unsigned_tx_to_proto( + unsigned: &UnsignedTransaction, + ) -> SigningResult> { + if unsigned.msgs.len() != 1 { + return SigningError::err(SigningErrorType::Error_invalid_params) + .context("Expected exactly one Transaction Message"); + } + let msg = unsigned + .msgs + .first() + .expect("There should be exactly one message") + .to_tw_proto(); + + Ok(Proto::SigningInput { + chain_id: unsigned.chain_id.clone().into(), + account_number: unsigned.account_number, + sequence: unsigned.sequence, + source: unsigned.source, + memo: unsigned.memo.clone().into(), + private_key: Cow::default(), + order_oneof: msg, + }) + } +} diff --git a/rust/chains/tw_binance/src/modules/wallet_connect/connector.rs b/rust/chains/tw_binance/src/modules/wallet_connect/connector.rs new file mode 100644 index 00000000000..e66b4688a2f --- /dev/null +++ b/rust/chains/tw_binance/src/modules/wallet_connect/connector.rs @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::modules::tx_builder::TxBuilder; +use crate::modules::wallet_connect::types::SignAminoRequest; +use tw_coin_entry::coin_context::CoinContext; +use tw_coin_entry::error::prelude::*; +use tw_coin_entry::modules::wallet_connector::WalletConnector; +use tw_coin_entry::signing_output_error; +use tw_proto::WalletConnect::Proto::{ + self as WCProto, mod_ParseRequestOutput::OneOfsigning_input_oneof as SigningInputEnum, +}; + +pub struct BinanceWalletConnector; + +impl WalletConnector for BinanceWalletConnector { + fn parse_request( + &self, + coin: &dyn CoinContext, + request: WCProto::ParseRequestInput<'_>, + ) -> WCProto::ParseRequestOutput<'static> { + Self::parse_request_impl(coin, request) + .unwrap_or_else(|e| signing_output_error!(WCProto::ParseRequestOutput, e)) + } +} + +impl BinanceWalletConnector { + fn parse_request_impl( + coin: &dyn CoinContext, + request: WCProto::ParseRequestInput<'_>, + ) -> SigningResult> { + match request.method { + WCProto::Method::CosmosSignAmino => Self::parse_sign_amino_request(coin, request), + _ => SigningError::err(SigningErrorType::Error_not_supported) + .context("Unknown WalletConnect method"), + } + } + + pub fn parse_sign_amino_request( + _coin: &dyn CoinContext, + request: WCProto::ParseRequestInput<'_>, + ) -> SigningResult> { + let amino_req: SignAminoRequest = serde_json::from_str(&request.payload) + .tw_err(|_| SigningErrorType::Error_input_parse) + .context("Error deserializing WalletConnect signAmino request as JSON")?; + + // Parse a `SigningInput` from the given `signDoc`. + let signing_input = TxBuilder::unsigned_tx_to_proto(&amino_req.sign_doc)?; + + Ok(WCProto::ParseRequestOutput { + signing_input_oneof: SigningInputEnum::binance(signing_input), + ..WCProto::ParseRequestOutput::default() + }) + } +} diff --git a/rust/chains/tw_binance/src/modules/wallet_connect/mod.rs b/rust/chains/tw_binance/src/modules/wallet_connect/mod.rs new file mode 100644 index 00000000000..1a90ae8a9cf --- /dev/null +++ b/rust/chains/tw_binance/src/modules/wallet_connect/mod.rs @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +pub mod connector; +pub mod types; diff --git a/rust/chains/tw_binance/src/modules/wallet_connect/types.rs b/rust/chains/tw_binance/src/modules/wallet_connect/types.rs new file mode 100644 index 00000000000..f5ac124e47e --- /dev/null +++ b/rust/chains/tw_binance/src/modules/wallet_connect/types.rs @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::transaction::UnsignedTransaction; +use serde::Deserialize; + +#[derive(Deserialize)] +pub struct SignAminoRequest { + #[serde(rename = "signDoc")] + pub sign_doc: UnsignedTransaction, +} diff --git a/rust/chains/tw_binance/src/signature.rs b/rust/chains/tw_binance/src/signature.rs new file mode 100644 index 00000000000..45e1b5c6fca --- /dev/null +++ b/rust/chains/tw_binance/src/signature.rs @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use tw_keypair::ecdsa::secp256k1; + +pub type BinanceSignature = secp256k1::VerifySignature; diff --git a/rust/chains/tw_binance/src/signer.rs b/rust/chains/tw_binance/src/signer.rs new file mode 100644 index 00000000000..86cb5da5b4b --- /dev/null +++ b/rust/chains/tw_binance/src/signer.rs @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::context::BinanceContext; +use crate::modules::preimager::{JsonPreimager, JsonTxPreimage}; +use crate::modules::serializer::BinanceAminoSerializer; +use crate::modules::tx_builder::TxBuilder; +use crate::signature::BinanceSignature; +use crate::transaction::SignerInfo; +use tw_coin_entry::coin_context::CoinContext; +use tw_coin_entry::error::prelude::*; +use tw_coin_entry::signing_output_error; +use tw_cosmos_sdk::modules::serializer::json_serializer::JsonSerializer; +use tw_cosmos_sdk::public_key::secp256k1::Secp256PublicKey; +use tw_keypair::ecdsa::secp256k1; +use tw_keypair::traits::{KeyPairTrait, SigningKeyTrait}; +use tw_misc::traits::ToBytesVec; +use tw_proto::Binance::Proto; + +pub struct BinanceSigner; + +impl BinanceSigner { + pub fn sign( + coin: &dyn CoinContext, + input: Proto::SigningInput<'_>, + ) -> Proto::SigningOutput<'static> { + Self::sign_impl(coin, input) + .unwrap_or_else(|e| signing_output_error!(Proto::SigningOutput, e)) + } + + fn sign_impl( + coin: &dyn CoinContext, + input: Proto::SigningInput<'_>, + ) -> SigningResult> { + let unsigned_tx = TxBuilder::unsigned_tx_from_proto(coin, &input)?; + let JsonTxPreimage { tx_hash, .. } = JsonPreimager::preimage_hash(&unsigned_tx)?; + + let key_pair = secp256k1::KeyPair::try_from(input.private_key.as_ref())?; + + let signature = BinanceSignature::from(key_pair.sign(tx_hash)?); + let public_key = + Secp256PublicKey::from_secp256k1_public_key(coin.public_key_type(), key_pair.public())?; + + let signature_bytes = signature.to_vec(); + let signature_json = JsonSerializer::::serialize_signature( + &public_key, + signature_bytes.clone(), + ); + + let signed_tx = unsigned_tx.into_signed(SignerInfo { + public_key, + signature, + }); + let encoded_tx = BinanceAminoSerializer::serialize_signed_tx(&signed_tx)?; + + let signature_json = + serde_json::to_string(&signature_json).tw_err(|_| SigningErrorType::Error_internal)?; + Ok(Proto::SigningOutput { + encoded: encoded_tx.into(), + signature: signature_bytes.into(), + signature_json: signature_json.into(), + ..Proto::SigningOutput::default() + }) + } +} diff --git a/rust/chains/tw_binance/src/transaction/message/htlt_order.rs b/rust/chains/tw_binance/src/transaction/message/htlt_order.rs new file mode 100644 index 00000000000..902ae019e82 --- /dev/null +++ b/rust/chains/tw_binance/src/transaction/message/htlt_order.rs @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::address::BinanceAddress; +use crate::amino::AminoEncoder; +use crate::transaction::message::{BinanceMessage, TWBinanceProto, Token}; +use serde::{Deserialize, Serialize}; +use tw_coin_entry::coin_context::CoinContext; +use tw_coin_entry::coin_entry::CoinAddress; +use tw_coin_entry::error::prelude::*; +use tw_encoding::hex::as_hex; +use tw_memory::Data; +use tw_proto::Binance::Proto; + +#[derive(Deserialize, Serialize)] +pub struct HTLTOrder { + pub amount: Vec, + pub cross_chain: bool, + pub expected_income: String, + pub from: BinanceAddress, + pub height_span: i64, + #[serde(with = "as_hex")] + pub random_number_hash: Data, + pub recipient_other_chain: String, + pub sender_other_chain: String, + pub timestamp: i64, + pub to: BinanceAddress, +} + +impl HTLTOrder { + /// cbindgen:ignore + pub const PREFIX: [u8; 4] = [0xB3, 0x3F, 0x9A, 0x24]; +} + +impl BinanceMessage for HTLTOrder { + fn to_amino_protobuf(&self) -> SigningResult { + Ok(AminoEncoder::new(&Self::PREFIX) + .extend_with_msg(&self.to_tw_proto())? + .encode()) + } +} + +impl TWBinanceProto for HTLTOrder { + type Proto<'a> = Proto::HTLTOrder<'a>; + + fn from_tw_proto(coin: &dyn CoinContext, msg: &Self::Proto<'_>) -> SigningResult { + let from = BinanceAddress::from_key_hash_with_coin(coin, msg.from.to_vec())?; + let to = BinanceAddress::from_key_hash_with_coin(coin, msg.to.to_vec())?; + + let amount = msg.amount.iter().map(Token::from_tw_proto).collect(); + + Ok(HTLTOrder { + from, + to, + recipient_other_chain: msg.recipient_other_chain.to_string(), + sender_other_chain: msg.sender_other_chain.to_string(), + random_number_hash: msg.random_number_hash.to_vec(), + timestamp: msg.timestamp, + amount, + expected_income: msg.expected_income.to_string(), + height_span: msg.height_span, + cross_chain: msg.cross_chain, + }) + } + + fn to_tw_proto(&self) -> Self::Proto<'static> { + Proto::HTLTOrder { + from: self.from.data().into(), + to: self.to.data().into(), + recipient_other_chain: self.recipient_other_chain.clone().into(), + sender_other_chain: self.sender_other_chain.clone().into(), + random_number_hash: self.random_number_hash.clone().into(), + timestamp: self.timestamp, + amount: self.amount.iter().map(Token::to_tw_proto).collect(), + expected_income: self.expected_income.clone().into(), + height_span: self.height_span, + cross_chain: self.cross_chain, + } + } +} + +#[derive(Deserialize, Serialize)] +pub struct DepositHTLTOrder { + pub amount: Vec, + pub from: BinanceAddress, + #[serde(with = "as_hex")] + pub swap_id: Data, +} + +impl DepositHTLTOrder { + /// cbindgen:ignore + pub const PREFIX: [u8; 4] = [0x63, 0x98, 0x64, 0x96]; +} + +impl BinanceMessage for DepositHTLTOrder { + fn to_amino_protobuf(&self) -> SigningResult { + Ok(AminoEncoder::new(&Self::PREFIX) + .extend_with_msg(&self.to_tw_proto())? + .encode()) + } +} + +impl TWBinanceProto for DepositHTLTOrder { + type Proto<'a> = Proto::DepositHTLTOrder<'a>; + + fn from_tw_proto(coin: &dyn CoinContext, msg: &Self::Proto<'_>) -> SigningResult { + let from = BinanceAddress::from_key_hash_with_coin(coin, msg.from.to_vec())?; + let amount = msg.amount.iter().map(Token::from_tw_proto).collect(); + + Ok(DepositHTLTOrder { + from, + amount, + swap_id: msg.swap_id.to_vec(), + }) + } + + fn to_tw_proto(&self) -> Self::Proto<'static> { + Proto::DepositHTLTOrder { + from: self.from.data().into(), + amount: self.amount.iter().map(Token::to_tw_proto).collect(), + swap_id: self.swap_id.clone().into(), + } + } +} + +#[derive(Deserialize, Serialize)] +pub struct ClaimHTLTOrder { + pub from: BinanceAddress, + #[serde(with = "as_hex")] + pub random_number: Data, + #[serde(with = "as_hex")] + pub swap_id: Data, +} + +impl ClaimHTLTOrder { + /// cbindgen:ignore + pub const PREFIX: [u8; 4] = [0xC1, 0x66, 0x53, 0x00]; +} + +impl BinanceMessage for ClaimHTLTOrder { + fn to_amino_protobuf(&self) -> SigningResult { + Ok(AminoEncoder::new(&Self::PREFIX) + .extend_with_msg(&self.to_tw_proto())? + .encode()) + } +} + +impl TWBinanceProto for ClaimHTLTOrder { + type Proto<'a> = Proto::ClaimHTLOrder<'a>; + + fn from_tw_proto(coin: &dyn CoinContext, msg: &Self::Proto<'_>) -> SigningResult { + let from = BinanceAddress::from_key_hash_with_coin(coin, msg.from.to_vec())?; + + Ok(ClaimHTLTOrder { + from, + swap_id: msg.swap_id.to_vec(), + random_number: msg.random_number.to_vec(), + }) + } + + fn to_tw_proto(&self) -> Self::Proto<'static> { + Proto::ClaimHTLOrder { + from: self.from.data().into(), + swap_id: self.swap_id.clone().into(), + random_number: self.random_number.clone().into(), + } + } +} + +#[derive(Deserialize, Serialize)] +pub struct RefundHTLTOrder { + pub from: BinanceAddress, + #[serde(with = "as_hex")] + pub swap_id: Data, +} + +impl RefundHTLTOrder { + /// cbindgen:ignore + pub const PREFIX: [u8; 4] = [0x34, 0x54, 0xA2, 0x7C]; +} + +impl TWBinanceProto for RefundHTLTOrder { + type Proto<'a> = Proto::RefundHTLTOrder<'a>; + + fn from_tw_proto(coin: &dyn CoinContext, msg: &Self::Proto<'_>) -> SigningResult { + let from = BinanceAddress::from_key_hash_with_coin(coin, msg.from.to_vec())?; + let swap_id = msg.swap_id.to_vec(); + + Ok(RefundHTLTOrder { from, swap_id }) + } + + fn to_tw_proto(&self) -> Self::Proto<'static> { + Proto::RefundHTLTOrder { + from: self.from.data().into(), + swap_id: self.swap_id.clone().into(), + } + } +} + +impl BinanceMessage for RefundHTLTOrder { + fn to_amino_protobuf(&self) -> SigningResult { + Ok(AminoEncoder::new(&Self::PREFIX) + .extend_with_msg(&self.to_tw_proto())? + .encode()) + } +} diff --git a/rust/chains/tw_binance/src/transaction/message/mod.rs b/rust/chains/tw_binance/src/transaction/message/mod.rs new file mode 100644 index 00000000000..0879bcf5b3e --- /dev/null +++ b/rust/chains/tw_binance/src/transaction/message/mod.rs @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use serde::{Deserialize, Serialize, Serializer}; +use tw_coin_entry::coin_context::CoinContext; +use tw_coin_entry::error::prelude::*; +use tw_memory::Data; +use tw_proto::Binance::Proto::{self, mod_SigningInput::OneOforder_oneof as BinanceMessageProto}; + +pub mod htlt_order; +pub mod send_order; +pub mod side_chain_delegate; +pub mod time_lock_order; +pub mod token_order; +pub mod trade_order; +pub mod tranfer_out_order; + +pub trait BinanceMessage { + fn to_amino_protobuf(&self) -> SigningResult; +} + +/// A Binance message represented as a Trust Wallet Core Protobuf message. +pub trait TWBinanceProto: Sized { + type Proto<'a>; + + fn from_tw_proto(coin: &dyn CoinContext, msg: &Self::Proto<'_>) -> SigningResult; + + fn to_tw_proto(&self) -> Self::Proto<'static>; +} + +/// Please note that some of the fields are typped such as `SideDelegateOrder`. +#[derive(Deserialize, Serialize)] +#[serde(untagged)] +pub enum BinanceMessageEnum { + HTLTOrder(htlt_order::HTLTOrder), + DepositHTLTOrder(htlt_order::DepositHTLTOrder), + ClaimHTLTOrder(htlt_order::ClaimHTLTOrder), + RefundHTLTOrder(htlt_order::RefundHTLTOrder), + SendOrder(send_order::SendOrder), + SideDelegateOrder(side_chain_delegate::SideDelegateOrder), + SideRedelegateOrder(side_chain_delegate::SideRedelegateOrder), + SideUndelegateOrder(side_chain_delegate::SideUndelegateOrder), + StakeMigrationOrder(side_chain_delegate::StakeMigrationOrder), + TimeLockOrder(time_lock_order::TimeLockOrder), + TimeRelockOrder(time_lock_order::TimeRelockOrder), + TimeUnlockOrder(time_lock_order::TimeUnlockOrder), + TokenFreezeOrder(token_order::TokenFreezeOrder), + TokenUnfreezeOrder(token_order::TokenUnfreezeOrder), + TokenIssueOrder(token_order::TokenIssueOrder), + TokenMintOrder(token_order::TokenMintOrder), + TokenBurnOrder(token_order::TokenBurnOrder), + NewTradeOrder(trade_order::NewTradeOrder), + CancelTradeOrder(trade_order::CancelTradeOrder), + TransferOutOrder(tranfer_out_order::TransferOutOrder), +} + +impl TWBinanceProto for BinanceMessageEnum { + type Proto<'a> = BinanceMessageProto<'a>; + + fn from_tw_proto(coin: &dyn CoinContext, msg: &Self::Proto<'_>) -> SigningResult { + match msg { + BinanceMessageProto::trade_order(ref order) => { + trade_order::NewTradeOrder::from_tw_proto(coin, order) + .map(BinanceMessageEnum::NewTradeOrder) + }, + BinanceMessageProto::cancel_trade_order(ref order) => { + trade_order::CancelTradeOrder::from_tw_proto(coin, order) + .map(BinanceMessageEnum::CancelTradeOrder) + }, + BinanceMessageProto::send_order(ref order) => { + send_order::SendOrder::from_tw_proto(coin, order).map(BinanceMessageEnum::SendOrder) + }, + BinanceMessageProto::freeze_order(ref order) => { + token_order::TokenFreezeOrder::from_tw_proto(coin, order) + .map(BinanceMessageEnum::TokenFreezeOrder) + }, + BinanceMessageProto::unfreeze_order(ref order) => { + token_order::TokenUnfreezeOrder::from_tw_proto(coin, order) + .map(BinanceMessageEnum::TokenUnfreezeOrder) + }, + BinanceMessageProto::htlt_order(ref order) => { + htlt_order::HTLTOrder::from_tw_proto(coin, order).map(BinanceMessageEnum::HTLTOrder) + }, + BinanceMessageProto::depositHTLT_order(ref order) => { + htlt_order::DepositHTLTOrder::from_tw_proto(coin, order) + .map(BinanceMessageEnum::DepositHTLTOrder) + }, + BinanceMessageProto::claimHTLT_order(ref order) => { + htlt_order::ClaimHTLTOrder::from_tw_proto(coin, order) + .map(BinanceMessageEnum::ClaimHTLTOrder) + }, + BinanceMessageProto::refundHTLT_order(ref order) => { + htlt_order::RefundHTLTOrder::from_tw_proto(coin, order) + .map(BinanceMessageEnum::RefundHTLTOrder) + }, + BinanceMessageProto::issue_order(ref order) => { + token_order::TokenIssueOrder::from_tw_proto(coin, order) + .map(BinanceMessageEnum::TokenIssueOrder) + }, + BinanceMessageProto::mint_order(ref order) => { + token_order::TokenMintOrder::from_tw_proto(coin, order) + .map(BinanceMessageEnum::TokenMintOrder) + }, + BinanceMessageProto::burn_order(ref order) => { + token_order::TokenBurnOrder::from_tw_proto(coin, order) + .map(BinanceMessageEnum::TokenBurnOrder) + }, + BinanceMessageProto::transfer_out_order(ref order) => { + tranfer_out_order::TransferOutOrder::from_tw_proto(coin, order) + .map(BinanceMessageEnum::TransferOutOrder) + }, + BinanceMessageProto::side_delegate_order(ref order) => { + side_chain_delegate::SideDelegateOrder::from_tw_proto(coin, order) + .map(BinanceMessageEnum::SideDelegateOrder) + }, + BinanceMessageProto::side_redelegate_order(ref order) => { + side_chain_delegate::SideRedelegateOrder::from_tw_proto(coin, order) + .map(BinanceMessageEnum::SideRedelegateOrder) + }, + BinanceMessageProto::side_undelegate_order(ref order) => { + side_chain_delegate::SideUndelegateOrder::from_tw_proto(coin, order) + .map(BinanceMessageEnum::SideUndelegateOrder) + }, + BinanceMessageProto::time_lock_order(ref order) => { + time_lock_order::TimeLockOrder::from_tw_proto(coin, order) + .map(BinanceMessageEnum::TimeLockOrder) + }, + BinanceMessageProto::time_relock_order(ref order) => { + time_lock_order::TimeRelockOrder::from_tw_proto(coin, order) + .map(BinanceMessageEnum::TimeRelockOrder) + }, + BinanceMessageProto::time_unlock_order(ref order) => { + time_lock_order::TimeUnlockOrder::from_tw_proto(coin, order) + .map(BinanceMessageEnum::TimeUnlockOrder) + }, + BinanceMessageProto::side_stake_migration_order(ref order) => { + side_chain_delegate::StakeMigrationOrder::from_tw_proto(coin, order) + .map(BinanceMessageEnum::StakeMigrationOrder) + }, + BinanceMessageProto::None => SigningError::err(SigningErrorType::Error_invalid_params), + } + } + + fn to_tw_proto(&self) -> Self::Proto<'static> { + match self { + BinanceMessageEnum::HTLTOrder(m) => BinanceMessageProto::htlt_order(m.to_tw_proto()), + BinanceMessageEnum::DepositHTLTOrder(m) => { + BinanceMessageProto::depositHTLT_order(m.to_tw_proto()) + }, + BinanceMessageEnum::ClaimHTLTOrder(m) => { + BinanceMessageProto::claimHTLT_order(m.to_tw_proto()) + }, + BinanceMessageEnum::RefundHTLTOrder(m) => { + BinanceMessageProto::refundHTLT_order(m.to_tw_proto()) + }, + BinanceMessageEnum::SendOrder(m) => BinanceMessageProto::send_order(m.to_tw_proto()), + BinanceMessageEnum::SideDelegateOrder(m) => { + BinanceMessageProto::side_delegate_order(m.to_tw_proto()) + }, + BinanceMessageEnum::SideRedelegateOrder(m) => { + BinanceMessageProto::side_redelegate_order(m.to_tw_proto()) + }, + BinanceMessageEnum::SideUndelegateOrder(m) => { + BinanceMessageProto::side_undelegate_order(m.to_tw_proto()) + }, + BinanceMessageEnum::StakeMigrationOrder(m) => { + BinanceMessageProto::side_stake_migration_order(m.to_tw_proto()) + }, + BinanceMessageEnum::TimeLockOrder(m) => { + BinanceMessageProto::time_lock_order(m.to_tw_proto()) + }, + BinanceMessageEnum::TimeRelockOrder(m) => { + BinanceMessageProto::time_relock_order(m.to_tw_proto()) + }, + BinanceMessageEnum::TimeUnlockOrder(m) => { + BinanceMessageProto::time_unlock_order(m.to_tw_proto()) + }, + BinanceMessageEnum::TokenFreezeOrder(m) => { + BinanceMessageProto::freeze_order(m.to_tw_proto()) + }, + BinanceMessageEnum::TokenUnfreezeOrder(m) => { + BinanceMessageProto::unfreeze_order(m.to_tw_proto()) + }, + BinanceMessageEnum::TokenIssueOrder(m) => { + BinanceMessageProto::issue_order(m.to_tw_proto()) + }, + BinanceMessageEnum::TokenMintOrder(m) => { + BinanceMessageProto::mint_order(m.to_tw_proto()) + }, + BinanceMessageEnum::TokenBurnOrder(m) => { + BinanceMessageProto::burn_order(m.to_tw_proto()) + }, + BinanceMessageEnum::NewTradeOrder(m) => { + BinanceMessageProto::trade_order(m.to_tw_proto()) + }, + BinanceMessageEnum::CancelTradeOrder(m) => { + BinanceMessageProto::cancel_trade_order(m.to_tw_proto()) + }, + BinanceMessageEnum::TransferOutOrder(m) => { + BinanceMessageProto::transfer_out_order(m.to_tw_proto()) + }, + } + } +} + +impl<'a> AsRef for BinanceMessageEnum { + fn as_ref(&self) -> &(dyn BinanceMessage + 'a) { + match self { + BinanceMessageEnum::HTLTOrder(m) => m, + BinanceMessageEnum::DepositHTLTOrder(m) => m, + BinanceMessageEnum::ClaimHTLTOrder(m) => m, + BinanceMessageEnum::RefundHTLTOrder(m) => m, + BinanceMessageEnum::SendOrder(m) => m, + BinanceMessageEnum::SideDelegateOrder(m) => m, + BinanceMessageEnum::SideRedelegateOrder(m) => m, + BinanceMessageEnum::SideUndelegateOrder(m) => m, + BinanceMessageEnum::StakeMigrationOrder(m) => m, + BinanceMessageEnum::TimeLockOrder(m) => m, + BinanceMessageEnum::TimeRelockOrder(m) => m, + BinanceMessageEnum::TimeUnlockOrder(m) => m, + BinanceMessageEnum::TokenFreezeOrder(m) => m, + BinanceMessageEnum::TokenUnfreezeOrder(m) => m, + BinanceMessageEnum::TokenIssueOrder(m) => m, + BinanceMessageEnum::TokenMintOrder(m) => m, + BinanceMessageEnum::TokenBurnOrder(m) => m, + BinanceMessageEnum::NewTradeOrder(m) => m, + BinanceMessageEnum::CancelTradeOrder(m) => m, + BinanceMessageEnum::TransferOutOrder(m) => m, + } + } +} + +#[derive(Deserialize, Serialize)] +pub struct Token { + /// Amount. + pub amount: i64, + /// Token ID. + pub denom: String, +} + +impl Token { + pub fn serialize_with_string_amount(&self, serializer: S) -> Result + where + S: Serializer, + { + #[derive(Serialize)] + struct TokenWithStringAmount<'a> { + amount: String, + denom: &'a str, + } + + TokenWithStringAmount { + amount: self.amount.to_string(), + denom: &self.denom, + } + .serialize(serializer) + } + + fn from_tw_proto(msg: &Proto::mod_SendOrder::Token<'_>) -> Self { + Token { + denom: msg.denom.to_string(), + amount: msg.amount, + } + } + + fn to_tw_proto(&self) -> Proto::mod_SendOrder::Token<'static> { + Proto::mod_SendOrder::Token { + denom: self.denom.clone().into(), + amount: self.amount, + } + } +} diff --git a/rust/chains/tw_binance/src/transaction/message/send_order.rs b/rust/chains/tw_binance/src/transaction/message/send_order.rs new file mode 100644 index 00000000000..6ffd7d69be2 --- /dev/null +++ b/rust/chains/tw_binance/src/transaction/message/send_order.rs @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::address::BinanceAddress; +use crate::amino::AminoEncoder; +use crate::transaction::message::{BinanceMessage, TWBinanceProto, Token}; +use serde::{Deserialize, Serialize}; +use tw_coin_entry::coin_context::CoinContext; +use tw_coin_entry::coin_entry::CoinAddress; +use tw_coin_entry::error::prelude::*; +use tw_memory::Data; +use tw_proto::Binance::Proto; + +/// Either an input or output of a `SendOrder`. +#[derive(Deserialize, Serialize)] +pub struct InOut { + /// Source address. + pub address: BinanceAddress, + + /// Input coin amounts. + pub coins: Vec, +} + +impl InOut { + pub fn to_input_proto(&self) -> Proto::mod_SendOrder::Input<'static> { + Proto::mod_SendOrder::Input { + address: self.address.data().into(), + coins: self.coins.iter().map(Token::to_tw_proto).collect(), + } + } + + pub fn to_output_proto(&self) -> Proto::mod_SendOrder::Output<'static> { + Proto::mod_SendOrder::Output { + address: self.address.data().into(), + coins: self.coins.iter().map(Token::to_tw_proto).collect(), + } + } +} + +#[derive(Deserialize, Serialize)] +pub struct SendOrder { + pub inputs: Vec, + pub outputs: Vec, +} + +impl SendOrder { + /// cbindgen:ignore + pub const PREFIX: [u8; 4] = [0x2A, 0x2C, 0x87, 0xFA]; +} + +impl BinanceMessage for SendOrder { + fn to_amino_protobuf(&self) -> SigningResult { + Ok(AminoEncoder::new(&Self::PREFIX) + .extend_with_msg(&self.to_tw_proto())? + .encode()) + } +} + +impl TWBinanceProto for SendOrder { + type Proto<'a> = Proto::SendOrder<'a>; + + fn from_tw_proto(coin: &dyn CoinContext, msg: &Self::Proto<'_>) -> SigningResult { + fn in_out_from_proto( + coin: &dyn CoinContext, + address_key_hash: &[u8], + coins: &[Proto::mod_SendOrder::Token], + ) -> SigningResult { + let address = BinanceAddress::from_key_hash_with_coin(coin, address_key_hash.to_vec())?; + let coins = coins.iter().map(Token::from_tw_proto).collect(); + + Ok(InOut { address, coins }) + } + + let inputs = msg + .inputs + .iter() + .map(|input| in_out_from_proto(coin, &input.address, &input.coins)) + .collect::>>()?; + + let outputs = msg + .outputs + .iter() + .map(|output| in_out_from_proto(coin, &output.address, &output.coins)) + .collect::>>()?; + + Ok(SendOrder { inputs, outputs }) + } + + fn to_tw_proto(&self) -> Self::Proto<'static> { + Proto::SendOrder { + inputs: self.inputs.iter().map(InOut::to_input_proto).collect(), + outputs: self.outputs.iter().map(InOut::to_output_proto).collect(), + } + } +} diff --git a/rust/chains/tw_binance/src/transaction/message/side_chain_delegate.rs b/rust/chains/tw_binance/src/transaction/message/side_chain_delegate.rs new file mode 100644 index 00000000000..4684056cede --- /dev/null +++ b/rust/chains/tw_binance/src/transaction/message/side_chain_delegate.rs @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::address::BinanceAddress; +use crate::amino::AminoEncoder; +use crate::transaction::message::{BinanceMessage, TWBinanceProto, Token}; +use serde::{Deserialize, Serialize}; +use tw_coin_entry::coin_context::CoinContext; +use tw_coin_entry::coin_entry::CoinAddress; +use tw_coin_entry::error::prelude::*; +use tw_evm::address::Address as EthereumAddress; +use tw_memory::Data; +use tw_misc::serde::Typed; +use tw_proto::Binance::Proto; + +pub type SideDelegateOrder = Typed; + +/// cosmos-sdk/MsgSideChainDelegate +#[derive(Deserialize, Serialize)] +pub struct SideDelegateOrderValue { + #[serde(serialize_with = "Token::serialize_with_string_amount")] + pub delegation: Token, + pub delegator_addr: BinanceAddress, + pub side_chain_id: String, + pub validator_addr: BinanceAddress, +} + +impl SideDelegateOrderValue { + /// cbindgen:ignore + pub const PREFIX: [u8; 4] = [0xE3, 0xA0, 0x7F, 0xD2]; + /// cbindgen:ignore + pub const MESSAGE_TYPE: &'static str = "cosmos-sdk/MsgSideChainDelegate"; +} + +impl BinanceMessage for SideDelegateOrder { + fn to_amino_protobuf(&self) -> SigningResult { + Ok(AminoEncoder::new(&SideDelegateOrderValue::PREFIX) + .extend_with_msg(&self.to_tw_proto())? + .encode()) + } +} + +impl TWBinanceProto for SideDelegateOrder { + type Proto<'a> = Proto::SideChainDelegate<'a>; + + fn from_tw_proto(coin: &dyn CoinContext, msg: &Self::Proto<'_>) -> SigningResult { + let delegator_addr = + BinanceAddress::from_key_hash_with_coin(coin, msg.delegator_addr.to_vec())?; + let validator_addr = BinanceAddress::new_validator_addr(msg.validator_addr.to_vec())?; + + let delegation = msg + .delegation + .as_ref() + .or_tw_err(SigningErrorType::Error_invalid_params)?; + + let value = SideDelegateOrderValue { + delegator_addr, + validator_addr, + delegation: Token::from_tw_proto(delegation), + side_chain_id: msg.chain_id.to_string(), + }; + Ok(Typed { + ty: SideDelegateOrderValue::MESSAGE_TYPE.to_string(), + value, + }) + } + + fn to_tw_proto(&self) -> Self::Proto<'static> { + Proto::SideChainDelegate { + delegator_addr: self.value.delegator_addr.data().into(), + validator_addr: self.value.validator_addr.data().into(), + delegation: Some(self.value.delegation.to_tw_proto()), + chain_id: self.value.side_chain_id.clone().into(), + } + } +} + +pub type SideRedelegateOrder = Typed; + +/// cosmos-sdk/MsgSideChainRedelegate +#[derive(Deserialize, Serialize)] +pub struct SideRedelegateOrderValue { + #[serde(serialize_with = "Token::serialize_with_string_amount")] + pub amount: Token, + pub delegator_addr: BinanceAddress, + pub side_chain_id: String, + pub validator_dst_addr: BinanceAddress, + pub validator_src_addr: BinanceAddress, +} + +impl SideRedelegateOrderValue { + /// cbindgen:ignore + pub const PREFIX: [u8; 4] = [0xE3, 0xCE, 0xD3, 0x64]; + /// cbindgen:ignore + pub const MESSAGE_TYPE: &'static str = "cosmos-sdk/MsgSideChainRedelegate"; +} + +impl BinanceMessage for SideRedelegateOrder { + fn to_amino_protobuf(&self) -> SigningResult { + Ok(AminoEncoder::new(&SideRedelegateOrderValue::PREFIX) + .extend_with_msg(&self.to_tw_proto())? + .encode()) + } +} + +impl TWBinanceProto for SideRedelegateOrder { + type Proto<'a> = Proto::SideChainRedelegate<'a>; + + fn from_tw_proto(coin: &dyn CoinContext, msg: &Self::Proto<'_>) -> SigningResult { + let delegator_addr = + BinanceAddress::from_key_hash_with_coin(coin, msg.delegator_addr.to_vec())?; + let validator_src_addr = + BinanceAddress::new_validator_addr(msg.validator_src_addr.to_vec())?; + let validator_dst_addr = + BinanceAddress::new_validator_addr(msg.validator_dst_addr.to_vec())?; + + let amount = msg + .amount + .as_ref() + .or_tw_err(SigningErrorType::Error_invalid_params)?; + + let value = SideRedelegateOrderValue { + delegator_addr, + validator_src_addr, + validator_dst_addr, + amount: Token::from_tw_proto(amount), + side_chain_id: msg.chain_id.to_string(), + }; + Ok(Typed { + ty: SideRedelegateOrderValue::MESSAGE_TYPE.to_string(), + value, + }) + } + + fn to_tw_proto(&self) -> Self::Proto<'static> { + Proto::SideChainRedelegate { + delegator_addr: self.value.delegator_addr.data().into(), + validator_src_addr: self.value.validator_src_addr.data().into(), + validator_dst_addr: self.value.validator_dst_addr.data().into(), + amount: Some(self.value.amount.to_tw_proto()), + chain_id: self.value.side_chain_id.clone().into(), + } + } +} + +pub type SideUndelegateOrder = Typed; + +/// cosmos-sdk/MsgSideChainUndelegate +#[derive(Deserialize, Serialize)] +pub struct SideUndelegateOrderValue { + #[serde(serialize_with = "Token::serialize_with_string_amount")] + pub amount: Token, + pub delegator_addr: BinanceAddress, + pub side_chain_id: String, + pub validator_addr: BinanceAddress, +} + +impl SideUndelegateOrderValue { + /// cbindgen:ignore + pub const PREFIX: [u8; 4] = [0x51, 0x4F, 0x7E, 0x0E]; + /// cbindgen:ignore + pub const MESSAGE_TYPE: &'static str = "cosmos-sdk/MsgSideChainUndelegate"; +} + +impl BinanceMessage for SideUndelegateOrder { + fn to_amino_protobuf(&self) -> SigningResult { + Ok(AminoEncoder::new(&SideUndelegateOrderValue::PREFIX) + .extend_with_msg(&self.to_tw_proto())? + .encode()) + } +} + +impl TWBinanceProto for SideUndelegateOrder { + type Proto<'a> = Proto::SideChainUndelegate<'a>; + + fn from_tw_proto(coin: &dyn CoinContext, msg: &Self::Proto<'_>) -> SigningResult { + let delegator_addr = + BinanceAddress::from_key_hash_with_coin(coin, msg.delegator_addr.to_vec())?; + let validator_addr = BinanceAddress::new_validator_addr(msg.validator_addr.to_vec())?; + + let amount = msg + .amount + .as_ref() + .or_tw_err(SigningErrorType::Error_invalid_params)?; + + let value = SideUndelegateOrderValue { + delegator_addr, + validator_addr, + amount: Token::from_tw_proto(amount), + side_chain_id: msg.chain_id.to_string(), + }; + Ok(Typed { + ty: SideUndelegateOrderValue::MESSAGE_TYPE.to_string(), + value, + }) + } + + fn to_tw_proto(&self) -> Self::Proto<'static> { + Proto::SideChainUndelegate { + delegator_addr: self.value.delegator_addr.data().into(), + validator_addr: self.value.validator_addr.data().into(), + amount: Some(self.value.amount.to_tw_proto()), + chain_id: self.value.side_chain_id.clone().into(), + } + } +} + +pub type StakeMigrationOrder = Typed; + +/// https://github.com/bnb-chain/bnc-cosmos-sdk/blob/cf3ab19af300ccd6a6381287c3fae6bf6ac12f5e/x/stake/types/stake_migration.go#L29-L35 +#[derive(Deserialize, Serialize)] +pub struct StakeMigrationOrderValue { + #[serde(serialize_with = "Token::serialize_with_string_amount")] + pub amount: Token, + pub delegator_addr: EthereumAddress, + pub refund_addr: BinanceAddress, + pub validator_dst_addr: EthereumAddress, + pub validator_src_addr: BinanceAddress, +} + +impl StakeMigrationOrderValue { + /// cbindgen:ignore + /// https://github.com/bnb-chain/javascript-sdk/blob/442286ac2923fdfd7cb4fb2299f722ec263c714c/src/types/tx/stdTx.ts#L68 + pub const PREFIX: [u8; 4] = [0x38, 0x58, 0x91, 0x96]; + /// cbindgen:ignore + pub const MESSAGE_TYPE: &'static str = "cosmos-sdk/MsgSideChainStakeMigration"; +} + +impl BinanceMessage for StakeMigrationOrder { + fn to_amino_protobuf(&self) -> SigningResult { + Ok(AminoEncoder::new(&StakeMigrationOrderValue::PREFIX) + .extend_with_msg(&self.to_tw_proto())? + .encode()) + } +} + +impl TWBinanceProto for StakeMigrationOrder { + type Proto<'a> = Proto::SideChainStakeMigration<'a>; + + fn from_tw_proto(coin: &dyn CoinContext, msg: &Self::Proto<'_>) -> SigningResult { + let delegator_addr = EthereumAddress::try_from(msg.delegator_addr.as_ref())?; + let refund_addr = BinanceAddress::from_key_hash_with_coin(coin, msg.refund_addr.to_vec())?; + let validator_dst_addr = EthereumAddress::try_from(msg.validator_dst_addr.as_ref())?; + let validator_src_addr = + BinanceAddress::new_validator_addr(msg.validator_src_addr.to_vec())?; + + let amount = msg + .amount + .as_ref() + .or_tw_err(SigningErrorType::Error_invalid_params)?; + + let value = StakeMigrationOrderValue { + amount: Token::from_tw_proto(amount), + delegator_addr, + refund_addr, + validator_dst_addr, + validator_src_addr, + }; + Ok(Typed { + ty: StakeMigrationOrderValue::MESSAGE_TYPE.to_string(), + value, + }) + } + + fn to_tw_proto(&self) -> Self::Proto<'static> { + Proto::SideChainStakeMigration { + delegator_addr: self.value.delegator_addr.data().into(), + validator_src_addr: self.value.validator_src_addr.data().into(), + validator_dst_addr: self.value.validator_dst_addr.data().into(), + refund_addr: self.value.refund_addr.data().into(), + amount: Some(self.value.amount.to_tw_proto()), + } + } +} diff --git a/rust/chains/tw_binance/src/transaction/message/time_lock_order.rs b/rust/chains/tw_binance/src/transaction/message/time_lock_order.rs new file mode 100644 index 00000000000..9e2e4e21e8c --- /dev/null +++ b/rust/chains/tw_binance/src/transaction/message/time_lock_order.rs @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::address::BinanceAddress; +use crate::amino::AminoEncoder; +use crate::transaction::message::{BinanceMessage, TWBinanceProto, Token}; +use serde::{Deserialize, Serialize}; +use tw_coin_entry::coin_context::CoinContext; +use tw_coin_entry::coin_entry::CoinAddress; +use tw_coin_entry::error::prelude::*; +use tw_memory::Data; +use tw_proto::Binance::Proto; + +#[derive(Deserialize, Serialize)] +pub struct TimeLockOrder { + pub amount: Vec, + pub description: String, + pub from: BinanceAddress, + pub lock_time: i64, +} + +impl TimeLockOrder { + /// cbindgen:ignore + pub const PREFIX: [u8; 4] = [0x07, 0x92, 0x15, 0x31]; +} + +impl BinanceMessage for TimeLockOrder { + fn to_amino_protobuf(&self) -> SigningResult { + Ok(AminoEncoder::new(&Self::PREFIX) + .extend_with_msg(&self.to_tw_proto())? + .encode()) + } +} + +impl TWBinanceProto for TimeLockOrder { + type Proto<'a> = Proto::TimeLockOrder<'a>; + + fn from_tw_proto(coin: &dyn CoinContext, msg: &Self::Proto<'_>) -> SigningResult { + let from = BinanceAddress::from_key_hash_with_coin(coin, msg.from_address.to_vec())?; + let amount = msg.amount.iter().map(Token::from_tw_proto).collect(); + + Ok(TimeLockOrder { + from, + description: msg.description.to_string(), + amount, + lock_time: msg.lock_time, + }) + } + + fn to_tw_proto(&self) -> Self::Proto<'static> { + Proto::TimeLockOrder { + from_address: self.from.data().into(), + description: self.description.clone().into(), + amount: self.amount.iter().map(Token::to_tw_proto).collect(), + lock_time: self.lock_time, + } + } +} + +#[derive(Deserialize, Serialize)] +pub struct TimeRelockOrder { + /// If the amount is empty or omitted, set null to avoid signature verification error. + pub amount: Option>, + pub description: String, + pub from: BinanceAddress, + pub lock_time: i64, + pub time_lock_id: i64, +} + +impl TimeRelockOrder { + /// cbindgen:ignore + pub const PREFIX: [u8; 4] = [0x50, 0x47, 0x11, 0xDA]; +} + +impl BinanceMessage for TimeRelockOrder { + fn to_amino_protobuf(&self) -> SigningResult { + Ok(AminoEncoder::new(&Self::PREFIX) + .extend_with_msg(&self.to_tw_proto())? + .encode()) + } +} + +impl TWBinanceProto for TimeRelockOrder { + type Proto<'a> = Proto::TimeRelockOrder<'a>; + + fn from_tw_proto(coin: &dyn CoinContext, msg: &Self::Proto<'_>) -> SigningResult { + let from = BinanceAddress::from_key_hash_with_coin(coin, msg.from_address.to_vec())?; + + let amount = if msg.amount.is_empty() { + None + } else { + Some(msg.amount.iter().map(Token::from_tw_proto).collect()) + }; + + Ok(TimeRelockOrder { + from, + time_lock_id: msg.id, + description: msg.description.to_string(), + amount, + lock_time: msg.lock_time, + }) + } + + fn to_tw_proto(&self) -> Self::Proto<'static> { + let amount = match self.amount { + Some(ref tokens) => tokens.iter().map(Token::to_tw_proto).collect(), + None => Vec::default(), + }; + + Proto::TimeRelockOrder { + from_address: self.from.data().into(), + id: self.time_lock_id, + description: self.description.clone().into(), + amount, + lock_time: self.lock_time, + } + } +} + +#[derive(Deserialize, Serialize)] +pub struct TimeUnlockOrder { + pub from: BinanceAddress, + pub time_lock_id: i64, +} + +impl TimeUnlockOrder { + /// cbindgen:ignore + pub const PREFIX: [u8; 4] = [0xC4, 0x05, 0x0C, 0x6C]; +} + +impl BinanceMessage for TimeUnlockOrder { + fn to_amino_protobuf(&self) -> SigningResult { + Ok(AminoEncoder::new(&Self::PREFIX) + .extend_with_msg(&self.to_tw_proto())? + .encode()) + } +} + +impl TWBinanceProto for TimeUnlockOrder { + type Proto<'a> = Proto::TimeUnlockOrder<'a>; + + fn from_tw_proto(coin: &dyn CoinContext, msg: &Self::Proto<'_>) -> SigningResult { + let from = BinanceAddress::from_key_hash_with_coin(coin, msg.from_address.to_vec())?; + Ok(TimeUnlockOrder { + from, + time_lock_id: msg.id, + }) + } + + fn to_tw_proto(&self) -> Self::Proto<'static> { + Proto::TimeUnlockOrder { + from_address: self.from.data().into(), + id: self.time_lock_id, + } + } +} diff --git a/rust/chains/tw_binance/src/transaction/message/token_order.rs b/rust/chains/tw_binance/src/transaction/message/token_order.rs new file mode 100644 index 00000000000..ec88ba88e26 --- /dev/null +++ b/rust/chains/tw_binance/src/transaction/message/token_order.rs @@ -0,0 +1,224 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::address::BinanceAddress; +use crate::amino::AminoEncoder; +use crate::transaction::message::{BinanceMessage, TWBinanceProto}; +use serde::{Deserialize, Serialize}; +use tw_coin_entry::coin_context::CoinContext; +use tw_coin_entry::coin_entry::CoinAddress; +use tw_coin_entry::error::prelude::*; +use tw_memory::Data; +use tw_proto::Binance::Proto; + +#[derive(Deserialize, Serialize)] +pub struct TokenFreezeOrder { + pub amount: i64, + pub from: BinanceAddress, + pub symbol: String, +} + +impl TokenFreezeOrder { + /// cbindgen:ignore + pub const PREFIX: [u8; 4] = [0xE7, 0x74, 0xB3, 0x2D]; +} + +impl BinanceMessage for TokenFreezeOrder { + fn to_amino_protobuf(&self) -> SigningResult { + Ok(AminoEncoder::new(&Self::PREFIX) + .extend_with_msg(&self.to_tw_proto())? + .encode()) + } +} + +impl TWBinanceProto for TokenFreezeOrder { + type Proto<'a> = Proto::TokenFreezeOrder<'a>; + + fn from_tw_proto(coin: &dyn CoinContext, msg: &Self::Proto<'_>) -> SigningResult { + let from = BinanceAddress::from_key_hash_with_coin(coin, msg.from.to_vec())?; + Ok(TokenFreezeOrder { + from, + symbol: msg.symbol.to_string(), + amount: msg.amount, + }) + } + + fn to_tw_proto(&self) -> Self::Proto<'static> { + Proto::TokenFreezeOrder { + from: self.from.data().into(), + symbol: self.symbol.clone().into(), + amount: self.amount, + } + } +} + +#[derive(Deserialize, Serialize)] +pub struct TokenUnfreezeOrder { + pub amount: i64, + pub from: BinanceAddress, + pub symbol: String, +} + +impl TokenUnfreezeOrder { + /// cbindgen:ignore + pub const PREFIX: [u8; 4] = [0x65, 0x15, 0xFF, 0x0D]; +} + +impl BinanceMessage for TokenUnfreezeOrder { + fn to_amino_protobuf(&self) -> SigningResult { + Ok(AminoEncoder::new(&Self::PREFIX) + .extend_with_msg(&self.to_tw_proto())? + .encode()) + } +} + +impl TWBinanceProto for TokenUnfreezeOrder { + type Proto<'a> = Proto::TokenUnfreezeOrder<'a>; + + fn from_tw_proto(coin: &dyn CoinContext, msg: &Self::Proto<'_>) -> SigningResult { + let from = BinanceAddress::from_key_hash_with_coin(coin, msg.from.to_vec())?; + Ok(TokenUnfreezeOrder { + from, + symbol: msg.symbol.to_string(), + amount: msg.amount, + }) + } + + fn to_tw_proto(&self) -> Self::Proto<'static> { + Proto::TokenUnfreezeOrder { + from: self.from.data().into(), + symbol: self.symbol.clone().into(), + amount: self.amount, + } + } +} + +#[derive(Deserialize, Serialize)] +pub struct TokenIssueOrder { + pub from: BinanceAddress, + pub mintable: bool, + pub name: String, + pub symbol: String, + pub total_supply: i64, +} + +impl TokenIssueOrder { + /// cbindgen:ignore + pub const PREFIX: [u8; 4] = [0x17, 0xEF, 0xAB, 0x80]; +} + +impl BinanceMessage for TokenIssueOrder { + fn to_amino_protobuf(&self) -> SigningResult { + Ok(AminoEncoder::new(&Self::PREFIX) + .extend_with_msg(&self.to_tw_proto())? + .encode()) + } +} + +impl TWBinanceProto for TokenIssueOrder { + type Proto<'a> = Proto::TokenIssueOrder<'a>; + + fn from_tw_proto(coin: &dyn CoinContext, msg: &Self::Proto<'_>) -> SigningResult { + let from = BinanceAddress::from_key_hash_with_coin(coin, msg.from.to_vec())?; + Ok(TokenIssueOrder { + from, + name: msg.name.to_string(), + symbol: msg.symbol.to_string(), + total_supply: msg.total_supply, + mintable: msg.mintable, + }) + } + + fn to_tw_proto(&self) -> Self::Proto<'static> { + Proto::TokenIssueOrder { + from: self.from.data().into(), + name: self.name.clone().into(), + symbol: self.symbol.clone().into(), + total_supply: self.total_supply, + mintable: self.mintable, + } + } +} + +#[derive(Deserialize, Serialize)] +pub struct TokenMintOrder { + pub amount: i64, + pub from: BinanceAddress, + pub symbol: String, +} + +impl TokenMintOrder { + /// cbindgen:ignore + pub const PREFIX: [u8; 4] = [0x46, 0x7E, 0x08, 0x29]; +} + +impl BinanceMessage for TokenMintOrder { + fn to_amino_protobuf(&self) -> SigningResult { + Ok(AminoEncoder::new(&Self::PREFIX) + .extend_with_msg(&self.to_tw_proto())? + .encode()) + } +} + +impl TWBinanceProto for TokenMintOrder { + type Proto<'a> = Proto::TokenMintOrder<'a>; + + fn from_tw_proto(coin: &dyn CoinContext, msg: &Self::Proto<'_>) -> SigningResult { + let from = BinanceAddress::from_key_hash_with_coin(coin, msg.from.to_vec())?; + Ok(TokenMintOrder { + from, + symbol: msg.symbol.to_string(), + amount: msg.amount, + }) + } + + fn to_tw_proto(&self) -> Self::Proto<'static> { + Proto::TokenMintOrder { + from: self.from.data().into(), + symbol: self.symbol.clone().into(), + amount: self.amount, + } + } +} + +#[derive(Deserialize, Serialize)] +pub struct TokenBurnOrder { + pub amount: i64, + pub from: BinanceAddress, + pub symbol: String, +} + +impl TokenBurnOrder { + /// cbindgen:ignore + pub const PREFIX: [u8; 4] = [0x7E, 0xD2, 0xD2, 0xA0]; +} + +impl BinanceMessage for TokenBurnOrder { + fn to_amino_protobuf(&self) -> SigningResult { + Ok(AminoEncoder::new(&Self::PREFIX) + .extend_with_msg(&self.to_tw_proto())? + .encode()) + } +} + +impl TWBinanceProto for TokenBurnOrder { + type Proto<'a> = Proto::TokenBurnOrder<'a>; + + fn from_tw_proto(coin: &dyn CoinContext, msg: &Self::Proto<'_>) -> SigningResult { + let from = BinanceAddress::from_key_hash_with_coin(coin, msg.from.to_vec())?; + Ok(TokenBurnOrder { + from, + symbol: msg.symbol.to_string(), + amount: msg.amount, + }) + } + + fn to_tw_proto(&self) -> Self::Proto<'static> { + Proto::TokenBurnOrder { + from: self.from.data().into(), + symbol: self.symbol.clone().into(), + amount: self.amount, + } + } +} diff --git a/rust/chains/tw_binance/src/transaction/message/trade_order.rs b/rust/chains/tw_binance/src/transaction/message/trade_order.rs new file mode 100644 index 00000000000..0add4dcd87b --- /dev/null +++ b/rust/chains/tw_binance/src/transaction/message/trade_order.rs @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::address::BinanceAddress; +use crate::amino::AminoEncoder; +use crate::transaction::message::{BinanceMessage, TWBinanceProto}; +use serde::{Deserialize, Serialize}; +use tw_coin_entry::coin_context::CoinContext; +use tw_coin_entry::coin_entry::CoinAddress; +use tw_coin_entry::error::prelude::*; +use tw_memory::Data; +use tw_proto::Binance::Proto; + +#[repr(i64)] +#[derive( + Clone, Copy, serde_repr::Deserialize_repr, serde_repr::Serialize_repr, strum_macros::FromRepr, +)] +pub enum OrderType { + /// https://github.com/bnb-chain/python-sdk/blob/0f6b8a6077f486b26eda3e448f3e84ef35bfff75/binance_chain/constants.py#L62 + Limit = 2, +} + +#[derive(Deserialize, Serialize)] +pub struct NewTradeOrder { + /// Order id, optional. + pub id: String, + /// Order type. + #[serde(rename = "ordertype")] + pub order_type: OrderType, + /// Price of the order, which is the real price multiplied by 1e8 (10^8) and rounded to integer. + pub price: i64, + /// Quantity of the order, which is the real price multiplied by 1e8 (10^8) and rounded to integer. + pub quantity: i64, + /// Originating address. + pub sender: BinanceAddress, + /// 1 for buy and 2 for sell. + pub side: i64, + /// Symbol for trading pair in full name of the tokens. + pub symbol: String, + /// 1 for Good Till Expire(GTE) order and 3 for Immediate Or Cancel (IOC). + #[serde(rename = "timeinforce")] + pub time_in_force: i64, +} + +impl NewTradeOrder { + /// cbindgen:ignore + pub const PREFIX: [u8; 4] = [0xCE, 0x6D, 0xC0, 0x43]; +} + +impl BinanceMessage for NewTradeOrder { + fn to_amino_protobuf(&self) -> SigningResult { + Ok(AminoEncoder::new(&Self::PREFIX) + .extend_with_msg(&self.to_tw_proto())? + .encode()) + } +} + +impl TWBinanceProto for NewTradeOrder { + type Proto<'a> = Proto::TradeOrder<'a>; + + fn from_tw_proto(coin: &dyn CoinContext, msg: &Self::Proto<'_>) -> SigningResult { + let order_type = OrderType::from_repr(msg.ordertype) + .or_tw_err(SigningErrorType::Error_invalid_params)?; + let sender = BinanceAddress::from_key_hash_with_coin(coin, msg.sender.to_vec())?; + + Ok(NewTradeOrder { + id: msg.id.to_string(), + order_type, + price: msg.price, + quantity: msg.quantity, + sender, + side: msg.side, + symbol: msg.symbol.to_string(), + time_in_force: msg.timeinforce, + }) + } + + fn to_tw_proto(&self) -> Self::Proto<'static> { + Proto::TradeOrder { + id: self.id.clone().into(), + ordertype: self.order_type as i64, + price: self.price, + quantity: self.quantity, + sender: self.sender.data().into(), + side: self.side, + symbol: self.symbol.clone().into(), + timeinforce: self.time_in_force, + } + } +} + +#[derive(Deserialize, Serialize)] +pub struct CancelTradeOrder { + /// Order id to cancel. + pub refid: String, + /// Originating address. + pub sender: BinanceAddress, + /// Symbol for trading pair in full name of the tokens. + pub symbol: String, +} + +impl CancelTradeOrder { + /// cbindgen:ignore + pub const PREFIX: [u8; 4] = [0x16, 0x6E, 0x68, 0x1B]; +} + +impl BinanceMessage for CancelTradeOrder { + fn to_amino_protobuf(&self) -> SigningResult { + Ok(AminoEncoder::new(&Self::PREFIX) + .extend_with_msg(&self.to_tw_proto())? + .encode()) + } +} + +impl TWBinanceProto for CancelTradeOrder { + type Proto<'a> = Proto::CancelTradeOrder<'a>; + + fn from_tw_proto(coin: &dyn CoinContext, msg: &Self::Proto<'_>) -> SigningResult { + let sender = BinanceAddress::from_key_hash_with_coin(coin, msg.sender.to_vec())?; + Ok(CancelTradeOrder { + sender, + symbol: msg.symbol.to_string(), + refid: msg.refid.to_string(), + }) + } + + fn to_tw_proto(&self) -> Self::Proto<'static> { + Proto::CancelTradeOrder { + sender: self.sender.data().into(), + symbol: self.symbol.clone().into(), + refid: self.refid.clone().into(), + } + } +} diff --git a/rust/chains/tw_binance/src/transaction/message/tranfer_out_order.rs b/rust/chains/tw_binance/src/transaction/message/tranfer_out_order.rs new file mode 100644 index 00000000000..30dfef73f56 --- /dev/null +++ b/rust/chains/tw_binance/src/transaction/message/tranfer_out_order.rs @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::address::BinanceAddress; +use crate::amino::AminoEncoder; +use crate::transaction::message::{BinanceMessage, TWBinanceProto, Token}; +use serde::{Deserialize, Serialize}; +use tw_coin_entry::coin_context::CoinContext; +use tw_coin_entry::coin_entry::CoinAddress; +use tw_coin_entry::error::prelude::*; +use tw_evm::address::Address as EthereumAddress; +use tw_hash::H160; +use tw_memory::Data; +use tw_proto::Binance::Proto; + +#[derive(Deserialize, Serialize)] +pub struct TransferOutOrder { + pub amount: Token, + pub expire_time: i64, + pub from: BinanceAddress, + pub to: EthereumAddress, +} + +impl TransferOutOrder { + /// cbindgen:ignore + pub const PREFIX: [u8; 4] = [0x80, 0x08, 0x19, 0xC0]; +} + +impl BinanceMessage for TransferOutOrder { + fn to_amino_protobuf(&self) -> SigningResult { + Ok(AminoEncoder::new(&Self::PREFIX) + .extend_with_msg(&self.to_tw_proto())? + .encode()) + } +} + +impl TWBinanceProto for TransferOutOrder { + type Proto<'a> = Proto::TransferOut<'a>; + + fn from_tw_proto(coin: &dyn CoinContext, msg: &Self::Proto<'_>) -> SigningResult { + let from = BinanceAddress::from_key_hash_with_coin(coin, msg.from.to_vec())?; + + let to_bytes = + H160::try_from(msg.to.as_ref()).tw_err(|_| SigningErrorType::Error_invalid_address)?; + let to = EthereumAddress::from_bytes(to_bytes); + + let amount_proto = msg + .amount + .as_ref() + .or_tw_err(SigningErrorType::Error_invalid_params)?; + + Ok(TransferOutOrder { + from, + to, + amount: Token::from_tw_proto(amount_proto), + expire_time: msg.expire_time, + }) + } + + fn to_tw_proto(&self) -> Self::Proto<'static> { + Proto::TransferOut { + from: self.from.data().into(), + to: self.to.data().into(), + amount: Some(self.amount.to_tw_proto()), + expire_time: self.expire_time, + } + } +} diff --git a/rust/chains/tw_binance/src/transaction/mod.rs b/rust/chains/tw_binance/src/transaction/mod.rs new file mode 100644 index 00000000000..fbd24f33ebe --- /dev/null +++ b/rust/chains/tw_binance/src/transaction/mod.rs @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use crate::signature::BinanceSignature; +use crate::transaction::message::BinanceMessageEnum; +use serde::{Deserialize, Serialize}; +use tw_cosmos_sdk::public_key::secp256k1::Secp256PublicKey; +use tw_memory::Data; +use tw_misc::serde::as_string; + +pub mod message; + +#[derive(Deserialize, Serialize)] +pub struct UnsignedTransaction { + #[serde(with = "as_string")] + pub account_number: i64, + pub chain_id: String, + pub data: Option, + pub memo: String, + pub msgs: Vec, + #[serde(with = "as_string")] + pub sequence: i64, + #[serde(with = "as_string")] + pub source: i64, +} + +impl UnsignedTransaction { + pub fn into_signed(self, signer: SignerInfo) -> SignedTransaction { + SignedTransaction { + unsigned: self, + signer, + } + } +} + +pub struct SignerInfo { + pub public_key: Secp256PublicKey, + pub signature: BinanceSignature, +} + +pub struct SignedTransaction { + pub unsigned: UnsignedTransaction, + pub signer: SignerInfo, +} diff --git a/rust/chains/tw_bitcoin/Cargo.toml b/rust/chains/tw_bitcoin/Cargo.toml new file mode 100644 index 00000000000..1d5571814b0 --- /dev/null +++ b/rust/chains/tw_bitcoin/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "tw_bitcoin" +version = "0.1.0" +edition = "2021" + +[dependencies] +bitcoin = { version = "0.30.0", features = ["rand-std"] } +secp256k1 = { version = "0.27.0", features = ["global-context", "rand-std"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +tw_bech32_address = { path = "../../tw_bech32_address" } +tw_base58_address = { path = "../../tw_base58_address" } +tw_coin_entry = { path = "../../tw_coin_entry", features = ["test-utils"] } +tw_encoding = { path = "../../tw_encoding" } +tw_hash = { path = "../../tw_hash" } +tw_keypair = { path = "../../tw_keypair" } +tw_memory = { path = "../../tw_memory" } +tw_misc = { path = "../../tw_misc" } +tw_proto = { path = "../../tw_proto" } +tw_utxo = { path = "../../frameworks/tw_utxo" } diff --git a/rust/chains/tw_bitcoin/src/context.rs b/rust/chains/tw_bitcoin/src/context.rs new file mode 100644 index 00000000000..8ecdd4f8e55 --- /dev/null +++ b/rust/chains/tw_bitcoin/src/context.rs @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use tw_coin_entry::error::prelude::SigningResult; +use tw_utxo::address::standard_bitcoin::StandardBitcoinAddress; +use tw_utxo::context::{AddressPrefixes, UtxoContext}; +use tw_utxo::script::Script; + +#[derive(Default)] +pub struct StandardBitcoinContext; + +impl UtxoContext for StandardBitcoinContext { + type Address = StandardBitcoinAddress; + + fn addr_to_script_pubkey( + addr: &Self::Address, + prefixes: AddressPrefixes, + ) -> SigningResult