├── .github └── workflows │ └── rust.yml ├── .gitignore ├── CONTRIBUTING.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md └── src ├── cmd ├── balance.rs ├── burn.rs ├── mod.rs ├── pay.rs ├── serializer.rs └── validator │ ├── mod.rs │ ├── stake.rs │ ├── transfer.rs │ └── unstake.rs ├── error.rs ├── lib.rs ├── main.rs └── memo.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | tags: ["v*"] 7 | pull_request: 8 | branches: [main] 9 | 10 | jobs: 11 | build-linux: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | - uses: actions-rs/toolchain@v1 16 | with: 17 | toolchain: stable 18 | default: true 19 | override: true 20 | components: clippy, rustfmt 21 | 22 | - name: Cancel previous runs 23 | uses: styfle/cancel-workflow-action@0.5.0 24 | with: 25 | access_token: ${{ github.token }} 26 | 27 | - name: Check formatting 28 | run: cargo fmt -- --check 29 | 30 | - name: Install libudev 31 | run: | 32 | sudo apt-get update 33 | sudo apt-get install libudev-dev 34 | 35 | - name: Clippy 36 | uses: actions-rs/clippy-check@v1 37 | with: 38 | token: ${{ secrets.GITHUB_TOKEN }} 39 | args: -- -Dclippy::all 40 | 41 | - name: Build 42 | run: cargo build --all --release 43 | 44 | - name: Name Release 45 | if: startsWith(github.ref, 'refs/tags/') 46 | id: name_release 47 | run: echo ::set-output name=RELEASE::helium-ledger-cli-$(echo $GITHUB_REF | cut -d / -f 3)-x86-64-linux 48 | 49 | - name: Prepare Release 50 | if: startsWith(github.ref, 'refs/tags/') 51 | env: 52 | NAME: ${{ steps.name_release.outputs.RELEASE }} 53 | run: | 54 | mkdir $NAME 55 | mv target/release/helium-ledger-cli $NAME/ 56 | cp README.md $NAME/ 57 | cp LICENSE $NAME/ 58 | tar -zcvf $NAME.tar.gz $NAME/ 59 | - name: Push Release 60 | uses: softprops/action-gh-release@v1 61 | if: startsWith(github.ref, 'refs/tags/') 62 | with: 63 | files: | 64 | ${{ steps.name_release.outputs.RELEASE }}.tar.gz 65 | env: 66 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 67 | 68 | build-mac: 69 | runs-on: macos-latest 70 | steps: 71 | - uses: actions/checkout@v2 72 | - uses: actions-rs/toolchain@v1 73 | with: 74 | toolchain: stable 75 | target: x86_64-apple-darwin 76 | default: true 77 | override: true 78 | 79 | - name: Cancel previous runs 80 | uses: styfle/cancel-workflow-action@0.5.0 81 | with: 82 | access_token: ${{ github.token }} 83 | 84 | - name: Build 85 | run: cargo build --all --release 86 | 87 | - name: Name Release 88 | if: startsWith(github.ref, 'refs/tags/') 89 | id: name_release 90 | run: echo ::set-output name=RELEASE::helium-ledger-cli-$(echo $GITHUB_REF | cut -d / -f 3)-x86-64-macos 91 | 92 | - name: Prepare Release 93 | if: startsWith(github.ref, 'refs/tags/') 94 | env: 95 | NAME: ${{ steps.name_release.outputs.RELEASE }} 96 | run: | 97 | mkdir $NAME 98 | mv target/release/helium-ledger-cli $NAME/ 99 | cp README.md $NAME/ 100 | cp LICENSE $NAME/ 101 | tar -zcvf $NAME.tar.gz $NAME/ 102 | - name: Push Release 103 | uses: softprops/action-gh-release@v1 104 | if: startsWith(github.ref, 'refs/tags/') 105 | with: 106 | files: | 107 | ${{ steps.name_release.outputs.RELEASE }}.tar.gz 108 | env: 109 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 110 | 111 | build-windows: 112 | runs-on: windows-latest 113 | steps: 114 | - name: Cache LLVM and Clang 115 | id: cache-llvm 116 | uses: actions/cache@v2 117 | with: 118 | path: ${{ runner.temp }}/llvm 119 | key: llvm-11.0 120 | 121 | - name: Install LLVM and Clang 122 | uses: KyleMayes/install-llvm-action@v1 123 | with: 124 | version: "11.0" 125 | directory: ${{ runner.temp }}/llvm 126 | cached: ${{ steps.cache-llvm.outputs.cache-hit }} 127 | 128 | - name: Set LIBCLANG_PATH 129 | run: echo "LIBCLANG_PATH=$((gcm clang).source -replace "clang.exe")" >> $env:GITHUB_ENV 130 | 131 | - uses: actions/checkout@v2 132 | - uses: actions-rs/toolchain@v1 133 | with: 134 | toolchain: stable 135 | target: x86_64-pc-windows-gnu 136 | default: true 137 | override: true 138 | 139 | - name: Cancel previous runs 140 | uses: styfle/cancel-workflow-action@0.5.0 141 | with: 142 | access_token: ${{ github.token }} 143 | 144 | - name: Build 145 | run: cargo build --all --release 146 | 147 | - name: Get the version 148 | id: get_version 149 | run: echo ::set-output name=VERSION::helium-ledger-cli-${GITHUB_REF/refs\/tags\//}-x86-64-win 150 | shell: bash 151 | 152 | - name: Prepare Release 153 | if: startsWith(github.ref, 'refs/tags/') 154 | env: 155 | NAME: ${{ steps.get_version.outputs.VERSION }} 156 | run: | 157 | mkdir $env:NAME 158 | mv target/release/helium-ledger-cli.exe $env:NAME/ 159 | cp README.md $env:NAME/ 160 | cp LICENSE $env:NAME/ 161 | 7z a "$env:NAME.zip" "$env:NAME/" 162 | 163 | - name: Push Release 164 | uses: softprops/action-gh-release@v1 165 | if: startsWith(github.ref, 'refs/tags/') 166 | with: 167 | files: | 168 | ${{ steps.get_version.outputs.VERSION }}.zip 169 | env: 170 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 171 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .idea/ 3 | 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute to this repository # 2 | 3 | We value contributions from the community and will do everything we 4 | can go get them reviewed in a timely fashion. If you have code to send 5 | our way or a bug to report: 6 | 7 | * **Contributing Code**: If you have new code or a bug fix, fork this 8 | repo, create a logically-named branch, and [submit a PR against this 9 | repo](https://github.com/helium/helium-ledger-cli/issues). Include a 10 | write up of the PR with details on what it does. 11 | 12 | * **Reporting Bugs**: Open an issue [against this 13 | repo](https://github.com/helium/helium-ledger-cli/issues) with as much 14 | detail as you can. At the very least you'll include steps to 15 | reproduce the problem. 16 | 17 | This project is intended to be a safe, welcoming space for 18 | collaboration, and contributors are expected to adhere to the 19 | [Contributor Covenant Code of 20 | Conduct](http://contributor-covenant.org/). 21 | 22 | Above all, thank you for taking the time to be a part of the Helium community. 23 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "adler" 7 | version = "1.0.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 10 | 11 | [[package]] 12 | name = "aead" 13 | version = "0.3.2" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" 16 | dependencies = [ 17 | "generic-array 0.14.5", 18 | ] 19 | 20 | [[package]] 21 | name = "aead" 22 | version = "0.4.3" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" 25 | dependencies = [ 26 | "generic-array 0.14.5", 27 | ] 28 | 29 | [[package]] 30 | name = "aes" 31 | version = "0.7.5" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" 34 | dependencies = [ 35 | "cfg-if 1.0.0", 36 | "cipher 0.3.0", 37 | "cpufeatures", 38 | "opaque-debug", 39 | ] 40 | 41 | [[package]] 42 | name = "aes-gcm" 43 | version = "0.9.4" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" 46 | dependencies = [ 47 | "aead 0.4.3", 48 | "aes", 49 | "cipher 0.3.0", 50 | "ctr", 51 | "ghash", 52 | "subtle", 53 | ] 54 | 55 | [[package]] 56 | name = "ahash" 57 | version = "0.7.6" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" 60 | dependencies = [ 61 | "getrandom 0.2.4", 62 | "once_cell", 63 | "version_check", 64 | ] 65 | 66 | [[package]] 67 | name = "aho-corasick" 68 | version = "0.7.18" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 71 | dependencies = [ 72 | "memchr", 73 | ] 74 | 75 | [[package]] 76 | name = "angry-purple-tiger" 77 | version = "0.1.0" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "49c749eb8b90a5c85a879ac35bba5374ba18ff41d609878d7d37dd2ac0122a3c" 80 | dependencies = [ 81 | "md5", 82 | ] 83 | 84 | [[package]] 85 | name = "ansi_term" 86 | version = "0.12.1" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" 89 | dependencies = [ 90 | "winapi", 91 | ] 92 | 93 | [[package]] 94 | name = "anyhow" 95 | version = "1.0.53" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0" 98 | 99 | [[package]] 100 | name = "approx" 101 | version = "0.4.0" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "3f2a05fd1bd10b2527e20a2cd32d8873d115b8b39fe219ee25f42a8aca6ba278" 104 | dependencies = [ 105 | "num-traits", 106 | ] 107 | 108 | [[package]] 109 | name = "arrayref" 110 | version = "0.3.6" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" 113 | 114 | [[package]] 115 | name = "arrayvec" 116 | version = "0.5.2" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" 119 | 120 | [[package]] 121 | name = "arrayvec" 122 | version = "0.7.2" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" 125 | 126 | [[package]] 127 | name = "as-slice" 128 | version = "0.1.5" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | checksum = "45403b49e3954a4b8428a0ac21a4b7afadccf92bfd96273f1a58cd4812496ae0" 131 | dependencies = [ 132 | "generic-array 0.12.4", 133 | "generic-array 0.13.3", 134 | "generic-array 0.14.5", 135 | "stable_deref_trait", 136 | ] 137 | 138 | [[package]] 139 | name = "async-compression" 140 | version = "0.3.12" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | checksum = "f2bf394cfbbe876f0ac67b13b6ca819f9c9f2fb9ec67223cceb1555fbab1c31a" 143 | dependencies = [ 144 | "flate2", 145 | "futures-core", 146 | "memchr", 147 | "pin-project-lite", 148 | "tokio", 149 | ] 150 | 151 | [[package]] 152 | name = "async-trait" 153 | version = "0.1.52" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3" 156 | dependencies = [ 157 | "proc-macro2", 158 | "quote", 159 | "syn", 160 | ] 161 | 162 | [[package]] 163 | name = "atty" 164 | version = "0.2.14" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 167 | dependencies = [ 168 | "hermit-abi", 169 | "libc", 170 | "winapi", 171 | ] 172 | 173 | [[package]] 174 | name = "autocfg" 175 | version = "1.1.0" 176 | source = "registry+https://github.com/rust-lang/crates.io-index" 177 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 178 | 179 | [[package]] 180 | name = "base16ct" 181 | version = "0.1.1" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" 184 | 185 | [[package]] 186 | name = "base64" 187 | version = "0.12.3" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" 190 | 191 | [[package]] 192 | name = "base64" 193 | version = "0.13.0" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 196 | 197 | [[package]] 198 | name = "bindgen" 199 | version = "0.59.2" 200 | source = "registry+https://github.com/rust-lang/crates.io-index" 201 | checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" 202 | dependencies = [ 203 | "bitflags", 204 | "cexpr", 205 | "clang-sys", 206 | "clap", 207 | "env_logger", 208 | "lazy_static", 209 | "lazycell", 210 | "log", 211 | "peeking_take_while", 212 | "proc-macro2", 213 | "quote", 214 | "regex", 215 | "rustc-hash", 216 | "shlex", 217 | "which", 218 | ] 219 | 220 | [[package]] 221 | name = "bitflags" 222 | version = "1.3.2" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 225 | 226 | [[package]] 227 | name = "bitvec" 228 | version = "1.0.0" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "1489fcb93a5bb47da0462ca93ad252ad6af2145cce58d10d46a83931ba9f016b" 231 | dependencies = [ 232 | "funty", 233 | "radium", 234 | "tap", 235 | "wyz", 236 | ] 237 | 238 | [[package]] 239 | name = "blake2b_simd" 240 | version = "0.5.11" 241 | source = "registry+https://github.com/rust-lang/crates.io-index" 242 | checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" 243 | dependencies = [ 244 | "arrayref", 245 | "arrayvec 0.5.2", 246 | "constant_time_eq", 247 | ] 248 | 249 | [[package]] 250 | name = "blake2b_simd" 251 | version = "1.0.0" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "72936ee4afc7f8f736d1c38383b56480b5497b4617b4a77bdbf1d2ababc76127" 254 | dependencies = [ 255 | "arrayref", 256 | "arrayvec 0.7.2", 257 | "constant_time_eq", 258 | ] 259 | 260 | [[package]] 261 | name = "blake2s_simd" 262 | version = "1.0.0" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | checksum = "db539cc2b5f6003621f1cd9ef92d7ded8ea5232c7de0f9faa2de251cd98730d4" 265 | dependencies = [ 266 | "arrayref", 267 | "arrayvec 0.7.2", 268 | "constant_time_eq", 269 | ] 270 | 271 | [[package]] 272 | name = "blake3" 273 | version = "1.3.1" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "a08e53fc5a564bb15bfe6fae56bd71522205f1f91893f9c0116edad6496c183f" 276 | dependencies = [ 277 | "arrayref", 278 | "arrayvec 0.7.2", 279 | "cc", 280 | "cfg-if 1.0.0", 281 | "constant_time_eq", 282 | ] 283 | 284 | [[package]] 285 | name = "block-buffer" 286 | version = "0.9.0" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 289 | dependencies = [ 290 | "generic-array 0.14.5", 291 | ] 292 | 293 | [[package]] 294 | name = "block-buffer" 295 | version = "0.10.2" 296 | source = "registry+https://github.com/rust-lang/crates.io-index" 297 | checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" 298 | dependencies = [ 299 | "generic-array 0.14.5", 300 | ] 301 | 302 | [[package]] 303 | name = "bs58" 304 | version = "0.4.0" 305 | source = "registry+https://github.com/rust-lang/crates.io-index" 306 | checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" 307 | dependencies = [ 308 | "sha2 0.9.9", 309 | ] 310 | 311 | [[package]] 312 | name = "bstr" 313 | version = "0.2.17" 314 | source = "registry+https://github.com/rust-lang/crates.io-index" 315 | checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" 316 | dependencies = [ 317 | "lazy_static", 318 | "memchr", 319 | "regex-automata", 320 | "serde", 321 | ] 322 | 323 | [[package]] 324 | name = "bumpalo" 325 | version = "3.9.1" 326 | source = "registry+https://github.com/rust-lang/crates.io-index" 327 | checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" 328 | 329 | [[package]] 330 | name = "byteorder" 331 | version = "1.4.3" 332 | source = "registry+https://github.com/rust-lang/crates.io-index" 333 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 334 | 335 | [[package]] 336 | name = "bytes" 337 | version = "1.1.0" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" 340 | 341 | [[package]] 342 | name = "cc" 343 | version = "1.0.73" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" 346 | 347 | [[package]] 348 | name = "cexpr" 349 | version = "0.6.0" 350 | source = "registry+https://github.com/rust-lang/crates.io-index" 351 | checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" 352 | dependencies = [ 353 | "nom", 354 | ] 355 | 356 | [[package]] 357 | name = "cfg-if" 358 | version = "0.1.10" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 361 | 362 | [[package]] 363 | name = "cfg-if" 364 | version = "1.0.0" 365 | source = "registry+https://github.com/rust-lang/crates.io-index" 366 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 367 | 368 | [[package]] 369 | name = "checked_int_cast" 370 | version = "1.0.0" 371 | source = "registry+https://github.com/rust-lang/crates.io-index" 372 | checksum = "17cc5e6b5ab06331c33589842070416baa137e8b0eb912b008cfd4a78ada7919" 373 | 374 | [[package]] 375 | name = "chrono" 376 | version = "0.4.19" 377 | source = "registry+https://github.com/rust-lang/crates.io-index" 378 | checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" 379 | dependencies = [ 380 | "libc", 381 | "num-integer", 382 | "num-traits", 383 | "serde", 384 | "time", 385 | "winapi", 386 | ] 387 | 388 | [[package]] 389 | name = "cipher" 390 | version = "0.2.5" 391 | source = "registry+https://github.com/rust-lang/crates.io-index" 392 | checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" 393 | dependencies = [ 394 | "generic-array 0.14.5", 395 | ] 396 | 397 | [[package]] 398 | name = "cipher" 399 | version = "0.3.0" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" 402 | dependencies = [ 403 | "generic-array 0.14.5", 404 | ] 405 | 406 | [[package]] 407 | name = "clang-sys" 408 | version = "1.3.1" 409 | source = "registry+https://github.com/rust-lang/crates.io-index" 410 | checksum = "4cc00842eed744b858222c4c9faf7243aafc6d33f92f96935263ef4d8a41ce21" 411 | dependencies = [ 412 | "glob", 413 | "libc", 414 | "libloading", 415 | ] 416 | 417 | [[package]] 418 | name = "clap" 419 | version = "2.34.0" 420 | source = "registry+https://github.com/rust-lang/crates.io-index" 421 | checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" 422 | dependencies = [ 423 | "ansi_term", 424 | "atty", 425 | "bitflags", 426 | "strsim", 427 | "textwrap", 428 | "unicode-width", 429 | "vec_map", 430 | ] 431 | 432 | [[package]] 433 | name = "cmake" 434 | version = "0.1.48" 435 | source = "registry+https://github.com/rust-lang/crates.io-index" 436 | checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" 437 | dependencies = [ 438 | "cc", 439 | ] 440 | 441 | [[package]] 442 | name = "console" 443 | version = "0.14.1" 444 | source = "registry+https://github.com/rust-lang/crates.io-index" 445 | checksum = "3993e6445baa160675931ec041a5e03ca84b9c6e32a056150d3aa2bdda0a1f45" 446 | dependencies = [ 447 | "encode_unicode", 448 | "lazy_static", 449 | "libc", 450 | "regex", 451 | "terminal_size", 452 | "unicode-width", 453 | "winapi", 454 | ] 455 | 456 | [[package]] 457 | name = "const-oid" 458 | version = "0.7.1" 459 | source = "registry+https://github.com/rust-lang/crates.io-index" 460 | checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" 461 | 462 | [[package]] 463 | name = "constant_time_eq" 464 | version = "0.1.5" 465 | source = "registry+https://github.com/rust-lang/crates.io-index" 466 | checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" 467 | 468 | [[package]] 469 | name = "core2" 470 | version = "0.4.0" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" 473 | dependencies = [ 474 | "memchr", 475 | ] 476 | 477 | [[package]] 478 | name = "cpufeatures" 479 | version = "0.2.1" 480 | source = "registry+https://github.com/rust-lang/crates.io-index" 481 | checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" 482 | dependencies = [ 483 | "libc", 484 | ] 485 | 486 | [[package]] 487 | name = "cpuid-bool" 488 | version = "0.2.0" 489 | source = "registry+https://github.com/rust-lang/crates.io-index" 490 | checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" 491 | 492 | [[package]] 493 | name = "crc32fast" 494 | version = "1.3.2" 495 | source = "registry+https://github.com/rust-lang/crates.io-index" 496 | checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" 497 | dependencies = [ 498 | "cfg-if 1.0.0", 499 | ] 500 | 501 | [[package]] 502 | name = "crossbeam-channel" 503 | version = "0.5.2" 504 | source = "registry+https://github.com/rust-lang/crates.io-index" 505 | checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" 506 | dependencies = [ 507 | "cfg-if 1.0.0", 508 | "crossbeam-utils", 509 | ] 510 | 511 | [[package]] 512 | name = "crossbeam-deque" 513 | version = "0.8.1" 514 | source = "registry+https://github.com/rust-lang/crates.io-index" 515 | checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" 516 | dependencies = [ 517 | "cfg-if 1.0.0", 518 | "crossbeam-epoch", 519 | "crossbeam-utils", 520 | ] 521 | 522 | [[package]] 523 | name = "crossbeam-epoch" 524 | version = "0.9.7" 525 | source = "registry+https://github.com/rust-lang/crates.io-index" 526 | checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9" 527 | dependencies = [ 528 | "cfg-if 1.0.0", 529 | "crossbeam-utils", 530 | "lazy_static", 531 | "memoffset", 532 | "scopeguard", 533 | ] 534 | 535 | [[package]] 536 | name = "crossbeam-utils" 537 | version = "0.8.7" 538 | source = "registry+https://github.com/rust-lang/crates.io-index" 539 | checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6" 540 | dependencies = [ 541 | "cfg-if 1.0.0", 542 | "lazy_static", 543 | ] 544 | 545 | [[package]] 546 | name = "crossterm" 547 | version = "0.23.0" 548 | source = "registry+https://github.com/rust-lang/crates.io-index" 549 | checksum = "77b75a27dc8d220f1f8521ea69cd55a34d720a200ebb3a624d9aa19193d3b432" 550 | dependencies = [ 551 | "bitflags", 552 | "crossterm_winapi", 553 | "libc", 554 | "mio 0.7.14", 555 | "parking_lot", 556 | "signal-hook", 557 | "signal-hook-mio", 558 | "winapi", 559 | ] 560 | 561 | [[package]] 562 | name = "crossterm_winapi" 563 | version = "0.9.0" 564 | source = "registry+https://github.com/rust-lang/crates.io-index" 565 | checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c" 566 | dependencies = [ 567 | "winapi", 568 | ] 569 | 570 | [[package]] 571 | name = "crypto-bigint" 572 | version = "0.3.2" 573 | source = "registry+https://github.com/rust-lang/crates.io-index" 574 | checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" 575 | dependencies = [ 576 | "generic-array 0.14.5", 577 | "rand_core 0.6.3", 578 | "subtle", 579 | "zeroize", 580 | ] 581 | 582 | [[package]] 583 | name = "crypto-common" 584 | version = "0.1.3" 585 | source = "registry+https://github.com/rust-lang/crates.io-index" 586 | checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" 587 | dependencies = [ 588 | "generic-array 0.14.5", 589 | "typenum", 590 | ] 591 | 592 | [[package]] 593 | name = "crypto-mac" 594 | version = "0.11.1" 595 | source = "registry+https://github.com/rust-lang/crates.io-index" 596 | checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" 597 | dependencies = [ 598 | "generic-array 0.14.5", 599 | "subtle", 600 | ] 601 | 602 | [[package]] 603 | name = "csv" 604 | version = "1.1.6" 605 | source = "registry+https://github.com/rust-lang/crates.io-index" 606 | checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" 607 | dependencies = [ 608 | "bstr", 609 | "csv-core", 610 | "itoa 0.4.8", 611 | "ryu", 612 | "serde", 613 | ] 614 | 615 | [[package]] 616 | name = "csv-core" 617 | version = "0.1.10" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" 620 | dependencies = [ 621 | "memchr", 622 | ] 623 | 624 | [[package]] 625 | name = "ctr" 626 | version = "0.8.0" 627 | source = "registry+https://github.com/rust-lang/crates.io-index" 628 | checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" 629 | dependencies = [ 630 | "cipher 0.3.0", 631 | ] 632 | 633 | [[package]] 634 | name = "curve25519-dalek" 635 | version = "3.2.0" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" 638 | dependencies = [ 639 | "byteorder", 640 | "digest 0.9.0", 641 | "rand_core 0.5.1", 642 | "subtle", 643 | "zeroize", 644 | ] 645 | 646 | [[package]] 647 | name = "der" 648 | version = "0.5.1" 649 | source = "registry+https://github.com/rust-lang/crates.io-index" 650 | checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" 651 | dependencies = [ 652 | "const-oid", 653 | ] 654 | 655 | [[package]] 656 | name = "dialoguer" 657 | version = "0.8.0" 658 | source = "registry+https://github.com/rust-lang/crates.io-index" 659 | checksum = "c9dd058f8b65922819fabb4a41e7d1964e56344042c26efbccd465202c23fa0c" 660 | dependencies = [ 661 | "console", 662 | "lazy_static", 663 | "tempfile", 664 | "zeroize", 665 | ] 666 | 667 | [[package]] 668 | name = "digest" 669 | version = "0.9.0" 670 | source = "registry+https://github.com/rust-lang/crates.io-index" 671 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 672 | dependencies = [ 673 | "generic-array 0.14.5", 674 | ] 675 | 676 | [[package]] 677 | name = "digest" 678 | version = "0.10.3" 679 | source = "registry+https://github.com/rust-lang/crates.io-index" 680 | checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" 681 | dependencies = [ 682 | "block-buffer 0.10.2", 683 | "crypto-common", 684 | "subtle", 685 | ] 686 | 687 | [[package]] 688 | name = "dirs" 689 | version = "1.0.5" 690 | source = "registry+https://github.com/rust-lang/crates.io-index" 691 | checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" 692 | dependencies = [ 693 | "libc", 694 | "redox_users", 695 | "winapi", 696 | ] 697 | 698 | [[package]] 699 | name = "ecdsa" 700 | version = "0.13.4" 701 | source = "registry+https://github.com/rust-lang/crates.io-index" 702 | checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" 703 | dependencies = [ 704 | "der", 705 | "elliptic-curve", 706 | "rfc6979", 707 | "signature", 708 | ] 709 | 710 | [[package]] 711 | name = "ed25519" 712 | version = "1.3.0" 713 | source = "registry+https://github.com/rust-lang/crates.io-index" 714 | checksum = "74e1069e39f1454367eb2de793ed062fac4c35c2934b76a81d90dd9abcd28816" 715 | dependencies = [ 716 | "signature", 717 | ] 718 | 719 | [[package]] 720 | name = "ed25519-dalek" 721 | version = "1.0.1" 722 | source = "git+https://github.com/helium/ed25519-dalek?branch=madninja/bump_rand#d9b58a5375dda817ddd96cf7260e74b6d1cfd1a6" 723 | dependencies = [ 724 | "curve25519-dalek", 725 | "ed25519", 726 | "rand", 727 | "serde", 728 | "sha2 0.9.9", 729 | "zeroize", 730 | ] 731 | 732 | [[package]] 733 | name = "either" 734 | version = "1.6.1" 735 | source = "registry+https://github.com/rust-lang/crates.io-index" 736 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 737 | 738 | [[package]] 739 | name = "elliptic-curve" 740 | version = "0.11.12" 741 | source = "registry+https://github.com/rust-lang/crates.io-index" 742 | checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" 743 | dependencies = [ 744 | "base16ct", 745 | "crypto-bigint", 746 | "der", 747 | "ff", 748 | "generic-array 0.14.5", 749 | "group", 750 | "rand_core 0.6.3", 751 | "sec1", 752 | "subtle", 753 | "zeroize", 754 | ] 755 | 756 | [[package]] 757 | name = "encode_unicode" 758 | version = "0.3.6" 759 | source = "registry+https://github.com/rust-lang/crates.io-index" 760 | checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 761 | 762 | [[package]] 763 | name = "encoding_rs" 764 | version = "0.8.30" 765 | source = "registry+https://github.com/rust-lang/crates.io-index" 766 | checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" 767 | dependencies = [ 768 | "cfg-if 1.0.0", 769 | ] 770 | 771 | [[package]] 772 | name = "env_logger" 773 | version = "0.9.0" 774 | source = "registry+https://github.com/rust-lang/crates.io-index" 775 | checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" 776 | dependencies = [ 777 | "atty", 778 | "humantime", 779 | "log", 780 | "regex", 781 | "termcolor", 782 | ] 783 | 784 | [[package]] 785 | name = "fastrand" 786 | version = "1.7.0" 787 | source = "registry+https://github.com/rust-lang/crates.io-index" 788 | checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" 789 | dependencies = [ 790 | "instant", 791 | ] 792 | 793 | [[package]] 794 | name = "ff" 795 | version = "0.11.0" 796 | source = "registry+https://github.com/rust-lang/crates.io-index" 797 | checksum = "b2958d04124b9f27f175eaeb9a9f383d026098aa837eadd8ba22c11f13a05b9e" 798 | dependencies = [ 799 | "rand_core 0.6.3", 800 | "subtle", 801 | ] 802 | 803 | [[package]] 804 | name = "fixedbitset" 805 | version = "0.4.1" 806 | source = "registry+https://github.com/rust-lang/crates.io-index" 807 | checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e" 808 | 809 | [[package]] 810 | name = "flate2" 811 | version = "1.0.22" 812 | source = "registry+https://github.com/rust-lang/crates.io-index" 813 | checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" 814 | dependencies = [ 815 | "cfg-if 1.0.0", 816 | "crc32fast", 817 | "libc", 818 | "miniz_oxide", 819 | ] 820 | 821 | [[package]] 822 | name = "fnv" 823 | version = "1.0.7" 824 | source = "registry+https://github.com/rust-lang/crates.io-index" 825 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 826 | 827 | [[package]] 828 | name = "form_urlencoded" 829 | version = "1.0.1" 830 | source = "registry+https://github.com/rust-lang/crates.io-index" 831 | checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" 832 | dependencies = [ 833 | "matches", 834 | "percent-encoding", 835 | ] 836 | 837 | [[package]] 838 | name = "funty" 839 | version = "2.0.0" 840 | source = "registry+https://github.com/rust-lang/crates.io-index" 841 | checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" 842 | 843 | [[package]] 844 | name = "futures" 845 | version = "0.3.21" 846 | source = "registry+https://github.com/rust-lang/crates.io-index" 847 | checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" 848 | dependencies = [ 849 | "futures-channel", 850 | "futures-core", 851 | "futures-executor", 852 | "futures-io", 853 | "futures-sink", 854 | "futures-task", 855 | "futures-util", 856 | ] 857 | 858 | [[package]] 859 | name = "futures-channel" 860 | version = "0.3.21" 861 | source = "registry+https://github.com/rust-lang/crates.io-index" 862 | checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" 863 | dependencies = [ 864 | "futures-core", 865 | "futures-sink", 866 | ] 867 | 868 | [[package]] 869 | name = "futures-core" 870 | version = "0.3.21" 871 | source = "registry+https://github.com/rust-lang/crates.io-index" 872 | checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" 873 | 874 | [[package]] 875 | name = "futures-executor" 876 | version = "0.3.21" 877 | source = "registry+https://github.com/rust-lang/crates.io-index" 878 | checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" 879 | dependencies = [ 880 | "futures-core", 881 | "futures-task", 882 | "futures-util", 883 | ] 884 | 885 | [[package]] 886 | name = "futures-io" 887 | version = "0.3.21" 888 | source = "registry+https://github.com/rust-lang/crates.io-index" 889 | checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" 890 | 891 | [[package]] 892 | name = "futures-macro" 893 | version = "0.3.21" 894 | source = "registry+https://github.com/rust-lang/crates.io-index" 895 | checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" 896 | dependencies = [ 897 | "proc-macro2", 898 | "quote", 899 | "syn", 900 | ] 901 | 902 | [[package]] 903 | name = "futures-sink" 904 | version = "0.3.21" 905 | source = "registry+https://github.com/rust-lang/crates.io-index" 906 | checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" 907 | 908 | [[package]] 909 | name = "futures-task" 910 | version = "0.3.21" 911 | source = "registry+https://github.com/rust-lang/crates.io-index" 912 | checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" 913 | 914 | [[package]] 915 | name = "futures-util" 916 | version = "0.3.21" 917 | source = "registry+https://github.com/rust-lang/crates.io-index" 918 | checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" 919 | dependencies = [ 920 | "futures-channel", 921 | "futures-core", 922 | "futures-io", 923 | "futures-macro", 924 | "futures-sink", 925 | "futures-task", 926 | "memchr", 927 | "pin-project-lite", 928 | "pin-utils", 929 | "slab", 930 | ] 931 | 932 | [[package]] 933 | name = "generic-array" 934 | version = "0.12.4" 935 | source = "registry+https://github.com/rust-lang/crates.io-index" 936 | checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" 937 | dependencies = [ 938 | "typenum", 939 | ] 940 | 941 | [[package]] 942 | name = "generic-array" 943 | version = "0.13.3" 944 | source = "registry+https://github.com/rust-lang/crates.io-index" 945 | checksum = "f797e67af32588215eaaab8327027ee8e71b9dd0b2b26996aedf20c030fce309" 946 | dependencies = [ 947 | "typenum", 948 | ] 949 | 950 | [[package]] 951 | name = "generic-array" 952 | version = "0.14.5" 953 | source = "registry+https://github.com/rust-lang/crates.io-index" 954 | checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" 955 | dependencies = [ 956 | "typenum", 957 | "version_check", 958 | ] 959 | 960 | [[package]] 961 | name = "geo" 962 | version = "0.18.0" 963 | source = "registry+https://github.com/rust-lang/crates.io-index" 964 | checksum = "02bf7fb342abefefb0abbb8d033f37233e6f857a1a970805d15f96560834d699" 965 | dependencies = [ 966 | "geo-types", 967 | "geographiclib-rs", 968 | "log", 969 | "num-traits", 970 | "robust", 971 | "rstar", 972 | ] 973 | 974 | [[package]] 975 | name = "geo-types" 976 | version = "0.7.2" 977 | source = "registry+https://github.com/rust-lang/crates.io-index" 978 | checksum = "d8bd2e95dd9f5c8ff74159ed9205ad7fd239a9569173a550863976421b45d2bb" 979 | dependencies = [ 980 | "approx", 981 | "num-traits", 982 | "rstar", 983 | ] 984 | 985 | [[package]] 986 | name = "geographiclib-rs" 987 | version = "0.2.0" 988 | source = "registry+https://github.com/rust-lang/crates.io-index" 989 | checksum = "b78e20d5d868fa2c4182a8170cb4df261e781a605810e3c1500269c1907da461" 990 | dependencies = [ 991 | "lazy_static", 992 | ] 993 | 994 | [[package]] 995 | name = "getrandom" 996 | version = "0.1.16" 997 | source = "registry+https://github.com/rust-lang/crates.io-index" 998 | checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" 999 | dependencies = [ 1000 | "cfg-if 1.0.0", 1001 | "libc", 1002 | "wasi 0.9.0+wasi-snapshot-preview1", 1003 | ] 1004 | 1005 | [[package]] 1006 | name = "getrandom" 1007 | version = "0.2.4" 1008 | source = "registry+https://github.com/rust-lang/crates.io-index" 1009 | checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" 1010 | dependencies = [ 1011 | "cfg-if 1.0.0", 1012 | "libc", 1013 | "wasi 0.10.2+wasi-snapshot-preview1", 1014 | ] 1015 | 1016 | [[package]] 1017 | name = "ghash" 1018 | version = "0.4.4" 1019 | source = "registry+https://github.com/rust-lang/crates.io-index" 1020 | checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" 1021 | dependencies = [ 1022 | "opaque-debug", 1023 | "polyval", 1024 | ] 1025 | 1026 | [[package]] 1027 | name = "glob" 1028 | version = "0.3.0" 1029 | source = "registry+https://github.com/rust-lang/crates.io-index" 1030 | checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" 1031 | 1032 | [[package]] 1033 | name = "group" 1034 | version = "0.11.0" 1035 | source = "registry+https://github.com/rust-lang/crates.io-index" 1036 | checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" 1037 | dependencies = [ 1038 | "ff", 1039 | "rand_core 0.6.3", 1040 | "subtle", 1041 | ] 1042 | 1043 | [[package]] 1044 | name = "h2" 1045 | version = "0.3.11" 1046 | source = "registry+https://github.com/rust-lang/crates.io-index" 1047 | checksum = "d9f1f717ddc7b2ba36df7e871fd88db79326551d3d6f1fc406fbfd28b582ff8e" 1048 | dependencies = [ 1049 | "bytes", 1050 | "fnv", 1051 | "futures-core", 1052 | "futures-sink", 1053 | "futures-util", 1054 | "http", 1055 | "indexmap", 1056 | "slab", 1057 | "tokio", 1058 | "tokio-util", 1059 | "tracing", 1060 | ] 1061 | 1062 | [[package]] 1063 | name = "h3ron" 1064 | version = "0.13.0" 1065 | source = "registry+https://github.com/rust-lang/crates.io-index" 1066 | checksum = "401943e2c7ed4629c30892f889b48cc634dbdf6d8eeb9c61d108d6c253f94105" 1067 | dependencies = [ 1068 | "ahash", 1069 | "geo", 1070 | "geo-types", 1071 | "h3ron-h3-sys", 1072 | "hashbrown", 1073 | "itertools", 1074 | "svgbobdoc", 1075 | "thiserror", 1076 | ] 1077 | 1078 | [[package]] 1079 | name = "h3ron-h3-sys" 1080 | version = "0.12.0" 1081 | source = "registry+https://github.com/rust-lang/crates.io-index" 1082 | checksum = "cc8039d07afea31b3003ae875d3c3814341fb107f70441c6d1a857df23977d28" 1083 | dependencies = [ 1084 | "bindgen", 1085 | "cmake", 1086 | "regex", 1087 | ] 1088 | 1089 | [[package]] 1090 | name = "hash32" 1091 | version = "0.1.1" 1092 | source = "registry+https://github.com/rust-lang/crates.io-index" 1093 | checksum = "d4041af86e63ac4298ce40e5cca669066e75b6f1aa3390fe2561ffa5e1d9f4cc" 1094 | dependencies = [ 1095 | "byteorder", 1096 | ] 1097 | 1098 | [[package]] 1099 | name = "hashbrown" 1100 | version = "0.11.2" 1101 | source = "registry+https://github.com/rust-lang/crates.io-index" 1102 | checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" 1103 | dependencies = [ 1104 | "ahash", 1105 | "rayon", 1106 | "serde", 1107 | ] 1108 | 1109 | [[package]] 1110 | name = "heapless" 1111 | version = "0.6.1" 1112 | source = "registry+https://github.com/rust-lang/crates.io-index" 1113 | checksum = "634bd4d29cbf24424d0a4bfcbf80c6960129dc24424752a7d1d1390607023422" 1114 | dependencies = [ 1115 | "as-slice", 1116 | "generic-array 0.14.5", 1117 | "hash32", 1118 | "stable_deref_trait", 1119 | ] 1120 | 1121 | [[package]] 1122 | name = "heck" 1123 | version = "0.3.3" 1124 | source = "registry+https://github.com/rust-lang/crates.io-index" 1125 | checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" 1126 | dependencies = [ 1127 | "unicode-segmentation", 1128 | ] 1129 | 1130 | [[package]] 1131 | name = "helium-api" 1132 | version = "3.3.0" 1133 | source = "registry+https://github.com/rust-lang/crates.io-index" 1134 | checksum = "b65e73b392df563b29559c7ab573635906b4921d75d0a7fd6dc2f12303bb0de5" 1135 | dependencies = [ 1136 | "async-trait", 1137 | "base64 0.13.0", 1138 | "chrono", 1139 | "futures", 1140 | "reqwest", 1141 | "rust_decimal", 1142 | "serde", 1143 | "serde_json", 1144 | "thiserror", 1145 | ] 1146 | 1147 | [[package]] 1148 | name = "helium-crypto" 1149 | version = "0.3.3" 1150 | source = "git+https://github.com/helium/helium-crypto-rs?tag=v0.3.3#882749ff33f1eab9d41ea78e8cdae4420627e4b7" 1151 | dependencies = [ 1152 | "base64 0.13.0", 1153 | "bs58", 1154 | "ed25519-dalek", 1155 | "multihash", 1156 | "p256", 1157 | "rand_core 0.6.3", 1158 | "serde", 1159 | "signature", 1160 | "thiserror", 1161 | ] 1162 | 1163 | [[package]] 1164 | name = "helium-ledger" 1165 | version = "2.2.4-alpha.1" 1166 | dependencies = [ 1167 | "anyhow", 1168 | "base64 0.12.3", 1169 | "bs58", 1170 | "byteorder", 1171 | "helium-api", 1172 | "helium-crypto", 1173 | "helium-proto", 1174 | "helium-wallet", 1175 | "ledger-transport", 1176 | "prettytable-rs", 1177 | "prost", 1178 | "qr2term", 1179 | "rust_decimal", 1180 | "serde", 1181 | "serde_json", 1182 | "structopt", 1183 | "thiserror", 1184 | "tokio", 1185 | ] 1186 | 1187 | [[package]] 1188 | name = "helium-proto" 1189 | version = "0.1.0" 1190 | source = "git+https://github.com/helium/proto?branch=master#52cd9427c1c6d69ce93fbb1ead6e0f0d02b8cde0" 1191 | dependencies = [ 1192 | "bytes", 1193 | "prost", 1194 | "prost-build", 1195 | "serde", 1196 | "serde_derive", 1197 | "serde_json", 1198 | ] 1199 | 1200 | [[package]] 1201 | name = "helium-wallet" 1202 | version = "1.7.4" 1203 | source = "git+https://github.com/helium/helium-wallet-rs#8710e8bfbaccf9ec7a5a157bdd861ad72496c13f" 1204 | dependencies = [ 1205 | "aes-gcm", 1206 | "angry-purple-tiger", 1207 | "anyhow", 1208 | "base64 0.12.3", 1209 | "bitvec", 1210 | "byteorder", 1211 | "dialoguer", 1212 | "geo-types", 1213 | "h3ron", 1214 | "helium-api", 1215 | "helium-crypto", 1216 | "helium-proto", 1217 | "hex", 1218 | "hmac 0.12.0", 1219 | "lazy_static", 1220 | "pbkdf2", 1221 | "prettytable-rs", 1222 | "qr2term", 1223 | "rand", 1224 | "regex", 1225 | "reqwest", 1226 | "rust_decimal", 1227 | "serde", 1228 | "serde_derive", 1229 | "serde_json", 1230 | "sha2 0.10.1", 1231 | "shamirsecretsharing", 1232 | "sodiumoxide", 1233 | "structopt", 1234 | "tokio", 1235 | ] 1236 | 1237 | [[package]] 1238 | name = "hermit-abi" 1239 | version = "0.1.19" 1240 | source = "registry+https://github.com/rust-lang/crates.io-index" 1241 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 1242 | dependencies = [ 1243 | "libc", 1244 | ] 1245 | 1246 | [[package]] 1247 | name = "hex" 1248 | version = "0.4.3" 1249 | source = "registry+https://github.com/rust-lang/crates.io-index" 1250 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 1251 | 1252 | [[package]] 1253 | name = "hidapi" 1254 | version = "1.3.3" 1255 | source = "registry+https://github.com/rust-lang/crates.io-index" 1256 | checksum = "7fd21b5ac4a597bf657ed92a5b078f46a011837bda14afb7a07a5c1157c33ac2" 1257 | dependencies = [ 1258 | "cc", 1259 | "libc", 1260 | "pkg-config", 1261 | ] 1262 | 1263 | [[package]] 1264 | name = "hmac" 1265 | version = "0.11.0" 1266 | source = "registry+https://github.com/rust-lang/crates.io-index" 1267 | checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" 1268 | dependencies = [ 1269 | "crypto-mac", 1270 | "digest 0.9.0", 1271 | ] 1272 | 1273 | [[package]] 1274 | name = "hmac" 1275 | version = "0.12.0" 1276 | source = "registry+https://github.com/rust-lang/crates.io-index" 1277 | checksum = "ddca131f3e7f2ce2df364b57949a9d47915cfbd35e46cfee355ccebbf794d6a2" 1278 | dependencies = [ 1279 | "digest 0.10.3", 1280 | ] 1281 | 1282 | [[package]] 1283 | name = "http" 1284 | version = "0.2.6" 1285 | source = "registry+https://github.com/rust-lang/crates.io-index" 1286 | checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03" 1287 | dependencies = [ 1288 | "bytes", 1289 | "fnv", 1290 | "itoa 1.0.1", 1291 | ] 1292 | 1293 | [[package]] 1294 | name = "http-body" 1295 | version = "0.4.4" 1296 | source = "registry+https://github.com/rust-lang/crates.io-index" 1297 | checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" 1298 | dependencies = [ 1299 | "bytes", 1300 | "http", 1301 | "pin-project-lite", 1302 | ] 1303 | 1304 | [[package]] 1305 | name = "httparse" 1306 | version = "1.6.0" 1307 | source = "registry+https://github.com/rust-lang/crates.io-index" 1308 | checksum = "9100414882e15fb7feccb4897e5f0ff0ff1ca7d1a86a23208ada4d7a18e6c6c4" 1309 | 1310 | [[package]] 1311 | name = "httpdate" 1312 | version = "1.0.2" 1313 | source = "registry+https://github.com/rust-lang/crates.io-index" 1314 | checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" 1315 | 1316 | [[package]] 1317 | name = "humantime" 1318 | version = "2.1.0" 1319 | source = "registry+https://github.com/rust-lang/crates.io-index" 1320 | checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 1321 | 1322 | [[package]] 1323 | name = "hyper" 1324 | version = "0.14.17" 1325 | source = "registry+https://github.com/rust-lang/crates.io-index" 1326 | checksum = "043f0e083e9901b6cc658a77d1eb86f4fc650bbb977a4337dd63192826aa85dd" 1327 | dependencies = [ 1328 | "bytes", 1329 | "futures-channel", 1330 | "futures-core", 1331 | "futures-util", 1332 | "h2", 1333 | "http", 1334 | "http-body", 1335 | "httparse", 1336 | "httpdate", 1337 | "itoa 1.0.1", 1338 | "pin-project-lite", 1339 | "socket2", 1340 | "tokio", 1341 | "tower-service", 1342 | "tracing", 1343 | "want", 1344 | ] 1345 | 1346 | [[package]] 1347 | name = "hyper-rustls" 1348 | version = "0.23.0" 1349 | source = "registry+https://github.com/rust-lang/crates.io-index" 1350 | checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" 1351 | dependencies = [ 1352 | "http", 1353 | "hyper", 1354 | "rustls", 1355 | "tokio", 1356 | "tokio-rustls", 1357 | ] 1358 | 1359 | [[package]] 1360 | name = "idna" 1361 | version = "0.2.3" 1362 | source = "registry+https://github.com/rust-lang/crates.io-index" 1363 | checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" 1364 | dependencies = [ 1365 | "matches", 1366 | "unicode-bidi", 1367 | "unicode-normalization", 1368 | ] 1369 | 1370 | [[package]] 1371 | name = "indexmap" 1372 | version = "1.8.0" 1373 | source = "registry+https://github.com/rust-lang/crates.io-index" 1374 | checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" 1375 | dependencies = [ 1376 | "autocfg", 1377 | "hashbrown", 1378 | ] 1379 | 1380 | [[package]] 1381 | name = "instant" 1382 | version = "0.1.12" 1383 | source = "registry+https://github.com/rust-lang/crates.io-index" 1384 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 1385 | dependencies = [ 1386 | "cfg-if 1.0.0", 1387 | ] 1388 | 1389 | [[package]] 1390 | name = "ipnet" 1391 | version = "2.3.1" 1392 | source = "registry+https://github.com/rust-lang/crates.io-index" 1393 | checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" 1394 | 1395 | [[package]] 1396 | name = "itertools" 1397 | version = "0.10.3" 1398 | source = "registry+https://github.com/rust-lang/crates.io-index" 1399 | checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" 1400 | dependencies = [ 1401 | "either", 1402 | ] 1403 | 1404 | [[package]] 1405 | name = "itoa" 1406 | version = "0.4.8" 1407 | source = "registry+https://github.com/rust-lang/crates.io-index" 1408 | checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" 1409 | 1410 | [[package]] 1411 | name = "itoa" 1412 | version = "1.0.1" 1413 | source = "registry+https://github.com/rust-lang/crates.io-index" 1414 | checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" 1415 | 1416 | [[package]] 1417 | name = "js-sys" 1418 | version = "0.3.56" 1419 | source = "registry+https://github.com/rust-lang/crates.io-index" 1420 | checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" 1421 | dependencies = [ 1422 | "wasm-bindgen", 1423 | ] 1424 | 1425 | [[package]] 1426 | name = "keccak" 1427 | version = "0.1.0" 1428 | source = "registry+https://github.com/rust-lang/crates.io-index" 1429 | checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" 1430 | 1431 | [[package]] 1432 | name = "lazy_static" 1433 | version = "1.4.0" 1434 | source = "registry+https://github.com/rust-lang/crates.io-index" 1435 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 1436 | 1437 | [[package]] 1438 | name = "lazycell" 1439 | version = "1.3.0" 1440 | source = "registry+https://github.com/rust-lang/crates.io-index" 1441 | checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" 1442 | 1443 | [[package]] 1444 | name = "ledger-apdu" 1445 | version = "0.7.0" 1446 | source = "git+https://github.com/helium/ledger-rs?branch=lthiery/tcp-transport#3066a3379e568805917459c78daa4e306b0cb12d" 1447 | 1448 | [[package]] 1449 | name = "ledger-transport" 1450 | version = "0.7.0" 1451 | source = "git+https://github.com/helium/ledger-rs?branch=lthiery/tcp-transport#3066a3379e568805917459c78daa4e306b0cb12d" 1452 | dependencies = [ 1453 | "byteorder", 1454 | "futures", 1455 | "js-sys", 1456 | "lazy_static", 1457 | "ledger-apdu", 1458 | "ledger-transport-hid", 1459 | "ledger-transport-tcp", 1460 | "serde", 1461 | "thiserror", 1462 | "trait-async", 1463 | "wasm-bindgen", 1464 | "wasm-bindgen-futures", 1465 | ] 1466 | 1467 | [[package]] 1468 | name = "ledger-transport-hid" 1469 | version = "0.7.0" 1470 | source = "git+https://github.com/helium/ledger-rs?branch=lthiery/tcp-transport#3066a3379e568805917459c78daa4e306b0cb12d" 1471 | dependencies = [ 1472 | "byteorder", 1473 | "cfg-if 0.1.10", 1474 | "hex", 1475 | "hidapi", 1476 | "lazy_static", 1477 | "ledger-apdu", 1478 | "libc", 1479 | "log", 1480 | "nix", 1481 | "thiserror", 1482 | ] 1483 | 1484 | [[package]] 1485 | name = "ledger-transport-tcp" 1486 | version = "0.7.0" 1487 | source = "git+https://github.com/helium/ledger-rs?branch=lthiery/tcp-transport#3066a3379e568805917459c78daa4e306b0cb12d" 1488 | dependencies = [ 1489 | "byteorder", 1490 | "hidapi", 1491 | "ledger-apdu", 1492 | "log", 1493 | "nix", 1494 | "thiserror", 1495 | "tokio", 1496 | ] 1497 | 1498 | [[package]] 1499 | name = "libc" 1500 | version = "0.2.118" 1501 | source = "registry+https://github.com/rust-lang/crates.io-index" 1502 | checksum = "06e509672465a0504304aa87f9f176f2b2b716ed8fb105ebe5c02dc6dce96a94" 1503 | 1504 | [[package]] 1505 | name = "libloading" 1506 | version = "0.7.3" 1507 | source = "registry+https://github.com/rust-lang/crates.io-index" 1508 | checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" 1509 | dependencies = [ 1510 | "cfg-if 1.0.0", 1511 | "winapi", 1512 | ] 1513 | 1514 | [[package]] 1515 | name = "libsodium-sys" 1516 | version = "0.2.7" 1517 | source = "registry+https://github.com/rust-lang/crates.io-index" 1518 | checksum = "6b779387cd56adfbc02ea4a668e704f729be8d6a6abd2c27ca5ee537849a92fd" 1519 | dependencies = [ 1520 | "cc", 1521 | "libc", 1522 | "pkg-config", 1523 | "walkdir", 1524 | ] 1525 | 1526 | [[package]] 1527 | name = "lock_api" 1528 | version = "0.4.6" 1529 | source = "registry+https://github.com/rust-lang/crates.io-index" 1530 | checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" 1531 | dependencies = [ 1532 | "scopeguard", 1533 | ] 1534 | 1535 | [[package]] 1536 | name = "log" 1537 | version = "0.4.14" 1538 | source = "registry+https://github.com/rust-lang/crates.io-index" 1539 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 1540 | dependencies = [ 1541 | "cfg-if 1.0.0", 1542 | ] 1543 | 1544 | [[package]] 1545 | name = "matches" 1546 | version = "0.1.9" 1547 | source = "registry+https://github.com/rust-lang/crates.io-index" 1548 | checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" 1549 | 1550 | [[package]] 1551 | name = "md5" 1552 | version = "0.7.0" 1553 | source = "registry+https://github.com/rust-lang/crates.io-index" 1554 | checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" 1555 | 1556 | [[package]] 1557 | name = "memchr" 1558 | version = "2.4.1" 1559 | source = "registry+https://github.com/rust-lang/crates.io-index" 1560 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 1561 | 1562 | [[package]] 1563 | name = "memoffset" 1564 | version = "0.6.5" 1565 | source = "registry+https://github.com/rust-lang/crates.io-index" 1566 | checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" 1567 | dependencies = [ 1568 | "autocfg", 1569 | ] 1570 | 1571 | [[package]] 1572 | name = "mime" 1573 | version = "0.3.16" 1574 | source = "registry+https://github.com/rust-lang/crates.io-index" 1575 | checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" 1576 | 1577 | [[package]] 1578 | name = "minimal-lexical" 1579 | version = "0.2.1" 1580 | source = "registry+https://github.com/rust-lang/crates.io-index" 1581 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 1582 | 1583 | [[package]] 1584 | name = "miniz_oxide" 1585 | version = "0.4.4" 1586 | source = "registry+https://github.com/rust-lang/crates.io-index" 1587 | checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" 1588 | dependencies = [ 1589 | "adler", 1590 | "autocfg", 1591 | ] 1592 | 1593 | [[package]] 1594 | name = "mio" 1595 | version = "0.7.14" 1596 | source = "registry+https://github.com/rust-lang/crates.io-index" 1597 | checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" 1598 | dependencies = [ 1599 | "libc", 1600 | "log", 1601 | "miow", 1602 | "ntapi", 1603 | "winapi", 1604 | ] 1605 | 1606 | [[package]] 1607 | name = "mio" 1608 | version = "0.8.0" 1609 | source = "registry+https://github.com/rust-lang/crates.io-index" 1610 | checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2" 1611 | dependencies = [ 1612 | "libc", 1613 | "log", 1614 | "miow", 1615 | "ntapi", 1616 | "winapi", 1617 | ] 1618 | 1619 | [[package]] 1620 | name = "miow" 1621 | version = "0.3.7" 1622 | source = "registry+https://github.com/rust-lang/crates.io-index" 1623 | checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" 1624 | dependencies = [ 1625 | "winapi", 1626 | ] 1627 | 1628 | [[package]] 1629 | name = "multihash" 1630 | version = "0.16.1" 1631 | source = "registry+https://github.com/rust-lang/crates.io-index" 1632 | checksum = "7392bffd88bc0c4f8297e36a777ab9f80b7127409c4a1acb8fee99c9f27addcd" 1633 | dependencies = [ 1634 | "blake2b_simd 1.0.0", 1635 | "blake2s_simd", 1636 | "blake3", 1637 | "core2", 1638 | "digest 0.10.3", 1639 | "multihash-derive", 1640 | "sha2 0.10.1", 1641 | "sha3", 1642 | "unsigned-varint", 1643 | ] 1644 | 1645 | [[package]] 1646 | name = "multihash-derive" 1647 | version = "0.8.0" 1648 | source = "registry+https://github.com/rust-lang/crates.io-index" 1649 | checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" 1650 | dependencies = [ 1651 | "proc-macro-crate", 1652 | "proc-macro-error", 1653 | "proc-macro2", 1654 | "quote", 1655 | "syn", 1656 | "synstructure", 1657 | ] 1658 | 1659 | [[package]] 1660 | name = "multimap" 1661 | version = "0.8.3" 1662 | source = "registry+https://github.com/rust-lang/crates.io-index" 1663 | checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" 1664 | 1665 | [[package]] 1666 | name = "nix" 1667 | version = "0.17.0" 1668 | source = "registry+https://github.com/rust-lang/crates.io-index" 1669 | checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363" 1670 | dependencies = [ 1671 | "bitflags", 1672 | "cc", 1673 | "cfg-if 0.1.10", 1674 | "libc", 1675 | "void", 1676 | ] 1677 | 1678 | [[package]] 1679 | name = "nom" 1680 | version = "7.1.0" 1681 | source = "registry+https://github.com/rust-lang/crates.io-index" 1682 | checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" 1683 | dependencies = [ 1684 | "memchr", 1685 | "minimal-lexical", 1686 | "version_check", 1687 | ] 1688 | 1689 | [[package]] 1690 | name = "ntapi" 1691 | version = "0.3.7" 1692 | source = "registry+https://github.com/rust-lang/crates.io-index" 1693 | checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" 1694 | dependencies = [ 1695 | "winapi", 1696 | ] 1697 | 1698 | [[package]] 1699 | name = "num-integer" 1700 | version = "0.1.44" 1701 | source = "registry+https://github.com/rust-lang/crates.io-index" 1702 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 1703 | dependencies = [ 1704 | "autocfg", 1705 | "num-traits", 1706 | ] 1707 | 1708 | [[package]] 1709 | name = "num-traits" 1710 | version = "0.2.14" 1711 | source = "registry+https://github.com/rust-lang/crates.io-index" 1712 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 1713 | dependencies = [ 1714 | "autocfg", 1715 | ] 1716 | 1717 | [[package]] 1718 | name = "num_cpus" 1719 | version = "1.13.1" 1720 | source = "registry+https://github.com/rust-lang/crates.io-index" 1721 | checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" 1722 | dependencies = [ 1723 | "hermit-abi", 1724 | "libc", 1725 | ] 1726 | 1727 | [[package]] 1728 | name = "once_cell" 1729 | version = "1.9.0" 1730 | source = "registry+https://github.com/rust-lang/crates.io-index" 1731 | checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" 1732 | 1733 | [[package]] 1734 | name = "opaque-debug" 1735 | version = "0.3.0" 1736 | source = "registry+https://github.com/rust-lang/crates.io-index" 1737 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" 1738 | 1739 | [[package]] 1740 | name = "p256" 1741 | version = "0.10.1" 1742 | source = "registry+https://github.com/rust-lang/crates.io-index" 1743 | checksum = "19736d80675fbe9fe33426268150b951a3fb8f5cfca2a23a17c85ef3adb24e3b" 1744 | dependencies = [ 1745 | "ecdsa", 1746 | "elliptic-curve", 1747 | "sec1", 1748 | "sha2 0.9.9", 1749 | ] 1750 | 1751 | [[package]] 1752 | name = "parking_lot" 1753 | version = "0.12.0" 1754 | source = "registry+https://github.com/rust-lang/crates.io-index" 1755 | checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" 1756 | dependencies = [ 1757 | "lock_api", 1758 | "parking_lot_core", 1759 | ] 1760 | 1761 | [[package]] 1762 | name = "parking_lot_core" 1763 | version = "0.9.1" 1764 | source = "registry+https://github.com/rust-lang/crates.io-index" 1765 | checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" 1766 | dependencies = [ 1767 | "cfg-if 1.0.0", 1768 | "libc", 1769 | "redox_syscall 0.2.10", 1770 | "smallvec", 1771 | "windows-sys", 1772 | ] 1773 | 1774 | [[package]] 1775 | name = "pbkdf2" 1776 | version = "0.10.0" 1777 | source = "registry+https://github.com/rust-lang/crates.io-index" 1778 | checksum = "a4628cc3cf953b82edcd3c1388c5715401420ce5524fedbab426bd5aba017434" 1779 | dependencies = [ 1780 | "digest 0.10.3", 1781 | ] 1782 | 1783 | [[package]] 1784 | name = "pdqselect" 1785 | version = "0.1.0" 1786 | source = "registry+https://github.com/rust-lang/crates.io-index" 1787 | checksum = "4ec91767ecc0a0bbe558ce8c9da33c068066c57ecc8bb8477ef8c1ad3ef77c27" 1788 | 1789 | [[package]] 1790 | name = "peeking_take_while" 1791 | version = "0.1.2" 1792 | source = "registry+https://github.com/rust-lang/crates.io-index" 1793 | checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" 1794 | 1795 | [[package]] 1796 | name = "percent-encoding" 1797 | version = "2.1.0" 1798 | source = "registry+https://github.com/rust-lang/crates.io-index" 1799 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 1800 | 1801 | [[package]] 1802 | name = "petgraph" 1803 | version = "0.6.0" 1804 | source = "registry+https://github.com/rust-lang/crates.io-index" 1805 | checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" 1806 | dependencies = [ 1807 | "fixedbitset", 1808 | "indexmap", 1809 | ] 1810 | 1811 | [[package]] 1812 | name = "pin-project-lite" 1813 | version = "0.2.8" 1814 | source = "registry+https://github.com/rust-lang/crates.io-index" 1815 | checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" 1816 | 1817 | [[package]] 1818 | name = "pin-utils" 1819 | version = "0.1.0" 1820 | source = "registry+https://github.com/rust-lang/crates.io-index" 1821 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1822 | 1823 | [[package]] 1824 | name = "pkg-config" 1825 | version = "0.3.24" 1826 | source = "registry+https://github.com/rust-lang/crates.io-index" 1827 | checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" 1828 | 1829 | [[package]] 1830 | name = "poly1305" 1831 | version = "0.6.2" 1832 | source = "registry+https://github.com/rust-lang/crates.io-index" 1833 | checksum = "4b7456bc1ad2d4cf82b3a016be4c2ac48daf11bf990c1603ebd447fe6f30fca8" 1834 | dependencies = [ 1835 | "cpuid-bool", 1836 | "universal-hash", 1837 | ] 1838 | 1839 | [[package]] 1840 | name = "polyval" 1841 | version = "0.5.3" 1842 | source = "registry+https://github.com/rust-lang/crates.io-index" 1843 | checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" 1844 | dependencies = [ 1845 | "cfg-if 1.0.0", 1846 | "cpufeatures", 1847 | "opaque-debug", 1848 | "universal-hash", 1849 | ] 1850 | 1851 | [[package]] 1852 | name = "pom" 1853 | version = "1.1.0" 1854 | source = "registry+https://github.com/rust-lang/crates.io-index" 1855 | checksum = "60f6ce597ecdcc9a098e7fddacb1065093a3d66446fa16c675e7e71d1b5c28e6" 1856 | 1857 | [[package]] 1858 | name = "ppv-lite86" 1859 | version = "0.2.16" 1860 | source = "registry+https://github.com/rust-lang/crates.io-index" 1861 | checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" 1862 | 1863 | [[package]] 1864 | name = "prettytable-rs" 1865 | version = "0.8.0" 1866 | source = "registry+https://github.com/rust-lang/crates.io-index" 1867 | checksum = "0fd04b170004fa2daccf418a7f8253aaf033c27760b5f225889024cf66d7ac2e" 1868 | dependencies = [ 1869 | "atty", 1870 | "csv", 1871 | "encode_unicode", 1872 | "lazy_static", 1873 | "term", 1874 | "unicode-width", 1875 | ] 1876 | 1877 | [[package]] 1878 | name = "proc-macro-crate" 1879 | version = "1.1.2" 1880 | source = "registry+https://github.com/rust-lang/crates.io-index" 1881 | checksum = "9dada8c9981fcf32929c3c0f0cd796a9284aca335565227ed88c83babb1d43dc" 1882 | dependencies = [ 1883 | "thiserror", 1884 | "toml", 1885 | ] 1886 | 1887 | [[package]] 1888 | name = "proc-macro-error" 1889 | version = "1.0.4" 1890 | source = "registry+https://github.com/rust-lang/crates.io-index" 1891 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 1892 | dependencies = [ 1893 | "proc-macro-error-attr", 1894 | "proc-macro2", 1895 | "quote", 1896 | "syn", 1897 | "version_check", 1898 | ] 1899 | 1900 | [[package]] 1901 | name = "proc-macro-error-attr" 1902 | version = "1.0.4" 1903 | source = "registry+https://github.com/rust-lang/crates.io-index" 1904 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 1905 | dependencies = [ 1906 | "proc-macro2", 1907 | "quote", 1908 | "version_check", 1909 | ] 1910 | 1911 | [[package]] 1912 | name = "proc-macro2" 1913 | version = "1.0.36" 1914 | source = "registry+https://github.com/rust-lang/crates.io-index" 1915 | checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" 1916 | dependencies = [ 1917 | "unicode-xid", 1918 | ] 1919 | 1920 | [[package]] 1921 | name = "prost" 1922 | version = "0.9.0" 1923 | source = "registry+https://github.com/rust-lang/crates.io-index" 1924 | checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" 1925 | dependencies = [ 1926 | "bytes", 1927 | "prost-derive", 1928 | ] 1929 | 1930 | [[package]] 1931 | name = "prost-build" 1932 | version = "0.9.0" 1933 | source = "registry+https://github.com/rust-lang/crates.io-index" 1934 | checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5" 1935 | dependencies = [ 1936 | "bytes", 1937 | "heck", 1938 | "itertools", 1939 | "lazy_static", 1940 | "log", 1941 | "multimap", 1942 | "petgraph", 1943 | "prost", 1944 | "prost-types", 1945 | "regex", 1946 | "tempfile", 1947 | "which", 1948 | ] 1949 | 1950 | [[package]] 1951 | name = "prost-derive" 1952 | version = "0.9.0" 1953 | source = "registry+https://github.com/rust-lang/crates.io-index" 1954 | checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" 1955 | dependencies = [ 1956 | "anyhow", 1957 | "itertools", 1958 | "proc-macro2", 1959 | "quote", 1960 | "syn", 1961 | ] 1962 | 1963 | [[package]] 1964 | name = "prost-types" 1965 | version = "0.9.0" 1966 | source = "registry+https://github.com/rust-lang/crates.io-index" 1967 | checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a" 1968 | dependencies = [ 1969 | "bytes", 1970 | "prost", 1971 | ] 1972 | 1973 | [[package]] 1974 | name = "qr2term" 1975 | version = "0.2.3" 1976 | source = "registry+https://github.com/rust-lang/crates.io-index" 1977 | checksum = "1d9ed66d596477e4a04d2ebdbc9b657c417e8316ae7cc504f82ace5a786d4d7d" 1978 | dependencies = [ 1979 | "crossterm", 1980 | "qrcode", 1981 | ] 1982 | 1983 | [[package]] 1984 | name = "qrcode" 1985 | version = "0.12.0" 1986 | source = "registry+https://github.com/rust-lang/crates.io-index" 1987 | checksum = "16d2f1455f3630c6e5107b4f2b94e74d76dea80736de0981fd27644216cff57f" 1988 | dependencies = [ 1989 | "checked_int_cast", 1990 | ] 1991 | 1992 | [[package]] 1993 | name = "quote" 1994 | version = "1.0.15" 1995 | source = "registry+https://github.com/rust-lang/crates.io-index" 1996 | checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" 1997 | dependencies = [ 1998 | "proc-macro2", 1999 | ] 2000 | 2001 | [[package]] 2002 | name = "radium" 2003 | version = "0.7.0" 2004 | source = "registry+https://github.com/rust-lang/crates.io-index" 2005 | checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" 2006 | 2007 | [[package]] 2008 | name = "rand" 2009 | version = "0.8.5" 2010 | source = "registry+https://github.com/rust-lang/crates.io-index" 2011 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 2012 | dependencies = [ 2013 | "libc", 2014 | "rand_chacha", 2015 | "rand_core 0.6.3", 2016 | ] 2017 | 2018 | [[package]] 2019 | name = "rand_chacha" 2020 | version = "0.3.1" 2021 | source = "registry+https://github.com/rust-lang/crates.io-index" 2022 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 2023 | dependencies = [ 2024 | "ppv-lite86", 2025 | "rand_core 0.6.3", 2026 | ] 2027 | 2028 | [[package]] 2029 | name = "rand_core" 2030 | version = "0.5.1" 2031 | source = "registry+https://github.com/rust-lang/crates.io-index" 2032 | checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 2033 | dependencies = [ 2034 | "getrandom 0.1.16", 2035 | ] 2036 | 2037 | [[package]] 2038 | name = "rand_core" 2039 | version = "0.6.3" 2040 | source = "registry+https://github.com/rust-lang/crates.io-index" 2041 | checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" 2042 | dependencies = [ 2043 | "getrandom 0.2.4", 2044 | ] 2045 | 2046 | [[package]] 2047 | name = "rayon" 2048 | version = "1.5.1" 2049 | source = "registry+https://github.com/rust-lang/crates.io-index" 2050 | checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" 2051 | dependencies = [ 2052 | "autocfg", 2053 | "crossbeam-deque", 2054 | "either", 2055 | "rayon-core", 2056 | ] 2057 | 2058 | [[package]] 2059 | name = "rayon-core" 2060 | version = "1.9.1" 2061 | source = "registry+https://github.com/rust-lang/crates.io-index" 2062 | checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" 2063 | dependencies = [ 2064 | "crossbeam-channel", 2065 | "crossbeam-deque", 2066 | "crossbeam-utils", 2067 | "lazy_static", 2068 | "num_cpus", 2069 | ] 2070 | 2071 | [[package]] 2072 | name = "redox_syscall" 2073 | version = "0.1.57" 2074 | source = "registry+https://github.com/rust-lang/crates.io-index" 2075 | checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" 2076 | 2077 | [[package]] 2078 | name = "redox_syscall" 2079 | version = "0.2.10" 2080 | source = "registry+https://github.com/rust-lang/crates.io-index" 2081 | checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" 2082 | dependencies = [ 2083 | "bitflags", 2084 | ] 2085 | 2086 | [[package]] 2087 | name = "redox_users" 2088 | version = "0.3.5" 2089 | source = "registry+https://github.com/rust-lang/crates.io-index" 2090 | checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" 2091 | dependencies = [ 2092 | "getrandom 0.1.16", 2093 | "redox_syscall 0.1.57", 2094 | "rust-argon2", 2095 | ] 2096 | 2097 | [[package]] 2098 | name = "regex" 2099 | version = "1.5.4" 2100 | source = "registry+https://github.com/rust-lang/crates.io-index" 2101 | checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" 2102 | dependencies = [ 2103 | "aho-corasick", 2104 | "memchr", 2105 | "regex-syntax", 2106 | ] 2107 | 2108 | [[package]] 2109 | name = "regex-automata" 2110 | version = "0.1.10" 2111 | source = "registry+https://github.com/rust-lang/crates.io-index" 2112 | checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" 2113 | 2114 | [[package]] 2115 | name = "regex-syntax" 2116 | version = "0.6.25" 2117 | source = "registry+https://github.com/rust-lang/crates.io-index" 2118 | checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" 2119 | 2120 | [[package]] 2121 | name = "remove_dir_all" 2122 | version = "0.5.3" 2123 | source = "registry+https://github.com/rust-lang/crates.io-index" 2124 | checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" 2125 | dependencies = [ 2126 | "winapi", 2127 | ] 2128 | 2129 | [[package]] 2130 | name = "reqwest" 2131 | version = "0.11.9" 2132 | source = "registry+https://github.com/rust-lang/crates.io-index" 2133 | checksum = "87f242f1488a539a79bac6dbe7c8609ae43b7914b7736210f239a37cccb32525" 2134 | dependencies = [ 2135 | "async-compression", 2136 | "base64 0.13.0", 2137 | "bytes", 2138 | "encoding_rs", 2139 | "futures-core", 2140 | "futures-util", 2141 | "h2", 2142 | "http", 2143 | "http-body", 2144 | "hyper", 2145 | "hyper-rustls", 2146 | "ipnet", 2147 | "js-sys", 2148 | "lazy_static", 2149 | "log", 2150 | "mime", 2151 | "percent-encoding", 2152 | "pin-project-lite", 2153 | "rustls", 2154 | "rustls-pemfile", 2155 | "serde", 2156 | "serde_json", 2157 | "serde_urlencoded", 2158 | "tokio", 2159 | "tokio-rustls", 2160 | "tokio-util", 2161 | "url", 2162 | "wasm-bindgen", 2163 | "wasm-bindgen-futures", 2164 | "web-sys", 2165 | "webpki-roots", 2166 | "winreg", 2167 | ] 2168 | 2169 | [[package]] 2170 | name = "rfc6979" 2171 | version = "0.1.0" 2172 | source = "registry+https://github.com/rust-lang/crates.io-index" 2173 | checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" 2174 | dependencies = [ 2175 | "crypto-bigint", 2176 | "hmac 0.11.0", 2177 | "zeroize", 2178 | ] 2179 | 2180 | [[package]] 2181 | name = "ring" 2182 | version = "0.16.20" 2183 | source = "registry+https://github.com/rust-lang/crates.io-index" 2184 | checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" 2185 | dependencies = [ 2186 | "cc", 2187 | "libc", 2188 | "once_cell", 2189 | "spin", 2190 | "untrusted", 2191 | "web-sys", 2192 | "winapi", 2193 | ] 2194 | 2195 | [[package]] 2196 | name = "robust" 2197 | version = "0.2.3" 2198 | source = "registry+https://github.com/rust-lang/crates.io-index" 2199 | checksum = "e5864e7ef1a6b7bcf1d6ca3f655e65e724ed3b52546a0d0a663c991522f552ea" 2200 | 2201 | [[package]] 2202 | name = "rstar" 2203 | version = "0.8.4" 2204 | source = "registry+https://github.com/rust-lang/crates.io-index" 2205 | checksum = "3a45c0e8804d37e4d97e55c6f258bc9ad9c5ee7b07437009dd152d764949a27c" 2206 | dependencies = [ 2207 | "heapless", 2208 | "num-traits", 2209 | "pdqselect", 2210 | "smallvec", 2211 | ] 2212 | 2213 | [[package]] 2214 | name = "rust-argon2" 2215 | version = "0.8.3" 2216 | source = "registry+https://github.com/rust-lang/crates.io-index" 2217 | checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" 2218 | dependencies = [ 2219 | "base64 0.13.0", 2220 | "blake2b_simd 0.5.11", 2221 | "constant_time_eq", 2222 | "crossbeam-utils", 2223 | ] 2224 | 2225 | [[package]] 2226 | name = "rust_decimal" 2227 | version = "1.21.0" 2228 | source = "registry+https://github.com/rust-lang/crates.io-index" 2229 | checksum = "4214023b1223d02a4aad9f0bb9828317634a56530870a2eaf7200a99c0c10f68" 2230 | dependencies = [ 2231 | "arrayvec 0.7.2", 2232 | "num-traits", 2233 | "serde", 2234 | ] 2235 | 2236 | [[package]] 2237 | name = "rustc-hash" 2238 | version = "1.1.0" 2239 | source = "registry+https://github.com/rust-lang/crates.io-index" 2240 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 2241 | 2242 | [[package]] 2243 | name = "rustls" 2244 | version = "0.20.3" 2245 | source = "registry+https://github.com/rust-lang/crates.io-index" 2246 | checksum = "b323592e3164322f5b193dc4302e4e36cd8d37158a712d664efae1a5c2791700" 2247 | dependencies = [ 2248 | "log", 2249 | "ring", 2250 | "sct", 2251 | "webpki", 2252 | ] 2253 | 2254 | [[package]] 2255 | name = "rustls-pemfile" 2256 | version = "0.2.1" 2257 | source = "registry+https://github.com/rust-lang/crates.io-index" 2258 | checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" 2259 | dependencies = [ 2260 | "base64 0.13.0", 2261 | ] 2262 | 2263 | [[package]] 2264 | name = "ryu" 2265 | version = "1.0.9" 2266 | source = "registry+https://github.com/rust-lang/crates.io-index" 2267 | checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" 2268 | 2269 | [[package]] 2270 | name = "salsa20" 2271 | version = "0.7.2" 2272 | source = "registry+https://github.com/rust-lang/crates.io-index" 2273 | checksum = "399f290ffc409596022fce5ea5d4138184be4784f2b28c62c59f0d8389059a15" 2274 | dependencies = [ 2275 | "cipher 0.2.5", 2276 | "zeroize", 2277 | ] 2278 | 2279 | [[package]] 2280 | name = "same-file" 2281 | version = "1.0.6" 2282 | source = "registry+https://github.com/rust-lang/crates.io-index" 2283 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 2284 | dependencies = [ 2285 | "winapi-util", 2286 | ] 2287 | 2288 | [[package]] 2289 | name = "scopeguard" 2290 | version = "1.1.0" 2291 | source = "registry+https://github.com/rust-lang/crates.io-index" 2292 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 2293 | 2294 | [[package]] 2295 | name = "sct" 2296 | version = "0.7.0" 2297 | source = "registry+https://github.com/rust-lang/crates.io-index" 2298 | checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" 2299 | dependencies = [ 2300 | "ring", 2301 | "untrusted", 2302 | ] 2303 | 2304 | [[package]] 2305 | name = "sec1" 2306 | version = "0.2.1" 2307 | source = "registry+https://github.com/rust-lang/crates.io-index" 2308 | checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" 2309 | dependencies = [ 2310 | "der", 2311 | "generic-array 0.14.5", 2312 | "subtle", 2313 | "zeroize", 2314 | ] 2315 | 2316 | [[package]] 2317 | name = "serde" 2318 | version = "1.0.136" 2319 | source = "registry+https://github.com/rust-lang/crates.io-index" 2320 | checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" 2321 | dependencies = [ 2322 | "serde_derive", 2323 | ] 2324 | 2325 | [[package]] 2326 | name = "serde_derive" 2327 | version = "1.0.136" 2328 | source = "registry+https://github.com/rust-lang/crates.io-index" 2329 | checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" 2330 | dependencies = [ 2331 | "proc-macro2", 2332 | "quote", 2333 | "syn", 2334 | ] 2335 | 2336 | [[package]] 2337 | name = "serde_json" 2338 | version = "1.0.79" 2339 | source = "registry+https://github.com/rust-lang/crates.io-index" 2340 | checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" 2341 | dependencies = [ 2342 | "itoa 1.0.1", 2343 | "ryu", 2344 | "serde", 2345 | ] 2346 | 2347 | [[package]] 2348 | name = "serde_urlencoded" 2349 | version = "0.7.1" 2350 | source = "registry+https://github.com/rust-lang/crates.io-index" 2351 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 2352 | dependencies = [ 2353 | "form_urlencoded", 2354 | "itoa 1.0.1", 2355 | "ryu", 2356 | "serde", 2357 | ] 2358 | 2359 | [[package]] 2360 | name = "sha2" 2361 | version = "0.9.9" 2362 | source = "registry+https://github.com/rust-lang/crates.io-index" 2363 | checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" 2364 | dependencies = [ 2365 | "block-buffer 0.9.0", 2366 | "cfg-if 1.0.0", 2367 | "cpufeatures", 2368 | "digest 0.9.0", 2369 | "opaque-debug", 2370 | ] 2371 | 2372 | [[package]] 2373 | name = "sha2" 2374 | version = "0.10.1" 2375 | source = "registry+https://github.com/rust-lang/crates.io-index" 2376 | checksum = "99c3bd8169c58782adad9290a9af5939994036b76187f7b4f0e6de91dbbfc0ec" 2377 | dependencies = [ 2378 | "cfg-if 1.0.0", 2379 | "cpufeatures", 2380 | "digest 0.10.3", 2381 | ] 2382 | 2383 | [[package]] 2384 | name = "sha3" 2385 | version = "0.10.0" 2386 | source = "registry+https://github.com/rust-lang/crates.io-index" 2387 | checksum = "31f935e31cf406e8c0e96c2815a5516181b7004ae8c5f296293221e9b1e356bd" 2388 | dependencies = [ 2389 | "digest 0.10.3", 2390 | "keccak", 2391 | ] 2392 | 2393 | [[package]] 2394 | name = "shamirsecretsharing" 2395 | version = "0.1.5" 2396 | source = "registry+https://github.com/rust-lang/crates.io-index" 2397 | checksum = "6c0df585cf14446dc081c77e9f3a56a9c5d79755e875b165d2d15e4cdf357972" 2398 | dependencies = [ 2399 | "cc", 2400 | "rand", 2401 | "xsalsa20poly1305", 2402 | ] 2403 | 2404 | [[package]] 2405 | name = "shlex" 2406 | version = "1.1.0" 2407 | source = "registry+https://github.com/rust-lang/crates.io-index" 2408 | checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" 2409 | 2410 | [[package]] 2411 | name = "signal-hook" 2412 | version = "0.3.13" 2413 | source = "registry+https://github.com/rust-lang/crates.io-index" 2414 | checksum = "647c97df271007dcea485bb74ffdb57f2e683f1306c854f468a0c244badabf2d" 2415 | dependencies = [ 2416 | "libc", 2417 | "signal-hook-registry", 2418 | ] 2419 | 2420 | [[package]] 2421 | name = "signal-hook-mio" 2422 | version = "0.2.1" 2423 | source = "registry+https://github.com/rust-lang/crates.io-index" 2424 | checksum = "29fd5867f1c4f2c5be079aee7a2adf1152ebb04a4bc4d341f504b7dece607ed4" 2425 | dependencies = [ 2426 | "libc", 2427 | "mio 0.7.14", 2428 | "signal-hook", 2429 | ] 2430 | 2431 | [[package]] 2432 | name = "signal-hook-registry" 2433 | version = "1.4.0" 2434 | source = "registry+https://github.com/rust-lang/crates.io-index" 2435 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" 2436 | dependencies = [ 2437 | "libc", 2438 | ] 2439 | 2440 | [[package]] 2441 | name = "signature" 2442 | version = "1.4.0" 2443 | source = "registry+https://github.com/rust-lang/crates.io-index" 2444 | checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" 2445 | dependencies = [ 2446 | "digest 0.9.0", 2447 | "rand_core 0.6.3", 2448 | ] 2449 | 2450 | [[package]] 2451 | name = "slab" 2452 | version = "0.4.5" 2453 | source = "registry+https://github.com/rust-lang/crates.io-index" 2454 | checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" 2455 | 2456 | [[package]] 2457 | name = "smallvec" 2458 | version = "1.8.0" 2459 | source = "registry+https://github.com/rust-lang/crates.io-index" 2460 | checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" 2461 | 2462 | [[package]] 2463 | name = "socket2" 2464 | version = "0.4.4" 2465 | source = "registry+https://github.com/rust-lang/crates.io-index" 2466 | checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" 2467 | dependencies = [ 2468 | "libc", 2469 | "winapi", 2470 | ] 2471 | 2472 | [[package]] 2473 | name = "sodiumoxide" 2474 | version = "0.2.7" 2475 | source = "registry+https://github.com/rust-lang/crates.io-index" 2476 | checksum = "e26be3acb6c2d9a7aac28482586a7856436af4cfe7100031d219de2d2ecb0028" 2477 | dependencies = [ 2478 | "ed25519", 2479 | "libc", 2480 | "libsodium-sys", 2481 | "serde", 2482 | ] 2483 | 2484 | [[package]] 2485 | name = "spin" 2486 | version = "0.5.2" 2487 | source = "registry+https://github.com/rust-lang/crates.io-index" 2488 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 2489 | 2490 | [[package]] 2491 | name = "stable_deref_trait" 2492 | version = "1.2.0" 2493 | source = "registry+https://github.com/rust-lang/crates.io-index" 2494 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 2495 | 2496 | [[package]] 2497 | name = "strsim" 2498 | version = "0.8.0" 2499 | source = "registry+https://github.com/rust-lang/crates.io-index" 2500 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 2501 | 2502 | [[package]] 2503 | name = "structopt" 2504 | version = "0.3.26" 2505 | source = "registry+https://github.com/rust-lang/crates.io-index" 2506 | checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" 2507 | dependencies = [ 2508 | "clap", 2509 | "lazy_static", 2510 | "structopt-derive", 2511 | ] 2512 | 2513 | [[package]] 2514 | name = "structopt-derive" 2515 | version = "0.4.18" 2516 | source = "registry+https://github.com/rust-lang/crates.io-index" 2517 | checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" 2518 | dependencies = [ 2519 | "heck", 2520 | "proc-macro-error", 2521 | "proc-macro2", 2522 | "quote", 2523 | "syn", 2524 | ] 2525 | 2526 | [[package]] 2527 | name = "subtle" 2528 | version = "2.4.1" 2529 | source = "registry+https://github.com/rust-lang/crates.io-index" 2530 | checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" 2531 | 2532 | [[package]] 2533 | name = "svg" 2534 | version = "0.5.12" 2535 | source = "registry+https://github.com/rust-lang/crates.io-index" 2536 | checksum = "a863ec1f8e7cfd4ea449f77445cca06aac240b9a677ccf12b0f65ef020db52c7" 2537 | 2538 | [[package]] 2539 | name = "svgbob" 2540 | version = "0.4.1" 2541 | source = "registry+https://github.com/rust-lang/crates.io-index" 2542 | checksum = "dd526cbbfdd8637f3d78b2a955f0291df671010563cc5a4aab50f200a981b4b5" 2543 | dependencies = [ 2544 | "pom", 2545 | "svg", 2546 | "unicode-width", 2547 | ] 2548 | 2549 | [[package]] 2550 | name = "svgbobdoc" 2551 | version = "0.2.3" 2552 | source = "registry+https://github.com/rust-lang/crates.io-index" 2553 | checksum = "0bd7b0c572b374ff863c20c8b8cb6c3d495e1ecff17d765c0a2a5c7ad55e4b5e" 2554 | dependencies = [ 2555 | "base64 0.12.3", 2556 | "lazy_static", 2557 | "proc-macro2", 2558 | "quote", 2559 | "regex", 2560 | "svg", 2561 | "svgbob", 2562 | "syn", 2563 | "unicode-width", 2564 | ] 2565 | 2566 | [[package]] 2567 | name = "syn" 2568 | version = "1.0.86" 2569 | source = "registry+https://github.com/rust-lang/crates.io-index" 2570 | checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" 2571 | dependencies = [ 2572 | "proc-macro2", 2573 | "quote", 2574 | "unicode-xid", 2575 | ] 2576 | 2577 | [[package]] 2578 | name = "synstructure" 2579 | version = "0.12.6" 2580 | source = "registry+https://github.com/rust-lang/crates.io-index" 2581 | checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" 2582 | dependencies = [ 2583 | "proc-macro2", 2584 | "quote", 2585 | "syn", 2586 | "unicode-xid", 2587 | ] 2588 | 2589 | [[package]] 2590 | name = "tap" 2591 | version = "1.0.1" 2592 | source = "registry+https://github.com/rust-lang/crates.io-index" 2593 | checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" 2594 | 2595 | [[package]] 2596 | name = "tempfile" 2597 | version = "3.3.0" 2598 | source = "registry+https://github.com/rust-lang/crates.io-index" 2599 | checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" 2600 | dependencies = [ 2601 | "cfg-if 1.0.0", 2602 | "fastrand", 2603 | "libc", 2604 | "redox_syscall 0.2.10", 2605 | "remove_dir_all", 2606 | "winapi", 2607 | ] 2608 | 2609 | [[package]] 2610 | name = "term" 2611 | version = "0.5.2" 2612 | source = "registry+https://github.com/rust-lang/crates.io-index" 2613 | checksum = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42" 2614 | dependencies = [ 2615 | "byteorder", 2616 | "dirs", 2617 | "winapi", 2618 | ] 2619 | 2620 | [[package]] 2621 | name = "termcolor" 2622 | version = "1.1.2" 2623 | source = "registry+https://github.com/rust-lang/crates.io-index" 2624 | checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" 2625 | dependencies = [ 2626 | "winapi-util", 2627 | ] 2628 | 2629 | [[package]] 2630 | name = "terminal_size" 2631 | version = "0.1.17" 2632 | source = "registry+https://github.com/rust-lang/crates.io-index" 2633 | checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" 2634 | dependencies = [ 2635 | "libc", 2636 | "winapi", 2637 | ] 2638 | 2639 | [[package]] 2640 | name = "textwrap" 2641 | version = "0.11.0" 2642 | source = "registry+https://github.com/rust-lang/crates.io-index" 2643 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 2644 | dependencies = [ 2645 | "unicode-width", 2646 | ] 2647 | 2648 | [[package]] 2649 | name = "thiserror" 2650 | version = "1.0.30" 2651 | source = "registry+https://github.com/rust-lang/crates.io-index" 2652 | checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" 2653 | dependencies = [ 2654 | "thiserror-impl", 2655 | ] 2656 | 2657 | [[package]] 2658 | name = "thiserror-impl" 2659 | version = "1.0.30" 2660 | source = "registry+https://github.com/rust-lang/crates.io-index" 2661 | checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" 2662 | dependencies = [ 2663 | "proc-macro2", 2664 | "quote", 2665 | "syn", 2666 | ] 2667 | 2668 | [[package]] 2669 | name = "time" 2670 | version = "0.1.43" 2671 | source = "registry+https://github.com/rust-lang/crates.io-index" 2672 | checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" 2673 | dependencies = [ 2674 | "libc", 2675 | "winapi", 2676 | ] 2677 | 2678 | [[package]] 2679 | name = "tinyvec" 2680 | version = "1.5.1" 2681 | source = "registry+https://github.com/rust-lang/crates.io-index" 2682 | checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" 2683 | dependencies = [ 2684 | "tinyvec_macros", 2685 | ] 2686 | 2687 | [[package]] 2688 | name = "tinyvec_macros" 2689 | version = "0.1.0" 2690 | source = "registry+https://github.com/rust-lang/crates.io-index" 2691 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 2692 | 2693 | [[package]] 2694 | name = "tokio" 2695 | version = "1.17.0" 2696 | source = "registry+https://github.com/rust-lang/crates.io-index" 2697 | checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" 2698 | dependencies = [ 2699 | "bytes", 2700 | "libc", 2701 | "memchr", 2702 | "mio 0.8.0", 2703 | "num_cpus", 2704 | "once_cell", 2705 | "parking_lot", 2706 | "pin-project-lite", 2707 | "signal-hook-registry", 2708 | "socket2", 2709 | "tokio-macros", 2710 | "winapi", 2711 | ] 2712 | 2713 | [[package]] 2714 | name = "tokio-macros" 2715 | version = "1.7.0" 2716 | source = "registry+https://github.com/rust-lang/crates.io-index" 2717 | checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" 2718 | dependencies = [ 2719 | "proc-macro2", 2720 | "quote", 2721 | "syn", 2722 | ] 2723 | 2724 | [[package]] 2725 | name = "tokio-rustls" 2726 | version = "0.23.2" 2727 | source = "registry+https://github.com/rust-lang/crates.io-index" 2728 | checksum = "a27d5f2b839802bd8267fa19b0530f5a08b9c08cd417976be2a65d130fe1c11b" 2729 | dependencies = [ 2730 | "rustls", 2731 | "tokio", 2732 | "webpki", 2733 | ] 2734 | 2735 | [[package]] 2736 | name = "tokio-util" 2737 | version = "0.6.9" 2738 | source = "registry+https://github.com/rust-lang/crates.io-index" 2739 | checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" 2740 | dependencies = [ 2741 | "bytes", 2742 | "futures-core", 2743 | "futures-sink", 2744 | "log", 2745 | "pin-project-lite", 2746 | "tokio", 2747 | ] 2748 | 2749 | [[package]] 2750 | name = "toml" 2751 | version = "0.5.8" 2752 | source = "registry+https://github.com/rust-lang/crates.io-index" 2753 | checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" 2754 | dependencies = [ 2755 | "serde", 2756 | ] 2757 | 2758 | [[package]] 2759 | name = "tower-service" 2760 | version = "0.3.1" 2761 | source = "registry+https://github.com/rust-lang/crates.io-index" 2762 | checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" 2763 | 2764 | [[package]] 2765 | name = "tracing" 2766 | version = "0.1.30" 2767 | source = "registry+https://github.com/rust-lang/crates.io-index" 2768 | checksum = "2d8d93354fe2a8e50d5953f5ae2e47a3fc2ef03292e7ea46e3cc38f549525fb9" 2769 | dependencies = [ 2770 | "cfg-if 1.0.0", 2771 | "pin-project-lite", 2772 | "tracing-core", 2773 | ] 2774 | 2775 | [[package]] 2776 | name = "tracing-core" 2777 | version = "0.1.22" 2778 | source = "registry+https://github.com/rust-lang/crates.io-index" 2779 | checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23" 2780 | dependencies = [ 2781 | "lazy_static", 2782 | ] 2783 | 2784 | [[package]] 2785 | name = "trait-async" 2786 | version = "0.1.24" 2787 | source = "registry+https://github.com/rust-lang/crates.io-index" 2788 | checksum = "dfe8c654712ee594c93b7222d98b4e61c7e003aec49e73877edac607a213699d" 2789 | dependencies = [ 2790 | "proc-macro2", 2791 | "quote", 2792 | "syn", 2793 | ] 2794 | 2795 | [[package]] 2796 | name = "try-lock" 2797 | version = "0.2.3" 2798 | source = "registry+https://github.com/rust-lang/crates.io-index" 2799 | checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" 2800 | 2801 | [[package]] 2802 | name = "typenum" 2803 | version = "1.15.0" 2804 | source = "registry+https://github.com/rust-lang/crates.io-index" 2805 | checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" 2806 | 2807 | [[package]] 2808 | name = "unicode-bidi" 2809 | version = "0.3.7" 2810 | source = "registry+https://github.com/rust-lang/crates.io-index" 2811 | checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" 2812 | 2813 | [[package]] 2814 | name = "unicode-normalization" 2815 | version = "0.1.19" 2816 | source = "registry+https://github.com/rust-lang/crates.io-index" 2817 | checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" 2818 | dependencies = [ 2819 | "tinyvec", 2820 | ] 2821 | 2822 | [[package]] 2823 | name = "unicode-segmentation" 2824 | version = "1.9.0" 2825 | source = "registry+https://github.com/rust-lang/crates.io-index" 2826 | checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" 2827 | 2828 | [[package]] 2829 | name = "unicode-width" 2830 | version = "0.1.9" 2831 | source = "registry+https://github.com/rust-lang/crates.io-index" 2832 | checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" 2833 | 2834 | [[package]] 2835 | name = "unicode-xid" 2836 | version = "0.2.2" 2837 | source = "registry+https://github.com/rust-lang/crates.io-index" 2838 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 2839 | 2840 | [[package]] 2841 | name = "universal-hash" 2842 | version = "0.4.1" 2843 | source = "registry+https://github.com/rust-lang/crates.io-index" 2844 | checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" 2845 | dependencies = [ 2846 | "generic-array 0.14.5", 2847 | "subtle", 2848 | ] 2849 | 2850 | [[package]] 2851 | name = "unsigned-varint" 2852 | version = "0.7.1" 2853 | source = "registry+https://github.com/rust-lang/crates.io-index" 2854 | checksum = "d86a8dc7f45e4c1b0d30e43038c38f274e77af056aa5f74b93c2cf9eb3c1c836" 2855 | 2856 | [[package]] 2857 | name = "untrusted" 2858 | version = "0.7.1" 2859 | source = "registry+https://github.com/rust-lang/crates.io-index" 2860 | checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" 2861 | 2862 | [[package]] 2863 | name = "url" 2864 | version = "2.2.2" 2865 | source = "registry+https://github.com/rust-lang/crates.io-index" 2866 | checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" 2867 | dependencies = [ 2868 | "form_urlencoded", 2869 | "idna", 2870 | "matches", 2871 | "percent-encoding", 2872 | ] 2873 | 2874 | [[package]] 2875 | name = "vec_map" 2876 | version = "0.8.2" 2877 | source = "registry+https://github.com/rust-lang/crates.io-index" 2878 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 2879 | 2880 | [[package]] 2881 | name = "version_check" 2882 | version = "0.9.4" 2883 | source = "registry+https://github.com/rust-lang/crates.io-index" 2884 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 2885 | 2886 | [[package]] 2887 | name = "void" 2888 | version = "1.0.2" 2889 | source = "registry+https://github.com/rust-lang/crates.io-index" 2890 | checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 2891 | 2892 | [[package]] 2893 | name = "walkdir" 2894 | version = "2.3.2" 2895 | source = "registry+https://github.com/rust-lang/crates.io-index" 2896 | checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" 2897 | dependencies = [ 2898 | "same-file", 2899 | "winapi", 2900 | "winapi-util", 2901 | ] 2902 | 2903 | [[package]] 2904 | name = "want" 2905 | version = "0.3.0" 2906 | source = "registry+https://github.com/rust-lang/crates.io-index" 2907 | checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" 2908 | dependencies = [ 2909 | "log", 2910 | "try-lock", 2911 | ] 2912 | 2913 | [[package]] 2914 | name = "wasi" 2915 | version = "0.9.0+wasi-snapshot-preview1" 2916 | source = "registry+https://github.com/rust-lang/crates.io-index" 2917 | checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 2918 | 2919 | [[package]] 2920 | name = "wasi" 2921 | version = "0.10.2+wasi-snapshot-preview1" 2922 | source = "registry+https://github.com/rust-lang/crates.io-index" 2923 | checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" 2924 | 2925 | [[package]] 2926 | name = "wasm-bindgen" 2927 | version = "0.2.79" 2928 | source = "registry+https://github.com/rust-lang/crates.io-index" 2929 | checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" 2930 | dependencies = [ 2931 | "cfg-if 1.0.0", 2932 | "wasm-bindgen-macro", 2933 | ] 2934 | 2935 | [[package]] 2936 | name = "wasm-bindgen-backend" 2937 | version = "0.2.79" 2938 | source = "registry+https://github.com/rust-lang/crates.io-index" 2939 | checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" 2940 | dependencies = [ 2941 | "bumpalo", 2942 | "lazy_static", 2943 | "log", 2944 | "proc-macro2", 2945 | "quote", 2946 | "syn", 2947 | "wasm-bindgen-shared", 2948 | ] 2949 | 2950 | [[package]] 2951 | name = "wasm-bindgen-futures" 2952 | version = "0.4.29" 2953 | source = "registry+https://github.com/rust-lang/crates.io-index" 2954 | checksum = "2eb6ec270a31b1d3c7e266b999739109abce8b6c87e4b31fcfcd788b65267395" 2955 | dependencies = [ 2956 | "cfg-if 1.0.0", 2957 | "js-sys", 2958 | "wasm-bindgen", 2959 | "web-sys", 2960 | ] 2961 | 2962 | [[package]] 2963 | name = "wasm-bindgen-macro" 2964 | version = "0.2.79" 2965 | source = "registry+https://github.com/rust-lang/crates.io-index" 2966 | checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" 2967 | dependencies = [ 2968 | "quote", 2969 | "wasm-bindgen-macro-support", 2970 | ] 2971 | 2972 | [[package]] 2973 | name = "wasm-bindgen-macro-support" 2974 | version = "0.2.79" 2975 | source = "registry+https://github.com/rust-lang/crates.io-index" 2976 | checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" 2977 | dependencies = [ 2978 | "proc-macro2", 2979 | "quote", 2980 | "syn", 2981 | "wasm-bindgen-backend", 2982 | "wasm-bindgen-shared", 2983 | ] 2984 | 2985 | [[package]] 2986 | name = "wasm-bindgen-shared" 2987 | version = "0.2.79" 2988 | source = "registry+https://github.com/rust-lang/crates.io-index" 2989 | checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" 2990 | 2991 | [[package]] 2992 | name = "web-sys" 2993 | version = "0.3.56" 2994 | source = "registry+https://github.com/rust-lang/crates.io-index" 2995 | checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" 2996 | dependencies = [ 2997 | "js-sys", 2998 | "wasm-bindgen", 2999 | ] 3000 | 3001 | [[package]] 3002 | name = "webpki" 3003 | version = "0.22.0" 3004 | source = "registry+https://github.com/rust-lang/crates.io-index" 3005 | checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" 3006 | dependencies = [ 3007 | "ring", 3008 | "untrusted", 3009 | ] 3010 | 3011 | [[package]] 3012 | name = "webpki-roots" 3013 | version = "0.22.2" 3014 | source = "registry+https://github.com/rust-lang/crates.io-index" 3015 | checksum = "552ceb903e957524388c4d3475725ff2c8b7960922063af6ce53c9a43da07449" 3016 | dependencies = [ 3017 | "webpki", 3018 | ] 3019 | 3020 | [[package]] 3021 | name = "which" 3022 | version = "4.2.4" 3023 | source = "registry+https://github.com/rust-lang/crates.io-index" 3024 | checksum = "2a5a7e487e921cf220206864a94a89b6c6905bfc19f1057fa26a4cb360e5c1d2" 3025 | dependencies = [ 3026 | "either", 3027 | "lazy_static", 3028 | "libc", 3029 | ] 3030 | 3031 | [[package]] 3032 | name = "winapi" 3033 | version = "0.3.9" 3034 | source = "registry+https://github.com/rust-lang/crates.io-index" 3035 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 3036 | dependencies = [ 3037 | "winapi-i686-pc-windows-gnu", 3038 | "winapi-x86_64-pc-windows-gnu", 3039 | ] 3040 | 3041 | [[package]] 3042 | name = "winapi-i686-pc-windows-gnu" 3043 | version = "0.4.0" 3044 | source = "registry+https://github.com/rust-lang/crates.io-index" 3045 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 3046 | 3047 | [[package]] 3048 | name = "winapi-util" 3049 | version = "0.1.5" 3050 | source = "registry+https://github.com/rust-lang/crates.io-index" 3051 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 3052 | dependencies = [ 3053 | "winapi", 3054 | ] 3055 | 3056 | [[package]] 3057 | name = "winapi-x86_64-pc-windows-gnu" 3058 | version = "0.4.0" 3059 | source = "registry+https://github.com/rust-lang/crates.io-index" 3060 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 3061 | 3062 | [[package]] 3063 | name = "windows-sys" 3064 | version = "0.32.0" 3065 | source = "registry+https://github.com/rust-lang/crates.io-index" 3066 | checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6" 3067 | dependencies = [ 3068 | "windows_aarch64_msvc", 3069 | "windows_i686_gnu", 3070 | "windows_i686_msvc", 3071 | "windows_x86_64_gnu", 3072 | "windows_x86_64_msvc", 3073 | ] 3074 | 3075 | [[package]] 3076 | name = "windows_aarch64_msvc" 3077 | version = "0.32.0" 3078 | source = "registry+https://github.com/rust-lang/crates.io-index" 3079 | checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" 3080 | 3081 | [[package]] 3082 | name = "windows_i686_gnu" 3083 | version = "0.32.0" 3084 | source = "registry+https://github.com/rust-lang/crates.io-index" 3085 | checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" 3086 | 3087 | [[package]] 3088 | name = "windows_i686_msvc" 3089 | version = "0.32.0" 3090 | source = "registry+https://github.com/rust-lang/crates.io-index" 3091 | checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" 3092 | 3093 | [[package]] 3094 | name = "windows_x86_64_gnu" 3095 | version = "0.32.0" 3096 | source = "registry+https://github.com/rust-lang/crates.io-index" 3097 | checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" 3098 | 3099 | [[package]] 3100 | name = "windows_x86_64_msvc" 3101 | version = "0.32.0" 3102 | source = "registry+https://github.com/rust-lang/crates.io-index" 3103 | checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" 3104 | 3105 | [[package]] 3106 | name = "winreg" 3107 | version = "0.7.0" 3108 | source = "registry+https://github.com/rust-lang/crates.io-index" 3109 | checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" 3110 | dependencies = [ 3111 | "winapi", 3112 | ] 3113 | 3114 | [[package]] 3115 | name = "wyz" 3116 | version = "0.5.0" 3117 | source = "registry+https://github.com/rust-lang/crates.io-index" 3118 | checksum = "30b31594f29d27036c383b53b59ed3476874d518f0efb151b27a4c275141390e" 3119 | dependencies = [ 3120 | "tap", 3121 | ] 3122 | 3123 | [[package]] 3124 | name = "xsalsa20poly1305" 3125 | version = "0.6.0" 3126 | source = "registry+https://github.com/rust-lang/crates.io-index" 3127 | checksum = "0304c336e98d753428f7b3d8899d60b8a87a961ef50bdfc44af0c1bea2651ce5" 3128 | dependencies = [ 3129 | "aead 0.3.2", 3130 | "poly1305", 3131 | "rand_core 0.5.1", 3132 | "salsa20", 3133 | "subtle", 3134 | "zeroize", 3135 | ] 3136 | 3137 | [[package]] 3138 | name = "zeroize" 3139 | version = "1.5.2" 3140 | source = "registry+https://github.com/rust-lang/crates.io-index" 3141 | checksum = "7c88870063c39ee00ec285a2f8d6a966e5b6fb2becc4e8dac77ed0d370ed6006" 3142 | dependencies = [ 3143 | "zeroize_derive", 3144 | ] 3145 | 3146 | [[package]] 3147 | name = "zeroize_derive" 3148 | version = "1.3.1" 3149 | source = "registry+https://github.com/rust-lang/crates.io-index" 3150 | checksum = "81e8f13fef10b63c06356d65d416b070798ddabcadc10d3ece0c5be9b3c7eddb" 3151 | dependencies = [ 3152 | "proc-macro2", 3153 | "quote", 3154 | "syn", 3155 | "synstructure", 3156 | ] 3157 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "helium-ledger" 3 | version = "2.2.4-alpha.1" 4 | authors = ["Louis Thiery "] 5 | edition = "2021" 6 | publish = false 7 | 8 | description = "A Rust Helium Ledger library" 9 | readme = "README.md" 10 | keywords = ["helium", "blockchain", "wallet", "ledger", "hardware wallet"] 11 | 12 | license = "Apache-2.0" 13 | 14 | [[bin]] 15 | name = "helium-ledger-cli" 16 | path = "src/main.rs" 17 | doc = false 18 | 19 | [dependencies] 20 | anyhow = "1" 21 | thiserror = "1" 22 | byteorder = "1" 23 | structopt = "0" 24 | helium-api = "3.3" 25 | helium-wallet = { git = "https://github.com/helium/helium-wallet-rs" } 26 | helium-crypto = {git = "https://github.com/helium/helium-crypto-rs", tag="v0.3.3"} 27 | helium-proto = { git = "https://github.com/helium/proto", branch="master"} 28 | prettytable-rs = "0" 29 | bs58 = {version = "0", features=["check"]} 30 | base64 = "0" 31 | rust_decimal = "1" 32 | prost = "0" 33 | qr2term = "0" 34 | serde = { version = "1", features = ["derive"] } 35 | serde_json = "1" 36 | tokio = {version = "1.2", features = ["full"]} 37 | 38 | [dependencies.ledger-transport] 39 | git = "https://github.com/helium/ledger-rs" 40 | branch = "lthiery/tcp-transport" 41 | default-features = false 42 | features = ["transport-hid", "transport-tcp"] 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2018 Helium Systems, Inc. 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Companion Application 2 | 3 | This is the companion application to be run on a laptop or desktop running Linux, Mac, or Windows. It submits the parameters of your requests to the Ledger Hardware Wallets, which will then display the information for confirmation. 4 | 5 | It is important to use the Ledger's display as the source of truth when confirming transactions as it is much more secure than your laptop or desktop and a compromised version of this application could be running. 6 | 7 | # Usage 8 | 9 | Please [use the documentation here](https://docs.helium.com/wallets/ledger) to learn how to use your Ledger hardware wallet with this companion app. 10 | -------------------------------------------------------------------------------- /src/cmd/balance.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use helium_api::models::Account; 3 | 4 | #[derive(Debug, StructOpt)] 5 | pub struct Cmd { 6 | /// Display QR code for a given single wallet. 7 | #[structopt(long = "qr")] 8 | pub qr_code: bool, 9 | /// Scans all accounts up until selected account index 10 | /// This is useful for displaying all balances 11 | #[structopt(long = "scan")] 12 | pub scan: bool, 13 | } 14 | 15 | impl Cmd { 16 | pub async fn run(self, opts: Opts, version: Version) -> Result> { 17 | if version.major < 2 && opts.account != 0 { 18 | panic!("Upgrade the Helium Ledger App to use additional wallet accounts"); 19 | }; 20 | let ledger_transport = get_ledger_transport(&opts).await?; 21 | if self.scan { 22 | if self.qr_code { 23 | println!("WARNING: to output a QR Code, do not use scan") 24 | } 25 | let mut account_results = Vec::new(); 26 | let network = version.network; 27 | for i in 0..opts.account { 28 | let pubkey = get_pubkey(i, &ledger_transport, PubkeyDisplay::Off).await?; 29 | let client = new_client(pubkey.network); 30 | let address = pubkey.to_string(); 31 | let result = accounts::get(&client, &address).await; 32 | account_results.push((pubkey, result)); 33 | } 34 | print_balance(network, &account_results).await?; 35 | } else { 36 | let pubkey = get_pubkey(opts.account, &ledger_transport, PubkeyDisplay::Off).await?; 37 | let pubkey_str = pubkey.to_string(); 38 | let client = new_client(pubkey.network); 39 | let address = pubkey.to_string(); 40 | let result = accounts::get(&client, &address).await; 41 | print_balance(pubkey.network, &vec![(pubkey, result)]).await?; 42 | if self.qr_code { 43 | print_qr(&pubkey_str)?; 44 | } 45 | // display pubkey on screen for comparison 46 | let _pubkey = get_pubkey(opts.account, &ledger_transport, PubkeyDisplay::On).await?; 47 | } 48 | Ok(None) 49 | } 50 | } 51 | 52 | /// The ResultsVec is used so that a failure made "at some point" while 53 | /// fetching all of the addresses does not ruin all previous or preceding 54 | /// addresses 55 | type ResultsVec = Vec<(PublicKey, std::result::Result)>; 56 | 57 | async fn print_balance(network: Network, results: &ResultsVec) -> Result { 58 | let mut table = Table::new(); 59 | table.set_format(*format::consts::FORMAT_NO_LINESEP_WITH_TITLE); 60 | let balance = match network { 61 | Network::TestNet => "Balance TNT", 62 | Network::MainNet => "Balance HNT", 63 | }; 64 | 65 | let staked_balance = match network { 66 | Network::TestNet => "Staked TNT", 67 | Network::MainNet => "Staked HNT", 68 | }; 69 | 70 | let mobile_balance = match network { 71 | Network::TestNet => "Balance TOBILE", 72 | Network::MainNet => "Balance MOBILE", 73 | }; 74 | 75 | let iot_balance = match network { 76 | Network::TestNet => "Balance TOT", 77 | Network::MainNet => "Balance IOT", 78 | }; 79 | 80 | let security_tokens = match network { 81 | Network::TestNet => "Testnet ST", 82 | Network::MainNet => "Security Tokens", 83 | }; 84 | 85 | if results.len() > 1 { 86 | table.set_titles(row![ 87 | "Index", 88 | "Wallet", 89 | balance, 90 | staked_balance, 91 | "Data Credits", 92 | security_tokens, 93 | iot_balance, 94 | mobile_balance, 95 | ]); 96 | } else { 97 | table.set_titles(row![ 98 | "Wallet 0", 99 | balance, 100 | staked_balance, 101 | "Data Credits", 102 | security_tokens, 103 | iot_balance, 104 | mobile_balance, 105 | ]); 106 | } 107 | for (account_index, (pubkey, result)) in results.iter().enumerate() { 108 | let address = pubkey.to_string(); 109 | if results.len() > 1 { 110 | match result { 111 | Ok(account) => table.add_row(row![ 112 | account_index, 113 | address, 114 | account.balance, 115 | account.staked_balance, 116 | account.dc_balance, 117 | account.sec_balance, 118 | account.iot_balance, 119 | account.mobile_balance, 120 | ]), 121 | Err(err) => table.add_row(row![account_index, address, H3 -> err.to_string()]), 122 | }; 123 | } else { 124 | match result { 125 | Ok(account) => table.add_row(row![ 126 | address, 127 | account.balance, 128 | account.staked_balance, 129 | account.dc_balance, 130 | account.sec_balance, 131 | account.iot_balance, 132 | account.mobile_balance, 133 | ]), 134 | Err(err) => table.add_row(row![address, H3 -> err.to_string()]), 135 | }; 136 | } 137 | } 138 | 139 | table.printstd(); 140 | Ok(()) 141 | } 142 | -------------------------------------------------------------------------------- /src/cmd/burn.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use memo::Memo; 3 | use std::str::FromStr; 4 | 5 | #[derive(Debug, StructOpt)] 6 | /// Burn HNT to Data Credits (DC) from this wallet to given payees wallet. 7 | pub struct Cmd { 8 | /// Account address to send the resulting DC to. 9 | #[structopt(long)] 10 | payee: PublicKey, 11 | 12 | /// Memo field to include. Provide as a base64 encoded string 13 | #[structopt(long, default_value)] 14 | memo: Memo, 15 | 16 | /// Amount of HNT to burn to DC 17 | #[structopt(long)] 18 | amount: Hnt, 19 | 20 | /// Manually set the nonce to use for the transaction 21 | #[structopt(long)] 22 | nonce: Option, 23 | 24 | /// Manually set the DC fee to pay for the transaction 25 | #[structopt(long)] 26 | fee: Option, 27 | } 28 | 29 | impl Cmd { 30 | pub async fn run(self, opts: Opts, version: Version) -> Result> { 31 | if version.major < 2 && (version.major == 2 && version.minor < 2) && opts.account != 0 { 32 | panic!("Upgrade the Helium Ledger App to use additional wallet accounts"); 33 | }; 34 | 35 | match ledger(opts, self).await? { 36 | Response::Txn(_txn, hash, network) => Ok(Some((hash, network))), 37 | Response::InsufficientHntBalance(balance, send_request) => { 38 | println!( 39 | "Account balance insufficient. {} HNT on account but attempting to burn {}", 40 | balance, send_request, 41 | ); 42 | Err(Error::txn()) 43 | } 44 | Response::InsufficientIotBalance(balance, send_request) => { 45 | println!( 46 | "Account balance insufficient. {} IOT on account but attempting to send {}", 47 | balance, send_request, 48 | ); 49 | Err(Error::txn()) 50 | } 51 | Response::InsufficientMobBalance(balance, send_request) => { 52 | println!( 53 | "Account balance insufficient. {} MOBILE on account but attempting to send {}", 54 | balance, send_request, 55 | ); 56 | Err(Error::txn()) 57 | } 58 | Response::InsufficientHstBalance(balance, send_request) => { 59 | println!( 60 | "Account balance insufficient. {} HST on account but attempting to send {}", 61 | balance, send_request, 62 | ); 63 | Err(Error::txn()) 64 | } 65 | Response::InsufficientSecBalance(balance, send_request) => { 66 | println!( 67 | "Account security balance insufficient. {} HST on account but attempting to transfer {}", 68 | balance, send_request, 69 | ); 70 | Err(Error::txn()) 71 | } 72 | Response::UserDeniedTransaction => { 73 | println!("Transaction not confirmed"); 74 | Err(Error::txn()) 75 | } 76 | } 77 | } 78 | } 79 | 80 | async fn ledger(opts: Opts, cmd: Cmd) -> Result> { 81 | let ledger_transport = get_ledger_transport(&opts).await?; 82 | let amount = cmd.amount; 83 | let payee = cmd.payee; 84 | 85 | // get nonce 86 | let pubkey = get_pubkey(opts.account, &ledger_transport, PubkeyDisplay::Off).await?; 87 | let client = new_client(pubkey.network); 88 | 89 | let account = accounts::get(&client, &pubkey.to_string()).await?; 90 | let nonce: u64 = if let Some(nonce) = cmd.nonce { 91 | nonce 92 | } else { 93 | account.speculative_nonce + 1 94 | }; 95 | 96 | if account.balance.get_decimal() < amount.get_decimal() { 97 | return Ok(Response::InsufficientHntBalance( 98 | account.balance, 99 | Hnt::new(amount.get_decimal()), 100 | )); 101 | } 102 | // serialize payer 103 | let payer = PublicKey::from_str(&account.address)?; 104 | 105 | let mut txn = BlockchainTxnTokenBurnV1 { 106 | payee: payee.to_vec(), 107 | payer: payer.to_vec(), 108 | amount: u64::from(amount), 109 | memo: u64::from(&cmd.memo), 110 | nonce, 111 | fee: 0, 112 | signature: vec![], 113 | }; 114 | txn.fee = if let Some(fee) = cmd.fee { 115 | fee 116 | } else { 117 | txn.txn_fee( 118 | &get_txn_fees(&client) 119 | .await 120 | .map_err(|_| Error::getting_fees())?, 121 | ) 122 | .map_err(|_| Error::getting_fees())? 123 | }; 124 | 125 | print_proposed_txn(&txn)?; 126 | 127 | let adpu_cmd = txn.apdu_serialize(opts.account)?; 128 | 129 | let exchange_pay_tx_result = read_from_ledger(&ledger_transport, adpu_cmd).await?; 130 | 131 | if exchange_pay_tx_result.data.len() == 1 { 132 | return Ok(Response::UserDeniedTransaction); 133 | } 134 | let data = exchange_pay_tx_result.data; 135 | let txn = BlockchainTxnTokenBurnV1::decode(data.as_slice())?; 136 | 137 | let envelope = txn.in_envelope(); 138 | // submit the signed tansaction to the API 139 | let pending_txn_status = submit_txn(&client, &envelope).await?; 140 | 141 | Ok(Response::Txn(txn, pending_txn_status.hash, payer.network)) 142 | } 143 | 144 | pub fn print_proposed_txn(txn: &BlockchainTxnTokenBurnV1) -> Result { 145 | let payee = PublicKey::try_from(txn.payee.clone())?; 146 | let units = match payee.network { 147 | Network::TestNet => "TNT", 148 | Network::MainNet => "HNT", 149 | }; 150 | 151 | let mut table = Table::new(); 152 | println!("Creating the following transaction:"); 153 | table.add_row(row![ 154 | "Payee", 155 | &format!("Burn Amount {}", units), 156 | "Memo", 157 | "Nonce", 158 | "DC Fee" 159 | ]); 160 | table.add_row(row![ 161 | payee, 162 | Hnt::from(txn.amount), 163 | Memo::from(txn.memo), 164 | txn.nonce, 165 | txn.fee 166 | ]); 167 | table.printstd(); 168 | println!( 169 | "WARNING: do not use this output as the source of truth. Instead, rely \ 170 | on the Ledger Display" 171 | ); 172 | Ok(()) 173 | } 174 | -------------------------------------------------------------------------------- /src/cmd/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::*; 2 | use byteorder::{LittleEndian as LE, WriteBytesExt}; 3 | use helium_api::{ 4 | accounts, 5 | models::{Hnt, Hst, Iot, Mobile, Token}, 6 | }; 7 | pub use helium_proto::{ 8 | BlockchainTxnPaymentV1, BlockchainTxnPaymentV2, BlockchainTxnSecurityExchangeV1, 9 | BlockchainTxnStakeValidatorV1, BlockchainTxnTokenBurnV1, BlockchainTxnTransferValidatorStakeV1, 10 | BlockchainTxnUnstakeValidatorV1, Payment, 11 | }; 12 | pub use helium_wallet::{ 13 | keypair::{Network, PublicKey}, 14 | traits::{TxnEnvelope, TxnFee, TxnFeeConfig}, 15 | }; 16 | pub use ledger_transport::*; 17 | pub use prost::Message; 18 | use std::convert::TryFrom; 19 | 20 | pub mod balance; 21 | pub mod burn; 22 | pub mod pay; 23 | pub mod serializer; 24 | pub mod validator; 25 | 26 | pub use serializer::*; 27 | 28 | const RETURN_CODE_OK: u16 = 0x9000; 29 | 30 | // This parameter indicates whether the ledgers screen display the public key or not 31 | // Thus, the `pay` function can do the Adpu transaction quietly to get the public key 32 | #[derive(Copy, Clone)] 33 | pub enum PubkeyDisplay { 34 | Off = 0, 35 | On = 1, 36 | } 37 | 38 | pub async fn get_ledger_transport(opts: &Opts) -> Result> { 39 | Ok(if let Some(port) = opts.emulator { 40 | use std::net::{IpAddr, Ipv4Addr, SocketAddr}; 41 | let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port); 42 | Box::new(TransportTcp::new(socket).await?) 43 | } else { 44 | Box::new(TransportNativeHID::new()?) 45 | }) 46 | } 47 | 48 | pub async fn get_app_version(opts: &Opts) -> Result { 49 | let ledger = get_ledger_transport(opts).await?; 50 | let request = VersionRequest.apdu_serialize(0)?; 51 | let read = read_from_ledger(&ledger, request).await?; 52 | let data = read.data; 53 | if read.retcode == RETURN_CODE_OK { 54 | if data.len() == 4 { 55 | Ok(Version::from_bytes([data[0], data[1], data[2], data[3]])?) 56 | } else { 57 | Err(Error::VersionError(format!( 58 | "Your ledger application may not be running or require an update. \ 59 | Unexpected response from ledger ({} bytes).", 60 | data.len() 61 | ))) 62 | } 63 | } else { 64 | Err(Error::VersionError( 65 | "App unresponsive. Is it waiting for a command?".to_string(), 66 | )) 67 | } 68 | } 69 | #[allow(clippy::borrowed_box)] 70 | pub async fn get_pubkey( 71 | account: u8, 72 | ledger: &Box, 73 | display: PubkeyDisplay, 74 | ) -> Result { 75 | let cmd = PubkeyRequest { display }.apdu_serialize(account)?; 76 | let public_key_result = read_from_ledger(ledger, cmd).await?; 77 | Ok(PublicKey::try_from(&public_key_result.data[1..34])?) 78 | } 79 | 80 | pub enum Response { 81 | Txn(T, String, Network), 82 | InsufficientHntBalance(Hnt, Hnt), 83 | InsufficientIotBalance(Iot, Iot), 84 | InsufficientMobBalance(Mobile, Mobile), 85 | InsufficientHstBalance(Hst, Hst), 86 | InsufficientSecBalance(Hst, Hst), 87 | /// to deprecate when deprecating sec 88 | UserDeniedTransaction, 89 | } 90 | 91 | #[allow(clippy::borrowed_box)] 92 | pub async fn read_from_ledger( 93 | ledger: &Box, 94 | command: APDUCommand, 95 | ) -> Result { 96 | let answer = ledger.exchange(&command).await?; 97 | 98 | if answer.data.is_empty() { 99 | Err(Error::AppNotRunning) 100 | } else { 101 | Ok(answer) 102 | } 103 | } 104 | 105 | pub async fn get_txn_fees(client: &Client) -> Result { 106 | let vars = helium_api::vars::get(client).await?; 107 | if vars.contains_key("txn_fees") { 108 | match vars["txn_fees"].as_bool() { 109 | Some(true) => { 110 | let config: TxnFeeConfig = serde_json::from_value(serde_json::Value::Object(vars))?; 111 | Ok(config) 112 | } 113 | _ => Ok(TxnFeeConfig::legacy()), 114 | } 115 | } else { 116 | Ok(TxnFeeConfig::legacy()) 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/cmd/pay.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use crate::memo::Memo; 3 | use helium_api::models::Account; 4 | use helium_proto::BlockchainTokenTypeV1; 5 | use serde::Deserialize; 6 | use std::str::FromStr; 7 | 8 | #[derive(Debug, Deserialize)] 9 | pub enum TokenInput { 10 | Hnt, 11 | Iot, 12 | Mobile, 13 | Hst, 14 | } 15 | 16 | #[derive(Debug, StructOpt)] 17 | pub struct Cmd { 18 | /// Address to send the tokens to 19 | address: PublicKey, 20 | /// Amount of token to send 21 | amount: Token, 22 | /// Type of token to send (hnt, iot, mobile, hst). 23 | #[structopt(default_value = "hnt")] 24 | token: TokenInput, 25 | /// Memo field to include. Provide as a base64 encoded string 26 | #[structopt(long, default_value = "AAAAAAAAAAA=")] 27 | memo: Memo, 28 | /// Manually set the DC fee to pay for the transaction 29 | #[structopt(long)] 30 | fee: Option, 31 | /// Manually set the nonce for the transaction 32 | #[structopt(long)] 33 | nonce: Option, 34 | } 35 | 36 | impl Cmd { 37 | pub async fn run(self, opts: Opts, version: Version) -> Result> { 38 | if version.major < 2 && opts.account != 0 { 39 | panic!("Upgrade the Helium Ledger App to use additional wallet accounts"); 40 | }; 41 | 42 | // must be versions after 2.2.3 to support payment_v2 43 | if version.major > 2 44 | || version.major == 2 && version.minor > 2 45 | || version.major == 2 && version.minor == 2 && version.revision >= 3 46 | { 47 | match ledger_v2(opts, self).await? { 48 | Response::Txn(_txn, hash, network) => Ok(Some((hash, network))), 49 | Response::InsufficientHntBalance(balance, send_request) => { 50 | println!( 51 | "Account balance insufficient. {} HNT on account but attempting to send {}", 52 | balance, send_request, 53 | ); 54 | Err(Error::txn()) 55 | } 56 | Response::InsufficientIotBalance(balance, send_request) => { 57 | println!( 58 | "Account balance insufficient. {} IOT on account but attempting to send {}", 59 | balance, send_request, 60 | ); 61 | Err(Error::txn()) 62 | } 63 | Response::InsufficientMobBalance(balance, send_request) => { 64 | println!( 65 | "Account balance insufficient. {} MOBILE on account but attempting to send {}", 66 | balance, send_request, 67 | ); 68 | Err(Error::txn()) 69 | } 70 | Response::InsufficientHstBalance(balance, send_request) => { 71 | println!( 72 | "Account balance insufficient. {} HST on account but attempting to send {}", 73 | balance, send_request, 74 | ); 75 | Err(Error::txn()) 76 | } 77 | Response::InsufficientSecBalance(balance, send_request) => { 78 | println!( 79 | "Account security balance insufficient. {} HST on account but attempting to send {}", 80 | balance, send_request, 81 | ); 82 | Err(Error::txn()) 83 | } 84 | Response::UserDeniedTransaction => { 85 | println!("Transaction not confirmed"); 86 | Err(Error::txn()) 87 | } 88 | } 89 | } else { 90 | Err(Error::UnsupportedLedgerVersion) 91 | } 92 | } 93 | } 94 | 95 | async fn ledger_v2(opts: Opts, cmd: Cmd) -> Result> { 96 | let ledger_transport = get_ledger_transport(&opts).await?; 97 | let amount = cmd.amount; 98 | let payee = cmd.address; 99 | 100 | // get nonce 101 | let pubkey = get_pubkey(opts.account, &ledger_transport, PubkeyDisplay::Off).await?; 102 | let client = new_client(pubkey.network); 103 | 104 | let account = accounts::get(&client, &pubkey.to_string()).await?; 105 | let nonce: u64 = if let Some(nonce) = cmd.nonce { 106 | nonce 107 | } else { 108 | account.speculative_nonce + 1 109 | }; 110 | 111 | if let Some(response) = invalid_balance_response(&cmd.token, &account, amount) { 112 | return Ok(response); 113 | } 114 | 115 | let payment = Payment { 116 | payee: payee.to_vec(), 117 | amount: u64::from(amount), 118 | memo: u64::from(&cmd.memo), 119 | max: false, 120 | token_type: match cmd.token { 121 | TokenInput::Hnt => BlockchainTokenTypeV1::Hnt.into(), 122 | TokenInput::Hst => BlockchainTokenTypeV1::Hst.into(), 123 | TokenInput::Iot => BlockchainTokenTypeV1::Iot.into(), 124 | TokenInput::Mobile => BlockchainTokenTypeV1::Mobile.into(), 125 | }, 126 | }; 127 | 128 | let mut txn = BlockchainTxnPaymentV2 { 129 | payer: pubkey.to_vec(), 130 | payments: vec![payment], 131 | nonce, 132 | fee: 0, 133 | signature: vec![], 134 | }; 135 | txn.fee = if let Some(fee) = cmd.fee { 136 | fee 137 | } else { 138 | txn.txn_fee( 139 | &get_txn_fees(&client) 140 | .await 141 | .map_err(|_| Error::getting_fees())?, 142 | ) 143 | .map_err(|_| Error::getting_fees())? 144 | }; 145 | 146 | print_proposed_txn_v2(&txn)?; 147 | 148 | let adpu_cmd = txn.apdu_serialize(opts.account)?; 149 | 150 | let exchange_pay_tx_result = read_from_ledger(&ledger_transport, adpu_cmd).await?; 151 | 152 | if exchange_pay_tx_result.data.len() == 1 { 153 | return Ok(Response::UserDeniedTransaction); 154 | } 155 | 156 | let txn = BlockchainTxnPaymentV2::decode(exchange_pay_tx_result.data.as_slice())?; 157 | let payer = PublicKey::from_bytes(&txn.payer)?; 158 | 159 | let envelope = txn.in_envelope(); 160 | // submit the signed tansaction to the API 161 | let pending_txn_status = submit_txn(&client, &envelope).await?; 162 | 163 | Ok(Response::Txn(txn, pending_txn_status.hash, payer.network)) 164 | } 165 | 166 | pub fn print_proposed_txn_v2(txn: &BlockchainTxnPaymentV2) -> Result { 167 | let payment = &txn.payments[0]; 168 | let payee = PublicKey::try_from(payment.payee.clone())?; 169 | let token_type = BlockchainTokenTypeV1::from_i32(txn.payments[0].token_type) 170 | .expect("Invalid token_type found in transaction!"); 171 | let units = match payee.network { 172 | Network::TestNet => match token_type { 173 | BlockchainTokenTypeV1::Hnt => "TNT", 174 | BlockchainTokenTypeV1::Hst => "TST", 175 | BlockchainTokenTypeV1::Iot => "TOT", 176 | BlockchainTokenTypeV1::Mobile => "TOBILE", 177 | }, 178 | Network::MainNet => match token_type { 179 | BlockchainTokenTypeV1::Hnt => "HNT", 180 | BlockchainTokenTypeV1::Hst => "HST", 181 | BlockchainTokenTypeV1::Iot => "IOT", 182 | BlockchainTokenTypeV1::Mobile => "MOBILE", 183 | }, 184 | }; 185 | 186 | let mut table = Table::new(); 187 | println!("Creating the following transaction:"); 188 | table.add_row(row![ 189 | "Payee", 190 | &format!("Pay Amount {}", units), 191 | "Nonce", 192 | "Memo", 193 | "DC Fee" 194 | ]); 195 | table.add_row(row![ 196 | payee, 197 | Token::from(payment.amount), 198 | txn.nonce, 199 | Memo::from(payment.memo).to_string(), 200 | txn.fee 201 | ]); 202 | table.printstd(); 203 | println!( 204 | "WARNING: do not use this output as the source of truth. Instead, rely \ 205 | on the Ledger Display" 206 | ); 207 | Ok(()) 208 | } 209 | 210 | impl FromStr for TokenInput { 211 | type Err = Error; 212 | 213 | fn from_str(s: &str) -> Result { 214 | let s = s.to_lowercase(); 215 | match s.as_str() { 216 | "hnt" => Ok(TokenInput::Hnt), 217 | "iot" => Ok(TokenInput::Iot), 218 | "mob" | "mobile" => Ok(TokenInput::Mobile), 219 | "hst" => Ok(TokenInput::Hst), 220 | _ => Err(Error::TokenTypeInput(s)), 221 | } 222 | } 223 | } 224 | 225 | fn invalid_balance_response( 226 | token: &TokenInput, 227 | account: &Account, 228 | amount: Token, 229 | ) -> Option> { 230 | match token { 231 | TokenInput::Hnt => { 232 | if account.balance.get_decimal() < amount.get_decimal() { 233 | return Some(Response::InsufficientHntBalance( 234 | account.balance, 235 | Hnt::new(amount.get_decimal()), 236 | )); 237 | } 238 | } 239 | TokenInput::Hst => { 240 | if account.sec_balance.get_decimal() < amount.get_decimal() { 241 | return Some(Response::InsufficientHstBalance( 242 | account.sec_balance, 243 | Hst::new(amount.get_decimal()), 244 | )); 245 | } 246 | } 247 | TokenInput::Iot => { 248 | if account.iot_balance.get_decimal() < amount.get_decimal() { 249 | return Some(Response::InsufficientIotBalance( 250 | account.iot_balance, 251 | Iot::new(amount.get_decimal()), 252 | )); 253 | } 254 | } 255 | TokenInput::Mobile => { 256 | if account.mobile_balance.get_decimal() < amount.get_decimal() { 257 | return Some(Response::InsufficientMobBalance( 258 | account.mobile_balance, 259 | Mobile::new(amount.get_decimal()), 260 | )); 261 | } 262 | } 263 | }; 264 | None 265 | } 266 | -------------------------------------------------------------------------------- /src/cmd/serializer.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | pub const INS_GET_VERSION: u8 = 0x01; 4 | pub const INS_GET_PUBLIC_KEY: u8 = 0x02; 5 | pub const INS_SIGN_PAYMENT_TXN: u8 = 0x08; 6 | pub const INS_SIGN_VALIDATOR_STAKE_TXN: u8 = 0x09; 7 | pub const INS_SIGN_VALIDATOR_TXFER_TXN: u8 = 0x0A; 8 | pub const INS_SIGN_VALIDATOR_UNSTAKE_TXN: u8 = 0x0B; 9 | pub const INS_SIGN_BURN_TXN: u8 = 0x0C; 10 | pub const INS_SIGN_TRANSFER_SEC_TXN: u8 = 0x0D; 11 | 12 | pub trait ApduSerializer { 13 | fn apdu_serialize(&self, account: u8) -> Result; 14 | } 15 | 16 | pub struct VersionRequest; 17 | 18 | impl ApduSerializer for VersionRequest { 19 | fn apdu_serialize(&self, _account: u8) -> Result { 20 | Ok(APDUCommand { 21 | cla: 0xe0, 22 | ins: INS_GET_VERSION, 23 | p1: 0x00, 24 | p2: 0x00, 25 | data: vec![], 26 | }) 27 | } 28 | } 29 | 30 | pub struct PubkeyRequest { 31 | pub display: PubkeyDisplay, 32 | } 33 | 34 | impl ApduSerializer for PubkeyRequest { 35 | fn apdu_serialize(&self, account: u8) -> Result { 36 | Ok(APDUCommand { 37 | cla: 0xe0, 38 | ins: INS_GET_PUBLIC_KEY, 39 | p1: self.display as u8, 40 | p2: account, 41 | data: vec![], 42 | }) 43 | } 44 | } 45 | 46 | impl ApduSerializer for BlockchainTxnPaymentV1 { 47 | fn apdu_serialize(&self, account: u8) -> Result { 48 | let mut data = Vec::new(); 49 | data.write_u64::(self.amount)?; 50 | data.write_u64::(self.fee)?; 51 | data.write_u64::(self.nonce)?; 52 | data.push(0); 53 | data.extend(self.payee.clone()); 54 | 55 | Ok(APDUCommand { 56 | cla: 0xe0, 57 | ins: INS_SIGN_PAYMENT_TXN, 58 | p1: account, 59 | p2: 0x00, 60 | data, 61 | }) 62 | } 63 | } 64 | 65 | impl ApduSerializer for BlockchainTxnPaymentV2 { 66 | fn apdu_serialize(&self, account: u8) -> Result { 67 | let mut data = Vec::new(); 68 | let payment = &self.payments[0]; 69 | data.write_u64::(payment.amount)?; 70 | data.write_u64::(self.fee)?; 71 | data.write_u64::(self.nonce)?; 72 | data.push(0); 73 | data.extend(payment.payee.clone()); 74 | data.write_u64::(payment.memo)?; 75 | data.write_u8(payment.token_type as u8)?; 76 | 77 | Ok(APDUCommand { 78 | cla: 0xe0, 79 | ins: INS_SIGN_PAYMENT_TXN, 80 | p1: account, 81 | p2: 0x00, 82 | data, 83 | }) 84 | } 85 | } 86 | 87 | impl ApduSerializer for BlockchainTxnStakeValidatorV1 { 88 | fn apdu_serialize(&self, account: u8) -> Result { 89 | let mut data: Vec = Vec::new(); 90 | data.write_u64::(self.stake)?; 91 | data.write_u64::(self.fee)?; 92 | data.push(0); 93 | data.extend(self.address.clone()); 94 | 95 | Ok(APDUCommand { 96 | cla: 0xe0, 97 | ins: INS_SIGN_VALIDATOR_STAKE_TXN, 98 | p1: account, 99 | p2: 0x00, 100 | data, 101 | }) 102 | } 103 | } 104 | 105 | impl ApduSerializer for BlockchainTxnTransferValidatorStakeV1 { 106 | fn apdu_serialize(&self, account: u8) -> Result { 107 | let mut data: Vec = Vec::new(); 108 | 109 | data.write_u64::(self.stake_amount)?; 110 | data.write_u64::(self.payment_amount)?; 111 | data.write_u64::(self.fee)?; 112 | 113 | data.push(0); 114 | data.extend(self.new_owner.clone()); 115 | 116 | data.push(0); 117 | data.extend(self.old_owner.clone()); 118 | 119 | data.push(0); 120 | data.extend(self.new_address.clone()); 121 | 122 | data.push(0); 123 | data.extend(self.old_address.clone()); 124 | 125 | Ok(APDUCommand { 126 | cla: 0xe0, 127 | ins: INS_SIGN_VALIDATOR_TXFER_TXN, 128 | p1: account, 129 | p2: 0x00, 130 | data, 131 | }) 132 | } 133 | } 134 | 135 | impl ApduSerializer for BlockchainTxnUnstakeValidatorV1 { 136 | fn apdu_serialize(&self, account: u8) -> Result { 137 | let mut data: Vec = Vec::new(); 138 | data.write_u64::(self.stake_amount)?; 139 | data.write_u64::(self.stake_release_height)?; 140 | data.write_u64::(self.fee)?; 141 | data.push(0); 142 | data.extend(self.address.clone()); 143 | 144 | Ok(APDUCommand { 145 | cla: 0xe0, 146 | ins: INS_SIGN_VALIDATOR_UNSTAKE_TXN, 147 | p1: account, 148 | p2: 0x00, 149 | data, 150 | }) 151 | } 152 | } 153 | 154 | impl ApduSerializer for BlockchainTxnTokenBurnV1 { 155 | fn apdu_serialize(&self, account: u8) -> Result { 156 | let mut data = Vec::new(); 157 | data.write_u64::(self.amount)?; 158 | data.write_u64::(self.fee)?; 159 | data.write_u64::(self.nonce)?; 160 | data.write_u64::(self.memo)?; 161 | data.push(0); 162 | data.extend(self.payee.clone()); 163 | 164 | Ok(APDUCommand { 165 | cla: 0xe0, 166 | ins: INS_SIGN_BURN_TXN, 167 | p1: account, 168 | p2: 0x00, 169 | data, 170 | }) 171 | } 172 | } 173 | 174 | impl ApduSerializer for BlockchainTxnSecurityExchangeV1 { 175 | fn apdu_serialize(&self, account: u8) -> Result { 176 | let mut data = Vec::new(); 177 | data.write_u64::(self.amount)?; 178 | data.write_u64::(self.fee)?; 179 | data.write_u64::(self.nonce)?; 180 | data.push(0); 181 | data.extend(self.payee.clone()); 182 | 183 | Ok(APDUCommand { 184 | cla: 0xe0, 185 | ins: INS_SIGN_TRANSFER_SEC_TXN, 186 | p1: account, 187 | p2: 0x00, 188 | data, 189 | }) 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/cmd/validator/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::{Network, Opts, Result, StructOpt, Version}; 2 | 3 | mod stake; 4 | mod transfer; 5 | mod unstake; 6 | 7 | #[derive(Debug, StructOpt)] 8 | /// Commands for validators 9 | pub enum Cmd { 10 | /// Stake a validator with the given wallet as the owner. 11 | Stake(stake::Cmd), 12 | /// Transfer a validator stake to a new validator and/or owner 13 | Transfer(Box), 14 | /// Unstake a validator with the given wallet as the owner. 15 | Unstake(unstake::Cmd), 16 | } 17 | 18 | impl Cmd { 19 | pub async fn run(self, opts: Opts, version: Version) -> Result> { 20 | if version.major < 2 || version.minor < 1 { 21 | panic!("Upgrade the Helium Ledger App to use validator commands"); 22 | }; 23 | match self { 24 | Cmd::Stake(stake) => stake.run(opts, version).await, 25 | Cmd::Transfer(transfer) => transfer.run(opts, version).await, 26 | Cmd::Unstake(unstake) => unstake.run(opts, version).await, 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/cmd/validator/stake.rs: -------------------------------------------------------------------------------- 1 | use crate::cmd::*; 2 | use rust_decimal::Decimal; 3 | use serde::Deserialize; 4 | use std::path::PathBuf; 5 | 6 | #[derive(Debug, StructOpt)] 7 | /// Onboard one (or more) validators with this wallet. 8 | /// 9 | /// The payment is not submitted to the system unless the '--commit' option is 10 | /// given. 11 | /// 12 | /// Note that multiple staking transactions are submitted individually and not as a 13 | /// single transaction. Any failures will abort the remaining staking entries. 14 | pub enum Cmd { 15 | /// Stake a single validator 16 | One(Validator), 17 | /// Stake multiple validators via file import 18 | Multi(Multi), 19 | } 20 | 21 | #[derive(Debug, StructOpt)] 22 | /// The input file for multiple validator stakes is expected to be json file 23 | /// with a list of address and staking amounts. For example: 24 | /// 25 | /// [ 26 | /// { 27 | /// "address": "", 28 | /// "stake": 10000 29 | /// }, 30 | /// { 31 | /// "address": "", 32 | /// "stake": 10000 33 | /// } 34 | /// ] 35 | pub struct Multi { 36 | /// File to read multiple stakes from 37 | path: PathBuf, 38 | } 39 | 40 | pub enum Response { 41 | Success, 42 | InsufficientBalance(Hnt, Hnt), // provides balance and send request 43 | UserDeniedTransaction, 44 | } 45 | 46 | impl Cmd { 47 | pub async fn run(self, opts: Opts, _version: Version) -> Result> { 48 | match self.ledger(opts).await? { 49 | Response::Success => Ok(None), 50 | Response::InsufficientBalance(balance, send_request) => { 51 | println!( 52 | "Account balance insufficient. {} HNT on account but attempting to stake {}", 53 | balance, send_request, 54 | ); 55 | Err(Error::txn()) 56 | } 57 | Response::UserDeniedTransaction => { 58 | println!("Transaction not confirmed"); 59 | Err(Error::txn()) 60 | } 61 | } 62 | } 63 | 64 | fn collect_validators(&self) -> Result> { 65 | match &self { 66 | Self::One(validator) => Ok(vec![validator.clone()]), 67 | Self::Multi(multi) => { 68 | let file = std::fs::File::open(multi.path.clone())?; 69 | let validators: Vec = serde_json::from_reader(file)?; 70 | Ok(validators) 71 | } 72 | } 73 | } 74 | 75 | pub async fn ledger(self, opts: Opts) -> Result { 76 | let validators = self.collect_validators()?; 77 | 78 | let ledger_transport = get_ledger_transport(&opts).await?; 79 | 80 | // get account from API so we can get nonce and balance 81 | let owner = get_pubkey(opts.account, &ledger_transport, PubkeyDisplay::Off).await?; 82 | 83 | let client = new_client(owner.network); 84 | 85 | let account = accounts::get(&client, &owner.to_string()).await?; 86 | 87 | let total_stake_amount = validators 88 | .iter() 89 | .map(|v| v.stake.get_decimal()) 90 | .sum::(); 91 | 92 | if account.balance.get_decimal() < total_stake_amount { 93 | return Ok(Response::InsufficientBalance( 94 | account.balance, 95 | Hnt::new(total_stake_amount), 96 | )); 97 | } 98 | 99 | for validator in validators { 100 | let mut txn = BlockchainTxnStakeValidatorV1 { 101 | owner: owner.to_vec(), 102 | address: validator.address.to_vec(), 103 | stake: u64::from(validator.stake), 104 | fee: 0, 105 | owner_signature: vec![], 106 | }; 107 | txn.fee = txn 108 | .txn_fee( 109 | &get_txn_fees(&client) 110 | .await 111 | .map_err(|_| Error::getting_fees())?, 112 | ) 113 | .map_err(|_| Error::getting_fees())?; 114 | print_proposed_transaction(&txn)?; 115 | 116 | let cmd = txn.apdu_serialize(opts.account)?; 117 | let exchange_pay_tx_result = read_from_ledger(&ledger_transport, cmd).await?; 118 | 119 | if exchange_pay_tx_result.data.len() == 1 { 120 | return Ok(Response::UserDeniedTransaction); 121 | } 122 | 123 | let txn = 124 | BlockchainTxnStakeValidatorV1::decode(exchange_pay_tx_result.data.as_slice())?; 125 | let envelope = txn.in_envelope(); 126 | // submit the signed tansaction to the API 127 | let pending_txn_status = submit_txn(&client, &envelope).await?; 128 | 129 | print_txn(pending_txn_status.hash, owner.network) 130 | } 131 | Ok(Response::Success) 132 | } 133 | } 134 | 135 | fn print_proposed_transaction(stake: &BlockchainTxnStakeValidatorV1) -> Result { 136 | let address = PublicKey::try_from(stake.address.clone())?; 137 | let units = match address.network { 138 | Network::TestNet => "TNT", 139 | Network::MainNet => "HNT", 140 | }; 141 | 142 | let mut table = Table::new(); 143 | println!("Creating the following stake transaction:"); 144 | table.add_row(row![ 145 | &format!("Stake Amount {}", units), 146 | "Validator Address", 147 | "DC Fee" 148 | ]); 149 | table.add_row(row![Hnt::from(stake.stake), address, stake.fee]); 150 | table.printstd(); 151 | println!( 152 | "WARNING: do not use this output as the source of truth. Instead, rely \ 153 | on the Ledger Display" 154 | ); 155 | Ok(()) 156 | } 157 | 158 | #[derive(Debug, Deserialize, StructOpt, Clone)] 159 | pub struct Validator { 160 | /// The validator address to stake 161 | address: PublicKey, 162 | /// The amount of HNT to stake 163 | stake: Hnt, 164 | } 165 | -------------------------------------------------------------------------------- /src/cmd/validator/transfer.rs: -------------------------------------------------------------------------------- 1 | use crate::cmd::*; 2 | use helium_wallet::traits::B64; 3 | 4 | #[allow(clippy::large_enum_variant)] 5 | #[derive(Debug, StructOpt)] 6 | /// Create or accept a validator transfer with this Ledger wallet 7 | pub enum Cmd { 8 | Create(Create), 9 | Accept(Accept), 10 | } 11 | 12 | #[derive(Debug, StructOpt)] 13 | /// Create a validator transfer transaction with a Ledger wallet as as the current (old) owner or 14 | /// new owner. If either owner is not specified, the select Ledger wallet account is assumed to be 15 | /// that/those owner(s). 16 | pub struct Create { 17 | /// The validator to transfer the stake from 18 | #[structopt(long)] 19 | old_address: PublicKey, 20 | 21 | /// The validator to transfer the stake to 22 | #[structopt(long)] 23 | new_address: PublicKey, 24 | 25 | /// The new owner of the transferred validator and stake. If not present 26 | /// the new owner is assumed to be the same as the current owner as defined 27 | /// on the blockchain. 28 | #[structopt(long)] 29 | new_owner: Option, 30 | 31 | /// The current (old) owner of the transferred validator and stake. If not present 32 | /// the old owner is set to the public key of the given wallet. 33 | #[structopt(long)] 34 | old_owner: Option, 35 | 36 | /// The amount of HNT to transfer from the new to the old owner as part of 37 | /// the stake transfer 38 | #[structopt(long, default_value = "0")] 39 | payment: Hnt, 40 | 41 | /// The amount of HNT of the original stake 42 | #[structopt(long)] 43 | stake_amount: Option, 44 | } 45 | 46 | #[derive(Debug, StructOpt)] 47 | /// Accept a given stake transfer transaction by signing it and committing to 48 | /// the API. The transaction is signed as either (or both) the new owner or the 49 | /// old owner if the owner keys match the public key of the given wallet. 50 | pub struct Accept { 51 | /// Base64 encoded transaction to sign. If no transaction if given 52 | /// stdin is read for the transaction. Note that the stdin feature 53 | /// only works if the wallet password is set in the 54 | /// HELIUM_WALLET_PASSWORD environment variable 55 | #[structopt(name = "TRANSACTION")] 56 | txn: Option, 57 | } 58 | 59 | impl Cmd { 60 | pub async fn run(self, opts: Opts, _version: Version) -> Result> { 61 | match self { 62 | Cmd::Create(create) => match ledger_create(opts, create).await? { 63 | Some(Response::Txn(_txn, hash, network)) => Ok(Some((hash, network))), 64 | Some(Response::InsufficientHntBalance(balance, send_request)) => { 65 | println!( 66 | "Account balance insufficient. {} HNT on account but attempting to stake {}", 67 | balance, send_request, 68 | ); 69 | Err(Error::txn()) 70 | } 71 | Some(Response::UserDeniedTransaction) => { 72 | println!("Transaction not confirmed"); 73 | Err(Error::txn()) 74 | } 75 | _ => Ok(None), 76 | }, 77 | Cmd::Accept(accept) => match ledger_accept(opts, accept).await? { 78 | Some(Response::Txn(_txn, hash, network)) => Ok(Some((hash, network))), 79 | Some(Response::InsufficientHntBalance(balance, send_request)) => { 80 | println!( 81 | "Account balance insufficient. {} HNT on account but attempting to stake {}", 82 | balance, send_request, 83 | ); 84 | Err(Error::txn()) 85 | } 86 | Some(Response::UserDeniedTransaction) => { 87 | println!("Transaction not confirmed"); 88 | Err(Error::txn()) 89 | } 90 | _ => Ok(None), 91 | }, 92 | } 93 | } 94 | } 95 | 96 | pub async fn ledger_create( 97 | opts: Opts, 98 | txfer_stake: Create, 99 | ) -> Result>> { 100 | let ledger = get_ledger_transport(&opts).await?; 101 | let this_wallet = get_pubkey(opts.account, &ledger, PubkeyDisplay::Off).await?; 102 | 103 | // old_owner defaults to self if not input 104 | let old_owner = if let Some(old_owner) = txfer_stake.old_owner { 105 | old_owner 106 | } else { 107 | this_wallet.clone() 108 | }; 109 | 110 | // old_owner defaults to self if not input 111 | let new_owner = if let Some(new_owner) = txfer_stake.new_owner { 112 | new_owner 113 | } else { 114 | this_wallet.clone() 115 | }; 116 | 117 | // verify that we are one of the parties involved 118 | if this_wallet != old_owner && this_wallet != new_owner { 119 | println!("ERROR: Selected Ledger account is neither current nor new owner of validator!"); 120 | return Ok(None); 121 | } 122 | 123 | let client = new_client(old_owner.network); 124 | // calculate fee 125 | let mut txn = BlockchainTxnTransferValidatorStakeV1 { 126 | new_owner: new_owner.to_vec(), 127 | old_owner: old_owner.to_vec(), 128 | new_address: txfer_stake.new_address.to_vec(), 129 | old_address: txfer_stake.old_address.to_vec(), 130 | fee: 0, 131 | payment_amount: u64::from(txfer_stake.payment), 132 | stake_amount: if let Some(stake_amount) = txfer_stake.stake_amount { 133 | u64::from(stake_amount) 134 | } else { 135 | helium_api::validators::get(&client, &txfer_stake.old_address.to_string()) 136 | .await? 137 | .stake 138 | .into() 139 | }, 140 | new_owner_signature: vec![], 141 | old_owner_signature: vec![], 142 | }; 143 | 144 | txn.fee = txn 145 | .txn_fee( 146 | &get_txn_fees(&client) 147 | .await 148 | .map_err(|_| Error::getting_fees())?, 149 | ) 150 | .map_err(|_| Error::getting_fees())?; 151 | 152 | print_proposed_transaction(&txn)?; 153 | 154 | let cmd = txn.apdu_serialize(opts.account)?; 155 | let result = read_from_ledger(&ledger, cmd).await?; 156 | if result.data.len() == 1 { 157 | return Ok(Some(Response::UserDeniedTransaction)); 158 | } 159 | let data = result.data; 160 | 161 | let mut txn = BlockchainTxnTransferValidatorStakeV1::decode(data.as_slice())?; 162 | 163 | // A create transfer can only be submitted if we are both old and new owners 164 | if old_owner == new_owner { 165 | // The APDU txn only passes the signature once as old_owner so as to avoid multiple APDU 166 | // frames. We make the copy here to accommodate 167 | txn.new_owner_signature = txn.old_owner_signature.clone(); 168 | 169 | // submit the signed transaction to the API 170 | let pending_txn_status = submit_txn(&client, &txn.in_envelope()).await?; 171 | 172 | Ok(Some(Response::Txn( 173 | txn, 174 | pending_txn_status.hash, 175 | old_owner.network, 176 | ))) 177 | } else { 178 | println!("Provide the following base64 output to the counter-party for counter-signing: "); 179 | println!("{}", txn.in_envelope().to_b64().unwrap()); 180 | Ok(None) 181 | } 182 | } 183 | 184 | pub async fn ledger_accept( 185 | opts: Opts, 186 | accept: Accept, 187 | ) -> Result>> { 188 | let read = read_txn(&accept.txn)?; 189 | let mut input_txn = BlockchainTxnTransferValidatorStakeV1::from_envelope(&read) 190 | .map_err(|_| Error::into_envelope())?; 191 | print_proposed_transaction(&input_txn)?; 192 | 193 | let old_owner = PublicKey::try_from(input_txn.old_owner.clone())?; 194 | let new_owner = PublicKey::try_from(input_txn.new_owner.clone())?; 195 | 196 | // get Ledger account so that we can verify relevance 197 | let ledger = get_ledger_transport(&opts).await?; 198 | 199 | let this_wallet = get_pubkey(opts.account, &ledger, PubkeyDisplay::Off).await?; 200 | 201 | // verify that we are one of the parties involved 202 | if this_wallet != old_owner && this_wallet != new_owner { 203 | println!("ERROR: Selected Ledger account is neither current nor new owner of validator!"); 204 | return Ok(None); 205 | } 206 | 207 | let cmd = input_txn.apdu_serialize(opts.account)?; 208 | let result = read_from_ledger(&ledger, cmd).await?; 209 | 210 | if result.data.len() == 1 { 211 | return Ok(Some(Response::UserDeniedTransaction)); 212 | } 213 | 214 | // Decode the transaction returned by the ledger 215 | let txn = BlockchainTxnTransferValidatorStakeV1::decode(result.data.as_slice())?; 216 | 217 | // We move the signatures returned by the Ledger for whatever roles it fulfills 218 | // We support an unsigned transactions where we are both old and new owners 219 | if this_wallet == old_owner { 220 | // The APDU txn only passes the signature once as old_owner so as to avoid multiple APDU 221 | // frames. We make the copy here to accommodate 222 | if this_wallet == new_owner { 223 | input_txn.new_owner_signature = txn.old_owner_signature.clone(); 224 | } 225 | input_txn.old_owner_signature = txn.old_owner_signature; 226 | } else if this_wallet == new_owner { 227 | input_txn.new_owner_signature = txn.new_owner_signature; 228 | } 229 | 230 | // submit the signed transaction to the API 231 | let client = new_client(old_owner.network); 232 | let pending_txn_status = submit_txn(&client, &input_txn.in_envelope()).await?; 233 | 234 | Ok(Some(Response::Txn( 235 | input_txn, 236 | pending_txn_status.hash, 237 | old_owner.network, 238 | ))) 239 | } 240 | 241 | #[derive(Debug, Clone)] 242 | pub struct Transaction(BlockchainTxn); 243 | 244 | impl std::str::FromStr for Transaction { 245 | type Err = Error; 246 | 247 | fn from_str(s: &str) -> Result { 248 | Ok(Self( 249 | BlockchainTxn::from_b64(s).map_err(|_| Error::from_b64())?, 250 | )) 251 | } 252 | } 253 | 254 | use std::io; 255 | fn read_txn(txn: &Option) -> Result { 256 | match txn { 257 | Some(txn) => Ok(txn.0.clone()), 258 | None => { 259 | let mut buffer = String::new(); 260 | io::stdin().read_line(&mut buffer)?; 261 | Ok(buffer.trim().parse::()?.0) 262 | } 263 | } 264 | } 265 | 266 | fn print_proposed_transaction(txn: &BlockchainTxnTransferValidatorStakeV1) -> Result { 267 | let old_address = PublicKey::try_from(txn.old_address.clone())?; 268 | 269 | let units = match old_address.network { 270 | Network::TestNet => "TNT", 271 | Network::MainNet => "HNT", 272 | }; 273 | 274 | let mut table = Table::new(); 275 | println!("Constructing transfer stake transaction:"); 276 | table.add_row(row!["Old Owner", "New Owner",]); 277 | table.add_row(row![ 278 | PublicKey::try_from(txn.old_owner.clone())?, 279 | PublicKey::try_from(txn.new_owner.clone())?, 280 | ]); 281 | table.printstd(); 282 | table = Table::new(); 283 | table.add_row(row!["Old Address", "New Address",]); 284 | table.add_row(row![ 285 | old_address, 286 | PublicKey::try_from(txn.new_address.clone())?, 287 | ]); 288 | table.printstd(); 289 | table = Table::new(); 290 | table.add_row(row![ 291 | "Payment to Old Owner", 292 | &format!("Stake Amount {}", units), 293 | "DC Fee" 294 | ]); 295 | table.add_row(row![ 296 | Hnt::from(txn.payment_amount), 297 | Hnt::from(txn.stake_amount), 298 | txn.fee 299 | ]); 300 | table.printstd(); 301 | println!( 302 | "WARNING: do not use this output as the source of truth. Instead, rely \ 303 | on the Ledger Display" 304 | ); 305 | Ok(()) 306 | } 307 | -------------------------------------------------------------------------------- /src/cmd/validator/unstake.rs: -------------------------------------------------------------------------------- 1 | use crate::cmd::*; 2 | 3 | #[derive(Debug, StructOpt)] 4 | /// Unstake a given validator. The stake will be in a cooldown period after 5 | /// unstaking before the HNT is returned to the owning wallet. 6 | pub struct Cmd { 7 | /// Address of the validator to unstake 8 | address: PublicKey, 9 | 10 | /// The amount of HNT of the original stake 11 | #[structopt(long)] 12 | stake_amount: Option, 13 | 14 | /// The stake release block height. This should be at least the current 15 | /// block height plus the cooldown period, and 5-10 blocks to allow for 16 | /// chain processing delays. 17 | #[structopt(long)] 18 | stake_release_height: u64, 19 | 20 | /// Manually set the fee to pay for the transaction 21 | #[structopt(long)] 22 | fee: Option, 23 | } 24 | 25 | impl Cmd { 26 | pub async fn run(self, opts: Opts, _version: Version) -> Result> { 27 | match ledger(opts, self).await? { 28 | Response::Txn(_txn, hash, network) => Ok(Some((hash, network))), 29 | Response::UserDeniedTransaction => { 30 | println!("Transaction not confirmed"); 31 | Err(Error::txn()) 32 | } 33 | _ => panic!("Invalid error for this transaction type"), 34 | } 35 | } 36 | } 37 | pub async fn ledger(opts: Opts, unstake: Cmd) -> Result> { 38 | let ledger = get_ledger_transport(&opts).await?; 39 | 40 | // get account from API so we can get nonce and balance 41 | let owner = get_pubkey(opts.account, &ledger, PubkeyDisplay::Off).await?; 42 | 43 | let client = new_client(owner.network); 44 | 45 | let mut txn = BlockchainTxnUnstakeValidatorV1 { 46 | owner: owner.to_vec(), 47 | address: unstake.address.to_vec(), 48 | stake_amount: if let Some(stake_amount) = unstake.stake_amount { 49 | u64::from(stake_amount) 50 | } else { 51 | helium_api::validators::get(&client, &unstake.address.to_string()) 52 | .await? 53 | .stake 54 | .into() 55 | }, 56 | stake_release_height: unstake.stake_release_height, 57 | fee: 0, 58 | owner_signature: vec![], 59 | }; 60 | 61 | txn.fee = if let Some(fee) = unstake.fee { 62 | fee 63 | } else { 64 | txn.txn_fee( 65 | &get_txn_fees(&client) 66 | .await 67 | .map_err(|_| Error::getting_fees())?, 68 | ) 69 | .map_err(|_| Error::getting_fees())? 70 | }; 71 | 72 | print_proposed_txn(&txn)?; 73 | 74 | let cmd = txn.apdu_serialize(opts.account)?; 75 | let exchange_pay_tx_result = read_from_ledger(&ledger, cmd).await?; 76 | 77 | if exchange_pay_tx_result.data.len() == 1 { 78 | return Ok(Response::UserDeniedTransaction); 79 | } 80 | 81 | let txn = BlockchainTxnUnstakeValidatorV1::decode(exchange_pay_tx_result.data.as_slice())?; 82 | let envelope = txn.in_envelope(); 83 | // submit the signed tansaction to the API 84 | let pending_txn_status = submit_txn(&client, &envelope).await?; 85 | 86 | Ok(Response::Txn(txn, pending_txn_status.hash, owner.network)) 87 | } 88 | 89 | pub fn print_proposed_txn(txn: &BlockchainTxnUnstakeValidatorV1) -> Result { 90 | let owner = PublicKey::try_from(txn.owner.clone())?; 91 | let units = match owner.network { 92 | Network::TestNet => "TNT", 93 | Network::MainNet => "HNT", 94 | }; 95 | 96 | let mut table = Table::new(); 97 | println!("Creating the following stake transaction:"); 98 | table.add_row(row![ 99 | &format!("Unstake Amount {}", units), 100 | "Stake Release Height", 101 | "Validator Address", 102 | "DC Fee" 103 | ]); 104 | table.add_row(row![ 105 | Hnt::from(txn.stake_amount), 106 | txn.stake_release_height, 107 | PublicKey::try_from(txn.address.clone())?, 108 | txn.fee 109 | ]); 110 | table.printstd(); 111 | 112 | println!( 113 | "WARNING: do not use this output as the source of truth. Instead, rely \ 114 | on the Ledger Display" 115 | ); 116 | 117 | println!( 118 | "\nINFO: After unstaking, a wallet cannot access the staked amount\n\ 119 | until the entered stake release height is reached (approx. five months)." 120 | ); 121 | Ok(()) 122 | } 123 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use thiserror::Error; 2 | 3 | #[derive(Error, Debug)] 4 | pub enum Error { 5 | #[error("Could not find ledger. Is it disconnected or locked? {0}")] 6 | CouldNotFindLedger(#[from] ledger_transport::errors::TransportError), 7 | #[error("Ledger is connected but Helium application does not appear to be running")] 8 | AppNotRunning, 9 | #[error("Error getting version: {0}. Consider updating")] 10 | VersionError(String), 11 | #[error("Your Helium Ledger Application is outdated. Please update using Ledger Live.")] 12 | UnsupportedLedgerVersion, 13 | #[error("Error generating QR {0}")] 14 | Qr(#[from] qr2term::QrError), 15 | #[error("Error accessing Ledger HID Device. Be sure that Ledger Live is not running. {0}")] 16 | Hid(#[from] ledger_transport::LedgerHIDError), 17 | #[error("Connection refused by Ledger emulator {0}")] 18 | Tcp(#[from] ledger_transport::TransportTcpError), 19 | #[error("Helium API Error {0}")] 20 | HeliumApi(#[from] helium_api::Error), 21 | #[error("Helium Crypto Error {0}")] 22 | HeliumCrypto(#[from] helium_crypto::Error), 23 | #[error("Getting Fees")] 24 | GettingFees, 25 | #[error("Io Error {0}")] 26 | Io(#[from] std::io::Error), 27 | #[error("Decoding Error {0}")] 28 | Decode(#[from] prost::DecodeError), 29 | #[error("Encoding Error {0}")] 30 | Encode(#[from] prost::EncodeError), 31 | #[error("Transaction Error")] 32 | Txn, 33 | #[error("Into Envelope Error")] 34 | IntoEnvelope, 35 | #[error("FromB64 Error")] 36 | FromB64, 37 | #[error("Decode Base64 Error {0}")] 38 | Base64Decode(#[from] base64::DecodeError), 39 | #[error("From Json Parsing Error {0}")] 40 | SerdeJson(#[from] serde_json::Error), 41 | #[error("Invalid token type input: {0}")] 42 | TokenTypeInput(String), 43 | } 44 | 45 | impl Error { 46 | pub fn getting_fees() -> Error { 47 | Error::GettingFees 48 | } 49 | pub fn txn() -> Error { 50 | Error::Txn 51 | } 52 | pub fn into_envelope() -> Error { 53 | Error::IntoEnvelope 54 | } 55 | pub fn from_b64() -> Error { 56 | Error::FromB64 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate prettytable; 3 | 4 | pub use error::Error; 5 | pub type Result = std::result::Result; 6 | pub use helium_api::models::transactions::PendingTxnStatus; 7 | pub use helium_proto::BlockchainTxn; 8 | pub use helium_wallet::keypair::Network; 9 | pub use ledger_transport::exchange::Exchange as LedgerTransport; 10 | pub use qr2term::print_qr; 11 | pub use std::{env, fmt, process}; 12 | pub use structopt::StructOpt; 13 | pub mod cmd; 14 | pub mod error; 15 | pub mod memo; 16 | 17 | const DEFAULT_TESTNET_BASE_URL: &str = "https://testnet-api.helium.wtf/v1"; 18 | pub static USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION")); 19 | 20 | const MAINNET_BYTE: u8 = 77; 21 | const TESTNET_BYTE: u8 = 84; 22 | 23 | /// Common options for most wallet commands 24 | #[derive(Debug, StructOpt)] 25 | pub struct Opts { 26 | /// Select account index to stake from 27 | #[structopt(long = "account", default_value = "0")] 28 | pub account: u8, 29 | 30 | /// Enable interaction with emulator for development and testing 31 | /// by configuring port for TCP connection here (typically 9999 32 | /// or 40000) 33 | #[structopt(long = "emulator")] 34 | pub emulator: Option, 35 | } 36 | 37 | #[derive(Debug, StructOpt)] 38 | pub struct Cli { 39 | #[structopt(flatten)] 40 | pub opts: Opts, 41 | 42 | #[structopt(flatten)] 43 | pub cmd: Cmd, 44 | } 45 | 46 | /// Interact with Ledger Nano S for hardware wallet management 47 | #[derive(Debug, StructOpt)] 48 | #[allow(clippy::large_enum_variant)] 49 | pub enum Cmd { 50 | /// Get wallet information 51 | Balance(cmd::balance::Cmd), 52 | /// Burn to given address. 53 | Burn(cmd::burn::Cmd), 54 | /// Pay a given address. 55 | Pay(cmd::pay::Cmd), 56 | /// Stake a validator 57 | Validators(cmd::validator::Cmd), 58 | /// Deprecated in favor for Pay with HST 59 | Securities, 60 | } 61 | 62 | pub struct Version { 63 | major: u8, 64 | minor: u8, 65 | revision: u8, 66 | network: Network, 67 | } 68 | 69 | impl Version { 70 | pub fn from_bytes(bytes: [u8; 4]) -> Result { 71 | let network = match bytes[3] { 72 | MAINNET_BYTE => Ok(Network::MainNet), 73 | TESTNET_BYTE => Ok(Network::TestNet), 74 | _ => Err(Error::VersionError(format!( 75 | "Network byte is invalid: {}", 76 | bytes[3] 77 | ))), 78 | }; 79 | Ok(Version { 80 | major: bytes[0], 81 | minor: bytes[1], 82 | revision: bytes[2], 83 | network: network?, 84 | }) 85 | } 86 | } 87 | 88 | impl fmt::Display for Version { 89 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 90 | write!( 91 | f, 92 | "v{}.{}.{} [{}]", 93 | self.major, self.minor, self.revision, self.network 94 | ) 95 | } 96 | } 97 | 98 | pub fn print_txn(hash: String, network: Network) { 99 | println!("\nSuccessfully submitted transaction to API:"); 100 | 101 | let mut table = Table::new(); 102 | table.add_row(row!["Network", "Hash"]); 103 | table.add_row(row![network, hash]); 104 | table.printstd(); 105 | 106 | println!("To check on transaction status, monitor the following URL:"); 107 | println!(" {}/pending_transactions/{}", api_url(network), hash); 108 | } 109 | 110 | use helium_api::Client; 111 | use prettytable::{format, Table}; 112 | 113 | pub async fn submit_txn(client: &Client, txn: &BlockchainTxn) -> Result { 114 | use helium_proto::Message; 115 | let mut data = vec![]; 116 | txn.encode(&mut data)?; 117 | helium_api::pending_transactions::submit(client, &data) 118 | .await 119 | .map_err(|e| e.into()) 120 | } 121 | 122 | fn new_client(network: Network) -> Client { 123 | Client::new_with_base_url(api_url(network), USER_AGENT) 124 | } 125 | 126 | fn api_url(network: Network) -> String { 127 | match network { 128 | Network::MainNet => { 129 | env::var("HELIUM_API_URL").unwrap_or_else(|_| helium_api::DEFAULT_BASE_URL.to_string()) 130 | } 131 | Network::TestNet => env::var("HELIUM_TESTNET_API_URL") 132 | .unwrap_or_else(|_| DEFAULT_TESTNET_BASE_URL.to_string()), 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use helium_ledger::*; 2 | 3 | #[tokio::main] 4 | async fn main() { 5 | println!("Communicating with Ledger - follow prompts on screen"); 6 | 7 | let cli = Cli::from_args(); 8 | if let Err(e) = run(cli).await { 9 | println!("error: {}", e); 10 | process::exit(1); 11 | } 12 | } 13 | 14 | async fn run(cli: Cli) -> Result { 15 | let version = cmd::get_app_version(&cli.opts).await?; 16 | println!("Ledger running Helium App {}\r\n", version); 17 | 18 | let result = match cli.cmd { 19 | Cmd::Balance(balance) => balance.run(cli.opts, version).await?, 20 | Cmd::Burn(burn) => burn.run(cli.opts, version).await?, 21 | Cmd::Pay(pay) => pay.run(cli.opts, version).await?, 22 | Cmd::Validators(validator) => validator.run(cli.opts, version).await?, 23 | Cmd::Securities => { 24 | println!("This command is deprecated in favor of payment_v2 with token type HST"); 25 | None 26 | } 27 | }; 28 | if let Some((hash, network)) = result { 29 | print_txn(hash, network); 30 | } 31 | 32 | Ok(()) 33 | } 34 | -------------------------------------------------------------------------------- /src/memo.rs: -------------------------------------------------------------------------------- 1 | use super::{Error, Result}; 2 | use helium_wallet::traits::B64; 3 | use serde::de::{self, Deserialize, Deserializer, Visitor}; 4 | use std::{fmt, str::FromStr}; 5 | 6 | #[derive(Debug, Default, PartialEq, Eq)] 7 | pub struct Memo(pub u64); 8 | 9 | impl FromStr for Memo { 10 | type Err = Error; 11 | 12 | fn from_str(s: &str) -> Result { 13 | let decoded = base64::decode(s)?; 14 | if decoded.len() != 8 { 15 | return Err(Error::from_b64()); 16 | } 17 | let bytes = [ 18 | decoded[0], decoded[1], decoded[2], decoded[3], decoded[4], decoded[5], decoded[6], 19 | decoded[7], 20 | ]; 21 | Ok(Memo(u64::from_le_bytes(bytes))) 22 | } 23 | } 24 | 25 | impl From for Memo { 26 | fn from(v: u64) -> Self { 27 | Memo(v) 28 | } 29 | } 30 | 31 | impl From<&Memo> for u64 { 32 | fn from(v: &Memo) -> Self { 33 | v.0 34 | } 35 | } 36 | 37 | impl fmt::Display for Memo { 38 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 39 | f.write_str(&self.0.to_b64().unwrap()) 40 | } 41 | } 42 | 43 | impl<'de> Deserialize<'de> for Memo { 44 | fn deserialize(deserializer: D) -> std::result::Result 45 | where 46 | D: Deserializer<'de>, 47 | { 48 | struct MemoVisitor; 49 | 50 | impl<'de> Visitor<'de> for MemoVisitor { 51 | type Value = Memo; 52 | 53 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 54 | formatter.write_str("base64 string") 55 | } 56 | 57 | fn visit_str(self, value: &str) -> std::result::Result 58 | where 59 | E: de::Error, 60 | { 61 | match u64::from_b64(value) { 62 | Ok(v) => Ok(Memo(v)), 63 | Err(_) => Err(de::Error::custom("invalid memo")), 64 | } 65 | } 66 | } 67 | 68 | deserializer.deserialize_str(MemoVisitor) 69 | } 70 | } 71 | --------------------------------------------------------------------------------