Compare commits

..

9 Commits

Author SHA1 Message Date
durch 31c6090576 Construct test routes from good nodes only 2022-04-03 20:11:06 +02:00
Drazen Urch 95b6ac50be Type safe bounds (#1179)
* Type safe bounds

* Debug get_all_delegations

* List raw delegations

* query all delegation values

* Get all keys and values

* Differentiate on len

* Clean up duplicates

* Remove stop gap

* Cleanup, fix paged query key

* Reduce queries required to get all delegations

* Sandbox migration

* Delete migration
2022-03-30 12:20:03 +02:00
Tommy Verrall 5f2247ab83 Merge pull request #1180 from nymtech/update-wallet-unbond
fix unbond page
2022-03-30 09:35:22 +01:00
Tommy Verrall 842bcfa782 fix unbond page 2022-03-30 09:34:17 +01:00
Drazen Urch c2938e0672 Fix delegation paging (#1174)
* Fix delegation paging and tests

* Circuit breaker, upgrade storage and cosmwasm

* beta6

* Cleanup delegation events
2022-03-29 17:02:56 +02:00
Tommy Verrall 278516ad11 Merge pull request #1172 from nymtech/feature/update-binary-version
Update binaries to rc version
2022-03-29 10:02:48 +01:00
Mark Sinclair ce241339bf Create nym-release-publish.yml 2022-03-28 18:16:08 +01:00
Tommy Verrall 8d7428923a Update binaries to rc version 2022-03-28 15:32:31 +01:00
Drazen Urch 4a1a4b6415 Different values for mixes and gateways (#1169) 2022-03-28 13:33:55 +02:00
176 changed files with 1847 additions and 10606 deletions
@@ -64,16 +64,12 @@ jobs:
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_IDENTITY_ID }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
run: yarn && yarn build
- name: Upload to release based on tag name
uses: softprops/action-gh-release@v1
with:
files: |
nym-wallet/target/release/bundle/dmg/*.dmg
nym-wallet/target/release/bundle/macos/*.app.tar.gz*
files: nym-wallet/target/release/bundle/dmg/*.dmg
- name: Clean up keychain
if: ${{ always() }}
@@ -37,16 +37,10 @@ jobs:
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install app dependencies
run: yarn
- name: Build app
run: yarn build
env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- name: Install app dependencies and build it
run: yarn && yarn build
- name: Upload to release based on tag name
uses: softprops/action-gh-release@v1
with:
files: |
nym-wallet/target/release/bundle/appimage/*.AppImage
nym-wallet/target/release/bundle/appimage/*.AppImage.tar.gz*
files: nym-wallet/target/release/bundle/appimage/*.AppImage
@@ -63,13 +63,9 @@ jobs:
ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }}
WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
run: yarn build
- name: Upload to release based on tag name
uses: softprops/action-gh-release@v1
with:
files: |
nym-wallet/target/release/bundle/msi/*.msi
nym-wallet/target/release/bundle/msi/*.msi.zip*
files: nym-wallet/target/release/bundle/msi/*.msi
@@ -1,55 +0,0 @@
name: Nym Wallet Storybook
on:
push:
paths:
- 'nym-wallet/**'
jobs:
build:
runs-on: custom-runner-linux
steps:
- uses: actions/checkout@v2
- name: Install rsync
run: sudo apt-get install rsync
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v2
with:
node-version: '16'
- name: Setup yarn
run: npm install -g yarn
- name: Build dependencies
run: yarn && yarn build
- name: Build storybook
run: yarn storybook:build
working-directory: ./nym-wallet
- name: Deploy branch to CI www (storybook)
continue-on-error: true
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "nym-wallet/storybook-static/"
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/wallet-${{ env.GITHUB_REF_SLUG }}
EXCLUDE: "/dist/, /node_modules/"
- name: Keybase - Node Install
run: npm install
working-directory: .github/workflows/support-files
- name: Keybase - Send Notification
env:
NYM_NOTIFICATION_KIND: nym-wallet
NYM_PROJECT_NAME: "nym-wallet"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
NYM_CI_WWW_LOCATION: "wallet-${{ env.GITHUB_REF_SLUG }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
KEYBASE_NYMBOT_PAPERKEY: "${{ secrets.KEYBASE_NYMBOT_PAPERKEY }}"
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMBOT_TEAM }}"
KEYBASE_NYM_CHANNEL: "ci-nym-wallet"
IS_SUCCESS: "${{ job.status == 'success' }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
@@ -3,7 +3,7 @@ require('dotenv').config();
const Bot = require('keybase-bot');
let context = {
kinds: ['nym-wallet', 'ts-packages', 'network-explorer', 'nightly'],
kinds: ['ts-packages', 'network-explorer', 'nightly'],
};
/**
@@ -1,29 +0,0 @@
const Handlebars = require('handlebars');
const fs = require('fs');
const path = require('path');
async function addToContextAndValidate(context) {
if (!context.env.NYM_CI_WWW_LOCATION) {
throw new Error('Please ensure the env var NYM_CI_WWW_LOCATION is set');
}
if (!context.env.NYM_CI_WWW_BASE) {
throw new Error('Please ensure the env var NYM_CI_WWW_BASE is set');
}
}
async function getMessageBody(context) {
const source = fs
.readFileSync(
context.env.IS_SUCCESS === 'true'
? path.resolve(__dirname, 'templates', 'success')
: path.resolve(__dirname, 'templates', 'failure'),
)
.toString();
const template = Handlebars.compile(source);
return template(context);
}
module.exports = {
addToContextAndValidate,
getMessageBody,
};
@@ -1,11 +0,0 @@
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
> :rocket: {{ env.NYM_PROJECT_NAME }}
> 🔴 **FAILURE** :cry:
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
Commit message:
```
{{ env.GIT_COMMIT_MESSAGE }}
```
@@ -1,15 +0,0 @@
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
> :rocket: {{ env.NYM_PROJECT_NAME }}
> ✅ **SUCCESS**
> ➡️➡️➡️➡️➡️ **View output:**
> `storybook`: https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
```
{{ env.GIT_COMMIT_MESSAGE }}
```
Generated
+56 -156
View File
@@ -20,7 +20,7 @@ version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"cipher 0.3.0",
"cpufeatures",
"ctr 0.8.0",
@@ -33,7 +33,7 @@ version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfe0133578c0986e1fe3dfcd4af1cc5b2dd6c3dbf534d69916ce16a2701d40ba"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"cipher 0.4.3",
"cpufeatures",
]
@@ -313,7 +313,7 @@ dependencies = [
"arrayref",
"arrayvec 0.7.2",
"cc",
"cfg-if 1.0.0",
"cfg-if",
"constant_time_eq",
"digest 0.10.3",
]
@@ -453,12 +453,6 @@ dependencies = [
"jobserver",
]
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "cfg-if"
version = "1.0.0"
@@ -555,7 +549,7 @@ dependencies = [
[[package]]
name = "client-core"
version = "0.12.0"
version = "1.0.0-rc.1"
dependencies = [
"config",
"crypto",
@@ -587,23 +581,13 @@ dependencies = [
"bitflags",
]
[[package]]
name = "coconut-bandwidth-contract-common"
version = "0.1.0"
dependencies = [
"schemars",
"serde",
]
[[package]]
name = "coconut-interface"
version = "0.1.0"
dependencies = [
"bs58",
"getset",
"nymcoconut",
"serde",
"thiserror",
]
[[package]]
@@ -623,7 +607,6 @@ version = "0.1.0"
dependencies = [
"handlebars",
"humantime-serde",
"log",
"network-defaults",
"serde",
"toml",
@@ -767,31 +750,31 @@ dependencies = [
[[package]]
name = "cosmwasm-crypto"
version = "1.0.0-beta6"
version = "1.0.0-beta7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dddc1443004c6340e55ca66d98e9d2f1a44aadf4ce2bed2c4f29baa8a15e7b7"
checksum = "88c2565b1e73a816fb659ef4838fc356143fbd35f43c48a51d2d7d4e5d6679d3"
dependencies = [
"digest 0.9.0",
"ed25519-zebra",
"k256 0.9.6",
"rand_core 0.5.1",
"rand_core 0.6.3",
"thiserror",
]
[[package]]
name = "cosmwasm-derive"
version = "1.0.0-beta6"
version = "1.0.0-beta7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe4f0f10f165b8bcc558a13cddb498140960544519aa0581532c766dd80b5598"
checksum = "fa89fcdf8dbbe0088e663d0a814aa7368e7ebe8fb045a3a150fb5fdc2ffe3b45"
dependencies = [
"syn",
]
[[package]]
name = "cosmwasm-std"
version = "1.0.0-beta6"
version = "1.0.0-beta7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f0f3145097b692b2d95fa5d2c7c6fdd60f193ccc709857e7e1987a608725300"
checksum = "bcb8f99a61d0b9069e1afc80a4ffea87dcc3523edd992080923870b13a677da0"
dependencies = [
"base64",
"cosmwasm-crypto",
@@ -834,30 +817,7 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "credential"
version = "0.1.0"
dependencies = [
"async-trait",
"bip39",
"cfg-if 0.1.10",
"clap 3.1.6",
"coconut-bandwidth-contract-common",
"coconut-interface",
"credentials",
"crypto",
"network-defaults",
"pemstore",
"pickledb",
"rand 0.7.3",
"serde",
"thiserror",
"tokio",
"url",
"validator-client",
"cfg-if",
]
[[package]]
@@ -866,10 +826,8 @@ version = "0.1.0"
dependencies = [
"bls12_381",
"coconut-interface",
"cosmrs",
"crypto",
"network-defaults",
"rand 0.7.3",
"thiserror",
"url",
"validator-client",
@@ -917,7 +875,7 @@ version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdbfe11fe19ff083c48923cf179540e8cd0535903dc35e178a1fdeeb59aef51f"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"crossbeam-utils",
]
@@ -927,7 +885,7 @@ version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
@@ -939,7 +897,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c"
dependencies = [
"autocfg 1.1.0",
"cfg-if 1.0.0",
"cfg-if",
"crossbeam-utils",
"lazy_static",
"memoffset",
@@ -952,7 +910,7 @@ version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"crossbeam-utils",
]
@@ -962,7 +920,7 @@ version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"lazy_static",
]
@@ -1113,20 +1071,9 @@ dependencies = [
[[package]]
name = "cw-storage-plus"
version = "0.11.1"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d7ee1963302b0ac2a9d42fe0faec826209c17452bfd36fbfd9d002a88929261"
dependencies = [
"cosmwasm-std",
"schemars",
"serde",
]
[[package]]
name = "cw-storage-plus"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c087ff98fb0475db4c2b5298a5fd12b2848d2854b39d1115d930ee6da24d1eed"
checksum = "5e8b7f9a758c030d375520df947323c052704f784561fc28dcaab4f988c50a30"
dependencies = [
"cosmwasm-std",
"schemars",
@@ -1174,7 +1121,7 @@ version = "4.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"num_cpus",
]
@@ -1364,16 +1311,17 @@ dependencies = [
[[package]]
name = "ed25519-zebra"
version = "2.2.0"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a128b76af6dd4b427e34a6fd43dc78dbfe73672ec41ff615a2414c1a0ad0409"
checksum = "403ef3e961ab98f0ba902771d29f842058578bb1ce7e3c59dad5a6a93e784c69"
dependencies = [
"curve25519-dalek",
"hex",
"rand_core 0.5.1",
"rand_core 0.6.3",
"serde",
"sha2",
"thiserror",
"zeroize",
]
[[package]]
@@ -1422,7 +1370,7 @@ version = "0.8.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
]
[[package]]
@@ -1512,7 +1460,7 @@ dependencies = [
[[package]]
name = "explorer-api"
version = "0.1.0"
version = "1.0.0-rc.1"
dependencies = [
"chrono",
"humantime-serde",
@@ -1630,7 +1578,7 @@ version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"crc32fast",
"libc",
"miniz_oxide",
@@ -1856,7 +1804,6 @@ name = "gateway-client"
version = "0.1.0"
dependencies = [
"coconut-interface",
"cosmrs",
"credentials",
"crypto",
"fluvio-wasm-timer",
@@ -1875,7 +1822,6 @@ dependencies = [
"tokio-tungstenite",
"tungstenite",
"url",
"validator-client",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-utils",
@@ -1940,7 +1886,7 @@ version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"js-sys",
"libc",
"wasi 0.9.0+wasi-snapshot-preview1",
@@ -1953,7 +1899,7 @@ version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"js-sys",
"libc",
"wasi 0.10.0+wasi-snapshot-preview1",
@@ -2441,7 +2387,7 @@ version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"js-sys",
"wasm-bindgen",
"web-sys",
@@ -2538,7 +2484,7 @@ version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "903ae2481bcdfdb7b68e0a9baa4b7c9aff600b9ae2e8e5bb5833b8c91ab851ea"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"ecdsa 0.12.4",
"elliptic-curve 0.10.6",
"sha2",
@@ -2550,7 +2496,7 @@ version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"ecdsa 0.13.4",
"elliptic-curve 0.11.12",
"sec1",
@@ -2623,12 +2569,6 @@ dependencies = [
"vcpkg",
]
[[package]]
name = "linked-hash-map"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
[[package]]
name = "lioness"
version = "0.1.2"
@@ -2656,7 +2596,7 @@ version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
]
[[package]]
@@ -2665,7 +2605,7 @@ version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edc5c7d328e32cc4954e8e01193d7f0ef5ab257b5090b70a964e099a36034309"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"generator",
"scoped-tls",
"serde",
@@ -2864,7 +2804,7 @@ dependencies = [
name = "network-defaults"
version = "0.1.0"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"hex-literal",
"once_cell",
"serde",
@@ -2952,7 +2892,7 @@ dependencies = [
[[package]]
name = "nym-client"
version = "0.12.1"
version = "1.0.0-rc.1"
dependencies = [
"clap 2.34.0",
"client-core",
@@ -2986,7 +2926,7 @@ dependencies = [
[[package]]
name = "nym-gateway"
version = "0.12.1"
version = "1.0.0-rc.1"
dependencies = [
"anyhow",
"async-trait",
@@ -3032,7 +2972,7 @@ dependencies = [
[[package]]
name = "nym-mixnode"
version = "0.12.1"
version = "1.0.0-rc.1"
dependencies = [
"anyhow",
"bs58",
@@ -3070,7 +3010,7 @@ dependencies = [
[[package]]
name = "nym-network-requester"
version = "0.12.0"
version = "1.0.0-rc.1"
dependencies = [
"clap 2.34.0",
"dirs",
@@ -3091,7 +3031,7 @@ dependencies = [
[[package]]
name = "nym-socks5-client"
version = "0.12.1"
version = "1.0.0-rc.1"
dependencies = [
"clap 2.34.0",
"client-core",
@@ -3126,14 +3066,12 @@ dependencies = [
[[package]]
name = "nym-validator-api"
version = "0.12.0"
version = "1.0.0-rc.1"
dependencies = [
"anyhow",
"async-trait",
"attohttpc",
"cfg-if 1.0.0",
"cfg-if",
"clap 2.34.0",
"coconut-bandwidth-contract-common",
"coconut-interface",
"config",
"console-subscriber",
@@ -3147,7 +3085,6 @@ dependencies = [
"humantime-serde",
"log",
"mixnet-contract-common",
"nymcoconut",
"nymsphinx",
"pin-project",
"pretty_env_logger",
@@ -3353,7 +3290,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95"
dependencies = [
"bitflags",
"cfg-if 1.0.0",
"cfg-if",
"foreign-types",
"libc",
"once_cell",
@@ -3457,7 +3394,7 @@ version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"instant",
"libc",
"redox_syscall",
@@ -3471,7 +3408,7 @@ version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"libc",
"redox_syscall",
"smallvec 1.8.0",
@@ -3620,19 +3557,6 @@ dependencies = [
"indexmap",
]
[[package]]
name = "pickledb"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9161694d67f6c5163519d42be942ae36bbdb55f439460144f105bc4f9f7d1d61"
dependencies = [
"bincode",
"serde",
"serde_cbor",
"serde_json",
"serde_yaml",
]
[[package]]
name = "pin-project"
version = "1.0.10"
@@ -4786,18 +4710,6 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_yaml"
version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a521f2940385c165a24ee286aa8599633d162077a54bdcae2a6fd5a7bfa7a0"
dependencies = [
"indexmap",
"ryu",
"serde",
"yaml-rust",
]
[[package]]
name = "serial_test"
version = "0.5.1"
@@ -4839,7 +4751,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6"
dependencies = [
"block-buffer 0.9.0",
"cfg-if 1.0.0",
"cfg-if",
"cpufeatures",
"digest 0.9.0",
"opaque-debug 0.3.0",
@@ -4851,7 +4763,7 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"cpufeatures",
"digest 0.10.3",
]
@@ -4878,7 +4790,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
dependencies = [
"block-buffer 0.9.0",
"cfg-if 1.0.0",
"cfg-if",
"cpufeatures",
"digest 0.9.0",
"opaque-debug 0.3.0",
@@ -5327,7 +5239,7 @@ version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"fastrand",
"libc",
"redox_syscall",
@@ -5805,7 +5717,7 @@ version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"log",
"pin-project-lite",
"tracing-attributes",
@@ -6069,12 +5981,10 @@ dependencies = [
"base64",
"bip39",
"coconut-interface",
"colored",
"config",
"cosmrs",
"cosmwasm-std",
"flate2",
"futures",
"itertools",
"log",
"mixnet-contract-common",
@@ -6085,7 +5995,6 @@ dependencies = [
"serde_json",
"sha2",
"thiserror",
"tokio",
"ts-rs",
"url",
"validator-api-requests",
@@ -6118,7 +6027,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6cf88d94e969e7956d924ba70741316796177fa0c79a2c9f4ab04998d96e966e"
dependencies = [
"anyhow",
"cfg-if 1.0.0",
"cfg-if",
"chrono",
"enum-iterator",
"getset",
@@ -6143,11 +6052,11 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "vesting-contract"
version = "0.1.0"
version = "1.0.0-rc.1"
dependencies = [
"config",
"cosmwasm-std",
"cw-storage-plus 0.12.1",
"cw-storage-plus",
"mixnet-contract-common",
"schemars",
"serde",
@@ -6161,7 +6070,7 @@ version = "0.1.0"
dependencies = [
"config",
"cosmwasm-std",
"cw-storage-plus 0.11.1",
"cw-storage-plus",
"mixnet-contract-common",
"schemars",
"serde",
@@ -6213,7 +6122,7 @@ version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"serde",
"serde_json",
"wasm-bindgen-macro",
@@ -6240,7 +6149,7 @@ version = "0.4.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e8d7523cb1f2a4c96c1317ca690031b714a51cc14e05f712446691f413f5d39"
dependencies = [
"cfg-if 1.0.0",
"cfg-if",
"js-sys",
"wasm-bindgen",
"web-sys",
@@ -6493,15 +6402,6 @@ dependencies = [
"zeroize",
]
[[package]]
name = "yaml-rust"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]
[[package]]
name = "yansi"
version = "0.5.0"
-2
View File
@@ -14,7 +14,6 @@ panic = "abort"
resolver = "2"
members = [
"clients/client-core",
"clients/credential",
"clients/native",
"clients/native/websocket-requests",
"clients/socks5",
@@ -27,7 +26,6 @@ members = [
"common/credentials",
"common/crypto",
"common/bandwidth-claim-contract",
"common/cosmwasm-smart-contracts/coconut-bandwidth-contract",
"common/cosmwasm-smart-contracts/contracts-common",
"common/cosmwasm-smart-contracts/mixnet-contract",
"common/cosmwasm-smart-contracts/vesting-contract",
+1 -1
View File
@@ -1,4 +1,4 @@
<svg viewBox="0 0 210 56" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg width="210" height="56" viewBox="0 0 210 56" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M45.8829 0.142822H45.7169V0.28114V48.637L25.3289 0.225818L25.3012 0.142822H25.1905H13.6272H0.652966H0.514648V0.28114V55.7189V55.8572H0.652966H13.6272H13.7655V55.7189V7.28002L34.2365 55.7742L34.2642 55.8572H34.3748H45.8829H58.8294H58.9677V55.7189V0.28114V0.142822H58.8294H45.8829Z"/>
<path d="M209.347 0.142822H184.616H184.477L184.45 0.253483L171.78 48.8583L159.082 0.253483L159.054 0.142822H158.944H134.157H133.991V0.28114V55.7189V55.8572H134.157H147.104H147.242V55.7189V7.66731L159.774 55.7466L159.801 55.8572H159.94H183.564H183.675L183.703 55.7466L196.234 7.66731V55.7189V55.8572H196.373H209.347H209.485V55.7189V0.28114V0.142822H209.347Z"/>
<path d="M112.663 0.142822H112.58L112.552 0.198153L96.8116 27.5574L80.988 0.198153L80.9604 0.142822H80.8774H65.9114H65.6348L65.7731 0.364136L90.1447 42.5787V55.7189V55.8572H90.283H103.257H103.396V55.7189V42.5787L127.767 0.364136L127.905 0.142822H127.629H112.663Z"/>

Before

Width:  |  Height:  |  Size: 1011 B

After

Width:  |  Height:  |  Size: 1.0 KiB

+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "client-core"
version = "0.12.0"
version = "1.0.0-rc.1"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
edition = "2021"
@@ -32,4 +32,4 @@ validator-client = { path = "../../common/client-libs/validator-client" }
tempfile = "3.1.0"
[features]
coconut = ["gateway-client/coconut", "gateway-requests/coconut"]
coconut = []
-3453
View File
File diff suppressed because it is too large Load Diff
-29
View File
@@ -1,29 +0,0 @@
[package]
name = "credential"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
async-trait = "0.1.52"
bip39 = "1.0.1"
cfg-if = "0.1"
clap = { version = "3.0.10", features = ["cargo", "derive"] }
pickledb = "0.4.1"
rand = "0.7.3"
serde = { version = "1.0", features = ["derive"] }
thiserror = "1.0"
url = "2.2"
tokio = { version = "1.4", features = ["rt-multi-thread", "net", "signal", "macros"] } # async runtime
coconut-bandwidth-contract-common = { path = "../../common/cosmwasm-smart-contracts/coconut-bandwidth-contract" }
coconut-interface = { path = "../../common/coconut-interface" }
credentials = { path = "../../common/credentials" }
crypto = { path = "../../common/crypto", features = ["rand", "asymmetric", "symmetric", "aes", "hashing"] }
network-defaults = { path = "../../common/network-defaults" }
pemstore = { path = "../../common/pemstore" }
validator-client = { path = "../../common/client-libs/validator-client", features = ["nymd-client"] }
[features]
coconut = ["credentials/coconut"]
-69
View File
@@ -1,69 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use bip39::Mnemonic;
use coconut_bandwidth_contract_common::deposit::DepositData;
use std::str::FromStr;
use url::Url;
use crate::error::Result;
use crate::{CONTRACT_ADDRESS, MNEMONIC, NYMD_URL};
use coconut_bandwidth_contract_common::msg::ExecuteMsg;
use network_defaults::DEFAULT_NETWORK;
use validator_client::nymd::{
AccountId, CosmosCoin, Decimal, Denom, NymdClient, SigningNymdClient,
};
pub(crate) struct Client {
nymd_client: NymdClient<SigningNymdClient>,
denom: Denom,
contract_address: AccountId,
}
impl Client {
pub fn new() -> Self {
let nymd_url = Url::from_str(NYMD_URL).unwrap();
let mnemonic = Mnemonic::from_str(MNEMONIC).unwrap();
let nymd_client = NymdClient::connect_with_mnemonic(
DEFAULT_NETWORK,
nymd_url.as_ref(),
None,
None,
None,
mnemonic,
None,
)
.unwrap();
let denom = Denom::from_str(network_defaults::DENOM).unwrap();
let contract_address = AccountId::from_str(CONTRACT_ADDRESS).unwrap();
Client {
nymd_client,
denom,
contract_address,
}
}
pub async fn deposit(
&self,
amount: u64,
info: &str,
verification_key: String,
encryption_key: String,
) -> Result<String> {
let req = ExecuteMsg::DepositFunds {
data: DepositData::new(info.to_string(), verification_key, encryption_key),
};
let funds = vec![CosmosCoin {
denom: self.denom.clone(),
amount: Decimal::from(amount),
}];
Ok(self
.nymd_client
.execute(&self.contract_address, &req, Default::default(), "", funds)
.await?
.transaction_hash
.to_string())
}
}
-186
View File
@@ -1,186 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use async_trait::async_trait;
use clap::{Args, Subcommand};
use pickledb::PickleDb;
use rand::rngs::OsRng;
use std::str::FromStr;
use url::Url;
use coconut_interface::{Attribute, Base58, BlindSignRequest, Bytable, Parameters};
use credentials::coconut::bandwidth::{BandwidthVoucher, TOTAL_ATTRIBUTES};
use credentials::coconut::utils::obtain_aggregate_signature;
use crypto::asymmetric::{encryption, identity};
use network_defaults::VOUCHER_INFO;
use validator_client::nymd::tx::Hash;
use crate::client::Client;
use crate::error::{CredentialClientError, Result};
use crate::state::{KeyPair, RequestData, State};
use crate::SIGNER_AUTHORITIES;
#[derive(Subcommand)]
pub(crate) enum Commands {
/// Deposit funds for buying coconut credential
Deposit(Deposit),
/// Lists the tx hashes of previous deposits
ListDeposits(ListDeposits),
/// Get a credential for a given deposit
GetCredential(GetCredential),
}
#[async_trait]
pub(crate) trait Execute {
async fn execute(&self, db: &mut PickleDb) -> Result<()>;
}
#[derive(Args, Clone)]
pub(crate) struct Deposit {
/// The amount that needs to be deposited
#[clap(long)]
amount: u64,
}
#[async_trait]
impl Execute for Deposit {
async fn execute(&self, db: &mut PickleDb) -> Result<()> {
let mut rng = OsRng;
let signing_keypair = KeyPair::from(identity::KeyPair::new(&mut rng));
let encryption_keypair = KeyPair::from(encryption::KeyPair::new(&mut rng));
let client = Client::new();
let tx_hash = client
.deposit(
self.amount,
VOUCHER_INFO,
signing_keypair.public_key.clone(),
encryption_keypair.public_key.clone(),
)
.await?;
let state = State {
amount: self.amount,
tx_hash: tx_hash.clone(),
signing_keypair,
encryption_keypair,
blind_request_data: None,
signature: None,
};
db.set(&tx_hash, &state).unwrap();
println!("{:?}", state);
Ok(())
}
}
#[derive(Args, Clone)]
pub(crate) struct ListDeposits {}
#[async_trait]
impl Execute for ListDeposits {
async fn execute(&self, db: &mut PickleDb) -> Result<()> {
for kv in db.iter() {
println!("{:?}", kv.get_value::<State>());
}
Ok(())
}
}
#[derive(Args, Clone)]
pub(crate) struct GetCredential {
/// The hash of a successful deposit transaction
#[clap(long)]
tx_hash: String,
/// If we want to get the signature without attaching a blind sign request; it is expected that
/// there is already a signature stored on the signer
#[clap(long, parse(from_flag))]
__no_request: bool,
}
#[async_trait]
impl Execute for GetCredential {
async fn execute(&self, db: &mut PickleDb) -> Result<()> {
let mut state = db
.get::<State>(&self.tx_hash)
.ok_or(CredentialClientError::NoDeposit)?;
let urls = SIGNER_AUTHORITIES.map(|addr| Url::from_str(addr).unwrap());
let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap();
let bandwidth_credential_attributes = if self.__no_request {
if let Some(blind_request_data) = state.blind_request_data {
let serial_number =
Attribute::try_from_byte_slice(&blind_request_data.serial_number)
.map_err(|_| CredentialClientError::CorruptedBlindSignRequest)?;
let binding_number =
Attribute::try_from_byte_slice(&blind_request_data.binding_number)
.map_err(|_| CredentialClientError::CorruptedBlindSignRequest)?;
let pedersen_commitments_openings = vec![
Attribute::try_from_byte_slice(&blind_request_data.first_attribute)
.map_err(|_| CredentialClientError::CorruptedBlindSignRequest)?,
Attribute::try_from_byte_slice(&blind_request_data.second_attribute)
.map_err(|_| CredentialClientError::CorruptedBlindSignRequest)?,
];
let blind_sign_request =
BlindSignRequest::from_bytes(blind_request_data.blind_sign_req.as_slice())
.map_err(|_| CredentialClientError::CorruptedBlindSignRequest)?;
BandwidthVoucher::new_with_blind_sign_req(
[serial_number, binding_number],
[&state.amount.to_string(), VOUCHER_INFO],
Hash::from_str(&self.tx_hash)
.map_err(|_| CredentialClientError::InvalidTxHash)?,
identity::PrivateKey::from_base58_string(&state.signing_keypair.private_key)?,
encryption::PrivateKey::from_base58_string(
&state.encryption_keypair.private_key,
)?,
pedersen_commitments_openings,
blind_sign_request,
)
} else {
return Err(CredentialClientError::NoLocalBlindSignRequest);
}
} else {
BandwidthVoucher::new(
&params,
state.amount.to_string(),
VOUCHER_INFO.to_string(),
Hash::from_str(&self.tx_hash).map_err(|_| CredentialClientError::InvalidTxHash)?,
identity::PrivateKey::from_base58_string(&state.signing_keypair.private_key)?,
encryption::PrivateKey::from_base58_string(&state.encryption_keypair.private_key)?,
)
};
// Back up the blind sign req data, in case of sporadic failures
state.blind_request_data = Some(RequestData::new(
bandwidth_credential_attributes.get_private_attributes(),
bandwidth_credential_attributes.pedersen_commitments_openings(),
bandwidth_credential_attributes.blind_sign_request(),
)?);
db.set(&self.tx_hash, &state).unwrap();
let signature =
obtain_aggregate_signature(&params, &bandwidth_credential_attributes, &urls).await?;
state.signature = Some(signature.to_bs58());
db.set(&self.tx_hash, &state).unwrap();
println!("Signature: {:?}", state.signature);
Ok(())
}
}
#[derive(Args, Clone)]
pub(crate) struct SpendCredential {
/// Spend one of the acquired credentials
#[clap(long)]
id: usize,
}
#[async_trait]
impl Execute for SpendCredential {
async fn execute(&self, _db: &mut PickleDb) -> Result<()> {
Ok(())
}
}
-41
View File
@@ -1,41 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use thiserror::Error;
use credentials::error::Error as CredentialError;
use crypto::asymmetric::encryption::KeyRecoveryError;
use crypto::asymmetric::identity::Ed25519RecoveryError;
use validator_client::nymd::error::NymdError;
pub type Result<T> = std::result::Result<T, CredentialClientError>;
#[derive(Error, Debug)]
pub enum CredentialClientError {
#[error("Nymd error: {0}")]
Nymd(#[from] NymdError),
#[error("Credential error: {0}")]
Credential(#[from] CredentialError),
#[error("No previous deposit with that tx hash")]
NoDeposit,
#[error("Wrong number of attributes")]
WrongAttributeNumber,
#[error("Could not find any backed up blind sign request data")]
NoLocalBlindSignRequest,
#[error("The local blind sign request data is corrupted")]
CorruptedBlindSignRequest,
#[error("The tx hash provided is not valid")]
InvalidTxHash,
#[error("Could not parse Ed25519 data")]
Ed25519ParseError(#[from] Ed25519RecoveryError),
#[error("Could not parse X25519 data")]
X25519ParseError(#[from] KeyRecoveryError),
}
-61
View File
@@ -1,61 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
cfg_if::cfg_if! {
if #[cfg(feature = "coconut")] {
mod client;
mod commands;
mod error;
mod state;
use commands::{Commands, Execute};
use error::Result;
use clap::Parser;
use pickledb::{PickleDb, PickleDbDumpPolicy, SerializationMethod};
pub const MNEMONIC: &str = "sun surge soon stomach flavor country gorilla dress oblige stamp attract hip soldier agree steel prize nuclear know enjoy arm bargain always theme matter";
pub const NYMD_URL: &str = "http://127.0.0.1:26657";
pub const CONTRACT_ADDRESS: &str = "nymt1vhjnzk9ly03dugffvzfcwgry4dgc8x0sscmfl2";
pub const SIGNER_AUTHORITIES: [&str; 1] = [
"http://127.0.0.1:8080",
];
#[derive(Parser)]
#[clap(author = "Nymtech", version, about)]
struct Cli {
#[clap(subcommand)]
command: Commands,
}
#[tokio::main]
async fn main() -> Result<()> {
let args = Cli::parse();
let mut db = match PickleDb::load(
"credential.db",
PickleDbDumpPolicy::AutoDump,
SerializationMethod::Json,
) {
Ok(db) => db,
Err(_) => PickleDb::new(
"credential.db",
PickleDbDumpPolicy::AutoDump,
SerializationMethod::Json,
),
};
match &args.command {
Commands::Deposit(m) => m.execute(&mut db).await?,
Commands::ListDeposits(m) => m.execute(&mut db).await?,
Commands::GetCredential(m) => m.execute(&mut db).await?,
}
Ok(())
}
} else {
fn main() {
println!("Crate only designed for coconut feature");
}
}
}
-72
View File
@@ -1,72 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use coconut_interface::{Attribute, BlindSignRequest, Bytable, PrivateAttribute};
use serde::{Deserialize, Serialize};
use crypto::asymmetric::{encryption, identity};
use crate::error::{CredentialClientError, Result};
#[derive(Clone, Debug, Deserialize, Serialize)]
pub(crate) struct KeyPair {
pub public_key: String,
pub private_key: String,
}
impl From<identity::KeyPair> for KeyPair {
fn from(kp: identity::KeyPair) -> Self {
Self {
public_key: kp.public_key().to_base58_string(),
private_key: kp.private_key().to_base58_string(),
}
}
}
impl From<encryption::KeyPair> for KeyPair {
fn from(kp: encryption::KeyPair) -> Self {
Self {
public_key: kp.public_key().to_base58_string(),
private_key: kp.private_key().to_base58_string(),
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub(crate) struct State {
pub amount: u64,
pub tx_hash: String,
pub signing_keypair: KeyPair,
pub encryption_keypair: KeyPair,
pub blind_request_data: Option<RequestData>,
pub signature: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub(crate) struct RequestData {
pub serial_number: Vec<u8>,
pub binding_number: Vec<u8>,
pub first_attribute: Vec<u8>,
pub second_attribute: Vec<u8>,
pub blind_sign_req: Vec<u8>,
}
impl RequestData {
pub fn new(
private_attributes: Vec<PrivateAttribute>,
attributes: &[Attribute],
blind_sign_request: &BlindSignRequest,
) -> Result<Self> {
if private_attributes.len() != 2 || attributes.len() != 2 {
Err(CredentialClientError::WrongAttributeNumber)
} else {
Ok(RequestData {
serial_number: private_attributes[0].to_byte_vec(),
binding_number: private_attributes[1].to_byte_vec(),
first_attribute: attributes[0].to_byte_vec(),
second_attribute: attributes[1].to_byte_vec(),
blind_sign_req: blind_sign_request.to_bytes(),
})
}
}
}
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "0.12.1"
version = "1.0.0-rc.1"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
edition = "2021"
rust-version = "1.56"
@@ -47,7 +47,7 @@ version-checker = { path = "../../common/version-checker" }
network-defaults = { path = "../../common/network-defaults" }
[features]
coconut = ["coconut-interface", "credentials", "credentials/coconut", "gateway-requests/coconut", "gateway-client/coconut"]
coconut = ["coconut-interface", "credentials", "gateway-requests/coconut", "gateway-client/coconut"]
eth = []
[dev-dependencies]
+11 -24
View File
@@ -5,12 +5,11 @@ use clap::{App, Arg, ArgMatches};
use client_core::client::key_manager::KeyManager;
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
#[cfg(feature = "coconut")]
use coconut_interface::{Credential, Parameters};
use coconut_interface::{hash_to_scalar, Credential, Parameters};
use config::NymConfig;
#[cfg(feature = "coconut")]
use credentials::coconut::{
bandwidth::prepare_for_spending, bandwidth::BandwidthVoucher, bandwidth::TOTAL_ATTRIBUTES,
utils::obtain_aggregate_signature,
use credentials::coconut::bandwidth::{
obtain_signature, prepare_for_spending, BandwidthVoucherAttributes, TOTAL_ATTRIBUTES,
};
#[cfg(feature = "coconut")]
use credentials::obtain_aggregate_verification_key;
@@ -18,7 +17,7 @@ use crypto::asymmetric::{encryption, identity};
use gateway_client::GatewayClient;
use gateway_requests::registration::handshake::SharedKeys;
#[cfg(feature = "coconut")]
use network_defaults::{BANDWIDTH_VALUE, VOUCHER_INFO};
use network_defaults::BANDWIDTH_VALUE;
use nymsphinx::addressing::clients::Recipient;
use nymsphinx::addressing::nodes::NodeIdentity;
use rand::rngs::OsRng;
@@ -29,8 +28,6 @@ use std::sync::Arc;
use std::time::Duration;
use topology::{filter::VersionFilterable, gateway};
use url::Url;
#[cfg(feature = "coconut")]
use validator_client::nymd::tx::Hash;
use crate::client::config::Config;
use crate::commands::override_config;
@@ -110,25 +107,15 @@ async fn _prepare_temporary_credential(validators: &[Url], raw_identity: &[u8])
.expect("could not obtain aggregate verification key of validators");
let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap();
let mut rng = OsRng;
let bandwidth_credential_attributes = BandwidthVoucher::new(
&params,
BANDWIDTH_VALUE.to_string(),
VOUCHER_INFO.to_string(),
Hash::new([0; 32]),
// workaround for putting a valid value here, without deriving clone for the private
// key, until we have actual useful values
identity::PrivateKey::from_base58_string(
identity::KeyPair::new(&mut rng)
.private_key()
.to_base58_string(),
)
.unwrap(),
encryption::KeyPair::new(&mut rng).private_key().clone(),
);
let bandwidth_credential_attributes = BandwidthVoucherAttributes {
serial_number: params.random_scalar(),
binding_number: params.random_scalar(),
voucher_value: hash_to_scalar(BANDWIDTH_VALUE.to_be_bytes()),
voucher_info: hash_to_scalar(String::from("BandwidthVoucher").as_bytes()),
};
let bandwidth_credential =
obtain_aggregate_signature(&params, &bandwidth_credential_attributes, validators)
obtain_signature(&params, &bandwidth_credential_attributes, validators)
.await
.expect("could not obtain bandwidth credential");
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "0.12.1"
version = "1.0.0-rc.1"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
edition = "2021"
rust-version = "1.56"
@@ -42,7 +42,7 @@ version-checker = { path = "../../common/version-checker" }
network-defaults = { path = "../../common/network-defaults" }
[features]
coconut = ["coconut-interface", "credentials", "gateway-requests/coconut", "gateway-client/coconut", "credentials/coconut"]
coconut = ["coconut-interface", "credentials", "gateway-requests/coconut", "gateway-client/coconut"]
eth = []
[build-dependencies]
+10 -23
View File
@@ -5,12 +5,11 @@ use clap::{App, Arg, ArgMatches};
use client_core::client::key_manager::KeyManager;
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
#[cfg(feature = "coconut")]
use coconut_interface::{Credential, Parameters};
use coconut_interface::{hash_to_scalar, Credential, Parameters};
use config::NymConfig;
#[cfg(feature = "coconut")]
use credentials::coconut::{
bandwidth::prepare_for_spending, bandwidth::BandwidthVoucher, bandwidth::TOTAL_ATTRIBUTES,
utils::obtain_aggregate_signature,
use credentials::coconut::bandwidth::{
obtain_signature, prepare_for_spending, BandwidthVoucherAttributes, TOTAL_ATTRIBUTES,
};
#[cfg(feature = "coconut")]
use credentials::obtain_aggregate_verification_key;
@@ -27,8 +26,6 @@ use std::sync::Arc;
use std::time::Duration;
use topology::{filter::VersionFilterable, gateway};
use url::Url;
#[cfg(feature = "coconut")]
use validator_client::nymd::tx::Hash;
use crate::client::config::Config;
use crate::commands::override_config;
@@ -110,25 +107,15 @@ async fn _prepare_temporary_credential(validators: &[Url], raw_identity: &[u8])
.expect("could not obtain aggregate verification key of validators");
let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap();
let mut rng = OsRng;
let bandwidth_credential_attributes = BandwidthVoucher::new(
&params,
BANDWIDTH_VALUE.to_string(),
network_defaults::VOUCHER_INFO.to_string(),
Hash::new([0; 32]),
// workaround for putting a valid value here, without deriving clone for the private
// key, until we have actual useful values
identity::PrivateKey::from_base58_string(
identity::KeyPair::new(&mut rng)
.private_key()
.to_base58_string(),
)
.unwrap(),
encryption::KeyPair::new(&mut rng).private_key().clone(),
);
let bandwidth_credential_attributes = BandwidthVoucherAttributes {
serial_number: params.random_scalar(),
binding_number: params.random_scalar(),
voucher_value: hash_to_scalar(BANDWIDTH_VALUE.to_be_bytes()),
voucher_info: hash_to_scalar("BandwidthVoucher"),
};
let bandwidth_credential =
obtain_aggregate_signature(&params, &bandwidth_credential_attributes, validators)
obtain_signature(&params, &bandwidth_credential_attributes, validators)
.await
.expect("could not obtain bandwidth credential");
+1 -1
View File
@@ -1,7 +1,7 @@
[package]
name = "nym-client-wasm"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jedrzej Stuczynski <andrew@nymtech.net>"]
version = "0.12.0"
version = "1.0.0-rc.1"
edition = "2021"
keywords = ["nym", "sphinx", "wasm", "webassembly", "privacy", "client"]
license = "Apache-2.0"
+1 -3
View File
@@ -19,7 +19,6 @@ secp256k1 = "0.20.3"
web3 = { version = "0.17.0", default-features = false }
# internal
cosmrs = { version = "0.4.1", optional = true }
credentials = { path = "../../credentials" }
crypto = { path = "../../crypto" }
gateway-requests = { path = "../../../gateway/gateway-requests" }
@@ -27,7 +26,6 @@ nymsphinx = { path = "../../nymsphinx" }
pemstore = { path = "../../pemstore" }
coconut-interface = { path = "../../coconut-interface", optional = true }
network-defaults = { path = "../../network-defaults" }
validator-client = { path = "../validator-client", optional = true }
[dependencies.tungstenite]
version = "0.13"
@@ -69,6 +67,6 @@ features = ["js"]
#url = "2.1"
[features]
coconut = ["gateway-requests/coconut", "coconut-interface", "validator-client", "credentials/coconut", "cosmrs"]
coconut = ["gateway-requests/coconut", "coconut-interface"]
wasm = ["web3/wasm", "web3/http", "web3/signing"]
default = ["web3/default"]
@@ -1,18 +1,18 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
#[cfg(feature = "coconut")]
use cosmrs::tx::Hash;
#[cfg(feature = "coconut")]
use credentials::coconut::{
bandwidth::{prepare_for_spending, BandwidthVoucher, TOTAL_ATTRIBUTES},
utils::{obtain_aggregate_signature, obtain_aggregate_verification_key},
bandwidth::{
obtain_signature, prepare_for_spending, BandwidthVoucherAttributes, TOTAL_ATTRIBUTES,
},
utils::obtain_aggregate_verification_key,
};
#[cfg(not(feature = "coconut"))]
use credentials::token::bandwidth::TokenCredential;
#[cfg(feature = "coconut")]
use crypto::asymmetric::encryption;
#[cfg(not(feature = "coconut"))]
use crypto::asymmetric::identity;
use crypto::asymmetric::identity::PublicKey;
use network_defaults::BANDWIDTH_VALUE;
#[cfg(not(feature = "coconut"))]
use network_defaults::{
@@ -22,6 +22,7 @@ use network_defaults::{
};
#[cfg(not(feature = "coconut"))]
use pemstore::traits::PemStorableKeyPair;
#[cfg(not(feature = "coconut"))]
use rand::rngs::OsRng;
#[cfg(not(feature = "coconut"))]
use secp256k1::SecretKey;
@@ -72,7 +73,7 @@ pub struct BandwidthController {
#[cfg(feature = "coconut")]
validator_endpoints: Vec<url::Url>,
#[cfg(feature = "coconut")]
identity: identity::PublicKey,
identity: PublicKey,
#[cfg(not(feature = "coconut"))]
contract: Contract<Http>,
#[cfg(not(feature = "coconut"))]
@@ -85,7 +86,7 @@ pub struct BandwidthController {
impl BandwidthController {
#[cfg(feature = "coconut")]
pub fn new(validator_endpoints: Vec<url::Url>, identity: identity::PublicKey) -> Self {
pub fn new(validator_endpoints: Vec<url::Url>, identity: PublicKey) -> Self {
BandwidthController {
validator_endpoints,
identity,
@@ -174,25 +175,17 @@ impl BandwidthController {
let verification_key = obtain_aggregate_verification_key(&self.validator_endpoints).await?;
let params = coconut_interface::Parameters::new(TOTAL_ATTRIBUTES).unwrap();
let mut rng = OsRng;
// TODO: Decide what is the value and additional info associated with the bandwidth voucher
let bandwidth_credential_attributes = BandwidthVoucher::new(
&params,
BANDWIDTH_VALUE.to_string(),
network_defaults::VOUCHER_INFO.to_string(),
Hash::new([0; 32]),
// workaround for putting a valid value here, without deriving clone for the private
// key, until we have actual useful values
identity::PrivateKey::from_base58_string(
identity::KeyPair::new(&mut rng)
.private_key()
.to_base58_string(),
)
.unwrap(),
encryption::KeyPair::new(&mut rng).private_key().clone(),
);
let bandwidth_credential_attributes = BandwidthVoucherAttributes {
serial_number: params.random_scalar(),
binding_number: params.random_scalar(),
voucher_value: coconut_interface::hash_to_scalar(BANDWIDTH_VALUE.to_be_bytes()),
voucher_info: coconut_interface::hash_to_scalar(
String::from("BandwidthVoucher").as_bytes(),
),
};
let bandwidth_credential = obtain_aggregate_signature(
let bandwidth_credential = obtain_signature(
&params,
&bandwidth_credential_attributes,
&self.validator_endpoints,
@@ -212,7 +205,7 @@ impl BandwidthController {
#[cfg(not(feature = "coconut"))]
pub async fn prepare_token_credential(
&self,
gateway_identity: identity::PublicKey,
gateway_identity: PublicKey,
gateway_owner: String,
) -> Result<TokenCredential, GatewayClientError> {
let kp = match self.restore_keypair() {
@@ -251,7 +244,7 @@ impl BandwidthController {
#[cfg(not(feature = "coconut"))]
pub async fn buy_token_credential(
&self,
verification_key: identity::PublicKey,
verification_key: PublicKey,
signed_verification_key: identity::Signature,
gateway_owner: String,
) -> Result<(), GatewayClientError> {
@@ -9,7 +9,6 @@ rust-version = "1.56"
[dependencies]
base64 = "0.13"
colored = "2.0"
mixnet-contract-common = { path= "../../cosmwasm-smart-contracts/mixnet-contract" }
vesting-contract-common = { path= "../../cosmwasm-smart-contracts/vesting-contract" }
vesting-contract = { path = "../../../contracts/vesting" }
@@ -19,8 +18,6 @@ reqwest = { version = "0.11", features = ["json"] }
thiserror = "1"
log = "0.4"
url = { version = "2.2", features = ["serde"] }
tokio = { version = "1.10", features = ["sync", "time"] }
futures = "0.3"
coconut-interface = { path = "../../coconut-interface" }
network-defaults = { path = "../../network-defaults" }
@@ -32,12 +29,16 @@ validator-api-requests = { path = "../../../validator-api/validator-api-requests
async-trait = { version = "0.1.51", optional = true }
bip39 = { version = "1", features = ["rand"], optional = true }
config = { path = "../../config", optional = true }
cosmrs = { git = "https://github.com/nymtech/cosmos-rust", branch = "bugfix/account-id-length-validation", features = ["rpc", "bip32", "cosmwasm"], optional = true}
cosmrs = { version = "0.4.1", features = [
"rpc",
"bip32",
"cosmwasm",
], optional = true }
prost = { version = "0.9", default-features = false, optional = true }
flate2 = { version = "1.0.20", optional = true }
sha2 = { version = "0.9.5", optional = true }
itertools = { version = "0.10", optional = true }
cosmwasm-std = { version = "1.0.0-beta3", optional = true }
cosmwasm-std = { version = "1.0.0-beta6", optional = true }
[dev-dependencies]
ts-rs = "6.1.2"
@@ -685,16 +685,6 @@ impl ApiClient {
Ok(self.validator_api.blind_sign(request_body).await?)
}
pub async fn partial_bandwidth_credential(
&self,
request_body: &str,
) -> Result<BlindedSignatureResponse, ValidatorClientError> {
Ok(self
.validator_api
.partial_bandwidth_credential(request_body)
.await?)
}
pub async fn get_coconut_verification_key(
&self,
) -> Result<VerificationKeyResponse, ValidatorClientError> {
@@ -1,238 +0,0 @@
use crate::nymd::error::NymdError;
use crate::nymd::{NymdClient, QueryNymdClient};
use crate::ApiClient;
use network_defaults::all::Network;
use colored::Colorize;
use core::fmt;
use itertools::Itertools;
use std::collections::HashMap;
use std::hash::BuildHasher;
use std::time::Duration;
use tokio::time::timeout;
use url::Url;
const MAX_URLS_TESTED: usize = 200;
const CONNECTION_TEST_TIMEOUT_SEC: u64 = 2;
// Run connection tests for all specified nymd and api urls. These are all run concurrently.
pub async fn run_validator_connection_test<H: BuildHasher + 'static>(
nymd_urls: impl Iterator<Item = (Network, Url)>,
api_urls: impl Iterator<Item = (Network, Url)>,
mixnet_contract_address: HashMap<Network, Option<cosmrs::AccountId>, H>,
) -> (
HashMap<Network, Vec<(Url, bool)>>,
HashMap<Network, Vec<(Url, bool)>>,
) {
// Setup all the clients for the connection tests
let connection_test_clients =
setup_connection_tests(nymd_urls, api_urls, mixnet_contract_address);
// Run all tests concurrently
let connection_results = futures::future::join_all(
connection_test_clients
.into_iter()
.take(MAX_URLS_TESTED)
.map(ClientForConnectionTest::run_connection_check),
)
.await;
// Seperate and collect results into HashMaps
(
extract_and_collect_results_into_map(&connection_results, &UrlType::Nymd),
extract_and_collect_results_into_map(&connection_results, &UrlType::Api),
)
}
fn setup_connection_tests<H: BuildHasher + 'static>(
nymd_urls: impl Iterator<Item = (Network, Url)>,
api_urls: impl Iterator<Item = (Network, Url)>,
mixnet_contract_address: HashMap<Network, Option<cosmrs::AccountId>, H>,
) -> impl Iterator<Item = ClientForConnectionTest> {
let nymd_connection_test_clients = nymd_urls.filter_map(move |(network, url)| {
let address = mixnet_contract_address
.get(&network)
.expect("No configured contract address")
.clone();
NymdClient::<QueryNymdClient>::connect(url.as_str(), address, None, None)
.map(move |client| ClientForConnectionTest::Nymd(network, url, Box::new(client)))
.ok()
});
let api_connection_test_clients = api_urls.map(|(network, url)| {
ClientForConnectionTest::Api(network, url.clone(), ApiClient::new(url))
});
nymd_connection_test_clients.chain(api_connection_test_clients)
}
fn extract_and_collect_results_into_map(
connection_results: &[ConnectionResult],
url_type: &UrlType,
) -> HashMap<Network, Vec<(Url, bool)>> {
connection_results
.iter()
.filter(|c| &c.url_type() == url_type)
.map(|c| {
let (network, url, result) = c.result();
(*network, (url.clone(), *result))
})
.into_group_map()
}
async fn test_nymd_connection(
network: Network,
url: &Url,
client: &NymdClient<QueryNymdClient>,
) -> ConnectionResult {
let result = match timeout(
Duration::from_secs(CONNECTION_TEST_TIMEOUT_SEC),
client.get_mixnet_contract_version(),
)
.await
{
Ok(Err(NymdError::TendermintError(e))) => {
// If we get a tendermint-rpc error, we classify the node as not contactable
log::debug!(
"Checking: nymd_url: {network}: {url}: {}: {}",
"failed".red(),
e
);
false
}
Ok(Err(NymdError::AbciError(code, log))) => {
// We accept the mixnet contract not found as ok from a connection standpoint. This happens
// for example on a pre-launch network.
log::debug!(
"Checking: nymd_url: {network}: {url}: {}, but with abci error: {code}: {log}",
"success".green()
);
code == 18
}
Ok(Err(error @ NymdError::NoContractAddressAvailable)) => {
log::debug!(
"Checking: nymd_url: {network}: {url}: {}: {error}",
"failed".red()
);
false
}
Ok(Err(e)) => {
// For any other error, we're optimistic and just try anyway.
log::debug!(
"Checking: nymd_url: {network}: {url}: {}, but with error: {e}",
"success".green()
);
true
}
Ok(Ok(_)) => {
log::debug!(
"Checking: nymd_url: {network}: {url}: {}",
"success".green()
);
true
}
Err(e) => {
log::debug!(
"Checking: nymd_url: {network}: {url}: {}: {e}",
"failed".red()
);
false
}
};
ConnectionResult::Nymd(network, url.clone(), result)
}
async fn test_api_connection(network: Network, url: &Url, client: &ApiClient) -> ConnectionResult {
let result = match timeout(
Duration::from_secs(CONNECTION_TEST_TIMEOUT_SEC),
client.get_cached_mixnodes(),
)
.await
{
Ok(Ok(_)) => {
log::debug!("Checking: api_url: {network}: {url}: {}", "success".green());
true
}
Ok(Err(e)) => {
log::debug!(
"Checking: api_url: {network}: {url}: {}: {e}",
"failed".red()
);
false
}
Err(e) => {
log::debug!(
"Checking: api_url: {network}: {url}: {}: {e}",
"failed".red()
);
false
}
};
ConnectionResult::Api(network, url.clone(), result)
}
enum ClientForConnectionTest {
Nymd(Network, Url, Box<NymdClient<QueryNymdClient>>),
Api(Network, Url, ApiClient),
}
impl ClientForConnectionTest {
async fn run_connection_check(self) -> ConnectionResult {
match self {
ClientForConnectionTest::Nymd(network, ref url, ref client) => {
test_nymd_connection(network, url, client).await
}
ClientForConnectionTest::Api(network, ref url, ref client) => {
test_api_connection(network, url, client).await
}
}
}
}
#[derive(Debug, PartialEq, Eq)]
enum UrlType {
Nymd,
Api,
}
impl fmt::Display for UrlType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
UrlType::Nymd => write!(f, "nymd"),
UrlType::Api => write!(f, "api"),
}
}
}
#[derive(Debug)]
enum ConnectionResult {
Nymd(Network, Url, bool),
Api(Network, Url, bool),
}
impl ConnectionResult {
fn result(&self) -> (&Network, &Url, &bool) {
match self {
ConnectionResult::Nymd(network, url, result)
| ConnectionResult::Api(network, url, result) => (network, url, result),
}
}
fn url_type(&self) -> UrlType {
match self {
ConnectionResult::Nymd(..) => UrlType::Nymd,
ConnectionResult::Api(..) => UrlType::Api,
}
}
}
impl fmt::Display for ConnectionResult {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (network, url, result) = self.result();
let url_type = self.url_type();
write!(
f,
"{network}: {url}: {url_type}: connection is successful: {result}"
)
}
}
@@ -2,8 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
pub mod client;
#[cfg(feature = "nymd-client")]
pub mod connection_tester;
mod error;
#[cfg(feature = "nymd-client")]
pub mod nymd;
@@ -29,12 +29,9 @@ pub use crate::nymd::cosmwasm_client::client::CosmWasmClient;
pub use crate::nymd::cosmwasm_client::signing_client::SigningCosmWasmClient;
pub use crate::nymd::fee::Fee;
use crate::nymd::fee::DEFAULT_SIMULATED_GAS_MULTIPLIER;
pub use cosmrs::rpc::endpoint::tx::Response as TxResponse;
pub use cosmrs::rpc::endpoint::validators::Response as ValidatorResponse;
pub use cosmrs::rpc::HttpClient as QueryNymdClient;
pub use cosmrs::rpc::Paging;
pub use cosmrs::tendermint::abci::responses::{DeliverTx, Event};
pub use cosmrs::tendermint::abci::tag::Tag;
pub use cosmrs::tendermint::block::Height;
pub use cosmrs::tendermint::hash;
pub use cosmrs::tendermint::validator::Info as TendermintValidatorInfo;
@@ -277,13 +274,6 @@ impl<C> NymdClient<C> {
self.client.get_balance(address, denom).await
}
pub async fn get_tx(&self, id: tx::Hash) -> Result<TxResponse, NymdError>
where
C: CosmWasmClient + Sync,
{
self.client.get_tx(id).await
}
pub async fn get_total_supply(&self) -> Result<Vec<Coin>, NymdError>
where
C: CosmWasmClient + Sync,
@@ -599,6 +589,7 @@ impl<C> NymdClient<C> {
&self,
mix_identity: IdentityKey,
delegator: &AccountId,
proxy: Option<String>,
) -> Result<Delegation, NymdError>
where
C: CosmWasmClient + Sync,
@@ -606,6 +597,7 @@ impl<C> NymdClient<C> {
let request = QueryMsg::GetDelegationDetails {
mix_identity,
delegator: delegator.to_string(),
proxy,
};
self.client
.query_contract_smart(self.mixnet_contract_address()?, &request)
@@ -7,7 +7,4 @@ pub enum ValidatorAPIError {
#[from]
source: reqwest::Error,
},
#[error("Request failed with error message - {0}")]
GenericRequestFailure(String),
}
@@ -14,7 +14,7 @@ use validator_api_requests::models::{
};
pub mod error;
pub mod routes;
pub(crate) mod routes;
type PathSegments<'a> = &'a [&'a str];
type Params<'a, K, V> = &'a [(K, V)];
@@ -66,14 +66,14 @@ impl Client {
V: AsRef<str>,
{
let url = create_api_url(&self.url, path, params);
let response = self.reqwest_client.post(url).json(json_body).send().await?;
if response.status().is_success() {
Ok(response.json().await?)
} else {
Err(ValidatorAPIError::GenericRequestFailure(
response.text().await?,
))
}
Ok(self
.reqwest_client
.post(url)
.json(json_body)
.send()
.await?
.json()
.await?)
}
pub async fn get_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorAPIError> {
@@ -254,29 +254,7 @@ impl Client {
request_body: &BlindSignRequestBody,
) -> Result<BlindedSignatureResponse, ValidatorAPIError> {
self.post_validator_api(
&[
routes::API_VERSION,
routes::COCONUT_ROUTES,
routes::BANDWIDTH,
routes::COCONUT_BLIND_SIGN,
],
NO_PARAMS,
request_body,
)
.await
}
pub async fn partial_bandwidth_credential(
&self,
request_body: &str,
) -> Result<BlindedSignatureResponse, ValidatorAPIError> {
self.post_validator_api(
&[
routes::API_VERSION,
routes::COCONUT_ROUTES,
routes::BANDWIDTH,
routes::COCONUT_PARTIAL_BANDWIDTH_CREDENTIAL,
],
&[routes::API_VERSION, routes::COCONUT_BLIND_SIGN],
NO_PARAMS,
request_body,
)
@@ -287,12 +265,7 @@ impl Client {
&self,
) -> Result<VerificationKeyResponse, ValidatorAPIError> {
self.query_validator_api(
&[
routes::API_VERSION,
routes::COCONUT_ROUTES,
routes::BANDWIDTH,
routes::COCONUT_VERIFICATION_KEY,
],
&[routes::API_VERSION, routes::COCONUT_VERIFICATION_KEY],
NO_PARAMS,
)
.await
@@ -10,11 +10,7 @@ pub const GATEWAYS: &str = "gateways";
pub const ACTIVE: &str = "active";
pub const REWARDED: &str = "rewarded";
pub const COCONUT_ROUTES: &str = "coconut";
pub const BANDWIDTH: &str = "bandwidth";
pub const COCONUT_BLIND_SIGN: &str = "blind-sign";
pub const COCONUT_PARTIAL_BANDWIDTH_CREDENTIAL: &str = "partial-bandwidth-credential";
pub const COCONUT_VERIFICATION_KEY: &str = "verification-key";
pub const STATUS_ROUTES: &str = "status";
+1 -3
View File
@@ -5,9 +5,7 @@ edition = "2021"
description = "Crutch library until there is proper SerDe support for coconut structs"
[dependencies]
bs58 = "0.4.0"
getset = "0.1.1"
serde = { version = "1.0", features = ["derive"] }
thiserror = "1"
getset = "0.1.1"
nymcoconut = {path = "../nymcoconut" }
+16 -4
View File
@@ -5,9 +5,21 @@ use thiserror::Error;
#[derive(Debug, Error)]
pub enum CoconutInterfaceError {
#[error("not enough bytes: {0} received, minimum {1} required")]
InvalidByteLength(usize, usize),
#[error("could not parse validator URL: {source}")]
UrlParsingError {
#[from]
source: url::ParseError,
},
#[error("Could not decode base 58 string - {0}")]
MalformedString(#[from] bs58::decode::Error),
#[error("could not aggregate verification key: {0}")]
AggregateVerificationKeyError(coconut_rs::CoconutError),
#[error("could not prove credential: {0}")]
ProveCredentialError(coconut_rs::CoconutError),
#[error("got invalid signature index: {0}")]
InvalidSignatureIdx(usize),
#[error("got too many total attributes(public + private): {0} received, {1} is the maximum")]
TooManyTotalAttributes(usize, u32),
}
+5 -53
View File
@@ -1,13 +1,9 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod error;
use getset::{CopyGetters, Getters};
use serde::{Deserialize, Serialize};
use error::CoconutInterfaceError;
pub use nymcoconut::*;
#[derive(Serialize, Deserialize, Getters, CopyGetters, Clone)]
@@ -83,39 +79,27 @@ impl VerifyCredentialBody {
}
}
// All strings are base58 encoded representations of structs
#[derive(Clone, Serialize, Deserialize, Debug, Getters, CopyGetters)]
#[derive(Serialize, Deserialize, Debug, Getters, CopyGetters)]
pub struct BlindSignRequestBody {
#[getset(get = "pub")]
blind_sign_request: BlindSignRequest,
#[getset(get = "pub")]
tx_hash: String,
#[getset(get = "pub")]
signature: String,
public_attributes: Vec<String>,
#[getset(get = "pub")]
public_attributes_plain: Vec<String>,
#[getset(get = "pub")]
total_params: u32,
}
impl BlindSignRequestBody {
pub fn new(
blind_sign_request: &BlindSignRequest,
tx_hash: String,
signature: String,
public_attributes: &[Attribute],
public_attributes_plain: Vec<String>,
total_params: u32,
) -> BlindSignRequestBody {
BlindSignRequestBody {
blind_sign_request: blind_sign_request.clone(),
tx_hash,
signature,
public_attributes: public_attributes
.iter()
.map(|attr| attr.to_bs58())
.collect(),
public_attributes_plain,
total_params,
}
}
@@ -128,46 +112,14 @@ impl BlindSignRequestBody {
}
}
#[derive(Debug, Serialize, Deserialize)]
#[derive(Serialize, Deserialize)]
pub struct BlindedSignatureResponse {
pub remote_key: [u8; 32],
pub encrypted_signature: Vec<u8>,
pub blinded_signature: BlindedSignature,
}
impl BlindedSignatureResponse {
pub fn new(encrypted_signature: Vec<u8>, remote_key: [u8; 32]) -> BlindedSignatureResponse {
BlindedSignatureResponse {
encrypted_signature,
remote_key,
}
}
pub fn to_base58_string(&self) -> String {
bs58::encode(&self.to_bytes()).into_string()
}
pub fn from_base58_string<I: AsRef<[u8]>>(val: I) -> Result<Self, CoconutInterfaceError> {
let bytes = bs58::decode(val).into_vec()?;
Self::from_bytes(&bytes)
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes = self.remote_key.to_vec();
bytes.extend_from_slice(&self.encrypted_signature);
bytes
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, CoconutInterfaceError> {
if bytes.len() < 32 {
return Err(CoconutInterfaceError::InvalidByteLength(bytes.len(), 32));
}
let mut remote_key = [0u8; 32];
remote_key.copy_from_slice(&bytes[..32]);
let encrypted_signature = bytes[32..].to_vec();
Ok(BlindedSignatureResponse {
remote_key,
encrypted_signature,
})
pub fn new(blinded_signature: BlindedSignature) -> BlindedSignatureResponse {
BlindedSignatureResponse { blinded_signature }
}
}
+1 -2
View File
@@ -9,9 +9,8 @@ edition = "2021"
[dependencies]
handlebars = "3.0.1"
humantime-serde = "1.0"
log = "0.4"
serde = { version = "1.0", features = ["derive"] }
toml = "0.5.6"
url = "2.2"
network-defaults = { path = "../network-defaults" }
network-defaults = { path = "../network-defaults" }
+1 -7
View File
@@ -13,7 +13,6 @@ pub trait NymConfig: Default + Serialize + DeserializeOwned {
fn template() -> &'static str;
fn config_file_name() -> String {
log::trace!("NymdConfig::config_file_name");
"config.toml".to_string()
}
@@ -21,7 +20,6 @@ pub trait NymConfig: Default + Serialize + DeserializeOwned {
// default, most probable, implementations; can be easily overridden where required
fn default_config_directory(id: Option<&str>) -> PathBuf {
log::trace!("NymdConfig::default_config_directory");
if let Some(id) = id {
Self::default_root_directory().join(id).join("config")
} else {
@@ -30,7 +28,6 @@ pub trait NymConfig: Default + Serialize + DeserializeOwned {
}
fn default_data_directory(id: Option<&str>) -> PathBuf {
log::trace!("NymdConfig::default_data_path");
if let Some(id) = id {
Self::default_root_directory().join(id).join("data")
} else {
@@ -39,7 +36,6 @@ pub trait NymConfig: Default + Serialize + DeserializeOwned {
}
fn default_config_file_path(id: Option<&str>) -> PathBuf {
log::trace!("NymdConfig::default_config_file_path");
Self::default_config_directory(id).join(Self::config_file_name())
}
@@ -72,9 +68,7 @@ pub trait NymConfig: Default + Serialize + DeserializeOwned {
}
fn load_from_file(id: Option<&str>) -> io::Result<Self> {
let file = Self::default_config_file_path(id);
log::trace!("Loading from file: {:#?}", file);
let config_contents = fs::read_to_string(file)?;
let config_contents = fs::read_to_string(Self::default_config_file_path(id))?;
toml::from_str(&config_contents)
.map_err(|toml_err| io::Error::new(io::ErrorKind::Other, toml_err))
@@ -1,10 +0,0 @@
[package]
name = "coconut-bandwidth-contract-common"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
schemars = "0.8"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
@@ -1,34 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct DepositData {
deposit_info: String,
identity_key: String,
encryption_key: String,
}
impl DepositData {
pub fn new(deposit_info: String, identity_key: String, encryption_key: String) -> Self {
DepositData {
deposit_info,
identity_key,
encryption_key,
}
}
pub fn deposit_info(&self) -> &str {
&self.deposit_info
}
pub fn identity_key(&self) -> &str {
&self.identity_key
}
pub fn encryption_key(&self) -> &str {
&self.encryption_key
}
}
@@ -1,11 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
// event types
pub const DEPOSITED_FUNDS_EVENT_TYPE: &str = "deposited-funds";
// attributes that are used in multiple places
pub const DEPOSIT_VALUE: &str = "deposit-value";
pub const DEPOSIT_INFO: &str = "deposit-info";
pub const DEPOSIT_IDENTITY_KEY: &str = "deposit-identity-key";
pub const DEPOSIT_ENCRYPTION_KEY: &str = "deposit-encryption-key";
@@ -1,3 +0,0 @@
pub mod deposit;
pub mod events;
pub mod msg;
@@ -1,24 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::deposit::DepositData;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct InstantiateMsg {}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
DepositFunds { data: DepositData },
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct MigrateMsg {}
@@ -7,4 +7,4 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
cosmwasm-std = "1.0.0-beta3"
cosmwasm-std = "1.0.0-beta6"
@@ -7,7 +7,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
cosmwasm-std = "1.0.0-beta3"
cosmwasm-std = "1.0.0-beta6"
serde = { version = "1.0", features = ["derive"] }
serde_repr = "0.1"
@@ -9,6 +9,23 @@ use cosmwasm_std::{Coin, Uint128};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::fmt::Display;
use std::hash::{Hash, Hasher};
type OwnerAddressBytes = Vec<u8>;
type BlockHeight = u64;
pub fn generate_storage_key(address: &Addr, proxy: Option<&Addr>) -> Vec<u8> {
if let Some(proxy) = &proxy {
address
.as_bytes()
.iter()
.zip(proxy.as_bytes())
.map(|(x, y)| x ^ y)
.collect()
} else {
address.as_bytes().to_vec()
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema)]
pub struct Delegation {
@@ -19,12 +36,24 @@ pub struct Delegation {
pub proxy: Option<Addr>, // proxy address used to delegate the funds on behalf of anouther address
}
impl Eq for Delegation {}
#[allow(clippy::derive_hash_xor_eq)]
impl Hash for Delegation {
fn hash<H: Hasher>(&self, state: &mut H) {
self.owner.hash(state);
self.node_identity.hash(state);
self.block_height.hash(state);
self.proxy.hash(state);
}
}
impl Delegation {
pub fn new(
owner: Addr,
node_identity: IdentityKey,
amount: Coin,
block_height: u64,
block_height: BlockHeight,
proxy: Option<Addr>,
) -> Self {
Delegation {
@@ -36,15 +65,30 @@ impl Delegation {
}
}
// TODO: change that to use .joined_key() and return Vec<u8>
pub fn storage_key(&self) -> (IdentityKey, Vec<u8>, u64) {
pub fn storage_key(&self) -> (IdentityKey, OwnerAddressBytes, BlockHeight) {
(
self.node_identity(),
self.owner().as_bytes().to_vec(),
self.proxy_storage_key(),
self.block_height(),
)
}
pub fn event_storage_key(&self) -> (OwnerAddressBytes, BlockHeight, IdentityKey) {
(
self.proxy_storage_key(),
self.block_height(),
self.node_identity(),
)
}
pub fn proxy_storage_key(&self) -> OwnerAddressBytes {
generate_storage_key(&self.owner, self.proxy.as_ref())
}
pub fn proxy(&self) -> Option<&Addr> {
self.proxy.as_ref()
}
pub fn increment_amount(&mut self, amount: Uint128, at_height: Option<u64>) {
self.amount.amount += amount;
if let Some(at_height) = at_height {
@@ -86,10 +130,10 @@ pub struct PagedMixDelegationsResponse {
}
impl PagedMixDelegationsResponse {
pub fn new(delegations: Vec<Delegation>, start_next_after: Option<(Addr, u64)>) -> Self {
pub fn new(delegations: Vec<Delegation>, start_next_after: Option<(String, u64)>) -> Self {
PagedMixDelegationsResponse {
delegations,
start_next_after: start_next_after.map(|(s, h)| (s.to_string(), h)),
start_next_after,
}
}
}
@@ -1,7 +1,7 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
mod delegation;
pub mod delegation;
pub mod error;
pub mod events;
mod gateway;
@@ -78,6 +78,35 @@ impl PendingUndelegate {
pub fn block_height(&self) -> u64 {
self.block_height
}
pub fn proxy_storage_key(&self) -> Vec<u8> {
if let Some(proxy) = &self.proxy {
self.delegate()
.as_bytes()
.iter()
.zip(proxy.as_bytes())
.map(|(x, y)| x ^ y)
.collect()
} else {
self.delegate().as_bytes().to_vec()
}
}
pub fn storage_key(&self) -> (IdentityKey, Vec<u8>) {
(self.mix_identity(), self.proxy_storage_key())
}
pub fn delegation_key(&self, block_height: u64) -> (IdentityKey, Vec<u8>, u64) {
(self.mix_identity(), self.proxy_storage_key(), block_height)
}
pub fn event_storage_key(&self) -> (Vec<u8>, u64, IdentityKey) {
(
self.proxy_storage_key(),
self.block_height(),
self.mix_identity(),
)
}
}
#[cfg_attr(test, derive(ts_rs::TS))]
@@ -101,6 +101,8 @@ pub enum ExecuteMsg {
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
GetAllDelegationKeys {},
DebugGetAllDelegationValues {},
GetContractVersion {},
GetMixNodes {
limit: Option<u32>,
@@ -137,6 +139,7 @@ pub enum QueryMsg {
GetDelegationDetails {
mix_identity: IdentityKey,
delegator: String,
proxy: Option<String>,
},
LayerDistribution {},
GetRewardPool {},
@@ -6,11 +6,11 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
cosmwasm-std = "1.0.0-beta3"
cosmwasm-std = "1.0.0-beta6"
mixnet-contract-common = { path = "../mixnet-contract" }
serde = { version = "1.0", features = ["derive"] }
schemars = "0.8"
cw-storage-plus = "0.11.1"
cw-storage-plus = "0.13.1"
config = { path = "../../config" }
[dev-dependencies]
+1 -8
View File
@@ -7,18 +7,11 @@ edition = "2021"
[dependencies]
bls12_381 = { version = "0.5", default-features = false, features = ["pairings", "alloc", "experimental"] }
cosmrs = { version = "0.4.1", optional = true }
thiserror = "1.0"
url = "2.2"
# I guess temporarily until we get serde support in coconut up and running
coconut-interface = { path = "../coconut-interface" }
crypto = { path = "../crypto", features = ["rand", "asymmetric", "symmetric", "hashing"] }
crypto = { path = "../crypto", features = ["asymmetric"] }
network-defaults = { path = "../network-defaults" }
validator-client = { path = "../client-libs/validator-client" }
[dev-dependencies]
rand = "0.7.3"
[features]
coconut = ["cosmrs"]
+22 -192
View File
@@ -7,167 +7,56 @@
// it's the simplest possible case
use coconut_interface::{
hash_to_scalar, prepare_blind_sign, Attribute, BlindSignRequest, Credential, Parameters,
PrivateAttribute, PublicAttribute, Signature, VerificationKey,
Credential, Parameters, PrivateAttribute, PublicAttribute, Signature, VerificationKey,
};
use crypto::asymmetric::{encryption, identity};
use network_defaults::BANDWIDTH_VALUE;
use url::Url;
use cosmrs::tx::Hash;
use super::utils::prepare_credential_for_spending;
use crate::error::Error;
use super::utils::{obtain_aggregate_signature, prepare_credential_for_spending};
pub const PUBLIC_ATTRIBUTES: u32 = 2;
pub const PRIVATE_ATTRIBUTES: u32 = 2;
pub const TOTAL_ATTRIBUTES: u32 = PUBLIC_ATTRIBUTES + PRIVATE_ATTRIBUTES;
pub struct BandwidthVoucher {
pub struct BandwidthVoucherAttributes {
// a random secret value generated by the client used for double-spending detection
serial_number: PrivateAttribute,
pub serial_number: PrivateAttribute,
// a random secret value generated by the client used to bind multiple credentials together
binding_number: PrivateAttribute,
pub binding_number: PrivateAttribute,
// the value (e.g., bandwidth) encoded in this voucher
voucher_value: PublicAttribute,
// the plain text value (e.g., bandwidth) encoded in this voucher
voucher_value_plain: String,
pub voucher_value: PublicAttribute,
// a field with public information, e.g., type of voucher, interval etc.
voucher_info: PublicAttribute,
// the plain text information
voucher_info_plain: String,
// the hash of the deposit transaction
tx_hash: Hash,
// base58 encoded private key ensuring the depositer requested these attributes
signing_key: identity::PrivateKey,
// base58 encoded private key ensuring only this client receives the signature share
encryption_key: encryption::PrivateKey,
pedersen_commitments_openings: Vec<Attribute>,
blind_sign_request: BlindSignRequest,
use_request: bool,
pub voucher_info: PublicAttribute,
}
impl BandwidthVoucher {
pub fn new_with_blind_sign_req(
private_attributes: [PrivateAttribute; PRIVATE_ATTRIBUTES as usize],
public_attributes_plain: [&str; PUBLIC_ATTRIBUTES as usize],
tx_hash: Hash,
signing_key: identity::PrivateKey,
encryption_key: encryption::PrivateKey,
pedersen_commitments_openings: Vec<Attribute>,
blind_sign_request: BlindSignRequest,
) -> Self {
let voucher_value = public_attributes_plain[0];
let voucher_info = public_attributes_plain[1];
let voucher_value_plain = voucher_value.to_string();
let voucher_info_plain = voucher_info.to_string();
let voucher_value = hash_to_scalar(voucher_value.as_bytes());
let voucher_info = hash_to_scalar(voucher_info.as_bytes());
BandwidthVoucher {
serial_number: private_attributes[0],
binding_number: private_attributes[1],
voucher_value,
voucher_value_plain,
voucher_info,
voucher_info_plain,
tx_hash,
signing_key,
encryption_key,
pedersen_commitments_openings,
blind_sign_request,
use_request: false,
}
}
pub fn new(
params: &Parameters,
voucher_value: String,
voucher_info: String,
tx_hash: Hash,
signing_key: identity::PrivateKey,
encryption_key: encryption::PrivateKey,
) -> Self {
let serial_number = params.random_scalar();
let binding_number = params.random_scalar();
let voucher_value_plain = voucher_value.clone();
let voucher_info_plain = voucher_info.clone();
let voucher_value = hash_to_scalar(voucher_value.as_bytes());
let voucher_info = hash_to_scalar(voucher_info.as_bytes());
let (pedersen_commitments_openings, blind_sign_request) = prepare_blind_sign(
params,
&[serial_number, binding_number],
&[voucher_value, voucher_info],
)
.unwrap();
BandwidthVoucher {
serial_number,
binding_number,
voucher_value,
voucher_value_plain,
voucher_info,
voucher_info_plain,
tx_hash,
signing_key,
encryption_key,
pedersen_commitments_openings,
blind_sign_request,
use_request: true,
}
}
/// Check if the plain values correspond to the PublicAttributes
pub fn verify_against_plain(values: &[PublicAttribute], plain_values: &[String]) -> bool {
values.len() == 2
&& plain_values.len() == 2
&& values[0] == hash_to_scalar(&plain_values[0])
&& values[1] == hash_to_scalar(&plain_values[1])
}
pub fn tx_hash(&self) -> &Hash {
&self.tx_hash
}
impl BandwidthVoucherAttributes {
pub fn get_public_attributes(&self) -> Vec<PublicAttribute> {
vec![self.voucher_value, self.voucher_info]
}
pub fn encryption_key(&self) -> &encryption::PrivateKey {
&self.encryption_key
}
pub fn pedersen_commitments_openings(&self) -> &Vec<Attribute> {
&self.pedersen_commitments_openings
}
pub fn blind_sign_request(&self) -> &BlindSignRequest {
&self.blind_sign_request
}
pub fn use_request(&self) -> bool {
self.use_request
}
pub fn get_public_attributes_plain(&self) -> Vec<String> {
vec![
self.voucher_value_plain.clone(),
self.voucher_info_plain.clone(),
]
}
pub fn get_private_attributes(&self) -> Vec<PrivateAttribute> {
vec![self.serial_number, self.binding_number]
}
}
pub fn sign(&self, request: &BlindSignRequest) -> identity::Signature {
let mut message = request.to_bytes();
message.extend_from_slice(self.tx_hash.as_bytes());
self.signing_key.sign(&message)
}
// TODO: this definitely has to be moved somewhere else. It's just a temporary solution
pub async fn obtain_signature(
params: &Parameters,
attributes: &BandwidthVoucherAttributes,
validators: &[Url],
) -> Result<Signature, Error> {
let public_attributes = attributes.get_public_attributes();
let private_attributes = attributes.get_private_attributes();
obtain_aggregate_signature(params, &public_attributes, &private_attributes, validators).await
}
pub fn prepare_for_spending(
raw_identity: &[u8],
signature: &Signature,
attributes: &BandwidthVoucher,
attributes: &BandwidthVoucherAttributes,
verification_key: &VerificationKey,
) -> Result<Credential, Error> {
let public_attributes = vec![
@@ -186,62 +75,3 @@ pub fn prepare_for_spending(
verification_key,
)
}
#[cfg(test)]
mod test {
use super::*;
use rand::rngs::OsRng;
#[test]
fn voucher_consistency() {
let params = Parameters::new(4).unwrap();
let mut rng = OsRng;
let voucher = BandwidthVoucher::new(
&params,
"1234".to_string(),
"voucher info".to_string(),
Hash::new([0; 32]),
identity::PrivateKey::from_base58_string(
identity::KeyPair::new(&mut rng)
.private_key()
.to_base58_string(),
)
.unwrap(),
encryption::KeyPair::new(&mut rng).private_key().clone(),
);
assert!(!BandwidthVoucher::verify_against_plain(
&[],
&voucher.get_public_attributes_plain()
));
assert!(!BandwidthVoucher::verify_against_plain(
&voucher.get_public_attributes(),
&[],
));
assert!(!BandwidthVoucher::verify_against_plain(
&voucher.get_public_attributes(),
&[
voucher.get_public_attributes_plain()[0].clone(),
String::new()
]
));
assert!(!BandwidthVoucher::verify_against_plain(
&voucher.get_public_attributes(),
&[
String::new(),
voucher.get_public_attributes_plain()[1].clone()
]
));
assert!(!BandwidthVoucher::verify_against_plain(
&[voucher.get_public_attributes()[0], Attribute::one()],
&voucher.get_public_attributes_plain()
));
assert!(!BandwidthVoucher::verify_against_plain(
&[Attribute::one(), voucher.get_public_attributes()[1]],
&voucher.get_public_attributes_plain()
));
assert!(BandwidthVoucher::verify_against_plain(
&voucher.get_public_attributes(),
&voucher.get_public_attributes_plain()
));
}
}
-1
View File
@@ -2,5 +2,4 @@
// SPDX-License-Identifier: Apache-2.0
pub mod bandwidth;
pub mod params;
pub mod utils;
-15
View File
@@ -1,15 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crypto::aes::Aes128;
use crypto::blake3;
use crypto::ctr;
type Aes128Ctr = ctr::Ctr64LE<Aes128>;
/// Hashing algorithm used during hkdf for ephemeral shared key generation per blinded signature
/// response encryption.
pub type ValidatorApiCredentialHkdfAlgorithm = blake3::Hasher;
/// Encryption algorithm used for end-to-end encryption of blinded signature response
pub type ValidatorApiCredentialEncryptionAlgorithm = Aes128Ctr;
+47 -57
View File
@@ -1,20 +1,15 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use bls12_381::Scalar;
use coconut_interface::{
aggregate_signature_shares, aggregate_verification_keys, prove_bandwidth_credential, Attribute,
BlindSignRequestBody, BlindedSignature, Credential, Parameters, Signature, SignatureShare,
VerificationKey,
aggregate_signature_shares, aggregate_verification_keys, prepare_blind_sign,
prove_bandwidth_credential, Attribute, BlindSignRequest, BlindSignRequestBody, Credential,
Parameters, Signature, SignatureShare, VerificationKey,
};
use crypto::asymmetric::encryption::PublicKey;
use crypto::shared_key::recompute_shared_key;
use crypto::symmetric::stream_cipher;
use url::Url;
use crate::coconut::bandwidth::{BandwidthVoucher, PRIVATE_ATTRIBUTES};
use crate::coconut::params::{
ValidatorApiCredentialEncryptionAlgorithm, ValidatorApiCredentialHkdfAlgorithm,
};
use crate::coconut::bandwidth::PRIVATE_ATTRIBUTES;
use crate::error::Error;
/// Contacts all provided validators and then aggregate their verification keys.
@@ -68,53 +63,31 @@ pub async fn obtain_aggregate_verification_key(
async fn obtain_partial_credential(
params: &Parameters,
attributes: &BandwidthVoucher,
public_attributes: &[Attribute],
private_attributes: &[Attribute],
pedersen_commitments_openings: &[Scalar],
blind_sign_request: &BlindSignRequest,
client: &validator_client::ApiClient,
validator_vk: &VerificationKey,
) -> Result<Signature, Error> {
let public_attributes = attributes.get_public_attributes();
let public_attributes_plain = attributes.get_public_attributes_plain();
let private_attributes = attributes.get_private_attributes();
let blind_sign_request = attributes.blind_sign_request();
let response = if attributes.use_request() {
let blind_sign_request_body = BlindSignRequestBody::new(
blind_sign_request,
attributes.tx_hash().to_string(),
attributes.sign(blind_sign_request).to_base58_string(),
&public_attributes,
public_attributes_plain,
(public_attributes.len() + private_attributes.len()) as u32,
);
client.blind_sign(&blind_sign_request_body).await?
} else {
client
.partial_bandwidth_credential(&attributes.tx_hash().to_string())
.await?
};
let encrypted_signature = response.encrypted_signature;
let remote_key = PublicKey::from_bytes(&response.remote_key)?;
let encryption_key = recompute_shared_key::<
ValidatorApiCredentialEncryptionAlgorithm,
ValidatorApiCredentialHkdfAlgorithm,
>(&remote_key, attributes.encryption_key());
let zero_iv = stream_cipher::zero_iv::<ValidatorApiCredentialEncryptionAlgorithm>();
let blinded_signature_bytes = stream_cipher::decrypt::<ValidatorApiCredentialEncryptionAlgorithm>(
&encryption_key,
&zero_iv,
&encrypted_signature,
let blind_sign_request_body = BlindSignRequestBody::new(
blind_sign_request,
public_attributes,
(public_attributes.len() + private_attributes.len()) as u32,
);
let blinded_signature = BlindedSignature::from_bytes(&blinded_signature_bytes)?;
let blinded_signature = client
.blind_sign(&blind_sign_request_body)
.await?
.blinded_signature;
let unblinded_signature = blinded_signature.unblind(
params,
validator_vk,
&private_attributes,
&public_attributes,
private_attributes,
public_attributes,
&blind_sign_request.get_commitment_hash(),
attributes.pedersen_commitments_openings(),
&*pedersen_commitments_openings,
)?;
Ok(unblinded_signature)
@@ -122,14 +95,13 @@ async fn obtain_partial_credential(
pub async fn obtain_aggregate_signature(
params: &Parameters,
attributes: &BandwidthVoucher,
public_attributes: &[Attribute],
private_attributes: &[Attribute],
validators: &[Url],
) -> Result<Signature, Error> {
if validators.is_empty() {
return Err(Error::NoValidatorsAvailable);
}
let public_attributes = attributes.get_public_attributes();
let private_attributes = attributes.get_private_attributes();
let mut shares = Vec::with_capacity(validators.len());
let mut validators_partial_vks: Vec<VerificationKey> = Vec::with_capacity(validators.len());
@@ -138,24 +110,42 @@ pub async fn obtain_aggregate_signature(
let validator_partial_vk = client.get_coconut_verification_key().await?;
validators_partial_vks.push(validator_partial_vk.key.clone());
let first =
obtain_partial_credential(params, attributes, &client, &validator_partial_vk.key).await?;
let (pedersen_commitments_openings, blind_sign_request) =
prepare_blind_sign(params, private_attributes, public_attributes)?;
let first = obtain_partial_credential(
params,
public_attributes,
private_attributes,
&pedersen_commitments_openings,
&blind_sign_request,
&client,
&validator_partial_vk.key,
)
.await?;
shares.push(SignatureShare::new(first, 1));
for (id, validator_url) in validators.iter().enumerate().skip(1) {
client.change_validator_api(validator_url.clone());
let validator_partial_vk = client.get_coconut_verification_key().await?;
validators_partial_vks.push(validator_partial_vk.key.clone());
let signature =
obtain_partial_credential(params, attributes, &client, &validator_partial_vk.key)
.await?;
let signature = obtain_partial_credential(
params,
public_attributes,
private_attributes,
&pedersen_commitments_openings,
&blind_sign_request,
&client,
&validator_partial_vk.key,
)
.await?;
let share = SignatureShare::new(signature, (id + 1) as u64);
shares.push(share)
}
let mut attributes = Vec::with_capacity(private_attributes.len() + public_attributes.len());
attributes.extend_from_slice(&private_attributes);
attributes.extend_from_slice(&public_attributes);
attributes.extend_from_slice(private_attributes);
attributes.extend_from_slice(public_attributes);
let mut indices: Vec<u64> = Vec::with_capacity(validators_partial_vks.len());
for i in 0..validators_partial_vks.len() {
+1 -8
View File
@@ -1,12 +1,9 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
#[cfg(feature = "coconut")]
use coconut_interface::CoconutError;
use crypto::asymmetric::encryption::KeyRecoveryError;
use validator_client::ValidatorClientError;
use thiserror::Error;
use validator_client::ValidatorClientError;
#[derive(Debug, Error)]
pub enum Error {
@@ -16,7 +13,6 @@ pub enum Error {
#[error("Could not contact any validator")]
NoValidatorsAvailable,
#[cfg(feature = "coconut")]
#[error("Run into a coconut error - {0}")]
CoconutError(#[from] CoconutError),
@@ -34,7 +30,4 @@ pub enum Error {
#[error("There is not associated bandwidth for the given client")]
MissingBandwidth,
#[error("Could not parse the key - {0}")]
ParsePublicKey(#[from] KeyRecoveryError),
}
-3
View File
@@ -1,11 +1,8 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
#[cfg(feature = "coconut")]
pub mod coconut;
pub mod error;
#[cfg(not(feature = "coconut"))]
pub mod token;
#[cfg(feature = "coconut")]
pub use coconut::utils::{obtain_aggregate_signature, obtain_aggregate_verification_key};
@@ -6,6 +6,7 @@ use crypto::asymmetric::identity::{PublicKey, Signature, PUBLIC_KEY_LENGTH, SIGN
use crate::error::Error;
use std::convert::TryInto;
#[cfg(not(feature = "coconut"))]
pub struct TokenCredential {
verification_key: PublicKey,
gateway_identity: PublicKey,
@@ -13,6 +14,7 @@ pub struct TokenCredential {
signature: Signature,
}
#[cfg(not(feature = "coconut"))]
impl TokenCredential {
pub fn new(
verification_key: PublicKey,
@@ -97,6 +99,7 @@ impl TokenCredential {
mod tests {
use super::*;
#[cfg(not(feature = "coconut"))]
#[test]
fn token_serde() {
// pre-generated, valid values
-2
View File
@@ -147,8 +147,6 @@ pub const UTOKENS_TO_BURN: u64 = TOKENS_TO_BURN * 1000000;
/// Default bandwidth (in bytes) that we try to buy
pub const BANDWIDTH_VALUE: u64 = TOKENS_TO_BURN * BYTES_PER_TOKEN;
pub const VOUCHER_INFO: &str = "BandwidthVoucher";
pub const ETH_MIN_BLOCK_DEPTH: usize = 7;
/// Defaults Cosmos Hub/ATOM path
+3 -5
View File
@@ -6,17 +6,15 @@ use crate::ValidatorDetails;
pub(crate) const BECH32_PREFIX: &str = "n";
pub const DENOM: &str = "unym";
pub(crate) const MIXNET_CONTRACT_ADDRESS: &str =
"n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjyvg3g";
pub(crate) const VESTING_CONTRACT_ADDRESS: &str =
"n1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq73f2nw";
pub(crate) const MIXNET_CONTRACT_ADDRESS: &str = "n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0";
pub(crate) const VESTING_CONTRACT_ADDRESS: &str = "n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0";
pub(crate) const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str =
"n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0";
pub(crate) const _ETH_CONTRACT_ADDRESS: [u8; 20] =
hex_literal::hex!("0000000000000000000000000000000000000000");
pub(crate) const _ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] =
hex_literal::hex!("0000000000000000000000000000000000000000");
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy";
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "n17zujduc46wvkwvp6f062mm5xhr7jc3fewvqu9e";
pub(crate) fn validators() -> Vec<ValidatorDetails> {
vec![ValidatorDetails::new(
+2 -1
View File
@@ -5,7 +5,6 @@ use std::convert::TryInto;
use bls12_381::Scalar;
pub use crate::traits::Bytable;
pub use elgamal::elgamal_keygen;
pub use elgamal::ElGamalKeyPair;
pub use elgamal::PublicKey;
@@ -29,6 +28,8 @@ pub use scheme::SignatureShare;
pub use traits::Base58;
pub use utils::hash_to_scalar;
use crate::traits::Bytable;
pub mod elgamal;
mod error;
mod impls;
+22 -54
View File
@@ -41,7 +41,7 @@ checksum = "f771a5d1f5503f7f4279a30f3643d3421ba149848b89ecaaec0ea2acf04a5ac4"
[[package]]
name = "bandwidth-claim"
version = "0.1.0"
version = "1.0.0-rc.1"
dependencies = [
"bandwidth-claim-contract",
"config",
@@ -191,35 +191,12 @@ dependencies = [
"generic-array 0.14.5",
]
[[package]]
name = "coconut-bandwidth"
version = "0.1.0"
dependencies = [
"bandwidth-claim-contract",
"coconut-bandwidth-contract-common",
"config",
"cosmwasm-std",
"cosmwasm-storage",
"schemars",
"serde",
"thiserror",
]
[[package]]
name = "coconut-bandwidth-contract-common"
version = "0.1.0"
dependencies = [
"schemars",
"serde",
]
[[package]]
name = "config"
version = "0.1.0"
dependencies = [
"handlebars",
"humantime-serde",
"log",
"network-defaults",
"serde",
"toml",
@@ -241,22 +218,22 @@ dependencies = [
[[package]]
name = "cosmwasm-crypto"
version = "1.0.0-beta6"
version = "1.0.0-beta7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dddc1443004c6340e55ca66d98e9d2f1a44aadf4ce2bed2c4f29baa8a15e7b7"
checksum = "88c2565b1e73a816fb659ef4838fc356143fbd35f43c48a51d2d7d4e5d6679d3"
dependencies = [
"digest 0.9.0",
"ed25519-zebra",
"k256",
"rand_core 0.5.1",
"rand_core 0.6.3",
"thiserror",
]
[[package]]
name = "cosmwasm-derive"
version = "1.0.0-beta6"
version = "1.0.0-beta7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe4f0f10f165b8bcc558a13cddb498140960544519aa0581532c766dd80b5598"
checksum = "fa89fcdf8dbbe0088e663d0a814aa7368e7ebe8fb045a3a150fb5fdc2ffe3b45"
dependencies = [
"syn",
]
@@ -273,9 +250,9 @@ dependencies = [
[[package]]
name = "cosmwasm-std"
version = "1.0.0-beta6"
version = "1.0.0-beta7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f0f3145097b692b2d95fa5d2c7c6fdd60f193ccc709857e7e1987a608725300"
checksum = "bcb8f99a61d0b9069e1afc80a4ffea87dcc3523edd992080923870b13a677da0"
dependencies = [
"base64",
"cosmwasm-crypto",
@@ -290,9 +267,9 @@ dependencies = [
[[package]]
name = "cosmwasm-storage"
version = "1.0.0-beta3"
version = "1.0.0-beta7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4a4e55f0d64fed54cd2202301b8d466af8de044589247dabd77a4222f52f749"
checksum = "07f856099c824aa8f2488e62d1da3fc06383d3fdbc764573595f451be43441a2"
dependencies = [
"cosmwasm-std",
"serde",
@@ -383,20 +360,9 @@ dependencies = [
[[package]]
name = "cw-storage-plus"
version = "0.11.1"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d7ee1963302b0ac2a9d42fe0faec826209c17452bfd36fbfd9d002a88929261"
dependencies = [
"cosmwasm-std",
"schemars",
"serde",
]
[[package]]
name = "cw-storage-plus"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c087ff98fb0475db4c2b5298a5fd12b2848d2854b39d1115d930ee6da24d1eed"
checksum = "5e8b7f9a758c030d375520df947323c052704f784561fc28dcaab4f988c50a30"
dependencies = [
"cosmwasm-std",
"schemars",
@@ -473,16 +439,17 @@ dependencies = [
[[package]]
name = "ed25519-zebra"
version = "2.2.0"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a128b76af6dd4b427e34a6fd43dc78dbfe73672ec41ff615a2414c1a0ad0409"
checksum = "403ef3e961ab98f0ba902771d29f842058578bb1ce7e3c59dad5a6a93e784c69"
dependencies = [
"curve25519-dalek",
"hex",
"rand_core 0.5.1",
"rand_core 0.6.3",
"serde",
"sha2",
"thiserror",
"zeroize",
]
[[package]]
@@ -843,7 +810,7 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]]
name = "mixnet-contract"
version = "0.1.0"
version = "1.0.0-rc.1"
dependencies = [
"az",
"bs58",
@@ -852,8 +819,9 @@ dependencies = [
"cosmwasm-std",
"cosmwasm-storage",
"crypto",
"cw-storage-plus 0.12.1",
"cw-storage-plus",
"fixed",
"hex",
"mixnet-contract-common",
"rand",
"rand_chacha",
@@ -1550,11 +1518,11 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "vesting-contract"
version = "0.1.0"
version = "1.0.0-rc.1"
dependencies = [
"config",
"cosmwasm-std",
"cw-storage-plus 0.12.1",
"cw-storage-plus",
"mixnet-contract-common",
"schemars",
"serde",
@@ -1568,7 +1536,7 @@ version = "0.1.0"
dependencies = [
"config",
"cosmwasm-std",
"cw-storage-plus 0.11.1",
"cw-storage-plus",
"mixnet-contract-common",
"schemars",
"serde",
+1 -1
View File
@@ -1,5 +1,5 @@
[workspace]
members = ["bandwidth-claim", "coconut-bandwidth", "mixnet", "vesting"]
members = ["bandwidth-claim", "mixnet", "vesting"]
[profile.release]
opt-level = 3
+3 -3
View File
@@ -1,6 +1,6 @@
[package]
name = "bandwidth-claim"
version = "0.1.0"
version = "1.0.0-rc.1"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -14,8 +14,8 @@ config = { path = "../../common/config"}
[dependencies]
bandwidth-claim-contract = { path = "../../common/bandwidth-claim-contract" }
cosmwasm-std = "1.0.0-beta3"
cosmwasm-storage = "1.0.0-beta3"
cosmwasm-std = "1.0.0-beta6"
cosmwasm-storage = "1.0.0-beta6"
schemars = "0.8"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
@@ -1,12 +1,14 @@
{
"rinkeby":
{"NYM_ERC20":"0xe58c12f8bA4a28e87841b10BdEdf80A47F86BA9B",
"BANDWIDTH_GENERATOR":"0xfa2714Bf14EB5Bb887e4A54984C6F7A7e3E6c84b",
"GRAVITY":"0xe58c12f8bA4a28e87841b10BdEdf80A47F86BA9B"},
"mainnet":
{"NYM_ERC20":"0x525A8F6F3Ba4752868cde25164382BfbaE3990e1",
"NYMT":"0xE8883BAeF3869e14E4823F46662e81D4F7d2A81F",
"BANDWIDTH_GENERATOR":"0x3FfEb99acca159A182f35F9944dAf3BF41Ae8165",
"rinkeby":{
"NYM_ERC20":"0xe58c12f8bA4a28e87841b10BdEdf80A47F86BA9B",
"BANDWIDTH_GENERATOR":"0x5FbDB2315678afecb367f032d93F642f64180aa3",
"GRAVITY":"0xe58c12f8bA4a28e87841b10BdEdf80A47F86BA9B"
},
"mainnet":{
"NYM_ERC20":"0x525A8F6F3Ba4752868cde25164382BfbaE3990e1",
"NYMT": "0xE8883BAeF3869e14E4823F46662e81D4F7d2A81F",
"BANDWIDTH_GENERATOR":"",
"BANDWIDTH_GENERATOR_NYMT":"0xB3BF30DD53044c9050B7309031Bbf26b2cecF3be",
"GRAVITY":"0xa4108aA1Ec4967F8b52220a4f7e94A8201F2D906"}
"GRAVITY":"0xa4108aA1Ec4967F8b52220a4f7e94A8201F2D906"
}
}
-867
View File
@@ -1,867 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "base64"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "block-buffer"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
dependencies = [
"block-padding",
"byte-tools",
"byteorder",
"generic-array 0.12.4",
]
[[package]]
name = "block-buffer"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [
"generic-array 0.14.4",
]
[[package]]
name = "block-padding"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
dependencies = [
"byte-tools",
]
[[package]]
name = "byte-tools"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "config"
version = "0.1.0"
dependencies = [
"handlebars",
"humantime-serde",
"network-defaults",
"serde",
"toml",
"url",
]
[[package]]
name = "const-oid"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdab415d6744056100f40250a66bc430c1a46f7a02e20bc11c94c79a0f0464df"
[[package]]
name = "cosmos_contract"
version = "0.1.0"
dependencies = [
"config",
"cosmwasm-std",
"cosmwasm-storage",
"erc20-bridge-contract",
"schemars",
"serde",
"thiserror",
]
[[package]]
name = "cosmwasm-crypto"
version = "1.0.0-beta2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c16b255449b3f5cd7fa4b79acd5225b5185655261087a3d8aaac44f88a0e23e9"
dependencies = [
"digest 0.9.0",
"ed25519-zebra",
"k256",
"rand_core 0.5.1",
"thiserror",
]
[[package]]
name = "cosmwasm-derive"
version = "1.0.0-beta2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abad1a6ff427a2f66890a4dce6354b4563cd07cee91a942300e011c921c09ed2"
dependencies = [
"syn",
]
[[package]]
name = "cosmwasm-std"
version = "1.0.0-beta2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1660ee3d5734672e1eb4f0ceda403e2d83345e15143a48845f340f3252ce99a6"
dependencies = [
"base64",
"cosmwasm-crypto",
"cosmwasm-derive",
"schemars",
"serde",
"serde-json-wasm",
"thiserror",
"uint",
]
[[package]]
name = "cosmwasm-storage"
version = "1.0.0-beta2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf3b4efe3b4f86df668520a02e9a29c23eea99b64dfcacb0e59b98346418af7f"
dependencies = [
"cosmwasm-std",
"serde",
]
[[package]]
name = "cpufeatures"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
dependencies = [
"libc",
]
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "crypto-bigint"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d12477e115c0d570c12a2dfd859f80b55b60ddb5075df210d3af06d133a69f45"
dependencies = [
"generic-array 0.14.4",
"rand_core 0.6.3",
"subtle",
"zeroize",
]
[[package]]
name = "crypto-mac"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714"
dependencies = [
"generic-array 0.14.4",
"subtle",
]
[[package]]
name = "curve25519-dalek"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61"
dependencies = [
"byteorder",
"digest 0.9.0",
"rand_core 0.5.1",
"subtle",
"zeroize",
]
[[package]]
name = "der"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28e98c534e9c8a0483aa01d6f6913bc063de254311bd267c9cf535e9b70e15b2"
dependencies = [
"const-oid",
]
[[package]]
name = "digest"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
dependencies = [
"generic-array 0.12.4",
]
[[package]]
name = "digest"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [
"generic-array 0.14.4",
]
[[package]]
name = "dyn-clone"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf"
[[package]]
name = "ecdsa"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43ee23aa5b4f68c7a092b5c3beb25f50c406adc75e2363634f242f28ab255372"
dependencies = [
"der",
"elliptic-curve",
"hmac",
"signature",
]
[[package]]
name = "ed25519-zebra"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a128b76af6dd4b427e34a6fd43dc78dbfe73672ec41ff615a2414c1a0ad0409"
dependencies = [
"curve25519-dalek",
"hex",
"rand_core 0.5.1",
"serde",
"sha2",
"thiserror",
]
[[package]]
name = "elliptic-curve"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "beca177dcb8eb540133e7680baff45e7cc4d93bf22002676cec549f82343721b"
dependencies = [
"crypto-bigint",
"ff",
"generic-array 0.14.4",
"group",
"pkcs8",
"rand_core 0.6.3",
"subtle",
"zeroize",
]
[[package]]
name = "erc20-bridge-contract"
version = "0.1.0"
dependencies = [
"schemars",
"serde",
]
[[package]]
name = "fake-simd"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
[[package]]
name = "ff"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f"
dependencies = [
"rand_core 0.6.3",
"subtle",
]
[[package]]
name = "form_urlencoded"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
dependencies = [
"matches",
"percent-encoding",
]
[[package]]
name = "generic-array"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd"
dependencies = [
"typenum",
]
[[package]]
name = "generic-array"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
"cfg-if",
"libc",
"wasi 0.9.0+wasi-snapshot-preview1",
]
[[package]]
name = "getrandom"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [
"cfg-if",
"libc",
"wasi 0.10.2+wasi-snapshot-preview1",
]
[[package]]
name = "group"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912"
dependencies = [
"ff",
"rand_core 0.6.3",
"subtle",
]
[[package]]
name = "handlebars"
version = "3.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4498fc115fa7d34de968184e473529abb40eeb6be8bc5f7faba3d08c316cb3e3"
dependencies = [
"log",
"pest",
"pest_derive",
"quick-error",
"serde",
"serde_json",
]
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hex-literal"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21e4590e13640f19f249fe3e4eca5113bc4289f2497710378190e7f4bd96f45b"
[[package]]
name = "hmac"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b"
dependencies = [
"crypto-mac",
"digest 0.9.0",
]
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "humantime-serde"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac34a56cfd4acddb469cc7fff187ed5ac36f498ba085caf8bbc725e3ff474058"
dependencies = [
"humantime",
"serde",
]
[[package]]
name = "idna"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
dependencies = [
"matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "itoa"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "k256"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "903ae2481bcdfdb7b68e0a9baa4b7c9aff600b9ae2e8e5bb5833b8c91ab851ea"
dependencies = [
"cfg-if",
"ecdsa",
"elliptic-curve",
"sha2",
]
[[package]]
name = "libc"
version = "0.2.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
[[package]]
name = "log"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
]
[[package]]
name = "maplit"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
[[package]]
name = "matches"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]]
name = "network-defaults"
version = "0.1.0"
dependencies = [
"hex-literal",
"serde",
"time",
"url",
]
[[package]]
name = "opaque-debug"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
[[package]]
name = "opaque-debug"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "percent-encoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "pest"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
dependencies = [
"ucd-trie",
]
[[package]]
name = "pest_derive"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0"
dependencies = [
"pest",
"pest_generator",
]
[[package]]
name = "pest_generator"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55"
dependencies = [
"pest",
"pest_meta",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "pest_meta"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d"
dependencies = [
"maplit",
"pest",
"sha-1",
]
[[package]]
name = "pkcs8"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee3ef9b64d26bad0536099c816c6734379e45bbd5f14798def6809e5cc350447"
dependencies = [
"der",
"spki",
]
[[package]]
name = "proc-macro2"
version = "1.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quick-error"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
[[package]]
name = "quote"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand_core"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
"getrandom 0.1.16",
]
[[package]]
name = "rand_core"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
dependencies = [
"getrandom 0.2.3",
]
[[package]]
name = "ryu"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "schemars"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7a48d098c2a7fdf5740b19deb1181b4fb8a9e68e03ae517c14cde04b5725409"
dependencies = [
"dyn-clone",
"schemars_derive",
"serde",
"serde_json",
]
[[package]]
name = "schemars_derive"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a9ea2a613fe4cd7118b2bb101a25d8ae6192e1975179b67b2f17afd11e70ac8"
dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals",
"syn",
]
[[package]]
name = "serde"
version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde-json-wasm"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50eef3672ec8fa45f3457fd423ba131117786784a895548021976117c1ded449"
dependencies = [
"serde",
]
[[package]]
name = "serde_derive"
version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_derive_internals"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dbab34ca63057a1f15280bdf3c39f2b1eb1b54c17e98360e511637aef7418c6"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "sha-1"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
dependencies = [
"block-buffer 0.7.3",
"digest 0.8.1",
"fake-simd",
"opaque-debug 0.2.3",
]
[[package]]
name = "sha2"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa"
dependencies = [
"block-buffer 0.9.0",
"cfg-if",
"cpufeatures",
"digest 0.9.0",
"opaque-debug 0.3.0",
]
[[package]]
name = "signature"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c19772be3c4dd2ceaacf03cb41d5885f2a02c4d8804884918e3a258480803335"
dependencies = [
"digest 0.9.0",
"rand_core 0.6.3",
]
[[package]]
name = "spki"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c01a0c15da1b0b0e1494112e7af814a678fec9bd157881b49beac661e9b6f32"
dependencies = [
"der",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "subtle"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]]
name = "syn"
version = "1.0.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3a1d708c221c5a612956ef9f75b37e454e88d1f7b899fbd3a18d4252012d663"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "thiserror"
version = "1.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "time"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99beeb0daeac2bd1e86ac2c21caddecb244b39a093594da1a661ec2060c7aedd"
dependencies = [
"libc",
"time-macros",
]
[[package]]
name = "time-macros"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25eb0ca3468fc0acc11828786797f6ef9aa1555e4a211a60d64cc8e4d1be47d6"
[[package]]
name = "tinyvec"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f83b2a3d4d9091d0abd7eba4dc2710b1718583bd4d8992e2190720ea38f391f7"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "toml"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
dependencies = [
"serde",
]
[[package]]
name = "typenum"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec"
[[package]]
name = "ucd-trie"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
[[package]]
name = "uint"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6470ab50f482bde894a037a57064480a246dbfdd5960bd65a44824693f08da5f"
dependencies = [
"byteorder",
"crunchy",
"hex",
"static_assertions",
]
[[package]]
name = "unicode-bidi"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
[[package]]
name = "unicode-normalization"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9"
dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "url"
version = "2.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
dependencies = [
"form_urlencoded",
"idna",
"matches",
"percent-encoding",
]
[[package]]
name = "version_check"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "zeroize"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd"
-21
View File
@@ -1,21 +0,0 @@
[package]
name = "coconut-bandwidth"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
bandwidth-claim-contract = { path = "../../common/bandwidth-claim-contract" }
coconut-bandwidth-contract-common = { path = "../../common/cosmwasm-smart-contracts/coconut-bandwidth-contract" }
config = { path = "../../common/config"}
cosmwasm-std = "1.0.0-beta3"
cosmwasm-storage = "1.0.0-beta3"
schemars = "0.8"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
thiserror = "1.0.23"
-26
View File
@@ -1,26 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_std::StdError;
use thiserror::Error;
use config::defaults::DENOM;
/// Custom errors for contract failure conditions.
///
/// Add any other custom errors you like here.
/// Look at https://docs.rs/thiserror/1.0.21/thiserror/ for details.
#[derive(Error, Debug, PartialEq)]
pub enum ContractError {
#[error("{0}")]
Std(#[from] StdError),
#[error("Received multiple coin types")]
MultipleDenoms,
#[error("No coin was sent for voucher")]
NoCoin,
#[error("Wrong coin denomination, you must send {}", DENOM)]
WrongDenom,
}
-73
View File
@@ -1,73 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
mod error;
mod support;
mod transactions;
use cosmwasm_std::{entry_point, DepsMut, Env, MessageInfo, Response};
use crate::error::ContractError;
use coconut_bandwidth_contract_common::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg};
/// Instantiate the contract.
///
/// `deps` contains Storage, API and Querier
/// `env` contains block, message and contract info
/// `msg` is the contract initialization message, sort of like a constructor call.
#[entry_point]
pub fn instantiate(
_deps: DepsMut<'_>,
_env: Env,
_info: MessageInfo,
_msg: InstantiateMsg,
) -> Result<Response, ContractError> {
Ok(Response::default())
}
/// Handle an incoming message
#[entry_point]
pub fn execute(
deps: DepsMut<'_>,
env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> Result<Response, ContractError> {
match msg {
ExecuteMsg::DepositFunds { data } => transactions::deposit_funds(deps, env, info, data),
}
}
#[entry_point]
pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
Ok(Default::default())
}
#[cfg(test)]
mod tests {
use super::*;
use config::defaults::DENOM;
use cosmwasm_std::coins;
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
#[test]
fn initialize_contract() {
let mut deps = mock_dependencies();
let env = mock_env();
let msg = InstantiateMsg {};
let info = mock_info("creator", &[]);
let res = instantiate(deps.as_mut(), env.clone(), info, msg).unwrap();
assert_eq!(0, res.messages.len());
// Contract balance should be 0
assert_eq!(
coins(0, DENOM),
vec![deps
.as_ref()
.querier
.query_balance(env.contract.address, DENOM)
.unwrap()]
);
}
}
@@ -1,3 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod tests;
@@ -1,19 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
#[cfg(test)]
pub mod helpers {
use crate::instantiate;
use coconut_bandwidth_contract_common::msg::InstantiateMsg;
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info, MockApi, MockQuerier};
use cosmwasm_std::{Empty, MemoryStorage, OwnedDeps};
pub fn init_contract() -> OwnedDeps<MemoryStorage, MockApi, MockQuerier<Empty>> {
let mut deps = mock_dependencies();
let msg = InstantiateMsg {};
let env = mock_env();
let info = mock_info("creator", &[]);
instantiate(deps.as_mut(), env.clone(), info, msg).unwrap();
return deps;
}
}
@@ -1,136 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_std::{DepsMut, Env, Event, MessageInfo, Response};
use crate::error::ContractError;
use coconut_bandwidth_contract_common::deposit::DepositData;
use coconut_bandwidth_contract_common::events::{
DEPOSITED_FUNDS_EVENT_TYPE, DEPOSIT_ENCRYPTION_KEY, DEPOSIT_IDENTITY_KEY, DEPOSIT_INFO,
DEPOSIT_VALUE,
};
use config::defaults::DENOM;
pub(crate) fn deposit_funds(
_deps: DepsMut<'_>,
_env: Env,
info: MessageInfo,
data: DepositData,
) -> Result<Response, ContractError> {
if info.funds.is_empty() {
return Err(ContractError::NoCoin);
}
if info.funds.len() > 1 {
return Err(ContractError::MultipleDenoms);
}
if info.funds[0].denom != DENOM {
return Err(ContractError::WrongDenom);
}
let voucher_value = info.funds.last().unwrap();
let event = Event::new(DEPOSITED_FUNDS_EVENT_TYPE)
.add_attribute(DEPOSIT_VALUE, voucher_value.amount)
.add_attribute(DEPOSIT_INFO, data.deposit_info())
.add_attribute(DEPOSIT_IDENTITY_KEY, data.identity_key())
.add_attribute(DEPOSIT_ENCRYPTION_KEY, data.encryption_key());
Ok(Response::new().add_event(event))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::support::tests::helpers;
use cosmwasm_std::testing::{mock_env, mock_info};
use cosmwasm_std::Coin;
#[test]
fn invalid_deposit() {
let mut deps = helpers::init_contract();
let env = mock_env();
let info = mock_info("requester", &[]);
let deposit_info = String::from("Deposit info");
let verification_key = String::from("Verification key");
let encryption_key = String::from("Encryption key");
let data = DepositData::new(deposit_info, verification_key, encryption_key);
assert_eq!(
deposit_funds(deps.as_mut(), env.clone(), info, data.clone()),
Err(ContractError::NoCoin)
);
let coin = Coin::new(1000000, DENOM);
let second_coin = Coin::new(1000000, "some_denom");
let info = mock_info("requester", &[coin, second_coin.clone()]);
assert_eq!(
deposit_funds(deps.as_mut(), env.clone(), info, data.clone()),
Err(ContractError::MultipleDenoms)
);
let info = mock_info("requester", &[second_coin]);
assert_eq!(
deposit_funds(deps.as_mut(), env, info, data),
Err(ContractError::WrongDenom)
);
}
#[test]
fn valid_deposit() {
let mut deps = helpers::init_contract();
let env = mock_env();
let deposit_info = String::from("Deposit info");
let verification_key = String::from("Verification key");
let encryption_key = String::from("Encryption key");
let deposit_value = 424242;
let data = DepositData::new(
deposit_info.clone(),
verification_key.clone(),
encryption_key.clone(),
);
let coin = Coin::new(deposit_value, DENOM);
let info = mock_info("requester", &[coin]);
let tx = deposit_funds(deps.as_mut(), env.clone(), info, data).unwrap();
let events: Vec<_> = tx
.events
.iter()
.filter(|event| event.ty == DEPOSITED_FUNDS_EVENT_TYPE)
.collect();
assert_eq!(events.len(), 1);
let event = events[0];
assert_eq!(event.attributes.len(), 4);
let deposit_attr = event
.attributes
.iter()
.find(|attr| attr.key == DEPOSIT_VALUE)
.unwrap();
assert_eq!(deposit_attr.value, deposit_value.to_string());
let info_attr = event
.attributes
.iter()
.find(|attr| attr.key == DEPOSIT_INFO)
.unwrap();
assert_eq!(info_attr.value, deposit_info);
let verification_key_attr = event
.attributes
.iter()
.find(|attr| attr.key == DEPOSIT_IDENTITY_KEY)
.unwrap();
assert_eq!(verification_key_attr.value, verification_key);
let encryption_key_attr = event
.attributes
.iter()
.find(|attr| attr.key == DEPOSIT_ENCRYPTION_KEY)
.unwrap();
assert_eq!(encryption_key_attr.value, encryption_key);
}
}
+5 -4
View File
@@ -1,6 +1,6 @@
[package]
name = "mixnet-contract"
version = "0.1.0"
version = "1.0.0-rc.1"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
edition = "2021"
@@ -20,9 +20,9 @@ mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-
vesting-contract-common = { path = "../../common/cosmwasm-smart-contracts/vesting-contract" }
config = { path = "../../common/config"}
cosmwasm-std = "1.0.0-beta3"
cosmwasm-storage = "1.0.0-beta3"
cw-storage-plus = "0.12.1"
cosmwasm-std = "1.0.0-beta6"
cosmwasm-storage = "1.0.0-beta6"
cw-storage-plus = "0.13.1"
az = "1.2.0"
bs58 = "0.4.0"
@@ -30,6 +30,7 @@ schemars = "0.8"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
thiserror = { version = "1.0.23" }
time = { version = "0.3", features = ["macros"] }
hex = "0.4.3"
[dev-dependencies]
cosmwasm-schema = "1.0.0-beta3"
+9 -54
View File
@@ -32,7 +32,7 @@ use cosmwasm_std::{
entry_point, to_binary, Addr, Deps, DepsMut, Env, MessageInfo, QueryResponse, Response, Uint128,
};
use mixnet_contract_common::{
ContractStateParams, Delegation, ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg,
ContractStateParams, ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg,
};
use time::OffsetDateTime;
@@ -312,11 +312,13 @@ pub fn query(deps: Deps<'_>, env: Env, msg: QueryMsg) -> Result<QueryResponse, C
QueryMsg::GetDelegationDetails {
mix_identity,
delegator,
proxy,
} => to_binary(&query_mixnode_delegation(
deps.storage,
deps.api,
mix_identity,
delegator,
proxy,
)?),
QueryMsg::GetRewardPool {} => to_binary(&query_reward_pool(deps)?),
QueryMsg::GetCirculatingSupply {} => to_binary(&query_circulating_supply(deps)?),
@@ -363,66 +365,19 @@ pub fn query(deps: Deps<'_>, env: Env, msg: QueryMsg) -> Result<QueryResponse, C
QueryMsg::GetPendingDelegationEvents { owner_address } => to_binary(
&query_pending_delegation_events(deps.storage, owner_address)?,
),
QueryMsg::GetAllDelegationKeys {} => to_binary(
&crate::delegations::queries::query_all_delegation_keys(deps.storage)?,
),
QueryMsg::DebugGetAllDelegationValues {} => to_binary(
&crate::delegations::queries::debug_query_all_delegation_values(deps.storage)?,
),
};
Ok(query_res?)
}
// MIGRATE OLD DELEGATION STORAGE
// applied on QAnet
#[allow(dead_code)]
fn migrate_delegations(deps: DepsMut<'_>) -> Result<(), ContractError> {
use crate::delegations::storage::{
DelegationIndex, DELEGATION_MIXNODE_IDX_NAMESPACE, DELEGATION_OWNER_IDX_NAMESPACE,
DELEGATION_PK_NAMESPACE,
};
use cosmwasm_std::Order;
use cw_storage_plus::{IndexedMap, MultiIndex};
type PrimaryKey = Vec<u8>;
fn old_delegations<'a>() -> IndexedMap<'a, PrimaryKey, Delegation, DelegationIndex<'a>> {
let indexes = DelegationIndex {
owner: MultiIndex::new(
|d| d.owner.clone(),
DELEGATION_PK_NAMESPACE,
DELEGATION_OWNER_IDX_NAMESPACE,
),
mixnode: MultiIndex::new(
|d| d.node_identity.clone(),
DELEGATION_PK_NAMESPACE,
DELEGATION_MIXNODE_IDX_NAMESPACE,
),
};
IndexedMap::new(DELEGATION_PK_NAMESPACE, indexes)
}
let old_delegations = old_delegations()
.range(deps.storage, None, None, Order::Ascending)
.filter_map(|r| r.ok())
.map(|(_key, delegation)| delegation)
.collect::<Vec<Delegation>>();
for delegation in old_delegations {
crate::delegations::storage::delegations().save(
deps.storage,
(
delegation.node_identity(),
delegation.owner().as_bytes().to_vec(),
delegation.block_height(),
),
&delegation,
)?;
}
Ok(())
}
#[entry_point]
pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
// TODO: Uncomment mainnet
// migrate_delegations(deps)?;
Ok(Default::default())
}
+170 -113
View File
@@ -43,14 +43,18 @@ pub(crate) fn query_delegator_delegations_paged(
.idx
.owner
.prefix(validated_owner)
.range(deps.storage, start, None, Order::Ascending)
.range_raw(deps.storage, start, None, Order::Ascending)
.take(limit)
.map(|record| record.map(|r| r.1))
.collect::<StdResult<Vec<_>>>()?;
let start_next_after = delegations
.last()
.map(|delegation| delegation.node_identity());
let start_next_after = if delegations.len() < limit {
None
} else {
delegations
.last()
.map(|delegation| delegation.node_identity())
};
Ok(PagedDelegatorDelegationsResponse::new(
delegations,
@@ -58,17 +62,70 @@ pub(crate) fn query_delegator_delegations_paged(
))
}
pub fn query_all_delegation_keys(storage: &dyn Storage) -> Result<Vec<String>, ContractError> {
Ok(storage::delegations()
.keys_raw(storage, None, None, Order::Ascending)
.map(hex::encode)
.collect())
}
use std::collections::HashSet;
// This should only be exposed directly on the contract via nymd binary, not through the nymd clients
pub fn debug_query_all_delegation_values(
storage: &dyn Storage,
) -> Result<HashSet<Delegation>, ContractError> {
use crate::delegations::storage::{
DelegationIndex, DELEGATION_MIXNODE_IDX_NAMESPACE, DELEGATION_OWNER_IDX_NAMESPACE,
DELEGATION_PK_NAMESPACE,
};
use cw_storage_plus::{IndexedMap, MultiIndex};
type PrimaryKey = Vec<u8>;
fn all_delegations<'a>() -> IndexedMap<'a, PrimaryKey, Delegation, DelegationIndex<'a>> {
let indexes = DelegationIndex {
owner: MultiIndex::new(
|d| d.owner.clone(),
DELEGATION_PK_NAMESPACE,
DELEGATION_OWNER_IDX_NAMESPACE,
),
mixnode: MultiIndex::new(
|d| d.node_identity.clone(),
DELEGATION_PK_NAMESPACE,
DELEGATION_MIXNODE_IDX_NAMESPACE,
),
};
IndexedMap::new(DELEGATION_PK_NAMESPACE, indexes)
}
let all_delegations = all_delegations()
.range(storage, None, None, Order::Ascending)
.filter_map(|r| r.ok())
.map(|(_key, delegation)| delegation)
.collect::<HashSet<Delegation>>();
Ok(all_delegations)
}
// queries for delegation value of given address for particular node
pub(crate) fn query_mixnode_delegation(
storage: &dyn Storage,
api: &dyn Api,
mix_identity: IdentityKey,
delegator: String,
proxy: Option<String>,
) -> Result<Vec<Delegation>, ContractError> {
let validated_delegator = api.addr_validate(&delegator)?;
let proxy = proxy.map(|p| api.addr_validate(&p).expect("Invalid proxy address"));
let storage_key = (
mix_identity.clone(),
validated_delegator.as_bytes().to_vec(),
mixnet_contract_common::delegation::generate_storage_key(
&validated_delegator,
proxy.as_ref(),
),
);
let delegations = storage::delegations()
@@ -99,21 +156,30 @@ pub(crate) fn query_mixnode_delegations_paged(
.min(storage::DELEGATION_PAGE_MAX_LIMIT) as usize;
let start = start_after.map(|(addr, height)| {
Bound::ExclusiveRaw((mix_identity.clone(), addr.as_bytes(), height).joined_key())
Bound::exclusive((
hex::decode(addr).expect("Could not hex decode proxy_storage_key"),
height,
))
});
let delegations = storage::delegations()
.idx
.mixnode
.prefix(mix_identity)
.sub_prefix(mix_identity)
.range(deps.storage, start, None, Order::Ascending)
.take(limit)
.map(|record| record.map(|r| r.1))
.collect::<StdResult<Vec<_>>>()?;
.filter_map(|r| r.ok())
.map(|record| record.1)
.collect::<Vec<Delegation>>();
let start_next_after = delegations
.last()
.map(|delegation| (delegation.owner(), delegation.block_height()));
let start_next_after = if delegations.len() < limit {
None
} else {
delegations.last().map(|delegation| {
(
hex::encode(delegation.proxy_storage_key()),
delegation.block_height(),
)
})
};
Ok(PagedMixDelegationsResponse::new(
delegations,
@@ -127,18 +193,22 @@ pub(crate) mod tests {
use crate::support::tests::test_helpers;
use config::defaults::DENOM;
use cosmwasm_std::{coin, Addr, Storage};
use rand::Rng;
pub fn store_n_mix_delegations(n: u32, storage: &mut dyn Storage, node_identity: &str) {
for i in 0..n {
let address = format!("address{}", i);
test_helpers::save_dummy_delegation(storage, node_identity, address);
test_helpers::save_dummy_delegation(storage, node_identity, address, 1);
}
}
#[cfg(test)]
mod querying_for_mixnode_delegations_paged {
use std::collections::HashSet;
use super::*;
use mixnet_contract_common::IdentityKey;
use rand::{distributions::Alphanumeric, SeedableRng};
#[test]
fn retrieval_obeys_limits() {
@@ -203,39 +273,37 @@ pub(crate) mod tests {
#[test]
fn pagination_works() {
let dummy_seed = [42u8; 32];
let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed);
let mut deps = test_helpers::init_contract();
let node_identity: IdentityKey = "foo".into();
let node_identity2: IdentityKey = "bar".into();
test_helpers::save_dummy_delegation(&mut deps.storage, &node_identity, "100");
test_helpers::save_dummy_delegation(&mut deps.storage, &node_identity2, "100");
let mut delegation_test_data = vec![];
let mut returned_delegation_data = HashSet::new();
let per_page = 2;
let page1 = query_mixnode_delegations_paged(
deps.as_ref(),
node_identity.clone(),
None,
Option::from(per_page),
)
.unwrap();
// Crete a bunch of randomly ordered (in storage) delegations
for _ in 0..200 {
delegation_test_data.push((
rng.clone()
.sample_iter(&Alphanumeric)
.take(30)
.map(char::from)
.collect::<String>(),
rng.gen::<u32>() as u64,
))
}
// page should have 1 result on it
assert_eq!(1, page1.delegations.len());
for (address, block_height) in delegation_test_data.iter() {
test_helpers::save_dummy_delegation(
&mut deps.storage,
&node_identity,
address,
*block_height,
);
}
// save another
test_helpers::save_dummy_delegation(&mut deps.storage, &node_identity, "200");
// page1 should have 2 results on it
let page1 = query_mixnode_delegations_paged(
deps.as_ref(),
node_identity.clone(),
None,
Option::from(per_page),
)
.unwrap();
assert_eq!(2, page1.delegations.len());
test_helpers::save_dummy_delegation(&mut deps.storage, &node_identity, "300");
let per_page = 100;
// page1 still has 2 results
let page1 = query_mixnode_delegations_paged(
@@ -245,10 +313,20 @@ pub(crate) mod tests {
Option::from(per_page),
)
.unwrap();
println!("{:?}", page1);
let start_after = page1.start_next_after.unwrap();
assert_eq!(2, page1.delegations.len());
assert_eq!(("200".to_string(), 12345), start_after);
assert_eq!(100, page1.delegations.len());
assert_eq!(
((
"5874735a724c52587679656777795a446a754a746c59694735423165694a".to_string(),
1594717548
)),
start_after
);
for delegation in page1.delegations {
returned_delegation_data.insert(delegation.owner().to_string());
}
// retrieving the next page should start after the last key on this page
@@ -259,37 +337,33 @@ pub(crate) mod tests {
Option::from(per_page),
)
.unwrap();
println!("{:?}", page2);
assert_eq!(1, page2.delegations.len());
assert_eq!(page2.delegations.last().unwrap().owner(), "300");
// save another one
test_helpers::save_dummy_delegation(&mut deps.storage, &node_identity, "400");
let start_after = page2.start_next_after.unwrap();
assert_eq!(
(
"7a6b48546c63674f57417948384e6f494a326c6b5a63767668597346696b".to_string(),
3448133410
),
start_after
);
let page2 = query_mixnode_delegations_paged(
for delegation in page2.delegations {
returned_delegation_data.insert(delegation.owner().to_string());
}
let page3 = query_mixnode_delegations_paged(
deps.as_ref(),
node_identity.clone(),
Option::from(start_after),
Option::from(per_page),
)
.unwrap();
// println!("{:?}", page2);
// now we have 2 pages, with 2 results on the second page
assert_eq!(2, page2.delegations.len());
assert_eq!(page2.delegations.last().unwrap().owner(), "400");
// Should be empty
let page3 = query_mixnode_delegations_paged(
deps.as_ref(),
node_identity,
page2.start_next_after,
Option::from(per_page),
)
.unwrap();
assert!(page3.delegations.is_empty());
assert!(page3.start_next_after.is_none());
for delegation in delegation_test_data {
assert!(returned_delegation_data.contains(&*delegation.0));
}
}
}
@@ -317,7 +391,8 @@ pub(crate) mod tests {
&deps.storage,
&deps.api,
node_identity,
delegation_owner.to_string()
delegation_owner.to_string(),
None
)
)
}
@@ -340,7 +415,8 @@ pub(crate) mod tests {
&deps.storage,
&deps.api,
node_identity1.clone(),
delegation_owner1.to_string()
delegation_owner1.to_string(),
None
)
);
@@ -366,7 +442,8 @@ pub(crate) mod tests {
&deps.storage,
&deps.api,
node_identity1.clone(),
delegation_owner1.to_string()
delegation_owner1.to_string(),
None
)
);
@@ -392,7 +469,8 @@ pub(crate) mod tests {
&deps.storage,
&deps.api,
node_identity1,
delegation_owner1.to_string()
delegation_owner1.to_string(),
None
)
)
}
@@ -404,7 +482,7 @@ pub(crate) mod tests {
fn store_n_reverse_delegations(n: u32, storage: &mut dyn Storage, delegation_owner: &str) {
for i in 0..n {
let node_identity = format!("node{}", i);
test_helpers::save_dummy_delegation(storage, node_identity, delegation_owner);
test_helpers::save_dummy_delegation(storage, node_identity, delegation_owner, 1);
}
}
@@ -475,9 +553,18 @@ pub(crate) mod tests {
let mut deps = test_helpers::init_contract();
let delegation_owner = "bar".to_string();
test_helpers::save_dummy_delegation(&mut deps.storage, "100", &delegation_owner);
for j in 0..20 {
for i in 0..10 {
test_helpers::save_dummy_delegation(
&mut deps.storage,
format!("{}-{}", j, i),
delegation_owner.clone(),
i,
);
}
}
let per_page = 2;
let per_page = 100;
let page1 = query_delegator_delegations_paged(
deps.as_ref(),
delegation_owner.clone(),
@@ -486,60 +573,30 @@ pub(crate) mod tests {
)
.unwrap();
// page should have 1 result on it
assert_eq!(1, page1.delegations.len());
let start_after = page1.start_next_after.unwrap();
assert_eq!(per_page as usize, page1.delegations.len());
assert_eq!(start_after, "9-9".to_string());
// save another
test_helpers::save_dummy_delegation(&mut deps.storage, "200", &delegation_owner);
// page1 should have 2 results on it
let page1 = query_delegator_delegations_paged(
deps.as_ref(),
delegation_owner.clone(),
None,
Option::from(per_page),
)
.unwrap();
assert_eq!(2, page1.delegations.len());
test_helpers::save_dummy_delegation(&mut deps.storage, "300", &delegation_owner);
// page1 still has 2 results
let page1 = query_delegator_delegations_paged(
deps.as_ref(),
delegation_owner.clone(),
None,
Option::from(per_page),
)
.unwrap();
assert_eq!(2, page1.delegations.len());
// retrieving the next page should start after the last key on this page
let start_after: IdentityKey = page1.start_next_after.unwrap();
let page2 = query_delegator_delegations_paged(
deps.as_ref(),
delegation_owner.clone(),
Option::from(start_after),
Some(start_after),
Option::from(per_page),
)
.unwrap();
assert_eq!(1, page2.delegations.len());
let start_after = page2.start_next_after.unwrap();
assert_eq!(start_after, "19-9".to_string());
// save another one
test_helpers::save_dummy_delegation(&mut deps.storage, "400", &delegation_owner);
let start_after = String::from("2");
let page2 = query_delegator_delegations_paged(
let page3 = query_delegator_delegations_paged(
deps.as_ref(),
delegation_owner,
Option::from(start_after),
delegation_owner.clone(),
Some(start_after),
Option::from(per_page),
)
.unwrap();
// now we have 2 pages, with 2 results on the second page
assert_eq!(2, page2.delegations.len());
assert!(page3.start_next_after.is_none());
}
}
}
+2 -2
View File
@@ -24,9 +24,9 @@ type OwnerAddress = Vec<u8>;
type PrimaryKey = (IdentityKey, OwnerAddress, BlockHeight);
pub(crate) struct DelegationIndex<'a> {
pub(crate) owner: MultiIndex<'a, Addr, Delegation>,
pub(crate) owner: MultiIndex<'a, Addr, Delegation, PrimaryKey>,
pub(crate) mixnode: MultiIndex<'a, IdentityKey, Delegation>,
pub(crate) mixnode: MultiIndex<'a, IdentityKey, Delegation, PrimaryKey>,
}
impl<'a> IndexList<Delegation> for DelegationIndex<'a> {
@@ -4,7 +4,6 @@ use super::storage::{self, PENDING_DELEGATION_EVENTS};
use crate::error::ContractError;
use crate::mixnet_contract_settings::storage as mixnet_params_storage;
use crate::mixnodes::storage as mixnodes_storage;
use crate::support::helpers::generate_storage_key;
use config::defaults::DENOM;
use cosmwasm_std::{
coins, wasm_execute, Addr, Api, BankMsg, Coin, DepsMut, Env, Event, MessageInfo, Order,
@@ -192,19 +191,18 @@ pub(crate) fn _try_delegate_to_mixnode(
});
}
let maybe_proxy_storage = generate_storage_key(&delegate, proxy.as_ref());
let storage_key = (maybe_proxy_storage, block_height, mix_identity.to_string());
let delegation = Delegation::new(
delegate.to_owned(),
mix_identity.to_string(),
amount.clone(),
block_height,
proxy.clone(),
);
storage::PENDING_DELEGATION_EVENTS.save(
storage,
storage_key,
&DelegationEvent::Delegate(Delegation::new(
delegate.to_owned(),
mix_identity.to_string(),
amount.clone(),
block_height,
proxy.clone(),
)),
delegation.event_storage_key(),
&DelegationEvent::Delegate(delegation),
)?;
Ok(Response::new().add_event(new_pending_delegation_event(
@@ -246,17 +244,9 @@ pub(crate) fn try_reconcile_undelegation(
pending_undelegate: &PendingUndelegate,
) -> Result<ReconcileUndelegateResponse, ContractError> {
let delegation_map = storage::delegations();
let maybe_proxy_storage = generate_storage_key(
&pending_undelegate.delegate(),
pending_undelegate.proxy().as_ref(),
);
let storage_key = (
pending_undelegate.mix_identity(),
maybe_proxy_storage.clone(),
);
let any_delegations = delegation_map
.prefix(storage_key.clone())
.prefix(pending_undelegate.storage_key())
.keys(storage, None, None, cosmwasm_std::Order::Ascending)
.filter_map(|v| v.ok())
.next()
@@ -287,7 +277,7 @@ pub(crate) fn try_reconcile_undelegation(
// Might want to introduce paging here
let delegation_heights = delegation_map
.prefix(storage_key)
.prefix(pending_undelegate.storage_key())
.keys(storage, None, None, cosmwasm_std::Order::Ascending)
.filter_map(|v| v.ok())
.collect::<Vec<u64>>();
@@ -317,14 +307,15 @@ pub(crate) fn try_reconcile_undelegation(
}
for h in delegation_heights {
let storage_key = (
pending_undelegate.mix_identity(),
maybe_proxy_storage.clone(),
h,
);
let delegation = delegation_map.load(storage, storage_key.clone())?;
let delegation =
delegation_map.load(storage, pending_undelegate.delegation_key(h).clone())?;
total_delegation += delegation.amount.amount;
delegation_map.replace(storage, storage_key, None, Some(&delegation))?;
delegation_map.replace(
storage,
pending_undelegate.delegation_key(h),
None,
Some(&delegation),
)?;
}
let bank_msg = BankMsg::Send {
@@ -386,19 +377,17 @@ pub(crate) fn _try_remove_delegation_from_mixnode(
) -> Result<Response, ContractError> {
let delegate = deps.api.addr_validate(delegate)?;
let event = PendingUndelegate::new(
mix_identity.to_string(),
delegate.clone(),
proxy.clone(),
env.block.height,
);
PENDING_DELEGATION_EVENTS.save(
deps.storage,
(
delegate.as_bytes().to_vec(),
env.block.height,
mix_identity.to_string(),
),
&DelegationEvent::Undelegate(PendingUndelegate::new(
mix_identity.to_string(),
delegate.clone(),
proxy.clone(),
env.block.height,
)),
event.event_storage_key(),
&DelegationEvent::Undelegate(event),
)?;
Ok(Response::new().add_event(new_pending_undelegation_event(
@@ -738,6 +727,7 @@ mod tests {
&deps.api,
identity,
delegation_owner.to_string(),
None,
)
.unwrap();
@@ -1074,6 +1064,7 @@ mod tests {
&deps.api,
identity.clone(),
delegation_owner.clone().into_string(),
None,
)
.unwrap();
@@ -1143,6 +1134,7 @@ mod tests {
&deps.api,
identity.clone(),
delegation_owner.clone().into_string(),
None,
)
.unwrap();
-13
View File
@@ -40,19 +40,6 @@ pub(crate) fn epoch_reward_params(
Ok(epoch_reward_params)
}
pub fn generate_storage_key(address: &Addr, proxy: Option<&Addr>) -> Vec<u8> {
if let Some(proxy) = &proxy {
address
.as_bytes()
.iter()
.zip(proxy.as_bytes())
.map(|(x, y)| x ^ y)
.collect()
} else {
address.as_bytes().to_vec()
}
}
// check if the target address has already bonded a mixnode or gateway,
// in either case, return an appropriate error
pub(crate) fn ensure_no_existing_bond(
+2 -1
View File
@@ -103,12 +103,13 @@ pub mod test_helpers {
storage: &mut dyn Storage,
mix: impl Into<String>,
owner: impl Into<String>,
block_height: u64,
) {
let delegation = Delegation {
owner: Addr::unchecked(owner.into()),
node_identity: mix.into(),
amount: coin(12345, DENOM),
block_height: 12345,
block_height: block_height,
proxy: None,
};
+3 -3
View File
@@ -1,6 +1,6 @@
[package]
name = "vesting-contract"
version = "0.1.0"
version = "1.0.0-rc.1"
authors = ["Drazen Urch <durch@users.noreply.github.com>"]
edition = "2021"
@@ -18,8 +18,8 @@ mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-
vesting-contract-common = { path = "../../common/cosmwasm-smart-contracts/vesting-contract" }
config = { path = "../../common/config" }
cosmwasm-std = { version = "1.0.0-beta4"}
cw-storage-plus = { version = "0.12.1", features = ["iterator"] }
cosmwasm-std = { version = "1.0.0-beta6"}
cw-storage-plus = { version = "0.13.1", features = ["iterator"] }
schemars = "0.8"
serde = { version = "1.0", default-features = false, features = ["derive"] }
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "explorer-api"
version = "0.1.0"
version = "1.0.0-rc.1"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-2
View File
@@ -18,8 +18,6 @@ We use the following:
## Development mode
Copy the `.env.prod` file to `.env` to configure your environment. Using the live sandbox Explorer API is the best way to do development, so the prod settings are good.
Run the following:
```
+6 -4
View File
@@ -10,7 +10,7 @@ import { DiscordIcon } from '../icons/socials/DiscordIcon';
export const TELEGRAM_LINK = 'https://t.me/nymchan';
export const TWITTER_LINK = 'https://twitter.com/nymproject';
export const GITHUB_LINK = 'https://github.com/nymtech';
export const DISCORD_LINK = 'https://discord.gg/ggxrUpbNnn';
export const DISCORD_LINK = 'https://discord.gg/jUqJYGB5';
export const Socials: React.FC<{ isFooter?: boolean }> = ({ isFooter }) => {
const theme = useTheme();
@@ -22,9 +22,11 @@ export const Socials: React.FC<{ isFooter?: boolean }> = ({ isFooter }) => {
<IconButton component="a" href={TELEGRAM_LINK} target="_blank" data-testid="telegram">
<TelegramIcon color={color} size={24} />
</IconButton>
<IconButton component="a" href={DISCORD_LINK} target="_blank" data-testid="discord">
<DiscordIcon color={color} size={24} />
</IconButton>
{false && (
<IconButton component="a" href={DISCORD_LINK} target="_blank" data-testid="discord">
<DiscordIcon color={color} size={24} />
</IconButton>
)}
<IconButton component="a" href={TWITTER_LINK} target="_blank" data-testid="twitter">
<TwitterIcon color={color} size={24} />
</IconButton>
+2 -2
View File
@@ -3,7 +3,7 @@
[package]
name = "nym-gateway"
version = "0.12.1"
version = "1.0.0-rc.1"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Mixnet Gateway"
edition = "2021"
@@ -55,7 +55,7 @@ validator-client = { path = "../common/client-libs/validator-client", features =
version-checker = { path = "../common/version-checker" }
[features]
coconut = ["coconut-interface", "gateway-requests/coconut", "gateway-client/coconut", "credentials/coconut"]
coconut = ["coconut-interface", "gateway-requests/coconut", "gateway-client/coconut"]
eth = []
[build-dependencies]
+1 -1
View File
@@ -27,7 +27,7 @@ coconut-interface = { path = "../../common/coconut-interface", optional = true }
credentials = { path = "../../common/credentials" }
[features]
coconut = ["coconut-interface", "credentials/coconut"]
coconut = ["coconut-interface"]
[dependencies.tungstenite]
version = "0.13.0"
+1 -1
View File
@@ -3,7 +3,7 @@
[package]
name = "nym-mixnode"
version = "0.12.1"
version = "1.0.0-rc.1"
authors = [
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
"Jędrzej Stuczyński <andrew@nymtech.net>",
-57
View File
@@ -1,57 +0,0 @@
/* eslint-disable no-param-reassign */
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
module.exports = {
stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
addons: ['@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-interactions'],
framework: '@storybook/react',
core: {
builder: 'webpack5',
},
// webpackFinal: async (config, { configType }) => {
// // `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION'
// // You can change the configuration based on that.
// // 'PRODUCTION' is used when building the static version of storybook.
webpackFinal: async (config) => {
config.module.rules.forEach((rule) => {
// look for SVG import rule and replace
// NOTE: the rule before modification is /\.(svg|ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/
if (rule.test?.toString().includes('svg')) {
rule.test = /\.(ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/;
}
});
// handle asset loading with this
config.module.rules.unshift({
test: /\.svg(\?.*)?$/i,
issuer: /\.[jt]sx?$/,
use: ['@svgr/webpack'],
});
config.resolve.extensions = ['.tsx', '.ts', '.js'];
config.resolve.plugins = [new TsconfigPathsPlugin()];
config.plugins.push(new ForkTsCheckerWebpackPlugin({
typescript: {
mode: 'write-references',
diagnosticOptions: {
semantic: true,
syntactic: true,
},
},
}));
if (!config.resolve.alias) {
config.resolve.alias = {};
}
config.resolve.alias['@tauri-apps/api'] = `${__dirname}/mocks/tauri`;
// Return the altered config
return config;
},
features: {
emotionAlias: false,
},
};
@@ -1,13 +0,0 @@
/**
* This is a mock for Tauri's API package (@tauri-apps/api), to prevent stories from being excluded, because they either use
* or import dependencies that use Tauri.
*/
module.exports = {
invoke: (operation) => {
console.error(`Tauri cannot be used in Storybook. The operation requested was "${operation}". You can add mock responses to "nym_wallet/.storybook/mocks/tauri.js" if you need. The default response is "void".`);
return new Promise((resolve, reject) => {
reject(new Error(`Tauri operation ${operation} not available in storybook.`));
});
},
}
@@ -1,10 +0,0 @@
/**
* This is a mock for Tauri's API package (@tauri-apps/api/window), to prevent stories from being excluded, because they either use
* or import dependencies that use Tauri.
*/
module.exports = {
appWindow: {
maximize: () => undefined,
}
}
-19
View File
@@ -1,19 +0,0 @@
import { NymWalletThemeWithMode } from '../src/theme/NymWalletTheme';
export const parameters = {
actions: { argTypesRegex: "^on[A-Z].*" },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
}
const withThemeProvider = (Story, context) => (
<NymWalletThemeWithMode mode="light">
<Story {...context} />
</NymWalletThemeWithMode>
);
export const decorators = [withThemeProvider];
+196 -427
View File
File diff suppressed because it is too large Load Diff
+1 -12
View File
@@ -10,15 +10,11 @@
"tauri:dev": "yarn tauri dev",
"tauri:build": "yarn tauri build",
"tsc": "tsc --noEmit true",
"tsc:watch": "tsc --noEmit true --watch",
"dev": "yarn run webpack:dev & yarn run tauri:dev",
"prebuild": "yarn --cwd .. build",
"build": "run-s webpack:prod tauri:build",
"lint": "eslint src",
"lint:fix": "eslint src --fix",
"prestorybook": "yarn --cwd .. build",
"storybook": "start-storybook -p 6006",
"storybook:build": "build-storybook"
"lint:fix": "eslint src --fix"
},
"dependencies": {
"@babel/preset-typescript": "^7.15.0",
@@ -42,7 +38,6 @@
"react-hook-form": "^7.14.2",
"react-router-dom": "^5.2.0",
"semver": "^6.3.0",
"use-clipboard-copy": "^0.2.0",
"yup": "^0.32.9"
},
"devDependencies": {
@@ -52,12 +47,6 @@
"@babel/preset-react": "^7.14.5",
"@nymproject/eslint-config-react-typescript": "^1.0.0",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.4",
"@storybook/addon-actions": "^6.4.19",
"@storybook/addon-essentials": "^6.4.19",
"@storybook/addon-interactions": "^6.4.19",
"@storybook/addon-links": "^6.4.19",
"@storybook/react": "^6.4.19",
"@storybook/testing-library": "^0.0.9",
"@svgr/webpack": "^6.1.1",
"@tauri-apps/cli": "^1.0.0-rc.5",
"@testing-library/jest-dom": "^5.14.1",
+14 -8
View File
@@ -1,11 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<meta name='viewport' content='width=device-width, initial-scale=1' />
<title>Nym Wallet</title>
</head>
<body>
<div id='root'></div>
</body>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Open+Sans&display=swap"
rel="stylesheet"
/>
<title>Nym Wallet</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
+4 -7
View File
@@ -1,6 +1,6 @@
[package]
name = "nym_wallet"
version = "1.0.2"
version = "1.0.1"
description = "Nym Native Wallet"
authors = ["Nym Technologies SA"]
license = ""
@@ -20,13 +20,9 @@ tauri-macros = "=1.0.0-rc.1"
[dependencies]
bip39 = "1.0"
cfg-if = "1.0.0"
colored = "2.0"
dirs = "4.0"
dotenv = "0.15.0"
eyre = "0.6.5"
futures = "0.3.15"
itertools = "0.10"
log = "0.4"
pretty_env_logger = "0.4"
rand = "0.6.5"
@@ -34,7 +30,7 @@ reqwest = "0.11.9"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
strum = { version = "0.23", features = ["derive"] }
tauri = { version = "=1.0.0-rc.2", features = ["clipboard-all", "shell-open", "updater", "window-maximize"] }
tauri = { version = "=1.0.0-rc.2", features = ["clipboard-all", "shell-open", "window-maximize"] }
tendermint-rpc = "0.23.0"
thiserror = "1.0"
tokio = { version = "1.10", features = ["sync", "time"] }
@@ -46,7 +42,7 @@ argon2 = { version = "0.3.2", features = ["std"] }
base64 = "0.13"
zeroize = "1.4.3"
cosmrs = { git = "https://github.com/nymtech/cosmos-rust", branch = "bugfix/account-id-length-validation", features = ["rpc", "bip32", "cosmwasm"] }
cosmrs = { version = "0.4.1", features = ["rpc", "bip32", "cosmwasm"] }
cosmwasm-std = "1.0.0-beta3"
validator-client = { path = "../../common/client-libs/validator-client", features = [
@@ -56,6 +52,7 @@ mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-
vesting-contract-common = { path = "../../common/cosmwasm-smart-contracts/vesting-contract" }
config = { path = "../../common/config" }
coconut-interface = { path = "../../common/coconut-interface" }
credentials = { path = "../../common/credentials" }
# Used for Type conversion, can be extracted but its a lot of work
vesting-contract = { path = "../../contracts/vesting" }
+176 -267
View File
@@ -1,60 +1,40 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::platform_constants::{CONFIG_DIR_NAME, CONFIG_FILENAME};
use crate::{error::BackendError, network::Network as WalletNetwork};
use config::defaults::all::Network;
use config::defaults::{all::SupportedNetworks, ValidatorDetails};
use core::fmt;
use itertools::Itertools;
use serde::de::DeserializeOwned;
use config::NymConfig;
use reqwest::StatusCode;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::str::FromStr;
use std::iter::zip;
use std::time::Duration;
use std::{fs, io, path::PathBuf};
use strum::IntoEnumIterator;
use url::Url;
pub const REMOTE_SOURCE_OF_VALIDATOR_URLS: &str =
const REMOTE_SOURCE_OF_VALIDATOR_URLS: &str =
"https://nymtech.net/.wellknown/wallet/validators.json";
#[derive(Debug, Default, Clone, PartialEq, Eq)]
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct Config {
// Base configuration is not part of the configuration file as it's not intended to be changed.
#[serde(skip)]
base: Base,
// Global configuration file
global: Option<GlobalConfig>,
// One configuration file per network
networks: HashMap<String, NetworkConfig>,
// Network level configuration
network: OptionalValidators,
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
struct Base {
/// Information on all the networks that the wallet connects to.
networks: SupportedNetworks,
}
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)]
pub struct GlobalConfig {
// TODO: there are no global settings (yet)
}
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)]
pub struct NetworkConfig {
// User selected urls
selected_nymd_url: Option<Url>,
selected_api_url: Option<Url>,
// Additional user provided validators
validator_urls: Option<Vec<ValidatorUrl>>,
}
impl NetworkConfig {
fn validators(&self) -> impl Iterator<Item = &ValidatorUrl> {
self.validator_urls.iter().flat_map(|v| v.iter())
}
/// Validators that have been fetched dynamically, probably during startup.
fetched_validators: OptionalValidators,
}
impl Default for Base {
@@ -62,125 +42,89 @@ impl Default for Base {
let networks = WalletNetwork::iter().map(Into::into).collect();
Base {
networks: SupportedNetworks::new(networks),
fetched_validators: OptionalValidators::default(),
}
}
}
impl Config {
fn root_directory() -> PathBuf {
tauri::api::path::config_dir().expect("Failed to get config directory")
impl NymConfig for Config {
fn template() -> &'static str {
// For now we're not using a template
unimplemented!();
}
fn config_directory() -> PathBuf {
Self::root_directory().join(CONFIG_DIR_NAME)
fn default_root_directory() -> PathBuf {
dirs::home_dir()
.expect("Failed to evaluate $HOME value")
.join(".nym")
.join("wallet")
}
fn config_file_path(network: Option<WalletNetwork>) -> PathBuf {
if let Some(network) = network {
let network_filename = format!("{}.toml", network.as_key());
Self::config_directory().join(network_filename)
} else {
Self::config_directory().join(CONFIG_FILENAME)
}
fn root_directory(&self) -> PathBuf {
Self::default_root_directory()
}
pub fn save_to_files(&self) -> io::Result<()> {
log::trace!("Config::save_to_file");
fn config_directory(&self) -> PathBuf {
self.root_directory().join("config")
}
fn data_directory(&self) -> PathBuf {
self.root_directory().join("data")
}
fn save_to_file(&self, custom_location: Option<PathBuf>) -> io::Result<()> {
let config_toml = toml::to_string_pretty(&self)
.map_err(|toml_err| io::Error::new(io::ErrorKind::Other, toml_err))?;
// Make sure the whole directory structure actually exists
fs::create_dir_all(Self::config_directory())?;
// Global config
if let Some(global) = &self.global {
let location = Self::config_file_path(None);
match toml::to_string_pretty(&global)
.map_err(|toml_err| io::Error::new(io::ErrorKind::Other, toml_err))
.map(|toml| fs::write(location.clone(), toml))
{
Ok(_) => log::debug!("Writing to: {:#?}", location),
Err(err) => log::warn!("Failed to write to {:#?}: {err}", location),
}
}
// One file per network
for (network, config) in &self.networks {
let network = match Network::from_str(network).map(Into::into) {
Ok(network) => network,
Err(err) => {
log::warn!("Unexpected name for network configuration, not saving: {err}");
break;
match custom_location.clone() {
Some(loc) => {
if let Some(parent_dir) = loc.parent() {
fs::create_dir_all(parent_dir)
} else {
Ok(())
}
};
let location = Self::config_file_path(Some(network));
match toml::to_string_pretty(config)
.map_err(|toml_err| io::Error::new(io::ErrorKind::Other, toml_err))
.map(|toml| fs::write(location.clone(), toml))
{
Ok(_) => log::debug!("Writing to: {:#?}", location),
Err(err) => log::warn!("Failed to write to {:#?}: {err}", location),
}
}
Ok(())
None => fs::create_dir_all(self.config_directory()),
}?;
fs::write(
custom_location.unwrap_or_else(|| self.config_directory().join(Self::config_file_name())),
config_toml,
)
}
}
pub fn load_from_files() -> Self {
// Global
let global = {
let file = Self::config_file_path(None);
match load_from_file::<GlobalConfig>(file.clone()) {
Ok(global) => {
log::debug!("Loaded from file {:#?}", file);
Some(global)
}
Err(err) => {
log::trace!("Not loading {:#?}: {}", file, err);
None
}
}
};
// One file per network
let mut networks = HashMap::new();
for network in WalletNetwork::iter() {
let file = Self::config_file_path(Some(network));
match load_from_file::<NetworkConfig>(file.clone()) {
Ok(config) => {
log::trace!("Loaded from file {:#?}", file);
networks.insert(network.as_key(), config);
}
Err(err) => log::trace!("Not loading {:#?}: {}", file, err),
};
}
Self {
base: Base::default(),
global,
networks,
}
}
pub fn get_base_validators(
&self,
network: WalletNetwork,
) -> impl Iterator<Item = ValidatorUrl> + '_ {
self.base.networks.validators(network.into()).map(|v| {
impl Config {
/// Get the available validators in the order
/// 1. from the configuration file
/// 2. provided remotely
/// 3. hardcoded fallback
pub fn get_validators(&self, network: WalletNetwork) -> impl Iterator<Item = ValidatorUrl> + '_ {
// The base validators are (currently) stored as strings
let base_validators = self.base.networks.validators(network.into()).map(|v| {
v.clone()
.try_into()
.expect("The hardcoded validators are assumed to be valid urls")
})
});
self
.base
.fetched_validators
.validators(network)
.chain(self.network.validators(network))
.cloned()
.chain(base_validators)
}
pub fn get_configured_validators(
pub fn get_validators_with_api_endpoint(
&self,
network: WalletNetwork,
) -> impl Iterator<Item = ValidatorUrl> + '_ {
) -> impl Iterator<Item = ValidatorUrlWithApiEndpoint> + '_ {
self
.networks
.get(&network.as_key())
.get_validators(network)
.into_iter()
.flat_map(|c| c.validators().cloned())
.filter_map(|validator| ValidatorUrlWithApiEndpoint::try_from(validator).ok())
}
pub fn get_mixnet_contract_address(&self, network: WalletNetwork) -> Option<cosmrs::AccountId> {
@@ -216,83 +160,70 @@ impl Config {
.ok()
}
pub fn select_validator_nymd_url(&mut self, nymd_url: Url, network: WalletNetwork) {
if let Some(net) = self.networks.get_mut(&network.as_key()) {
net.selected_nymd_url = Some(nymd_url);
} else {
self.networks.insert(
network.as_key(),
NetworkConfig {
selected_nymd_url: Some(nymd_url),
..NetworkConfig::default()
},
);
}
pub async fn fetch_updated_validator_urls(&mut self) -> Result<(), BackendError> {
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(3))
.build()?;
let response = client
.get(REMOTE_SOURCE_OF_VALIDATOR_URLS.to_string())
.send()
.await?;
self.base.fetched_validators = serde_json::from_str(&response.text().await?)?;
Ok(())
}
pub fn select_validator_api_url(&mut self, api_url: Url, network: WalletNetwork) {
if let Some(net) = self.networks.get_mut(&network.as_key()) {
net.selected_api_url = Some(api_url);
} else {
self.networks.insert(
network.as_key(),
NetworkConfig {
selected_nymd_url: Some(api_url),
..NetworkConfig::default()
},
);
}
}
pub async fn check_validator_health(
&self,
network: WalletNetwork,
) -> Result<Vec<(ValidatorUrl, StatusCode)>, BackendError> {
// Limit the number of validators we query
let max_validators = 200_usize;
let validators_to_query = || self.get_validators(network).take(max_validators);
pub fn get_selected_validator_nymd_url(&self, network: &WalletNetwork) -> Option<Url> {
self
.networks
.get(&network.as_key())
.and_then(|config| config.selected_nymd_url.clone())
}
let validator_urls = validators_to_query().map(|v| {
let mut health_url = v.nymd_url.clone();
health_url.set_path("health");
(v, health_url)
});
pub fn get_selected_validator_api_url(&self, network: &WalletNetwork) -> Option<Url> {
self
.networks
.get(&network.as_key())
.and_then(|config| config.selected_api_url.clone())
}
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(3))
.build()?;
pub fn add_validator_url(&mut self, url: ValidatorUrl, network: WalletNetwork) {
if let Some(net) = self.networks.get_mut(&network.as_key()) {
if let Some(ref mut urls) = net.validator_urls {
urls.push(url);
} else {
net.validator_urls = Some(vec![url]);
}
} else {
self.networks.insert(
network.as_key(),
NetworkConfig {
validator_urls: Some(vec![url]),
..NetworkConfig::default()
},
);
}
let requests = validator_urls.map(|(_, url)| client.get(url).send());
let responses = futures::future::join_all(requests).await;
let validators_responding_success =
zip(validators_to_query(), responses).filter_map(|(v, r)| match r {
Ok(r) if r.status().is_success() => Some((v, r.status())),
_ => None,
});
Ok(validators_responding_success.collect::<Vec<_>>())
}
#[allow(unused)]
pub fn remove_validator_url(&mut self, _url: ValidatorUrl, _network: WalletNetwork) {
todo!();
pub async fn check_validator_health_for_all_networks(
&self,
) -> Result<HashMap<WalletNetwork, Vec<(ValidatorUrl, StatusCode)>>, BackendError> {
let validator_health_requests =
WalletNetwork::iter().map(|network| self.check_validator_health(network));
let responses_keyed_by_network = zip(
WalletNetwork::iter(),
futures::future::join_all(validator_health_requests).await,
);
// Iterate and collect manually to be able to return errors in the response
let mut responses = HashMap::new();
for (network, response) in responses_keyed_by_network {
responses.insert(network, response?);
}
Ok(responses)
}
}
fn load_from_file<T>(file: PathBuf) -> Result<T, io::Error>
where
T: DeserializeOwned,
{
fs::read_to_string(file).and_then(|contents| {
toml::from_str::<T>(&contents)
.map_err(|toml_err| io::Error::new(io::ErrorKind::Other, toml_err))
})
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct ValidatorUrl {
pub nymd_url: Url,
pub api_url: Option<Url>,
@@ -312,20 +243,29 @@ impl TryFrom<ValidatorDetails> for ValidatorUrl {
}
}
impl fmt::Display for ValidatorUrl {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s1 = format!("nymd_url: {}", self.nymd_url);
let s2 = self
.api_url
.as_ref()
.map(|url| format!(", api_url: {}", url));
write!(f, " {}{},", s1, s2.unwrap_or_default())
#[derive(Clone, Debug)]
pub struct ValidatorUrlWithApiEndpoint {
pub nymd_url: Url,
pub api_url: Url,
}
impl TryFrom<ValidatorUrl> for ValidatorUrlWithApiEndpoint {
type Error = BackendError;
fn try_from(validator: ValidatorUrl) -> Result<Self, Self::Error> {
match validator.api_url {
Some(api_url) => Ok(ValidatorUrlWithApiEndpoint {
nymd_url: validator.nymd_url,
api_url,
}),
None => Err(BackendError::NoValidatorApiUrlConfigured),
}
}
}
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct OptionalValidators {
struct OptionalValidators {
// User supplied additional validator urls in addition to the hardcoded ones.
// These are separate fields, rather than a map, to force the serialization order.
mainnet: Option<Vec<ValidatorUrl>>,
@@ -334,7 +274,7 @@ pub struct OptionalValidators {
}
impl OptionalValidators {
pub fn validators(&self, network: WalletNetwork) -> impl Iterator<Item = &ValidatorUrl> {
fn validators(&self, network: WalletNetwork) -> impl Iterator<Item = &ValidatorUrl> {
match network {
WalletNetwork::MAINNET => self.mainnet.as_ref(),
WalletNetwork::SANDBOX => self.sandbox.as_ref(),
@@ -345,89 +285,58 @@ impl OptionalValidators {
}
}
impl fmt::Display for OptionalValidators {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s1 = self
.mainnet
.as_ref()
.map(|validators| format!("mainnet: [\n{}\n]", validators.iter().format("\n")))
.unwrap_or_default();
let s2 = self
.sandbox
.as_ref()
.map(|validators| format!(",\nsandbox: [\n{}\n]", validators.iter().format("\n")))
.unwrap_or_default();
let s3 = self
.qa
.as_ref()
.map(|validators| format!(",\nqa: [\n{}\n]", validators.iter().format("\n")))
.unwrap_or_default();
write!(f, "{}{}{}", s1, s2, s3)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn test_config() -> Config {
let netconfig = NetworkConfig {
selected_nymd_url: None,
selected_api_url: Some("https://my_api_url.com".parse().unwrap()),
validator_urls: Some(vec![
ValidatorUrl {
nymd_url: "https://foo".parse().unwrap(),
api_url: None,
},
ValidatorUrl {
nymd_url: "https://bar".parse().unwrap(),
api_url: Some("https://bar/api".parse().unwrap()),
},
ValidatorUrl {
nymd_url: "https://baz".parse().unwrap(),
api_url: Some("https://baz/api".parse().unwrap()),
},
]),
};
Config {
base: Base::default(),
global: Some(GlobalConfig::default()),
networks: [(WalletNetwork::MAINNET.as_key(), netconfig)]
.into_iter()
.collect(),
network: OptionalValidators {
mainnet: Some(vec![
ValidatorDetails {
nymd_url: "https://foo".to_string(),
api_url: None,
}
.try_into()
.unwrap(),
ValidatorUrl {
nymd_url: "https://baz".parse().unwrap(),
api_url: Some("https://baz/api".parse().unwrap()),
},
]),
sandbox: Some(vec![ValidatorUrl {
nymd_url: "https://bar".parse().unwrap(),
api_url: Some("https://bar/api".parse().unwrap()),
}]),
qa: None,
},
}
}
#[test]
fn serialize_to_toml() {
let config = test_config();
let netconfig = &config.networks[&WalletNetwork::MAINNET.as_key()];
assert_eq!(
toml::to_string_pretty(netconfig).unwrap(),
r#"selected_api_url = 'https://my_api_url.com/'
[[validator_urls]]
toml::to_string_pretty(&test_config()).unwrap(),
r#"[[network.mainnet]]
nymd_url = 'https://foo/'
[[validator_urls]]
nymd_url = 'https://bar/'
api_url = 'https://bar/api'
[[validator_urls]]
[[network.mainnet]]
nymd_url = 'https://baz/'
api_url = 'https://baz/api'
[[network.sandbox]]
nymd_url = 'https://bar/'
api_url = 'https://bar/api'
"#
);
}
#[test]
fn serialize_and_deserialize_to_toml() {
let config = test_config();
let netconfig = &config.networks[&WalletNetwork::MAINNET.as_key()];
let config_str = toml::to_string_pretty(netconfig).unwrap();
let config_from_toml: NetworkConfig = toml::from_str(&config_str).unwrap();
assert_eq!(netconfig, &config_from_toml);
let config_str = toml::to_string_pretty(&config).unwrap();
let config_from_toml = toml::from_str(&config_str).unwrap();
assert_eq!(config, config_from_toml);
}
#[test]
@@ -435,7 +344,7 @@ api_url = 'https://baz/api'
let config = test_config();
let nymd_url = config
.get_configured_validators(WalletNetwork::MAINNET)
.get_validators(WalletNetwork::MAINNET)
.next()
.map(|v| v.nymd_url)
.unwrap();
@@ -443,7 +352,7 @@ api_url = 'https://baz/api'
// The first entry is missing an API URL
let api_url = config
.get_configured_validators(WalletNetwork::MAINNET)
.get_validators(WalletNetwork::MAINNET)
.next()
.and_then(|v| v.api_url);
assert_eq!(api_url, None);
@@ -454,14 +363,14 @@ api_url = 'https://baz/api'
let config = Config::default();
let nymd_url = config
.get_base_validators(WalletNetwork::MAINNET)
.get_validators(WalletNetwork::MAINNET)
.next()
.map(|v| v.nymd_url)
.unwrap();
assert_eq!(nymd_url.as_ref(), "https://rpc.nyx.nodes.guru/");
let api_url = config
.get_base_validators(WalletNetwork::MAINNET)
.get_validators(WalletNetwork::MAINNET)
.next()
.and_then(|v| v.api_url)
.unwrap();
+2 -10
View File
@@ -77,18 +77,10 @@ pub enum BackendError {
NetworkNotSupported(config::defaults::all::Network),
#[error("Could not access the local data storage directory")]
UnknownStorageDirectory,
#[error("No nymd validator configured")]
NoNymdValidatorConfigured,
#[error("No validator API URL configured")]
NoValidatorApiUrlConfigured,
#[error("The wallet file already exists")]
WalletFileAlreadyExists,
#[error("The wallet file is not found")]
WalletFileNotFound,
#[error("Account ID not found in wallet")]
NoSuchIdInWallet,
#[error("Account ID already found in wallet")]
IdAlreadyExistsInWallet,
#[error("Adding a different password to the wallet not currently supported")]
WalletDifferentPasswordDetected,
}
impl Serialize for BackendError {
+2 -10
View File
@@ -15,9 +15,10 @@ mod error;
mod menu;
mod network;
mod operations;
mod platform_constants;
mod state;
mod utils;
// temporarily until it is actually used
#[allow(unused)]
mod wallet_storage;
use crate::menu::AddDefaultSubmenus;
@@ -28,27 +29,18 @@ use crate::operations::vesting;
use crate::state::State;
fn main() {
dotenv::dotenv().ok();
setup_logging();
tauri::Builder::default()
.manage(Arc::new(RwLock::new(State::default())))
.invoke_handler(tauri::generate_handler![
mixnet::account::connect_with_mnemonic,
mixnet::account::validate_mnemonic,
mixnet::account::create_new_account,
mixnet::account::create_new_mnemonic,
mixnet::account::create_password,
mixnet::account::does_password_file_exist,
mixnet::account::get_balance,
mixnet::account::get_validator_nymd_urls,
mixnet::account::get_validator_api_urls,
mixnet::account::logout,
mixnet::account::remove_password,
mixnet::account::sign_in_with_password,
mixnet::account::switch_network,
mixnet::account::update_validator_urls,
mixnet::account::validate_mnemonic,
mixnet::admin::get_contract_settings,
mixnet::admin::update_contract_settings,
mixnet::bond::bond_gateway,
-4
View File
@@ -21,10 +21,6 @@ pub enum Network {
}
impl Network {
pub fn as_key(&self) -> String {
self.to_string().to_lowercase()
}
pub fn denom(&self) -> Denom {
match self {
// network defaults should be correctly formatted
@@ -1,27 +1,22 @@
use crate::coin::{Coin, Denom};
use crate::config::Config;
use crate::config::{Config, ValidatorUrlWithApiEndpoint};
use crate::error::BackendError;
use crate::network::Network as WalletNetwork;
use crate::network::Network;
use crate::nymd_client;
use crate::state::State;
use crate::wallet_storage::{self, DEFAULT_WALLET_ACCOUNT_ID};
use bip39::{Language, Mnemonic};
use config::defaults::all::Network;
use config::defaults::COSMOS_DERIVATION_PATH;
use cosmrs::bip32::DerivationPath;
use itertools::Itertools;
use rand::seq::SliceRandom;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::convert::TryInto;
use std::str::FromStr;
use std::sync::Arc;
use std::time::Duration;
use strum::IntoEnumIterator;
use tokio::sync::RwLock;
use url::Url;
use validator_client::{nymd::SigningNymdClient, Client};
use validator_client::nymd::error::NymdError;
use validator_client::nymd::SigningNymdClient;
use validator_client::Client;
#[cfg_attr(test, derive(ts_rs::TS))]
#[cfg_attr(test, ts(export, export_to = "../src/types/rust/account.ts"))]
@@ -58,13 +53,6 @@ pub struct Balance {
printable_balance: String,
}
#[cfg_attr(test, derive(ts_rs::TS))]
#[cfg_attr(test, ts(export, export_to = "../src/types/rust/validatorurls.ts"))]
#[derive(Serialize, Deserialize)]
pub struct ValidatorUrls {
urls: Vec<String>,
}
#[tauri::command]
pub async fn connect_with_mnemonic(
mnemonic: String,
@@ -118,15 +106,10 @@ pub async fn create_new_mnemonic() -> Result<String, BackendError> {
Ok(rand_mnemonic.to_string())
}
#[tauri::command]
pub fn validate_mnemonic(mnemonic: &str) -> bool {
Mnemonic::from_str(mnemonic).is_ok()
}
#[tauri::command]
pub async fn switch_network(
state: tauri::State<'_, Arc<RwLock<State>>>,
network: WalletNetwork,
network: Network,
) -> Result<Account, BackendError> {
let account = {
let r_state = state.read().await;
@@ -167,90 +150,21 @@ pub async fn update_validator_urls(
Ok(())
}
#[tauri::command]
pub async fn get_validator_nymd_urls(
network: WalletNetwork,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<ValidatorUrls, BackendError> {
let state = state.read().await;
let urls: Vec<String> = state
.get_nymd_urls(network)
.map(|url| url.to_string())
.collect();
Ok(ValidatorUrls { urls })
}
#[tauri::command]
pub async fn get_validator_api_urls(
network: WalletNetwork,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<ValidatorUrls, BackendError> {
let state = state.read().await;
let urls: Vec<String> = state
.get_api_urls(network)
.map(|url| url.to_string())
.collect();
Ok(ValidatorUrls { urls })
}
async fn _connect_with_mnemonic(
mnemonic: Mnemonic,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<Account, BackendError> {
{
let mut w_state = state.write().await;
w_state.load_config_files();
}
update_validator_urls(state.clone()).await?;
let validators = choose_validators(mnemonic.clone(), &state).await?;
let config = {
let state = state.read().await;
// Take the oppertunity to list all the known validators while we have the state.
for network in WalletNetwork::iter() {
log::debug!(
"List of validators for {network}: [\n{}\n]",
state.get_validators(network).format(",\n")
);
}
state.config().clone()
};
// Get all the urls needed for the connection test
let (untested_nymd_urls, untested_api_urls) = {
let state = state.read().await;
(state.get_all_nymd_urls(), state.get_all_api_urls())
};
let default_nymd_urls: HashMap<WalletNetwork, Url> = untested_nymd_urls
.iter()
.map(|(network, urls)| (*network, urls.iter().next().unwrap().clone()))
.collect();
let default_api_urls: HashMap<WalletNetwork, Url> = untested_api_urls
.iter()
.map(|(network, urls)| (*network, urls.iter().next().unwrap().clone()))
.collect();
// Run connection tests on all nymd and validator-api endpoints
let (nymd_urls, api_urls) =
run_connection_test(untested_nymd_urls, untested_api_urls, &config).await;
// Create clients for all networks
let clients = create_clients(
&nymd_urls,
&api_urls,
&default_nymd_urls,
&default_api_urls,
&config,
&mnemonic,
)?;
let config = state.read().await.config();
let clients = create_clients(&validators, &mnemonic, &config)?;
// Set the default account
let default_network: WalletNetwork = config::defaults::DEFAULT_NETWORK.into();
let default_network: Network = config::defaults::DEFAULT_NETWORK.into();
let client_for_default_network = clients
.iter()
.find(|client| WalletNetwork::from(client.network) == default_network);
.find(|client| Network::from(client.network) == default_network);
let account_for_default_network = match client_for_default_network {
Some(client) => Ok(Account::new(
client.nymd.mixnet_contract_address()?.to_string(),
@@ -264,7 +178,7 @@ async fn _connect_with_mnemonic(
// Register all the clients
for client in clients {
let network: WalletNetwork = client.network.into();
let network: Network = client.network.into();
let mut w_state = state.write().await;
w_state.add_client(network, client);
}
@@ -272,78 +186,18 @@ async fn _connect_with_mnemonic(
account_for_default_network
}
async fn run_connection_test(
untested_nymd_urls: HashMap<WalletNetwork, Vec<Url>>,
untested_api_urls: HashMap<WalletNetwork, Vec<Url>>,
config: &Config,
) -> (
HashMap<Network, Vec<(Url, bool)>>,
HashMap<Network, Vec<(Url, bool)>>,
) {
let mixnet_contract_address = WalletNetwork::iter()
.map(|network| (network.into(), config.get_mixnet_contract_address(network)))
.collect::<HashMap<_, _>>();
let untested_nymd_urls = untested_nymd_urls
.into_iter()
.flat_map(|(net, urls)| urls.into_iter().map(move |url| (net.into(), url)));
let untested_api_urls = untested_api_urls
.into_iter()
.flat_map(|(net, urls)| urls.into_iter().map(move |url| (net.into(), url)));
validator_client::connection_tester::run_validator_connection_test(
untested_nymd_urls,
untested_api_urls,
mixnet_contract_address,
)
.await
}
fn create_clients(
nymd_urls: &HashMap<Network, Vec<(Url, bool)>>,
api_urls: &HashMap<Network, Vec<(Url, bool)>>,
default_nymd_urls: &HashMap<WalletNetwork, Url>,
default_api_urls: &HashMap<WalletNetwork, Url>,
config: &Config,
validators: &HashMap<Network, ValidatorUrlWithApiEndpoint>,
mnemonic: &Mnemonic,
config: &Config,
) -> Result<Vec<Client<SigningNymdClient>>, BackendError> {
let mut clients = Vec::new();
for network in WalletNetwork::iter() {
let nymd_url = if let Some(url) = config.get_selected_validator_nymd_url(&network) {
log::debug!("Using selected nymd_url for {network}: {url}");
url.clone()
} else {
let default_nymd_url = default_nymd_urls
.get(&network)
.expect("Expected at least one nymd_url");
select_random_responding_url(nymd_urls, network).unwrap_or_else(|| {
log::debug!("No successful nymd_urls for {network}: using default: {default_nymd_url}");
default_nymd_url.clone()
})
};
let api_url = if let Some(url) = config.get_selected_validator_api_url(&network) {
log::debug!("Using selected api_url for {network}: {url}");
url.clone()
} else {
let default_api_url = default_api_urls
.get(&network)
.expect("Expected at least one api url");
select_first_responding_url(api_urls, network).unwrap_or_else(|| {
log::debug!("No passing api_urls for {network}: using default: {default_api_url}");
default_api_url.clone()
})
};
log::info!("Connecting to: nymd_url: {nymd_url} for {network}");
log::info!("Connecting to: api_url: {api_url} for {network}");
for network in Network::iter() {
let client = validator_client::Client::new_signing(
validator_client::Config::new(
network.into(),
nymd_url,
api_url,
validators[&network].nymd_url.clone(),
validators[&network].api_url.clone(),
config.get_mixnet_contract_address(network),
config.get_vesting_contract_address(network),
config.get_bandwidth_claim_contract_address(network),
@@ -355,76 +209,116 @@ fn create_clients(
Ok(clients)
}
fn select_random_responding_url(
urls: &HashMap<Network, Vec<(Url, bool)>>,
network: WalletNetwork,
) -> Option<Url> {
urls.get(&network.into()).and_then(|urls| {
let urls: Vec<_> = urls
.iter()
.filter_map(|(url, result)| if *result { Some(url.clone()) } else { None })
.collect();
urls.choose(&mut rand::thread_rng()).cloned()
})
async fn choose_validators(
mnemonic: Mnemonic,
state: &tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<HashMap<Network, ValidatorUrlWithApiEndpoint>, BackendError> {
let config = state.read().await.config();
// Try to connect to validators on all networks
let mut validators = select_responding_validators(&config, &mnemonic).await?;
// If for a network we didn't manage to connect to any validators, just go ahead and try with the
// first in the list
for network in Network::iter() {
validators.entry(network).or_insert_with(|| {
let default_validator = config
.get_validators_with_api_endpoint(network)
.next()
// We always have at least one hardcoded default validator
.unwrap();
println!(
"Using default for {network}: {}, {}",
default_validator.nymd_url, default_validator.api_url,
);
default_validator
});
}
Ok(validators)
}
fn select_first_responding_url(
urls: &HashMap<Network, Vec<(Url, bool)>>,
network: WalletNetwork,
//config: &Config,
) -> Option<Url> {
urls.get(&network.into()).and_then(|urls| {
urls
.iter()
.find_map(|(url, result)| if *result { Some(url.clone()) } else { None })
})
// For each network, try the list of available validators one by one and use the first responding
// one.
async fn select_responding_validators(
config: &Config,
mnemonic: &Mnemonic,
) -> Result<HashMap<Network, ValidatorUrlWithApiEndpoint>, BackendError> {
use tokio::time::timeout;
let validators = futures::future::join_all(Network::iter().map(|network| {
timeout(
Duration::from_millis(3000),
try_connect_to_validators(
config.get_validators_with_api_endpoint(network),
config,
network,
mnemonic.clone(),
),
)
}))
.await;
// Drop networks that failed the global timeout
let validators = validators.into_iter().filter_map(Result::ok);
// Rewrap to return any errors during client creation
let validators = validators.collect::<Result<Vec<_>, _>>()?;
// Filter out networks where we exhausted all listed validators
let validators = validators.into_iter().flatten();
Ok(validators.collect::<HashMap<_, _>>())
}
#[tauri::command]
pub fn does_password_file_exist() -> Result<bool, BackendError> {
log::info!("Checking wallet file");
let file = wallet_storage::wallet_login_filepath()?;
if file.exists() {
log::info!("Exists: {}", file.to_string_lossy());
Ok(true)
async fn try_connect_to_validators(
validators: impl Iterator<Item = ValidatorUrlWithApiEndpoint>,
config: &Config,
network: Network,
mnemonic: Mnemonic,
) -> Result<Option<(Network, ValidatorUrlWithApiEndpoint)>, BackendError> {
for validator in validators {
if let Some(responding_validator) =
try_connect_to_validator(&validator, config, network, mnemonic.clone()).await?
{
// Pick the first successful one
return Ok(Some(responding_validator));
}
}
Ok(None)
}
async fn try_connect_to_validator(
validator: &ValidatorUrlWithApiEndpoint,
config: &Config,
network: Network,
mnemonic: Mnemonic,
) -> Result<Option<(Network, ValidatorUrlWithApiEndpoint)>, BackendError> {
let client = validator_client::Client::new_signing(
validator_client::Config::new(
network.into(),
validator.nymd_url.clone(),
validator.api_url.clone(),
config.get_mixnet_contract_address(network),
config.get_vesting_contract_address(network),
config.get_bandwidth_claim_contract_address(network),
),
mnemonic,
)?;
if is_validator_connection_ok(&client).await {
println!(
"Connection ok for {network}: {}, {}",
validator.nymd_url, validator.api_url
);
Ok(Some((network, validator.clone())))
} else {
log::info!("Does not exist: {}", file.to_string_lossy());
Ok(false)
Ok(None)
}
}
#[tauri::command]
pub fn create_password(mnemonic: String, password: String) -> Result<(), BackendError> {
if does_password_file_exist()? {
return Err(BackendError::WalletFileAlreadyExists);
// The criteria used to determina if a validator endpoint is to be used
async fn is_validator_connection_ok(client: &Client<SigningNymdClient>) -> bool {
match client.get_mixnet_contract_version().await {
Err(NymdError::TendermintError(_)) => false,
Err(_) | Ok(_) => true,
}
log::info!("Creating password");
let mnemonic = Mnemonic::from_str(&mnemonic)?;
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
// Currently we only support a single, default, id in the wallet
let id = wallet_storage::WalletAccountId::new(DEFAULT_WALLET_ACCOUNT_ID.to_string());
let password = wallet_storage::UserPassword::new(password);
wallet_storage::store_wallet_login_information(mnemonic, hd_path, id, &password)
}
#[tauri::command]
pub async fn sign_in_with_password(
password: String,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<Account, BackendError> {
log::info!("Signing in with password");
// Currently we only support a single, default, id in the wallet
let id = wallet_storage::WalletAccountId::new(DEFAULT_WALLET_ACCOUNT_ID.to_string());
let password = wallet_storage::UserPassword::new(password);
let stored_account = wallet_storage::load_existing_wallet_login_information(&id, &password)?;
_connect_with_mnemonic(stored_account.mnemonic().clone(), state).await
}
#[tauri::command]
pub fn remove_password() -> Result<(), BackendError> {
log::info!("Removing password");
let id = wallet_storage::WalletAccountId::new(DEFAULT_WALLET_ACCOUNT_ID.to_string());
wallet_storage::remove_wallet_login_information(&id)
}

Some files were not shown because too many files have changed in this diff Show More