Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 419782fb16 | |||
| 6026ddebfd |
@@ -58,7 +58,7 @@ jobs:
|
||||
name: Clippy checks
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --workspace --all-features
|
||||
args: --all-features
|
||||
|
||||
- name: Run clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
name: Build release of Nym smart contracts
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: contracts
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
target: wasm32-unknown-unknown
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Build release contracts
|
||||
run: RUSTFLAGS='-C link-arg=-s' cargo build --release --target wasm32-unknown-unknown
|
||||
|
||||
- name: Upload Mixnet Contract Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mixnet_contract.wasm
|
||||
path: contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm
|
||||
retention-days: 5
|
||||
|
||||
- name: Upload Vesting Contract Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: vesting_contract.wasm
|
||||
path: contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm
|
||||
retention-days: 5
|
||||
@@ -2,7 +2,7 @@ name: Nightly builds
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '14 1 * * *'
|
||||
- cron: '14 4 * * *'
|
||||
jobs:
|
||||
matrix_prep:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
name: Publish Nym Connect (MacOS)
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: nym-connect
|
||||
|
||||
jobs:
|
||||
publish-tauri:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [macos-latest]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Check the release tag starts with `nym-connect-`
|
||||
if: startsWith(github.ref, 'refs/tags/nym-connect-') == false && github.event_name != 'workflow_dispatch'
|
||||
uses: actions/github-script@v3
|
||||
with:
|
||||
script: |
|
||||
core.setFailed('Release tag did not start with nym-connect-...')
|
||||
|
||||
- name: Node v16
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Install the Apple developer certificate for code signing
|
||||
env:
|
||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
||||
run: |
|
||||
# create variables
|
||||
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
|
||||
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
|
||||
|
||||
# import certificate and provisioning profile from secrets
|
||||
echo -n "$APPLE_CERTIFICATE" | base64 --decode --output $CERTIFICATE_PATH
|
||||
|
||||
# create temporary keychain
|
||||
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
||||
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
||||
|
||||
# import certificate to keychain
|
||||
security import $CERTIFICATE_PATH -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
||||
security list-keychain -d user -s $KEYCHAIN_PATH
|
||||
|
||||
- name: Create env file
|
||||
uses: timheuer/base64-to-file@v1.1
|
||||
with:
|
||||
fileName: '.env'
|
||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||
|
||||
- name: Install app dependencies and build it
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
ENABLE_CODE_SIGNING: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
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 Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: nym-connect_1.0.0_x64.dmg
|
||||
path: nym-connect/target/release/bundle/dmg/nym-connect_1.0.0_x64.dmg
|
||||
retention-days: 30
|
||||
|
||||
- name: Clean up keychain
|
||||
if: ${{ always() }}
|
||||
run: |
|
||||
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
|
||||
|
||||
- name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
nym-connect/target/release/bundle/dmg/*.dmg
|
||||
nym-connect/target/release/bundle/macos/*.app.tar.gz*
|
||||
@@ -1,68 +0,0 @@
|
||||
name: Publish Nym Connect (Ubuntu)
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: nym-connect
|
||||
|
||||
jobs:
|
||||
publish-tauri:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu-latest]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Tauri dependencies
|
||||
run: >
|
||||
sudo apt-get update &&
|
||||
sudo apt-get install -y webkit2gtk-4.0 libayatana-appindicator3-dev
|
||||
- name: Check the release tag starts with `nym-connect-`
|
||||
if: startsWith(github.ref, 'refs/tags/nym-connect-') == false && github.event_name != 'workflow_dispatch'
|
||||
uses: actions/github-script@v3
|
||||
with:
|
||||
script: |
|
||||
core.setFailed('Release tag did not start with nym-connect-...')
|
||||
|
||||
- name: Node v16
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Install app dependencies
|
||||
run: yarn
|
||||
- name: Create env file
|
||||
uses: timheuer/base64-to-file@v1.1
|
||||
with:
|
||||
fileName: '.env'
|
||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||
|
||||
- name: Build app
|
||||
run: yarn build
|
||||
env:
|
||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: nym-connect.AppImage.tar.gz
|
||||
path: nym-connect/target/release/bundle/appimage/nym-connect_1.0.0_amd64.AppImage
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
nym-connect/target/release/bundle/appimage/*.AppImage
|
||||
nym-connect/target/release/bundle/appimage/*.AppImage.tar.gz*
|
||||
@@ -1,90 +0,0 @@
|
||||
name: Publish Nym Connect (Windows 10)
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: nym-connect
|
||||
|
||||
jobs:
|
||||
publish-tauri:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [windows10]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- name: Clean up first
|
||||
continue-on-error: true
|
||||
working-directory: .
|
||||
run: |
|
||||
cd ..
|
||||
del /s /q /A:H nym
|
||||
rmdir /s /q nym
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Check the release tag starts with `nym-connect-`
|
||||
if: startsWith(github.ref, 'refs/tags/nym-connect-') == false && github.event_name != 'workflow_dispatch'
|
||||
uses: actions/github-script@v3
|
||||
with:
|
||||
script: |
|
||||
core.setFailed('Release tag did not start with nym-connect-...')
|
||||
|
||||
- name: Import signing certificate
|
||||
env:
|
||||
WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
|
||||
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
|
||||
run: |
|
||||
New-Item -ItemType directory -Path certificate
|
||||
Set-Content -Path certificate/tempCert.txt -Value $env:WINDOWS_CERTIFICATE
|
||||
certutil -decode certificate/tempCert.txt certificate/certificate.pfx
|
||||
Remove-Item -path certificate -include tempCert.txt
|
||||
Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
|
||||
|
||||
- name: Node v16
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Create env file
|
||||
uses: timheuer/base64-to-file@v1.1
|
||||
with:
|
||||
fileName: '.env'
|
||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||
|
||||
- name: Install app dependencies
|
||||
run: yarn
|
||||
|
||||
- name: Build and sign it
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
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 Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: nym-connect_1.0.0_x64_en-US.msi
|
||||
path: nym-connect/target/release/bundle/msi/nym-connect_1.0.0_x64_en-US.msi
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
nym-connect/target/release/bundle/msi/*.msi
|
||||
nym-connect/target/release/bundle/msi/*.msi.zip*
|
||||
@@ -9,10 +9,8 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
- socks5 client/websocket client: add `--force-register-gateway` flag, useful when rerunning init ([#1353])
|
||||
- nym-connect: initial proof-of-concept of a UI around the socks5 client was added
|
||||
- nym-connect: add ability to select network requester and gateway ([#1427]).
|
||||
- all: added network compilation target to `--help` (or `--version`) commands ([#1256]).
|
||||
- explorer-api: learned how to sum the delegations by owner in a new endpoint.
|
||||
- explorer-api: add apy values to `mix_nodes` endpoint
|
||||
- gateway: Added gateway coconut verifications and validator-api communication for double spending protection ([#1261])
|
||||
- network-explorer-ui: Upgrade to React Router 6
|
||||
- rewarding: replace circulating supply with staking supply in reward calculations ([#1324])
|
||||
@@ -20,25 +18,19 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
- validator-api: add detailed mixnode bond endpoints, and explorer-api makes use of that data to append stake saturation
|
||||
- validator-api: add Swagger to document the REST API ([#1249]).
|
||||
- validator-api: Added new endpoints for coconut spending flow and communications with coconut & multisig contracts ([#1261])
|
||||
- validator-api: add `uptime`, `estimated_operator_apy`, `estimated_delegators_apy` to `/mixnodes/detailed` endpoint ([#1393])
|
||||
- network-statistics: a new mixnet service that aggregates and exposes anonymized data about mixnet services ([#1328])
|
||||
- wallet: when simulating gas costs, an automatic adjustment is being used ([#1388]).
|
||||
- mixnode: Added basic mixnode hardware reporting to the HTTP API ([#1308]).
|
||||
- validator-api: endpoint, in coconut mode, for returning the validator-api cosmos address ([#1404]).
|
||||
|
||||
### Fixed
|
||||
|
||||
- mixnode, gateway: attempting to determine reconnection backoff to persistently failing mixnode could result in a crash ([#1260])
|
||||
- mixnode: the mixnode learned how to shutdown gracefully
|
||||
- mixnode: listen out for SIGTERM and SIGQUIT too, making it play nicely as a system service.
|
||||
- native & socks5 clients: fail early when clients try to re-init with a different gateway, which is not supported yet ([#1322])
|
||||
- native & socks5 clients: rerun init will now reuse previous gateway configuration instead of failing ([#1353])
|
||||
- native & socks5 clients: deduplicate big chunks of init logic
|
||||
- validator: fixed local docker-compose setup to work on Apple M1 ([#1329])
|
||||
|
||||
### Changed
|
||||
|
||||
- nym-connect: reuse config id instead of creating a new id on each connection.
|
||||
- validator-client: created internal `Coin` type that replaces coins from `cosmrs` and `cosmwasm` for API entrypoints [[#1295]]
|
||||
- all: updated all `cosmwasm`-related dependencies to `1.0.0` and `cw-storage-plus` to `0.13.4` [[#1318]]
|
||||
- all: updated `rocket` to `0.5.0-rc.2`.
|
||||
@@ -61,10 +53,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
[#1329]: https://github.com/nymtech/nym/pull/1329
|
||||
[#1353]: https://github.com/nymtech/nym/pull/1353
|
||||
[#1376]: https://github.com/nymtech/nym/pull/1376
|
||||
[#1388]: https://github.com/nymtech/nym/pull/1388
|
||||
[#1393]: https://github.com/nymtech/nym/pull/1393
|
||||
[#1404]: https://github.com/nymtech/nym/pull/1404
|
||||
[#1427]: https://github.com/nymtech/nym/pull/1427
|
||||
|
||||
## [nym-contracts-v1.0.1](https://github.com/nymtech/nym/tree/nym-contracts-v1.0.1) (2022-06-22)
|
||||
|
||||
|
||||
Generated
+28
-11
@@ -924,7 +924,6 @@ dependencies = [
|
||||
"rand 0.7.3",
|
||||
"thiserror",
|
||||
"url",
|
||||
"validator-api-requests",
|
||||
"validator-client",
|
||||
]
|
||||
|
||||
@@ -1343,9 +1342,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "4.0.0"
|
||||
version = "3.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
|
||||
checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
@@ -1664,9 +1663,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fixed"
|
||||
version = "1.15.0"
|
||||
version = "1.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36a65312835c1097a0c926ff3702df965285fadc33d948b87397ff8961bad881"
|
||||
checksum = "86d3f4dd10ddfcb0bd2b2efe9f18aff37ed48265fda3e20e5d53f046aba9d50a"
|
||||
dependencies = [
|
||||
"az",
|
||||
"bytemuck",
|
||||
@@ -3121,7 +3120,6 @@ dependencies = [
|
||||
"tokio-tungstenite",
|
||||
"tokio-util 0.7.3",
|
||||
"url",
|
||||
"validator-api-requests",
|
||||
"validator-client",
|
||||
"vergen",
|
||||
"version-checker",
|
||||
@@ -3156,6 +3154,7 @@ dependencies = [
|
||||
"rand 0.7.3",
|
||||
"rocket",
|
||||
"serde",
|
||||
"serial_test",
|
||||
"sysinfo",
|
||||
"task",
|
||||
"tokio",
|
||||
@@ -5018,6 +5017,28 @@ dependencies = [
|
||||
"yaml-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serial_test"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0bccbcf40c8938196944a3da0e133e031a33f4d6b72db3bda3cc556e361905d"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"parking_lot 0.11.2",
|
||||
"serial_test_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serial_test_derive"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2acd6defeddb41eb60bb468f8825d0cfd0c2a76bc03bfd235b6a1dc4f6a1ad5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha-1"
|
||||
version = "0.8.2"
|
||||
@@ -6233,10 +6254,6 @@ checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||
name = "validator-api-requests"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"coconut-interface",
|
||||
"cosmrs",
|
||||
"getset",
|
||||
"mixnet-contract-common",
|
||||
"schemars",
|
||||
"serde",
|
||||
@@ -6329,7 +6346,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "vesting-contract"
|
||||
version = "1.0.1"
|
||||
version = "1.0.0"
|
||||
dependencies = [
|
||||
"config",
|
||||
"cosmwasm-std",
|
||||
|
||||
+1
-1
@@ -81,4 +81,4 @@ default-members = [
|
||||
"explorer-api",
|
||||
]
|
||||
|
||||
exclude = ["explorer", "contracts", "tokenomics-py", "clients/webassembly", "nym-wallet", "nym-connect"]
|
||||
exclude = ["explorer", "contracts", "tokenomics-py", "clients/webassembly", "nym-wallet"]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
test-all: test cargo-test-expensive
|
||||
test: build clippy-all cargo-test wasm fmt
|
||||
test-all: test cargo-test-expensive
|
||||
no-clippy: build cargo-test wasm fmt
|
||||
happy: fmt clippy-happy test
|
||||
clippy-all: clippy-all-main clippy-all-contracts clippy-all-wallet clippy-all-connect
|
||||
|
||||
@@ -9,8 +9,8 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
|
||||
|
||||
* nym-mixnode - shuffles [Sphinx](https://github.com/nymtech/sphinx) packets together to provide privacy against network-level attackers.
|
||||
* nym-client - an executable which you can build into your own applications. Use it for interacting with Nym nodes.
|
||||
* nym-socks5-client - a Socks5 proxy you can run on your machine and use with existing applications.
|
||||
* nym-gateway - acts sort of like a mailbox for mixnet messages, which removes the need for direct delivery to potentially offline or firewalled devices.
|
||||
* nym-socks5-client - a Socks5 proxy you can run on your machine, and use with existing applications
|
||||
* nym-gateway - acts sort of like a mailbox for mixnet messages, removing the need for directly delivery to potentially offline or firewalled devices.
|
||||
* nym-network-monitor - sends packets through the full system to check that they are working as expected, and stores node uptime histories as the basis of a rewards system ("mixmining" or "proof-of-mixing").
|
||||
* nym-explorer - a (projected) block explorer and (existing) mixnet viewer.
|
||||
* nym-wallet - a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework.
|
||||
|
||||
@@ -7,7 +7,7 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
dirs = "4.0"
|
||||
dirs = "3.0"
|
||||
futures = "0.3"
|
||||
humantime-serde = "1.0"
|
||||
log = "0.4"
|
||||
|
||||
@@ -272,7 +272,7 @@ impl<T: NymConfig> Default for Config<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||
pub struct GatewayEndpoint {
|
||||
/// gateway_id specifies ID of the gateway to which the client should send messages.
|
||||
/// If initially omitted, a random gateway will be chosen from the available topology.
|
||||
@@ -296,7 +296,7 @@ impl From<topology::gateway::Node> for GatewayEndpoint {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
pub struct Client<T> {
|
||||
/// Version of the client for which this configuration was created.
|
||||
#[serde(default = "missing_string_value")]
|
||||
@@ -419,7 +419,7 @@ impl<T: NymConfig> Client<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Logging {}
|
||||
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//! Collection of initialization steps used by client implementations
|
||||
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
use config::NymConfig;
|
||||
use crypto::asymmetric::{encryption, identity};
|
||||
use gateway_client::GatewayClient;
|
||||
use gateway_requests::registration::handshake::SharedKeys;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::addressing::nodes::NodeIdentity;
|
||||
use rand::rngs::OsRng;
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::thread_rng;
|
||||
use topology::{filter::VersionFilterable, gateway};
|
||||
use url::Url;
|
||||
|
||||
use crate::{
|
||||
client::key_manager::KeyManager,
|
||||
config::{persistence::key_pathfinder::ClientKeyPathfinder, Config},
|
||||
};
|
||||
|
||||
pub async fn query_gateway_details(
|
||||
validator_servers: Vec<Url>,
|
||||
chosen_gateway_id: Option<&str>,
|
||||
) -> gateway::Node {
|
||||
let validator_api = validator_servers
|
||||
.choose(&mut thread_rng())
|
||||
.expect("The list of validator apis is empty");
|
||||
let validator_client = validator_client::ApiClient::new(validator_api.clone());
|
||||
|
||||
log::trace!("Fetching list of gateways from: {}", validator_api);
|
||||
let gateways = validator_client.get_cached_gateways().await.unwrap();
|
||||
let valid_gateways = gateways
|
||||
.into_iter()
|
||||
.filter_map(|gateway| gateway.try_into().ok())
|
||||
.collect::<Vec<gateway::Node>>();
|
||||
|
||||
let filtered_gateways = valid_gateways.filter_by_version(env!("CARGO_PKG_VERSION"));
|
||||
|
||||
// if we have chosen particular gateway - use it, otherwise choose a random one.
|
||||
// (remember that in active topology all gateways have at least 100 reputation so should
|
||||
// be working correctly)
|
||||
if let Some(gateway_id) = chosen_gateway_id {
|
||||
filtered_gateways
|
||||
.iter()
|
||||
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
|
||||
.expect(&*format!("no gateway with id {} exists!", gateway_id))
|
||||
.clone()
|
||||
} else {
|
||||
filtered_gateways
|
||||
.choose(&mut rand::thread_rng())
|
||||
.expect("there are no gateways on the network!")
|
||||
.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn register_with_gateway_and_store_keys<T>(
|
||||
gateway_details: gateway::Node,
|
||||
config: &Config<T>,
|
||||
) where
|
||||
T: NymConfig,
|
||||
{
|
||||
let mut rng = OsRng;
|
||||
let mut key_manager = KeyManager::new(&mut rng);
|
||||
|
||||
let shared_keys = register_with_gateway(&gateway_details, key_manager.identity_keypair()).await;
|
||||
key_manager.insert_gateway_shared_key(shared_keys);
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config);
|
||||
key_manager
|
||||
.store_keys(&pathfinder)
|
||||
.expect("Failed to generated keys");
|
||||
}
|
||||
|
||||
async fn register_with_gateway(
|
||||
gateway: &gateway::Node,
|
||||
our_identity: Arc<identity::KeyPair>,
|
||||
) -> Arc<SharedKeys> {
|
||||
let timeout = Duration::from_millis(1500);
|
||||
let mut gateway_client = GatewayClient::new_init(
|
||||
gateway.clients_address(),
|
||||
gateway.identity_key,
|
||||
gateway.owner.clone(),
|
||||
our_identity.clone(),
|
||||
timeout,
|
||||
);
|
||||
gateway_client
|
||||
.establish_connection()
|
||||
.await
|
||||
.expect("failed to establish connection with the gateway!");
|
||||
gateway_client
|
||||
.perform_initial_authentication()
|
||||
.await
|
||||
.expect("failed to register with the gateway!")
|
||||
}
|
||||
|
||||
pub fn show_address<T>(config: &Config<T>)
|
||||
where
|
||||
T: config::NymConfig,
|
||||
{
|
||||
fn load_identity_keys(pathfinder: &ClientKeyPathfinder) -> identity::KeyPair {
|
||||
let identity_keypair: identity::KeyPair =
|
||||
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||
pathfinder.private_identity_key().to_owned(),
|
||||
pathfinder.public_identity_key().to_owned(),
|
||||
))
|
||||
.expect("Failed to read stored identity key files");
|
||||
identity_keypair
|
||||
}
|
||||
|
||||
fn load_sphinx_keys(pathfinder: &ClientKeyPathfinder) -> encryption::KeyPair {
|
||||
let sphinx_keypair: encryption::KeyPair =
|
||||
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||
pathfinder.private_encryption_key().to_owned(),
|
||||
pathfinder.public_encryption_key().to_owned(),
|
||||
))
|
||||
.expect("Failed to read stored sphinx key files");
|
||||
sphinx_keypair
|
||||
}
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config);
|
||||
let identity_keypair = load_identity_keys(&pathfinder);
|
||||
let sphinx_keypair = load_sphinx_keys(&pathfinder);
|
||||
|
||||
let client_recipient = Recipient::new(
|
||||
*identity_keypair.public_key(),
|
||||
*sphinx_keypair.public_key(),
|
||||
// TODO: below only works under assumption that gateway address == gateway id
|
||||
// (which currently is true)
|
||||
NodeIdentity::from_base58_string(config.get_gateway_id()).unwrap(),
|
||||
);
|
||||
|
||||
println!("\nThe address of this client is: {}", client_recipient);
|
||||
}
|
||||
@@ -1,3 +1,2 @@
|
||||
pub mod client;
|
||||
pub mod config;
|
||||
pub mod init;
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::{MNEMONIC, NYMD_URL};
|
||||
use bip39::Mnemonic;
|
||||
use network_defaults::{DEFAULT_NETWORK, MIX_DENOM, VOUCHER_INFO};
|
||||
use std::str::FromStr;
|
||||
use url::Url;
|
||||
use validator_client::nymd;
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::{MNEMONIC, NYMD_URL};
|
||||
|
||||
use network_defaults::{DEFAULT_NETWORK, DENOM, VOUCHER_INFO};
|
||||
use validator_client::nymd::traits::CoconutBandwidthSigningClient;
|
||||
use validator_client::nymd::{Coin, Fee, NymdClient, SigningNymdClient};
|
||||
|
||||
@@ -19,10 +20,9 @@ impl Client {
|
||||
pub fn new() -> Self {
|
||||
let nymd_url = Url::from_str(NYMD_URL).unwrap();
|
||||
let mnemonic = Mnemonic::from_str(MNEMONIC).unwrap();
|
||||
let config = nymd::Config::try_from_nym_network_details(&DEFAULT_NETWORK.details())
|
||||
.expect("failed to construct valid validator client config with the provided network");
|
||||
let nymd_client =
|
||||
NymdClient::connect_with_mnemonic(config, nymd_url.as_ref(), mnemonic, None).unwrap();
|
||||
NymdClient::connect_with_mnemonic(DEFAULT_NETWORK, nymd_url.as_ref(), mnemonic, None)
|
||||
.unwrap();
|
||||
|
||||
Client { nymd_client }
|
||||
}
|
||||
@@ -34,7 +34,7 @@ impl Client {
|
||||
encryption_key: String,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<String> {
|
||||
let amount = Coin::new(amount as u128, MIX_DENOM.base.to_string());
|
||||
let amount = Coin::new(amount as u128, DENOM.to_string());
|
||||
Ok(self
|
||||
.nymd_client
|
||||
.deposit(
|
||||
|
||||
@@ -20,7 +20,7 @@ futures = "0.3" # bunch of futures stuff, however, now that I think about it, it
|
||||
url = "2.2"
|
||||
|
||||
clap = "2.33.0" # for the command line arguments
|
||||
dirs = "4.0"
|
||||
dirs = "3.0" # for determining default store directories in config
|
||||
dotenv = "0.15.0" # for obtaining environmental variables (only used for RUST_LOG for time being)
|
||||
log = "0.4" # self explanatory
|
||||
pretty_env_logger = "0.4" # for formatting log messages
|
||||
|
||||
@@ -11,7 +11,7 @@ use std::path::PathBuf;
|
||||
|
||||
mod template;
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone, Copy)]
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize, Clone, Copy)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub enum SocketType {
|
||||
WebSocket,
|
||||
@@ -105,7 +105,7 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Socket {
|
||||
socket_type: SocketType,
|
||||
|
||||
@@ -2,8 +2,22 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use client_core::config::GatewayEndpoint;
|
||||
use client_core::client::key_manager::KeyManager;
|
||||
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||
use config::NymConfig;
|
||||
use crypto::asymmetric::{encryption, identity};
|
||||
use gateway_client::GatewayClient;
|
||||
use gateway_requests::registration::handshake::SharedKeys;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::addressing::nodes::NodeIdentity;
|
||||
use rand::rngs::OsRng;
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::thread_rng;
|
||||
use std::convert::TryInto;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use topology::{filter::VersionFilterable, gateway};
|
||||
use url::Url;
|
||||
|
||||
use crate::client::config::Config;
|
||||
use crate::commands::override_config;
|
||||
@@ -79,6 +93,133 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
app
|
||||
}
|
||||
|
||||
async fn register_with_gateway(
|
||||
gateway: &gateway::Node,
|
||||
our_identity: Arc<identity::KeyPair>,
|
||||
) -> Arc<SharedKeys> {
|
||||
let timeout = Duration::from_millis(1500);
|
||||
let mut gateway_client = GatewayClient::new_init(
|
||||
gateway.clients_address(),
|
||||
gateway.identity_key,
|
||||
gateway.owner.clone(),
|
||||
our_identity.clone(),
|
||||
timeout,
|
||||
);
|
||||
gateway_client
|
||||
.establish_connection()
|
||||
.await
|
||||
.expect("failed to establish connection with the gateway!");
|
||||
gateway_client
|
||||
.perform_initial_authentication()
|
||||
.await
|
||||
.expect("failed to register with the gateway!")
|
||||
}
|
||||
|
||||
async fn gateway_details(
|
||||
validator_servers: Vec<Url>,
|
||||
chosen_gateway_id: Option<&str>,
|
||||
) -> gateway::Node {
|
||||
let validator_api = validator_servers
|
||||
.choose(&mut thread_rng())
|
||||
.expect("The list of validator apis is empty");
|
||||
let validator_client = validator_client::ApiClient::new(validator_api.clone());
|
||||
|
||||
log::trace!("Fetching list of gateways from: {}", validator_api);
|
||||
let gateways = validator_client.get_cached_gateways().await.unwrap();
|
||||
let valid_gateways = gateways
|
||||
.into_iter()
|
||||
.filter_map(|gateway| gateway.try_into().ok())
|
||||
.collect::<Vec<gateway::Node>>();
|
||||
|
||||
let filtered_gateways = valid_gateways.filter_by_version(env!("CARGO_PKG_VERSION"));
|
||||
|
||||
// if we have chosen particular gateway - use it, otherwise choose a random one.
|
||||
// (remember that in active topology all gateways have at least 100 reputation so should
|
||||
// be working correctly)
|
||||
if let Some(gateway_id) = chosen_gateway_id {
|
||||
filtered_gateways
|
||||
.iter()
|
||||
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
|
||||
.expect(&*format!("no gateway with id {} exists!", gateway_id))
|
||||
.clone()
|
||||
} else {
|
||||
filtered_gateways
|
||||
.choose(&mut rand::thread_rng())
|
||||
.expect("there are no gateways on the network!")
|
||||
.clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn show_address(config: &Config) {
|
||||
fn load_identity_keys(pathfinder: &ClientKeyPathfinder) -> identity::KeyPair {
|
||||
let identity_keypair: identity::KeyPair =
|
||||
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||
pathfinder.private_identity_key().to_owned(),
|
||||
pathfinder.public_identity_key().to_owned(),
|
||||
))
|
||||
.expect("Failed to read stored identity key files");
|
||||
identity_keypair
|
||||
}
|
||||
|
||||
fn load_sphinx_keys(pathfinder: &ClientKeyPathfinder) -> encryption::KeyPair {
|
||||
let sphinx_keypair: encryption::KeyPair =
|
||||
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||
pathfinder.private_encryption_key().to_owned(),
|
||||
pathfinder.public_encryption_key().to_owned(),
|
||||
))
|
||||
.expect("Failed to read stored sphinx key files");
|
||||
sphinx_keypair
|
||||
}
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
let identity_keypair = load_identity_keys(&pathfinder);
|
||||
let sphinx_keypair = load_sphinx_keys(&pathfinder);
|
||||
|
||||
let client_recipient = Recipient::new(
|
||||
*identity_keypair.public_key(),
|
||||
*sphinx_keypair.public_key(),
|
||||
// TODO: below only works under assumption that gateway address == gateway id
|
||||
// (which currently is true)
|
||||
NodeIdentity::from_base58_string(config.get_base().get_gateway_id()).unwrap(),
|
||||
);
|
||||
|
||||
println!("\nThe address of this client is: {}", client_recipient);
|
||||
}
|
||||
|
||||
async fn set_gateway_config(config: &mut Config, chosen_gateway_id: Option<&str>) -> gateway::Node {
|
||||
println!("Setting gateway config");
|
||||
log::trace!("Chosen gateway: {:?}", chosen_gateway_id);
|
||||
|
||||
// Get the gateway details by querying the validator-api, and using the chosen one if it's
|
||||
// among the available ones.
|
||||
let gateway_details = gateway_details(
|
||||
config.get_base().get_validator_api_endpoints(),
|
||||
chosen_gateway_id,
|
||||
)
|
||||
.await;
|
||||
log::trace!("Used gateway: {}", gateway_details);
|
||||
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_endpoint(gateway_details.clone().into());
|
||||
gateway_details
|
||||
}
|
||||
|
||||
async fn register_and_store_gateway_keys(gateway_details: gateway::Node, config: &Config) {
|
||||
println!("Registering gateway");
|
||||
|
||||
let mut rng = OsRng;
|
||||
let mut key_manager = KeyManager::new(&mut rng);
|
||||
let shared_keys = register_with_gateway(&gateway_details, key_manager.identity_keypair()).await;
|
||||
key_manager.insert_gateway_shared_key(shared_keys);
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
key_manager
|
||||
.store_keys(&pathfinder)
|
||||
.expect("Failed to generated keys");
|
||||
println!("Saved all generated keys");
|
||||
}
|
||||
|
||||
pub async fn execute(matches: ArgMatches<'static>) {
|
||||
println!("Initialising client...");
|
||||
|
||||
@@ -95,31 +236,51 @@ pub async fn execute(matches: ArgMatches<'static>) {
|
||||
|
||||
// Usually you only register with the gateway on the first init, however you can force
|
||||
// re-registering if wanted.
|
||||
let user_wants_force_register = matches.is_present("force-register-gateway");
|
||||
let should_force_register = matches.is_present("force-register-gateway");
|
||||
|
||||
// If the client was already initialized, don't generate new keys and don't re-register with
|
||||
// the gateway (because this would create a new shared key).
|
||||
// Unless the user really wants to.
|
||||
let register_gateway = !already_init || user_wants_force_register;
|
||||
let will_register_gateway = !already_init || should_force_register;
|
||||
|
||||
// Attempt to use a user-provided gateway, if possible
|
||||
let user_chosen_gateway_id = matches.value_of("gateway");
|
||||
let is_gateway_provided = matches.value_of("gateway").is_some();
|
||||
|
||||
let mut config = Config::new(id);
|
||||
|
||||
// TODO: ideally that should be the last thing that's being done to config.
|
||||
// However, we are later further overriding it with gateway id
|
||||
config = override_config(config, &matches);
|
||||
if matches.is_present("fastmode") {
|
||||
config.get_base_mut().set_high_default_traffic_volume();
|
||||
}
|
||||
|
||||
let gateway = setup_gateway(id, register_gateway, user_chosen_gateway_id, &config).await;
|
||||
config.get_base_mut().with_gateway_endpoint(gateway);
|
||||
if will_register_gateway {
|
||||
// Create identity, encryption and ack keys.
|
||||
let gateway_details = set_gateway_config(&mut config, matches.value_of("gateway")).await;
|
||||
register_and_store_gateway_keys(gateway_details, &config).await;
|
||||
} else if is_gateway_provided {
|
||||
// Just set the config, don't register or create any keys
|
||||
set_gateway_config(&mut config, matches.value_of("gateway")).await;
|
||||
} else {
|
||||
// Read the existing config to reuse the gateway configuration
|
||||
println!("Not registering gateway, will reuse existing config and keys");
|
||||
if let Ok(existing_config) = Config::load_from_file(Some(id)) {
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_endpoint(existing_config.get_base().get_gateway_endpoint().clone());
|
||||
} else {
|
||||
log::warn!(
|
||||
"Existing configuration found, but enable to load gateway details. \
|
||||
Proceeding anyway."
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
let config_save_location = config.get_config_file_save_location();
|
||||
config
|
||||
.save_to_file(None)
|
||||
.expect("Failed to save the config file");
|
||||
|
||||
println!("Saved configuration file to {:?}", config_save_location);
|
||||
println!("Using gateway: {}", config.get_base().get_gateway_id());
|
||||
log::debug!("Gateway id: {}", config.get_base().get_gateway_id());
|
||||
@@ -130,58 +291,5 @@ pub async fn execute(matches: ArgMatches<'static>) {
|
||||
);
|
||||
println!("Client configuration completed.");
|
||||
|
||||
client_core::init::show_address(config.get_base());
|
||||
}
|
||||
|
||||
async fn setup_gateway(
|
||||
id: &str,
|
||||
register: bool,
|
||||
user_chosen_gateway_id: Option<&str>,
|
||||
config: &Config,
|
||||
) -> GatewayEndpoint {
|
||||
if register {
|
||||
// Get the gateway details by querying the validator-api. Either pick one at random or use
|
||||
// the chosen one if it's among the available ones.
|
||||
println!("Configuring gateway");
|
||||
let gateway = client_core::init::query_gateway_details(
|
||||
config.get_base().get_validator_api_endpoints(),
|
||||
user_chosen_gateway_id,
|
||||
)
|
||||
.await;
|
||||
log::debug!("Querying gateway gives: {}", gateway);
|
||||
|
||||
// Registering with gateway by setting up and writing shared keys to disk
|
||||
log::trace!("Registering gateway");
|
||||
client_core::init::register_with_gateway_and_store_keys(gateway.clone(), config.get_base())
|
||||
.await;
|
||||
println!("Saved all generated keys");
|
||||
|
||||
gateway.into()
|
||||
} else if user_chosen_gateway_id.is_some() {
|
||||
// Just set the config, don't register or create any keys
|
||||
// This assumes that the user knows what they are doing, and that the existing keys are
|
||||
// valid for the gateway being used
|
||||
println!("Using gateway provided by user, keeping existing keys");
|
||||
let gateway = client_core::init::query_gateway_details(
|
||||
config.get_base().get_validator_api_endpoints(),
|
||||
user_chosen_gateway_id,
|
||||
)
|
||||
.await;
|
||||
log::debug!("Querying gateway gives: {}", gateway);
|
||||
gateway.into()
|
||||
} else {
|
||||
println!("Not registering gateway, will reuse existing config and keys");
|
||||
match Config::load_from_file(Some(id)) {
|
||||
Ok(existing_config) => existing_config.get_base().get_gateway_endpoint().clone(),
|
||||
Err(err) => {
|
||||
panic!(
|
||||
"Unable to configure gateway: {err}. \n
|
||||
Seems like the client was already initialized but it was not possible to read \
|
||||
the existing configuration file. \n
|
||||
CAUTION: Consider backing up your gateway keys and try force gateway registration, or \
|
||||
removing the existing configuration and starting over."
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
show_address(&config);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
// no need to go fancy here like we've done in other places.
|
||||
#[derive(PartialEq, Eq, Clone, Serialize, Deserialize)]
|
||||
#[derive(PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub struct Error {
|
||||
pub kind: ErrorKind,
|
||||
pub message: String,
|
||||
@@ -30,7 +30,7 @@ impl Error {
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(PartialEq, Eq, Clone, Serialize, Deserialize)]
|
||||
#[derive(PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub enum ErrorKind {
|
||||
/// The received request contained no data.
|
||||
EmptyRequest = 0x01,
|
||||
|
||||
@@ -11,7 +11,7 @@ path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = "2.33.0"
|
||||
dirs = "4.0"
|
||||
dirs = "3.0" # for determining default store directories in config
|
||||
dotenv = "0.15.0"
|
||||
futures = "0.3"
|
||||
log = "0.4"
|
||||
|
||||
@@ -89,7 +89,7 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Socks5 {
|
||||
/// The port on which the client will be listening for incoming requests
|
||||
|
||||
@@ -2,8 +2,20 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use client_core::config::GatewayEndpoint;
|
||||
use client_core::client::key_manager::KeyManager;
|
||||
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||
use config::NymConfig;
|
||||
use crypto::asymmetric::{encryption, identity};
|
||||
use gateway_client::GatewayClient;
|
||||
use gateway_requests::registration::handshake::SharedKeys;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::addressing::nodes::NodeIdentity;
|
||||
use rand::{prelude::SliceRandom, rngs::OsRng, thread_rng};
|
||||
use std::convert::TryInto;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use topology::{filter::VersionFilterable, gateway};
|
||||
use url::Url;
|
||||
|
||||
use crate::client::config::Config;
|
||||
use crate::commands::override_config;
|
||||
@@ -81,6 +93,137 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
app
|
||||
}
|
||||
|
||||
// TODO: make this private again after refactoring the config setup
|
||||
pub async fn register_with_gateway(
|
||||
gateway: &gateway::Node,
|
||||
our_identity: Arc<identity::KeyPair>,
|
||||
) -> Arc<SharedKeys> {
|
||||
let timeout = Duration::from_millis(1500);
|
||||
let mut gateway_client = GatewayClient::new_init(
|
||||
gateway.clients_address(),
|
||||
gateway.identity_key,
|
||||
gateway.owner.clone(),
|
||||
our_identity.clone(),
|
||||
timeout,
|
||||
);
|
||||
gateway_client
|
||||
.establish_connection()
|
||||
.await
|
||||
.expect("failed to establish connection with the gateway!");
|
||||
gateway_client
|
||||
.perform_initial_authentication()
|
||||
.await
|
||||
.expect("failed to register with the gateway!")
|
||||
}
|
||||
|
||||
// TODO: make this private again after refactoring the config setup
|
||||
pub async fn gateway_details(
|
||||
validator_servers: Vec<Url>,
|
||||
chosen_gateway_id: Option<&str>,
|
||||
) -> gateway::Node {
|
||||
let validator_api = validator_servers
|
||||
.choose(&mut thread_rng())
|
||||
.expect("The list of validator apis is empty");
|
||||
let validator_client = validator_client::ApiClient::new(validator_api.clone());
|
||||
|
||||
log::trace!("Fetching list of gateways from: {}", validator_api);
|
||||
let gateways = validator_client.get_cached_gateways().await.unwrap();
|
||||
let valid_gateways = gateways
|
||||
.into_iter()
|
||||
.filter_map(|gateway| gateway.try_into().ok())
|
||||
.collect::<Vec<gateway::Node>>();
|
||||
|
||||
let filtered_gateways = valid_gateways.filter_by_version(env!("CARGO_PKG_VERSION"));
|
||||
|
||||
// if we have chosen particular gateway - use it, otherwise choose a random one.
|
||||
// (remember that in active topology all gateways have at least 100 reputation so should
|
||||
// be working correctly)
|
||||
if let Some(gateway_id) = chosen_gateway_id {
|
||||
filtered_gateways
|
||||
.iter()
|
||||
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
|
||||
.expect(&*format!("no gateway with id {} exists!", gateway_id))
|
||||
.clone()
|
||||
} else {
|
||||
filtered_gateways
|
||||
.choose(&mut rand::thread_rng())
|
||||
.expect("there are no gateways on the network!")
|
||||
.clone()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: make this private again after refactoring the config setup
|
||||
pub fn show_address(config: &Config) {
|
||||
fn load_identity_keys(pathfinder: &ClientKeyPathfinder) -> identity::KeyPair {
|
||||
let identity_keypair: identity::KeyPair =
|
||||
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||
pathfinder.private_identity_key().to_owned(),
|
||||
pathfinder.public_identity_key().to_owned(),
|
||||
))
|
||||
.expect("Failed to read stored identity key files");
|
||||
identity_keypair
|
||||
}
|
||||
|
||||
fn load_sphinx_keys(pathfinder: &ClientKeyPathfinder) -> encryption::KeyPair {
|
||||
let sphinx_keypair: encryption::KeyPair =
|
||||
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||
pathfinder.private_encryption_key().to_owned(),
|
||||
pathfinder.public_encryption_key().to_owned(),
|
||||
))
|
||||
.expect("Failed to read stored sphinx key files");
|
||||
sphinx_keypair
|
||||
}
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
let identity_keypair = load_identity_keys(&pathfinder);
|
||||
let sphinx_keypair = load_sphinx_keys(&pathfinder);
|
||||
|
||||
let client_recipient = Recipient::new(
|
||||
*identity_keypair.public_key(),
|
||||
*sphinx_keypair.public_key(),
|
||||
// TODO: below only works under assumption that gateway address == gateway id
|
||||
// (which currently is true)
|
||||
NodeIdentity::from_base58_string(config.get_base().get_gateway_id()).unwrap(),
|
||||
);
|
||||
|
||||
println!("\nThe address of this client is: {}", client_recipient);
|
||||
}
|
||||
|
||||
async fn set_gateway_config(config: &mut Config, chosen_gateway_id: Option<&str>) -> gateway::Node {
|
||||
println!("Setting gateway config");
|
||||
log::trace!("Chosen gateway: {:?}", chosen_gateway_id);
|
||||
|
||||
// Get the gateway details by querying the validator-api, and using the chosen one if it's
|
||||
// among the available ones.
|
||||
let gateway_details = gateway_details(
|
||||
config.get_base().get_validator_api_endpoints(),
|
||||
chosen_gateway_id,
|
||||
)
|
||||
.await;
|
||||
|
||||
log::trace!("Used gateway: {}", gateway_details);
|
||||
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_endpoint(gateway_details.clone().into());
|
||||
gateway_details
|
||||
}
|
||||
|
||||
async fn register_and_store_gateway_keys(gateway_details: gateway::Node, config: &Config) {
|
||||
println!("Registering gateway");
|
||||
|
||||
let mut rng = OsRng;
|
||||
let mut key_manager = KeyManager::new(&mut rng);
|
||||
let shared_keys = register_with_gateway(&gateway_details, key_manager.identity_keypair()).await;
|
||||
key_manager.insert_gateway_shared_key(shared_keys);
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
key_manager
|
||||
.store_keys(&pathfinder)
|
||||
.expect("Failed to generated keys");
|
||||
println!("Saved all generated keys");
|
||||
}
|
||||
|
||||
pub async fn execute(matches: ArgMatches<'static>) {
|
||||
println!("Initialising client...");
|
||||
|
||||
@@ -98,31 +241,51 @@ pub async fn execute(matches: ArgMatches<'static>) {
|
||||
|
||||
// Usually you only register with the gateway on the first init, however you can force
|
||||
// re-registering if wanted.
|
||||
let user_wants_force_register = matches.is_present("force-register-gateway");
|
||||
let should_force_register = matches.is_present("force-register-gateway");
|
||||
|
||||
// If the client was already initialized, don't generate new keys and don't re-register with
|
||||
// the gateway (because this would create a new shared key).
|
||||
// Unless the user really wants to.
|
||||
let register_gateway = !already_init || user_wants_force_register;
|
||||
let will_register_gateway = !already_init || should_force_register;
|
||||
|
||||
// Attempt to use a user-provided gateway, if possible
|
||||
let user_chosen_gateway_id = matches.value_of("gateway");
|
||||
let is_gateway_provided = matches.value_of("gateway").is_some();
|
||||
|
||||
let mut config = Config::new(id, provider_address);
|
||||
|
||||
// TODO: ideally that should be the last thing that's being done to config.
|
||||
// However, we are later further overriding it with gateway id
|
||||
config = override_config(config, &matches);
|
||||
if matches.is_present("fastmode") {
|
||||
config.get_base_mut().set_high_default_traffic_volume();
|
||||
}
|
||||
|
||||
let gateway = setup_gateway(id, register_gateway, user_chosen_gateway_id, &config).await;
|
||||
config.get_base_mut().with_gateway_endpoint(gateway);
|
||||
if will_register_gateway {
|
||||
// Create identity, encryption and ack keys.
|
||||
let gateway_details = set_gateway_config(&mut config, matches.value_of("gateway")).await;
|
||||
register_and_store_gateway_keys(gateway_details, &config).await;
|
||||
} else if is_gateway_provided {
|
||||
// Just set the config, don't register or create any keys
|
||||
set_gateway_config(&mut config, matches.value_of("gateway")).await;
|
||||
} else {
|
||||
// Read the existing config to reuse the gateway configuration
|
||||
println!("Not registering gateway, will reuse existing config and keys");
|
||||
if let Ok(existing_config) = Config::load_from_file(Some(id)) {
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_endpoint(existing_config.get_base().get_gateway_endpoint().clone());
|
||||
} else {
|
||||
log::warn!(
|
||||
"Existing configuration found, but enable to load gateway details. \
|
||||
Proceeding anyway."
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
let config_save_location = config.get_config_file_save_location();
|
||||
config
|
||||
.save_to_file(None)
|
||||
.expect("Failed to save the config file");
|
||||
|
||||
println!("Saved configuration file to {:?}", config_save_location);
|
||||
println!("Using gateway: {}", config.get_base().get_gateway_id());
|
||||
log::debug!("Gateway id: {}", config.get_base().get_gateway_id());
|
||||
@@ -133,58 +296,5 @@ pub async fn execute(matches: ArgMatches<'static>) {
|
||||
);
|
||||
println!("Client configuration completed.");
|
||||
|
||||
client_core::init::show_address(config.get_base());
|
||||
}
|
||||
|
||||
async fn setup_gateway(
|
||||
id: &str,
|
||||
register: bool,
|
||||
user_chosen_gateway_id: Option<&str>,
|
||||
config: &Config,
|
||||
) -> GatewayEndpoint {
|
||||
if register {
|
||||
// Get the gateway details by querying the validator-api. Either pick one at random or use
|
||||
// the chosen one if it's among the available ones.
|
||||
println!("Configuring gateway");
|
||||
let gateway = client_core::init::query_gateway_details(
|
||||
config.get_base().get_validator_api_endpoints(),
|
||||
user_chosen_gateway_id,
|
||||
)
|
||||
.await;
|
||||
log::debug!("Querying gateway gives: {}", gateway);
|
||||
|
||||
// Registering with gateway by setting up and writing shared keys to disk
|
||||
log::trace!("Registering gateway");
|
||||
client_core::init::register_with_gateway_and_store_keys(gateway.clone(), config.get_base())
|
||||
.await;
|
||||
println!("Saved all generated keys");
|
||||
|
||||
gateway.into()
|
||||
} else if user_chosen_gateway_id.is_some() {
|
||||
// Just set the config, don't register or create any keys
|
||||
// This assumes that the user knows what they are doing, and that the existing keys are
|
||||
// valid for the gateway being used
|
||||
println!("Using gateway provided by user, keeping existing keys");
|
||||
let gateway = client_core::init::query_gateway_details(
|
||||
config.get_base().get_validator_api_endpoints(),
|
||||
user_chosen_gateway_id,
|
||||
)
|
||||
.await;
|
||||
log::debug!("Querying gateway gives: {}", gateway);
|
||||
gateway.into()
|
||||
} else {
|
||||
println!("Not registering gateway, will reuse existing config and keys");
|
||||
match Config::load_from_file(Some(id)) {
|
||||
Ok(existing_config) => existing_config.get_base().get_gateway_endpoint().clone(),
|
||||
Err(err) => {
|
||||
panic!(
|
||||
"Unable to configure gateway: {err}. \n
|
||||
Seems like the client was already initialized but it was not possible to read \
|
||||
the existing configuration file. \n
|
||||
CAUTION: Consider backing up your gateway keys and try force gateway registration, or \
|
||||
removing the existing configuration and starting over."
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
show_address(&config);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ pub(crate) enum AuthenticationMethods {
|
||||
NoMethods = 0xFF,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
/// A socks5 user with a matching password.
|
||||
pub struct User {
|
||||
pub username: String,
|
||||
|
||||
+14
-14
@@ -221,7 +221,7 @@
|
||||
"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf"
|
||||
integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==
|
||||
integrity sha1-m4sMxmPWaafY9vXQiToU00jzD78=
|
||||
|
||||
"@protobufjs/base64@^1.1.2":
|
||||
version "1.1.2"
|
||||
@@ -236,12 +236,12 @@
|
||||
"@protobufjs/eventemitter@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70"
|
||||
integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==
|
||||
integrity sha1-NVy8mLr61ZePntCV85diHx0Ga3A=
|
||||
|
||||
"@protobufjs/fetch@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45"
|
||||
integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==
|
||||
integrity sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=
|
||||
dependencies:
|
||||
"@protobufjs/aspromise" "^1.1.1"
|
||||
"@protobufjs/inquire" "^1.1.0"
|
||||
@@ -249,27 +249,27 @@
|
||||
"@protobufjs/float@^1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1"
|
||||
integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==
|
||||
integrity sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=
|
||||
|
||||
"@protobufjs/inquire@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089"
|
||||
integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==
|
||||
integrity sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=
|
||||
|
||||
"@protobufjs/path@^1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d"
|
||||
integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==
|
||||
integrity sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=
|
||||
|
||||
"@protobufjs/pool@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54"
|
||||
integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==
|
||||
integrity sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=
|
||||
|
||||
"@protobufjs/utf8@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
|
||||
integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
|
||||
integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=
|
||||
|
||||
"@types/json-schema@^7.0.9":
|
||||
version "7.0.11"
|
||||
@@ -282,9 +282,9 @@
|
||||
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
|
||||
|
||||
"@types/long@^4.0.1":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a"
|
||||
integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9"
|
||||
integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==
|
||||
|
||||
"@types/node@>=13.7.0":
|
||||
version "17.0.23"
|
||||
@@ -1642,9 +1642,9 @@ protobufjs@^6.8.8, protobufjs@~6.11.2:
|
||||
long "^4.0.0"
|
||||
|
||||
protobufjs@~6.10.2:
|
||||
version "6.10.3"
|
||||
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.10.3.tgz#11ed1dd02acbfcb330becf1611461d4b407f9eef"
|
||||
integrity sha512-yvAslS0hNdBhlSKckI4R1l7wunVilX66uvrjzE4MimiAt7/qw1nLpMhZrn/ObuUTM/c3Xnfl01LYMdcSJe6dwg==
|
||||
version "6.10.2"
|
||||
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.10.2.tgz#b9cb6bd8ec8f87514592ba3fdfd28e93f33a469b"
|
||||
integrity sha512-27yj+04uF6ya9l+qfpH187aqEzfCF4+Uit0I9ZBQVqK09hk/SQzKa2MUqUpXaVa7LOFRg1TSSr3lVxGOk6c0SQ==
|
||||
dependencies:
|
||||
"@protobufjs/aspromise" "^1.1.2"
|
||||
"@protobufjs/base64" "^1.1.2"
|
||||
|
||||
+1
-2
@@ -24,8 +24,7 @@
|
||||
},
|
||||
"../pkg": {
|
||||
"name": "@nymproject/nym-client-wasm",
|
||||
"version": "1.0.1",
|
||||
"license": "Apache-2.0"
|
||||
"version": "0.0.1"
|
||||
},
|
||||
"node_modules/@discoveryjs/json-ext": {
|
||||
"version": "0.5.7",
|
||||
|
||||
@@ -5,7 +5,7 @@ use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// Serializable structures for what we find in common/crypto
|
||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, JsonSchema)]
|
||||
pub struct PublicKey([u8; 32]);
|
||||
|
||||
impl PublicKey {
|
||||
@@ -24,7 +24,7 @@ impl AsRef<[u8]> for PublicKey {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
pub struct Signature([u8; 32], [u8; 32]);
|
||||
|
||||
impl Signature {
|
||||
|
||||
@@ -7,16 +7,16 @@ use serde::{Deserialize, Serialize};
|
||||
use crate::keys::PublicKey;
|
||||
use crate::payment::LinkPaymentData;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
pub struct InstantiateMsg {}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ExecuteMsg {
|
||||
LinkPayment { data: LinkPaymentData },
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum QueryMsg {
|
||||
GetPayments {
|
||||
@@ -25,6 +25,6 @@ pub enum QueryMsg {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct MigrateMsg {}
|
||||
|
||||
@@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::keys::{PublicKey, Signature};
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
pub struct Payment {
|
||||
verification_key: PublicKey,
|
||||
gateway_identity: PublicKey,
|
||||
@@ -27,7 +27,7 @@ impl Payment {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
pub struct LinkPaymentData {
|
||||
pub verification_key: PublicKey,
|
||||
pub gateway_identity: PublicKey,
|
||||
@@ -51,7 +51,7 @@ impl LinkPaymentData {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
pub struct PagedPaymentResponse {
|
||||
pub payments: Vec<Payment>,
|
||||
pub per_page: usize,
|
||||
|
||||
@@ -1,49 +1,47 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::GatewayClientError;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use crate::wasm_storage::Storage;
|
||||
use crate::wasm_storage::{Storage, StorageError};
|
||||
#[cfg(feature = "coconut")]
|
||||
use coconut_interface::Base58;
|
||||
#[cfg(feature = "coconut")]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use credential_storage::error::StorageError;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use credential_storage::storage::Storage;
|
||||
|
||||
#[cfg(all(target_arch = "wasm32", feature = "coconut"))]
|
||||
use crate::wasm_storage::StorageError;
|
||||
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "coconut"))]
|
||||
use credential_storage::error::StorageError;
|
||||
|
||||
#[cfg(feature = "coconut")]
|
||||
use {
|
||||
coconut_interface::Base58,
|
||||
credentials::coconut::{
|
||||
bandwidth::prepare_for_spending, utils::obtain_aggregate_verification_key,
|
||||
},
|
||||
use credentials::coconut::{
|
||||
bandwidth::prepare_for_spending, utils::obtain_aggregate_verification_key,
|
||||
};
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use credentials::token::bandwidth::TokenCredential;
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use crypto::asymmetric::identity;
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use network_defaults::{
|
||||
eth_contract::ETH_ERC20_JSON_ABI, eth_contract::ETH_JSON_ABI, BANDWIDTH_VALUE,
|
||||
ETH_BURN_FUNCTION_NAME, ETH_CONTRACT_ADDRESS, ETH_ERC20_APPROVE_FUNCTION_NAME,
|
||||
ETH_ERC20_CONTRACT_ADDRESS, ETH_MIN_BLOCK_DEPTH, TOKENS_TO_BURN, UTOKENS_TO_BURN,
|
||||
};
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use pemstore::traits::PemStorableKeyPair;
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use rand::rngs::OsRng;
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use secp256k1::SecretKey;
|
||||
use std::str::FromStr;
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use web3::{
|
||||
contract::{Contract, Options},
|
||||
ethabi::Token,
|
||||
signing::{Key, SecretKeyRef},
|
||||
transports::Http,
|
||||
types::{Address, U256, U64},
|
||||
Web3,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use {
|
||||
credentials::token::bandwidth::TokenCredential,
|
||||
crypto::asymmetric::identity,
|
||||
network_defaults::{
|
||||
eth_contract::ETH_ERC20_JSON_ABI, eth_contract::ETH_JSON_ABI, BANDWIDTH_VALUE,
|
||||
ETH_BURN_FUNCTION_NAME, ETH_CONTRACT_ADDRESS, ETH_ERC20_APPROVE_FUNCTION_NAME,
|
||||
ETH_ERC20_CONTRACT_ADDRESS, ETH_MIN_BLOCK_DEPTH, TOKENS_TO_BURN, UTOKENS_TO_BURN,
|
||||
},
|
||||
pemstore::traits::PemStorableKeyPair,
|
||||
rand::rngs::OsRng,
|
||||
secp256k1::SecretKey,
|
||||
web3::{
|
||||
contract::{Contract, Options},
|
||||
ethabi::Token,
|
||||
signing::{Key, SecretKeyRef},
|
||||
transports::Http,
|
||||
types::{Address, U256, U64},
|
||||
Web3,
|
||||
},
|
||||
};
|
||||
use crate::error::GatewayClientError;
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
pub fn eth_contract(web3: Web3<Http>) -> Contract<Http> {
|
||||
|
||||
@@ -27,7 +27,7 @@ futures = "0.3"
|
||||
|
||||
coconut-interface = { path = "../../coconut-interface" }
|
||||
network-defaults = { path = "../../network-defaults" }
|
||||
validator-api-requests = { path = "../../../validator-api/validator-api-requests", features = ["coconut"] }
|
||||
validator-api-requests = { path = "../../../validator-api/validator-api-requests" }
|
||||
|
||||
# required for nymd-client
|
||||
# at some point it might be possible to make it wasm-compatible
|
||||
|
||||
@@ -2,24 +2,27 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{validator_api, ValidatorClientError};
|
||||
use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixNodeBond};
|
||||
use url::Url;
|
||||
use validator_api_requests::coconut::{
|
||||
use coconut_interface::{
|
||||
BlindSignRequestBody, BlindedSignatureResponse, ExecuteReleaseFundsRequestBody,
|
||||
ProposeReleaseFundsRequestBody, ProposeReleaseFundsResponse, VerificationKeyResponse,
|
||||
VerifyCredentialBody, VerifyCredentialResponse,
|
||||
};
|
||||
use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixNodeBond};
|
||||
use url::Url;
|
||||
|
||||
use validator_api_requests::models::{
|
||||
CoreNodeStatusResponse, MixnodeStatusResponse, RewardEstimationResponse,
|
||||
StakeSaturationResponse,
|
||||
};
|
||||
|
||||
#[cfg(feature = "nymd-client")]
|
||||
use validator_api_requests::models::{MixNodeBondAnnotated, UptimeResponse};
|
||||
|
||||
#[cfg(feature = "nymd-client")]
|
||||
use network_defaults::DEFAULT_NETWORK;
|
||||
|
||||
#[cfg(feature = "nymd-client")]
|
||||
use crate::nymd::{
|
||||
self, error::NymdError, CosmWasmClient, NymdClient, QueryNymdClient, SigningNymdClient,
|
||||
error::NymdError, CosmWasmClient, NymdClient, QueryNymdClient, SigningNymdClient,
|
||||
};
|
||||
|
||||
#[cfg(feature = "nymd-client")]
|
||||
@@ -29,18 +32,18 @@ use mixnet_contract_common::{
|
||||
RewardedSetUpdateDetails,
|
||||
};
|
||||
#[cfg(feature = "nymd-client")]
|
||||
use network_defaults::{all::Network, NymNetworkDetails};
|
||||
#[cfg(feature = "nymd-client")]
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
#[cfg(feature = "nymd-client")]
|
||||
#[must_use]
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub struct Config {
|
||||
network: network_defaults::all::Network,
|
||||
api_url: Url,
|
||||
nymd_url: Url,
|
||||
|
||||
nymd_config: nymd::Config,
|
||||
mixnet_contract_address: cosmrs::AccountId,
|
||||
vesting_contract_address: cosmrs::AccountId,
|
||||
bandwidth_claim_contract_address: cosmrs::AccountId,
|
||||
|
||||
mixnode_page_limit: Option<u32>,
|
||||
gateway_page_limit: Option<u32>,
|
||||
@@ -50,44 +53,42 @@ pub struct Config {
|
||||
|
||||
#[cfg(feature = "nymd-client")]
|
||||
impl Config {
|
||||
pub fn try_from_nym_network_details(
|
||||
details: &NymNetworkDetails,
|
||||
) -> Result<Self, ValidatorClientError> {
|
||||
let mut api_url = details
|
||||
.endpoints
|
||||
.iter()
|
||||
.filter_map(|d| d.api_url.as_ref())
|
||||
.map(|url| Url::parse(url))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
if api_url.is_empty() {
|
||||
return Err(ValidatorClientError::NoAPIUrlAvailable);
|
||||
}
|
||||
|
||||
Ok(Config {
|
||||
api_url: api_url.pop().unwrap(),
|
||||
nymd_url: details.endpoints[0]
|
||||
.nymd_url
|
||||
pub fn new(network: network_defaults::all::Network, nymd_url: Url, api_url: Url) -> Self {
|
||||
Config {
|
||||
network,
|
||||
nymd_url,
|
||||
mixnet_contract_address: DEFAULT_NETWORK
|
||||
.mixnet_contract_address()
|
||||
.parse()
|
||||
.map_err(ValidatorClientError::MalformedUrlProvided)?,
|
||||
nymd_config: nymd::Config::try_from_nym_network_details(details)?,
|
||||
.expect("Error parsing mixnet contract address"),
|
||||
vesting_contract_address: DEFAULT_NETWORK
|
||||
.vesting_contract_address()
|
||||
.parse()
|
||||
.expect("Error parsing vesting contract address"),
|
||||
bandwidth_claim_contract_address: DEFAULT_NETWORK
|
||||
.bandwidth_claim_contract_address()
|
||||
.parse()
|
||||
.expect("Error parsing bandwidth claim contract address"),
|
||||
api_url,
|
||||
mixnode_page_limit: None,
|
||||
gateway_page_limit: None,
|
||||
mixnode_delegations_page_limit: None,
|
||||
rewarded_set_page_limit: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this method shouldn't really exist as all information should be included immediately
|
||||
// via `from_nym_network_details`, but it's here for, you guessed it, legacy compatibility
|
||||
pub fn with_urls(mut self, nymd_url: Url, api_url: Url) -> Self {
|
||||
self.nymd_url = nymd_url;
|
||||
self.api_url = api_url;
|
||||
pub fn with_mixnode_contract_address(mut self, address: cosmrs::AccountId) -> Self {
|
||||
self.mixnet_contract_address = address;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_nymd_url(mut self, nymd_url: Url) -> Self {
|
||||
self.nymd_url = nymd_url;
|
||||
pub fn with_vesting_contract_address(mut self, address: cosmrs::AccountId) -> Self {
|
||||
self.vesting_contract_address = address;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_bandwidth_claim_contract_address(mut self, address: cosmrs::AccountId) -> Self {
|
||||
self.bandwidth_claim_contract_address = address;
|
||||
self
|
||||
}
|
||||
|
||||
@@ -114,11 +115,10 @@ impl Config {
|
||||
|
||||
#[cfg(feature = "nymd-client")]
|
||||
pub struct Client<C> {
|
||||
// compatibility : (
|
||||
pub network: Network,
|
||||
|
||||
// TODO: we really shouldn't be storing a mnemonic here, but removing it would be
|
||||
// non-trivial amount of work and it's out of scope of the current branch
|
||||
pub network: network_defaults::all::Network,
|
||||
mixnet_contract_address: cosmrs::AccountId,
|
||||
vesting_contract_address: cosmrs::AccountId,
|
||||
bandwidth_claim_contract_address: cosmrs::AccountId,
|
||||
mnemonic: Option<bip39::Mnemonic>,
|
||||
|
||||
mixnode_page_limit: Option<u32>,
|
||||
@@ -135,26 +135,29 @@ pub struct Client<C> {
|
||||
impl Client<SigningNymdClient> {
|
||||
pub fn new_signing(
|
||||
config: Config,
|
||||
// we need to provide network argument due to compatibility with other components (wallet...)
|
||||
// that rely on its existence...
|
||||
network: Network,
|
||||
mnemonic: bip39::Mnemonic,
|
||||
) -> Result<Client<SigningNymdClient>, ValidatorClientError> {
|
||||
let validator_api_client = validator_api::Client::new(config.api_url.clone());
|
||||
let nymd_client = NymdClient::connect_with_mnemonic(
|
||||
config.nymd_config.clone(),
|
||||
config.network,
|
||||
config.nymd_url.as_str(),
|
||||
mnemonic.clone(),
|
||||
None,
|
||||
)?;
|
||||
)?
|
||||
.with_mixnet_contract_address(config.mixnet_contract_address.clone())
|
||||
.with_vesting_contract_address(config.vesting_contract_address.clone())
|
||||
.with_bandwidth_claim_contract_address(config.bandwidth_claim_contract_address.clone());
|
||||
|
||||
Ok(Client {
|
||||
network,
|
||||
network: config.network,
|
||||
mixnet_contract_address: config.mixnet_contract_address,
|
||||
vesting_contract_address: config.vesting_contract_address,
|
||||
bandwidth_claim_contract_address: config.bandwidth_claim_contract_address,
|
||||
mnemonic: Some(mnemonic),
|
||||
mixnode_page_limit: config.mixnode_page_limit,
|
||||
gateway_page_limit: config.gateway_page_limit,
|
||||
mixnode_delegations_page_limit: config.mixnode_delegations_page_limit,
|
||||
rewarded_set_page_limit: config.rewarded_set_page_limit,
|
||||
rewarded_set_page_limit: None,
|
||||
validator_api: validator_api_client,
|
||||
nymd: nymd_client,
|
||||
})
|
||||
@@ -162,11 +165,14 @@ impl Client<SigningNymdClient> {
|
||||
|
||||
pub fn change_nymd(&mut self, new_endpoint: Url) -> Result<(), ValidatorClientError> {
|
||||
self.nymd = NymdClient::connect_with_mnemonic(
|
||||
self.nymd.current_config().clone(),
|
||||
self.network,
|
||||
new_endpoint.as_ref(),
|
||||
self.mnemonic.clone().unwrap(),
|
||||
None,
|
||||
)?;
|
||||
)?
|
||||
.with_mixnet_contract_address(self.mixnet_contract_address.clone())
|
||||
.with_vesting_contract_address(self.vesting_contract_address.clone())
|
||||
.with_bandwidth_claim_contract_address(self.bandwidth_claim_contract_address.clone());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -177,18 +183,17 @@ impl Client<SigningNymdClient> {
|
||||
|
||||
#[cfg(feature = "nymd-client")]
|
||||
impl Client<QueryNymdClient> {
|
||||
pub fn new_query(
|
||||
config: Config,
|
||||
// we need to provide network argument due to compatibility with other components (wallet...)
|
||||
// that rely on its existence...
|
||||
network: Network,
|
||||
) -> Result<Client<QueryNymdClient>, ValidatorClientError> {
|
||||
pub fn new_query(config: Config) -> Result<Client<QueryNymdClient>, ValidatorClientError> {
|
||||
let validator_api_client = validator_api::Client::new(config.api_url.clone());
|
||||
let nymd_client =
|
||||
NymdClient::connect(config.nymd_config.clone(), config.nymd_url.as_str())?;
|
||||
let nymd_client = NymdClient::connect(config.nymd_url.as_str())?
|
||||
.with_mixnet_contract_address(config.mixnet_contract_address.clone())
|
||||
.with_vesting_contract_address(config.vesting_contract_address.clone());
|
||||
|
||||
Ok(Client {
|
||||
network,
|
||||
network: config.network,
|
||||
mixnet_contract_address: config.mixnet_contract_address,
|
||||
vesting_contract_address: config.vesting_contract_address,
|
||||
bandwidth_claim_contract_address: config.bandwidth_claim_contract_address,
|
||||
mnemonic: None,
|
||||
mixnode_page_limit: config.mixnode_page_limit,
|
||||
gateway_page_limit: config.gateway_page_limit,
|
||||
@@ -200,7 +205,10 @@ impl Client<QueryNymdClient> {
|
||||
}
|
||||
|
||||
pub fn change_nymd(&mut self, new_endpoint: Url) -> Result<(), ValidatorClientError> {
|
||||
self.nymd = NymdClient::connect(self.nymd.current_config().clone(), new_endpoint.as_ref())?;
|
||||
self.nymd = NymdClient::connect(new_endpoint.as_ref())?
|
||||
.with_mixnet_contract_address(self.mixnet_contract_address.clone())
|
||||
.with_vesting_contract_address(self.vesting_contract_address.clone())
|
||||
.with_bandwidth_claim_contract_address(self.bandwidth_claim_contract_address.clone());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -214,12 +222,11 @@ impl<C> Client<C> {
|
||||
// use case: somebody initialised client without a contract in order to upload and initialise one
|
||||
// and now they want to actually use it without making new client
|
||||
pub fn set_mixnet_contract_address(&mut self, mixnet_contract_address: cosmrs::AccountId) {
|
||||
self.nymd
|
||||
.set_mixnet_contract_address(mixnet_contract_address)
|
||||
self.mixnet_contract_address = mixnet_contract_address
|
||||
}
|
||||
|
||||
pub fn get_mixnet_contract_address(&self) -> cosmrs::AccountId {
|
||||
self.nymd.mixnet_contract_address().clone()
|
||||
self.mixnet_contract_address.clone()
|
||||
}
|
||||
|
||||
pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError> {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::nymd::error::NymdError;
|
||||
use crate::nymd::{Config as ClientConfig, NymdClient, QueryNymdClient};
|
||||
use crate::nymd::{NymdClient, QueryNymdClient};
|
||||
use crate::ApiClient;
|
||||
use network_defaults::all::Network;
|
||||
|
||||
@@ -54,20 +54,10 @@ fn setup_connection_tests<H: BuildHasher + 'static>(
|
||||
.get(&network)
|
||||
.expect("No configured contract address")
|
||||
.clone();
|
||||
let config = ClientConfig::try_from_nym_network_details(&network.details())
|
||||
.expect("failed to create valid nymd client config");
|
||||
|
||||
if let Ok(mut client) = NymdClient::<QueryNymdClient>::connect(config, url.as_str()) {
|
||||
// possibly redundant, but lets just leave it here
|
||||
client.set_mixnet_contract_address(address);
|
||||
Some(ClientForConnectionTest::Nymd(
|
||||
network,
|
||||
url,
|
||||
Box::new(client),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
NymdClient::<QueryNymdClient>::connect(url.as_str())
|
||||
.map(|client| client.with_mixnet_contract_address(address))
|
||||
.map(move |client| ClientForConnectionTest::Nymd(network, url, Box::new(client)))
|
||||
.ok()
|
||||
});
|
||||
|
||||
let api_connection_test_clients = api_urls.map(|(network, url)| {
|
||||
@@ -86,7 +76,7 @@ fn extract_and_collect_results_into_map(
|
||||
.filter(|c| &c.url_type() == url_type)
|
||||
.map(|c| {
|
||||
let (network, url, result) = c.result();
|
||||
(network.clone(), (url.clone(), *result))
|
||||
(*network, (url.clone(), *result))
|
||||
})
|
||||
.into_group_map()
|
||||
}
|
||||
|
||||
@@ -18,7 +18,4 @@ pub enum ValidatorClientError {
|
||||
#[cfg(feature = "nymd-client")]
|
||||
#[error("There was an issue with the Nymd client - {0}")]
|
||||
NymdError(#[from] crate::nymd::error::NymdError),
|
||||
|
||||
#[error("No validator API url has been provided")]
|
||||
NoAPIUrlAvailable,
|
||||
}
|
||||
|
||||
@@ -6,14 +6,14 @@ use std::fmt;
|
||||
pub use cosmrs::Coin as CosmosCoin;
|
||||
pub use cosmwasm_std::Coin as CosmWasmCoin;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Copy, Default, Debug, PartialEq, Eq)]
|
||||
#[derive(Serialize, Deserialize, Clone, Copy, Default, Debug, PartialEq)]
|
||||
pub struct MismatchedDenoms;
|
||||
|
||||
// the reason the coin is created here as opposed to different place in the codebase is that
|
||||
// eventually we want to either publish the cosmwasm client separately or commit it to
|
||||
// some other project, like cosmrs. Either way, in that case we can't really have
|
||||
// a dependency on an internal type
|
||||
#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, Eq)]
|
||||
#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq)]
|
||||
pub struct Coin {
|
||||
pub amount: u128,
|
||||
pub denom: String,
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::nymd::cosmwasm_client::types::*;
|
||||
use crate::nymd::error::NymdError;
|
||||
use crate::nymd::fee::{Fee, DEFAULT_SIMULATED_GAS_MULTIPLIER};
|
||||
use crate::nymd::wallet::DirectSecp256k1HdWallet;
|
||||
use crate::nymd::{Coin, GasAdjustable, GasPrice, TxResponse};
|
||||
use crate::nymd::{Coin, GasPrice, TxResponse};
|
||||
use async_trait::async_trait;
|
||||
use cosmrs::bank::MsgSend;
|
||||
use cosmrs::distribution::MsgWithdrawDelegatorReward;
|
||||
@@ -490,35 +490,28 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
|
||||
fee: Fee,
|
||||
memo: &String,
|
||||
) -> Result<tx::Fee, NymdError> {
|
||||
let auto_fee = |multiplier: Option<f32>| async move {
|
||||
debug!("Trying to simulate gas costs...");
|
||||
// from what I've seen in manual testing, gas estimation does not exist if transaction
|
||||
// fails to get executed (for example if you send 'BondMixnode" with invalid signature)
|
||||
let gas_estimation = self
|
||||
.simulate(signer_address, messages.to_vec(), memo.clone())
|
||||
.await?
|
||||
.gas_info
|
||||
.ok_or(NymdError::GasEstimationFailure)?
|
||||
.gas_used;
|
||||
|
||||
let multiplier = multiplier.unwrap_or(DEFAULT_SIMULATED_GAS_MULTIPLIER);
|
||||
let gas = gas_estimation.adjust_gas(multiplier);
|
||||
|
||||
debug!("Gas estimation: {}", gas_estimation);
|
||||
debug!("Multiplying the estimation by {}", multiplier);
|
||||
debug!("Final gas limit used: {}", gas);
|
||||
|
||||
let fee = self.gas_price() * gas;
|
||||
Ok::<tx::Fee, NymdError>(tx::Fee::from_amount_and_gas(fee, gas))
|
||||
};
|
||||
let fee = match fee {
|
||||
Fee::Manual(fee) => fee,
|
||||
Fee::Auto(multiplier) => auto_fee(multiplier).await?,
|
||||
Fee::PayerGranterAuto(multiplier, payer, granter) => {
|
||||
let mut fee = auto_fee(multiplier).await?;
|
||||
fee.payer = payer;
|
||||
fee.granter = granter;
|
||||
fee
|
||||
Fee::Auto(multiplier) => {
|
||||
debug!("Trying to simulate gas costs...");
|
||||
// from what I've seen in manual testing, gas estimation does not exist if transaction
|
||||
// fails to get executed (for example if you send 'BondMixnode" with invalid signature)
|
||||
let gas_estimation = self
|
||||
.simulate(signer_address, messages.to_vec(), memo.clone())
|
||||
.await?
|
||||
.gas_info
|
||||
.ok_or(NymdError::GasEstimationFailure)?
|
||||
.gas_used;
|
||||
|
||||
let multiplier = multiplier.unwrap_or(DEFAULT_SIMULATED_GAS_MULTIPLIER);
|
||||
let gas = ((gas_estimation.value() as f32 * multiplier) as u64).into();
|
||||
|
||||
debug!("Gas estimation: {}", gas_estimation);
|
||||
debug!("Multiplying the estimation by {}", multiplier);
|
||||
debug!("Final gas limit used: {}", gas);
|
||||
|
||||
let fee = self.gas_price() * gas;
|
||||
tx::Fee::from_amount_and_gas(fee, gas)
|
||||
}
|
||||
};
|
||||
debug!("Fee used for the transaction: {:?}", fee);
|
||||
|
||||
@@ -130,9 +130,6 @@ pub enum NymdError {
|
||||
|
||||
#[error("Coconut interface error: {0}")]
|
||||
CoconutInterfaceError(#[from] coconut_interface::error::CoconutInterfaceError),
|
||||
|
||||
#[error("Account had an unexpected bech32 prefix. Expected: {expected}, got: {got}")]
|
||||
UnexpectedBech32Prefix { got: String, expected: String },
|
||||
}
|
||||
|
||||
impl NymdError {
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nymd::Gas;
|
||||
use cosmrs::{tx, AccountId};
|
||||
use cosmrs::tx;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub mod gas_price;
|
||||
|
||||
pub type GasAdjustment = f32;
|
||||
|
||||
pub const DEFAULT_SIMULATED_GAS_MULTIPLIER: GasAdjustment = 1.3;
|
||||
pub const DEFAULT_SIMULATED_GAS_MULTIPLIER: f32 = 1.3;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum Fee {
|
||||
Manual(#[serde(with = "sealed::TxFee")] tx::Fee),
|
||||
Auto(Option<GasAdjustment>),
|
||||
PayerGranterAuto(Option<GasAdjustment>, Option<AccountId>, Option<AccountId>),
|
||||
Auto(Option<f32>),
|
||||
}
|
||||
|
||||
impl From<tx::Fee> for Fee {
|
||||
@@ -24,8 +20,8 @@ impl From<tx::Fee> for Fee {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GasAdjustment> for Fee {
|
||||
fn from(multiplier: GasAdjustment) -> Self {
|
||||
impl From<f32> for Fee {
|
||||
fn from(multiplier: f32) -> Self {
|
||||
Fee::Auto(Some(multiplier))
|
||||
}
|
||||
}
|
||||
@@ -36,21 +32,6 @@ impl Default for Fee {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait GasAdjustable {
|
||||
fn adjust_gas(&self, adjustment: GasAdjustment) -> Self;
|
||||
}
|
||||
|
||||
impl GasAdjustable for Gas {
|
||||
fn adjust_gas(&self, adjustment: GasAdjustment) -> Self {
|
||||
if adjustment == 1.0 {
|
||||
*self
|
||||
} else {
|
||||
let adjusted = (self.value() as f32 * adjustment).ceil();
|
||||
(adjusted as u64).into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// a workaround to provide serde implementation for tx::Fee. We don't want to ever expose any of those
|
||||
// types to the public and ideally they will get replaced by proper implementation inside comrs
|
||||
mod sealed {
|
||||
|
||||
@@ -15,6 +15,7 @@ use cosmrs::rpc::HttpClientUrl;
|
||||
use cosmrs::tx::Msg;
|
||||
use cosmwasm_std::Uint128;
|
||||
use execute::execute;
|
||||
pub use fee::gas_price::GasPrice;
|
||||
use mixnet_contract_common::mixnode::DelegationEvent;
|
||||
use mixnet_contract_common::{
|
||||
ContractStateParams, Delegation, ExecuteMsg, Gateway, GatewayBond, GatewayBondResponse,
|
||||
@@ -24,6 +25,7 @@ use mixnet_contract_common::{
|
||||
PagedMixDelegationsResponse, PagedMixnodeResponse, PagedRewardedSetResponse, QueryMsg,
|
||||
RewardedSetUpdateDetails,
|
||||
};
|
||||
use network_defaults::DEFAULT_NETWORK;
|
||||
use serde::Serialize;
|
||||
use std::convert::TryInto;
|
||||
use vesting_contract_common::ExecuteMsg as VestingExecuteMsg;
|
||||
@@ -48,8 +50,6 @@ pub use cosmrs::tx::{self, Gas};
|
||||
pub use cosmrs::Coin as CosmosCoin;
|
||||
pub use cosmrs::{bip32, AccountId, Decimal, Denom};
|
||||
pub use cosmwasm_std::Coin as CosmWasmCoin;
|
||||
pub use fee::{gas_price::GasPrice, GasAdjustable, GasAdjustment};
|
||||
use network_defaults::{ChainDetails, NymNetworkDetails};
|
||||
pub use signing_client::Client as SigningNymdClient;
|
||||
pub use traits::{VestingQueryClient, VestingSigningClient};
|
||||
|
||||
@@ -60,92 +60,67 @@ pub mod fee;
|
||||
pub mod traits;
|
||||
pub mod wallet;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
pub(crate) chain_details: ChainDetails,
|
||||
|
||||
// I'd love to have used `NymContracts` struct directly here instead,
|
||||
// however, I'd really prefer to use something more strongly typed (i.e. AccountId vs String)
|
||||
pub(crate) mixnet_contract_address: Option<AccountId>,
|
||||
pub(crate) vesting_contract_address: Option<AccountId>,
|
||||
pub(crate) bandwidth_claim_contract_address: Option<AccountId>,
|
||||
pub(crate) coconut_bandwidth_contract_address: Option<AccountId>,
|
||||
pub(crate) multisig_contract_address: Option<AccountId>,
|
||||
// TODO: add this in later commits
|
||||
// pub(crate) gas_price: GasPrice,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
fn parse_optional_account(
|
||||
raw: Option<&String>,
|
||||
expected_prefix: &str,
|
||||
) -> Result<Option<AccountId>, NymdError> {
|
||||
if let Some(address) = raw {
|
||||
let parsed: AccountId = address
|
||||
.parse()
|
||||
.map_err(|_| NymdError::MalformedAccountAddress(address.clone()))?;
|
||||
if parsed.prefix() != expected_prefix {
|
||||
Err(NymdError::UnexpectedBech32Prefix {
|
||||
got: parsed.prefix().into(),
|
||||
expected: expected_prefix.into(),
|
||||
})
|
||||
} else {
|
||||
Ok(Some(parsed))
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_from_nym_network_details(details: &NymNetworkDetails) -> Result<Self, NymdError> {
|
||||
let prefix = &details.chain_details.bech32_account_prefix;
|
||||
Ok(Config {
|
||||
chain_details: details.chain_details.clone(),
|
||||
mixnet_contract_address: Self::parse_optional_account(
|
||||
details.contracts.mixnet_contract_address.as_ref(),
|
||||
prefix,
|
||||
)?,
|
||||
vesting_contract_address: Self::parse_optional_account(
|
||||
details.contracts.vesting_contract_address.as_ref(),
|
||||
prefix,
|
||||
)?,
|
||||
bandwidth_claim_contract_address: Self::parse_optional_account(
|
||||
details.contracts.bandwidth_claim_contract_address.as_ref(),
|
||||
prefix,
|
||||
)?,
|
||||
coconut_bandwidth_contract_address: Self::parse_optional_account(
|
||||
details
|
||||
.contracts
|
||||
.coconut_bandwidth_contract_address
|
||||
.as_ref(),
|
||||
prefix,
|
||||
)?,
|
||||
multisig_contract_address: Self::parse_optional_account(
|
||||
details.contracts.multisig_contract_address.as_ref(),
|
||||
prefix,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NymdClient<C> {
|
||||
client: C,
|
||||
config: Config,
|
||||
mixnet_contract_address: AccountId,
|
||||
vesting_contract_address: AccountId,
|
||||
bandwidth_claim_contract_address: AccountId,
|
||||
coconut_bandwidth_contract_address: AccountId,
|
||||
multisig_contract_address: AccountId,
|
||||
client_address: Option<Vec<AccountId>>,
|
||||
simulated_gas_multiplier: f32,
|
||||
}
|
||||
|
||||
impl<C> NymdClient<C> {
|
||||
pub fn with_mixnet_contract_address(mut self, address: AccountId) -> Self {
|
||||
self.mixnet_contract_address = address;
|
||||
self
|
||||
}
|
||||
pub fn with_vesting_contract_address(mut self, address: AccountId) -> Self {
|
||||
self.vesting_contract_address = address;
|
||||
self
|
||||
}
|
||||
pub fn with_bandwidth_claim_contract_address(mut self, address: AccountId) -> Self {
|
||||
self.bandwidth_claim_contract_address = address;
|
||||
self
|
||||
}
|
||||
pub fn with_coconut_bandwidth_contract_address(mut self, address: AccountId) -> Self {
|
||||
self.coconut_bandwidth_contract_address = address;
|
||||
self
|
||||
}
|
||||
pub fn with_multisig_contract_address(mut self, address: AccountId) -> Self {
|
||||
self.multisig_contract_address = address;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl NymdClient<QueryNymdClient> {
|
||||
pub fn connect<U>(config: Config, endpoint: U) -> Result<NymdClient<QueryNymdClient>, NymdError>
|
||||
pub fn connect<U>(endpoint: U) -> Result<NymdClient<QueryNymdClient>, NymdError>
|
||||
where
|
||||
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
|
||||
{
|
||||
Ok(NymdClient {
|
||||
client: QueryNymdClient::new(endpoint)?,
|
||||
config,
|
||||
client_address: None,
|
||||
simulated_gas_multiplier: DEFAULT_SIMULATED_GAS_MULTIPLIER,
|
||||
mixnet_contract_address: DEFAULT_NETWORK
|
||||
.mixnet_contract_address()
|
||||
.parse()
|
||||
.expect("Error parsing mixnet contract address"),
|
||||
vesting_contract_address: DEFAULT_NETWORK
|
||||
.vesting_contract_address()
|
||||
.parse()
|
||||
.expect("Error parsing vesting contract address"),
|
||||
bandwidth_claim_contract_address: DEFAULT_NETWORK
|
||||
.bandwidth_claim_contract_address()
|
||||
.parse()
|
||||
.expect("Error parsing bandwidth claim contract address"),
|
||||
coconut_bandwidth_contract_address: DEFAULT_NETWORK
|
||||
.coconut_bandwidth_contract_address()
|
||||
.parse()
|
||||
.unwrap(),
|
||||
multisig_contract_address: DEFAULT_NETWORK.multisig_contract_address().parse().unwrap(),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -153,7 +128,6 @@ impl NymdClient<QueryNymdClient> {
|
||||
impl NymdClient<SigningNymdClient> {
|
||||
// maybe the wallet could be made into a generic, but for now, let's just have this one implementation
|
||||
pub fn connect_with_signer<U: Clone>(
|
||||
config: Config,
|
||||
network: config::defaults::all::Network,
|
||||
endpoint: U,
|
||||
signer: DirectSecp256k1HdWallet,
|
||||
@@ -162,24 +136,40 @@ impl NymdClient<SigningNymdClient> {
|
||||
where
|
||||
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
|
||||
{
|
||||
let denom = network.base_mix_denom();
|
||||
let denom = network.denom();
|
||||
let client_address = signer
|
||||
.try_derive_accounts()?
|
||||
.into_iter()
|
||||
.map(|account| account.address)
|
||||
.collect();
|
||||
let gas_price = gas_price.unwrap_or(GasPrice::new_with_default_price(&denom)?);
|
||||
let gas_price = gas_price.unwrap_or(GasPrice::new_with_default_price(denom)?);
|
||||
|
||||
Ok(NymdClient {
|
||||
client: SigningNymdClient::connect_with_signer(endpoint, signer, gas_price)?,
|
||||
config,
|
||||
client_address: Some(client_address),
|
||||
simulated_gas_multiplier: DEFAULT_SIMULATED_GAS_MULTIPLIER,
|
||||
mixnet_contract_address: DEFAULT_NETWORK
|
||||
.mixnet_contract_address()
|
||||
.parse()
|
||||
.expect("Error parsing mixnet contract address"),
|
||||
vesting_contract_address: DEFAULT_NETWORK
|
||||
.vesting_contract_address()
|
||||
.parse()
|
||||
.expect("Error parsing vesting contract address"),
|
||||
bandwidth_claim_contract_address: DEFAULT_NETWORK
|
||||
.bandwidth_claim_contract_address()
|
||||
.parse()
|
||||
.expect("Error parsing bandwidth claim contract address"),
|
||||
coconut_bandwidth_contract_address: DEFAULT_NETWORK
|
||||
.coconut_bandwidth_contract_address()
|
||||
.parse()
|
||||
.unwrap(),
|
||||
multisig_contract_address: DEFAULT_NETWORK.multisig_contract_address().parse().unwrap(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn connect_with_mnemonic<U: Clone>(
|
||||
config: Config,
|
||||
network: config::defaults::all::Network,
|
||||
endpoint: U,
|
||||
mnemonic: bip39::Mnemonic,
|
||||
gas_price: Option<GasPrice>,
|
||||
@@ -187,8 +177,8 @@ impl NymdClient<SigningNymdClient> {
|
||||
where
|
||||
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
|
||||
{
|
||||
let prefix = &config.chain_details.bech32_account_prefix;
|
||||
let denom = &config.chain_details.mix_denom.base;
|
||||
let prefix = network.bech32_prefix();
|
||||
let denom = network.denom();
|
||||
let wallet = DirectSecp256k1HdWallet::from_mnemonic(prefix, mnemonic)?;
|
||||
let client_address = wallet
|
||||
.try_derive_accounts()?
|
||||
@@ -199,82 +189,48 @@ impl NymdClient<SigningNymdClient> {
|
||||
|
||||
Ok(NymdClient {
|
||||
client: SigningNymdClient::connect_with_signer(endpoint, wallet, gas_price)?,
|
||||
config,
|
||||
client_address: Some(client_address),
|
||||
simulated_gas_multiplier: DEFAULT_SIMULATED_GAS_MULTIPLIER,
|
||||
mixnet_contract_address: network
|
||||
.mixnet_contract_address()
|
||||
.parse()
|
||||
.expect("Error parsing mixnet contract address"),
|
||||
vesting_contract_address: network
|
||||
.vesting_contract_address()
|
||||
.parse()
|
||||
.expect("Error parsing vesting contract address"),
|
||||
bandwidth_claim_contract_address: network
|
||||
.bandwidth_claim_contract_address()
|
||||
.parse()
|
||||
.expect("Error parsing bandwidth claim contract address"),
|
||||
coconut_bandwidth_contract_address: network
|
||||
.coconut_bandwidth_contract_address()
|
||||
.parse()
|
||||
.unwrap(),
|
||||
multisig_contract_address: network.multisig_contract_address().parse().unwrap(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> NymdClient<C> {
|
||||
pub fn current_config(&self) -> &Config {
|
||||
&self.config
|
||||
}
|
||||
|
||||
pub fn set_mixnet_contract_address(&mut self, address: AccountId) {
|
||||
self.config.mixnet_contract_address = Some(address);
|
||||
}
|
||||
|
||||
pub fn set_vesting_contract_address(&mut self, address: AccountId) {
|
||||
self.config.vesting_contract_address = Some(address);
|
||||
}
|
||||
|
||||
pub fn set_bandwidth_claim_contract_address(&mut self, address: AccountId) {
|
||||
self.config.bandwidth_claim_contract_address = Some(address);
|
||||
}
|
||||
|
||||
pub fn set_coconut_bandwidth_contract_address(&mut self, address: AccountId) {
|
||||
self.config.coconut_bandwidth_contract_address = Some(address);
|
||||
}
|
||||
|
||||
pub fn set_multisig_contract_address(&mut self, address: AccountId) {
|
||||
self.config.multisig_contract_address = Some(address);
|
||||
}
|
||||
|
||||
// TODO: this should get changed into Result<&AccountId, NymdError> (or Option<&AccountId> in future commits
|
||||
// note: what unwrap is doing here is just moving a failure that would have normally
|
||||
// occurred in `connect` when attempting to parse an empty address,
|
||||
// so it's not introducing new source of failure (just moves it)
|
||||
pub fn mixnet_contract_address(&self) -> &AccountId {
|
||||
self.config.mixnet_contract_address.as_ref().unwrap()
|
||||
&self.mixnet_contract_address
|
||||
}
|
||||
|
||||
// TODO: this should get changed into Result<&AccountId, NymdError> (or Option<&AccountId> in future commits
|
||||
// note: what unwrap is doing here is just moving a failure that would have normally
|
||||
// occurred in `connect` when attempting to parse an empty address,
|
||||
// so it's not introducing new source of failure (just moves it)
|
||||
pub fn vesting_contract_address(&self) -> &AccountId {
|
||||
self.config.vesting_contract_address.as_ref().unwrap()
|
||||
&self.vesting_contract_address
|
||||
}
|
||||
|
||||
// TODO: this should get changed into Result<&AccountId, NymdError> (or Option<&AccountId> in future commits
|
||||
// note: what unwrap is doing here is just moving a failure that would have normally
|
||||
// occurred in `connect` when attempting to parse an empty address,
|
||||
// so it's not introducing new source of failure (just moves it)
|
||||
pub fn bandwidth_claim_contract_address(&self) -> &AccountId {
|
||||
self.config
|
||||
.bandwidth_claim_contract_address
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
&self.bandwidth_claim_contract_address
|
||||
}
|
||||
|
||||
// TODO: this should get changed into Result<&AccountId, NymdError> (or Option<&AccountId> in future commits
|
||||
// note: what unwrap is doing here is just moving a failure that would have normally
|
||||
// occurred in `connect` when attempting to parse an empty address,
|
||||
// so it's not introducing new source of failure (just moves it)
|
||||
pub fn coconut_bandwidth_contract_address(&self) -> &AccountId {
|
||||
self.config
|
||||
.coconut_bandwidth_contract_address
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
&self.coconut_bandwidth_contract_address
|
||||
}
|
||||
|
||||
// TODO: this should get changed into Result<&AccountId, NymdError> (or Option<&AccountId> in future commits
|
||||
// note: what unwrap is doing here is just moving a failure that would have normally
|
||||
// occurred in `connect` when attempting to parse an empty address,
|
||||
// so it's not introducing new source of failure (just moves it)
|
||||
pub fn multisig_contract_address(&self) -> &AccountId {
|
||||
self.config.multisig_contract_address.as_ref().unwrap()
|
||||
&self.multisig_contract_address
|
||||
}
|
||||
|
||||
pub fn set_simulated_gas_multiplier(&mut self, multiplier: f32) {
|
||||
@@ -314,10 +270,6 @@ impl<C> NymdClient<C> {
|
||||
self.client.gas_price()
|
||||
}
|
||||
|
||||
pub fn gas_adjustment(&self) -> GasAdjustment {
|
||||
self.simulated_gas_multiplier
|
||||
}
|
||||
|
||||
pub async fn account_sequence(&self) -> Result<SequenceResponse, NymdError>
|
||||
where
|
||||
C: SigningCosmWasmClient + Sync,
|
||||
@@ -962,6 +914,29 @@ impl<C> NymdClient<C> {
|
||||
.await
|
||||
}
|
||||
|
||||
#[execute("mixnet")]
|
||||
fn _compound_reward(
|
||||
&self,
|
||||
operator: Option<String>,
|
||||
delegator: Option<String>,
|
||||
mix_identity: Option<IdentityKey>,
|
||||
proxy: Option<String>,
|
||||
fee: Option<Fee>,
|
||||
) -> (ExecuteMsg, Option<Fee>)
|
||||
where
|
||||
C: SigningCosmWasmClient + Sync,
|
||||
{
|
||||
(
|
||||
ExecuteMsg::CompoundReward {
|
||||
operator,
|
||||
delegator,
|
||||
mix_identity,
|
||||
proxy,
|
||||
},
|
||||
fee,
|
||||
)
|
||||
}
|
||||
|
||||
#[execute("mixnet")]
|
||||
fn _compound_operator_reward(&self, fee: Option<Fee>) -> (ExecuteMsg, Option<Fee>)
|
||||
where
|
||||
|
||||
@@ -49,7 +49,7 @@ impl<C: SigningCosmWasmClient + Sync + Send> MultisigSigningClient for NymdClien
|
||||
) -> Result<ExecuteResult, NymdError> {
|
||||
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
||||
let release_funds_req = CoconutBandwidthExecuteMsg::ReleaseFunds {
|
||||
funds: Coin::new(voucher_value, DEFAULT_NETWORK.mix_denom().base),
|
||||
funds: Coin::new(voucher_value, DEFAULT_NETWORK.denom()),
|
||||
};
|
||||
let release_funds_msg = CosmosMsg::Wasm(WasmMsg::Execute {
|
||||
contract_addr: self.coconut_bandwidth_contract_address().to_string(),
|
||||
|
||||
@@ -214,7 +214,7 @@ mod tests {
|
||||
];
|
||||
|
||||
for prefix in prefixes {
|
||||
let addrs = match prefix.as_ref() {
|
||||
let addrs = match prefix {
|
||||
"nymt" => vec![
|
||||
"nymt1jw6mp7d5xqc7w6xm79lha27glmd0vdt339me94",
|
||||
"nymt1h5hgn94nsq4kh99rjj794hr5h5q6yfm23rjshv",
|
||||
@@ -229,7 +229,7 @@ mod tests {
|
||||
};
|
||||
for (idx, mnemonic) in mnemonics.iter().enumerate() {
|
||||
let wallet =
|
||||
DirectSecp256k1HdWallet::from_mnemonic(&prefix, mnemonic.parse().unwrap())
|
||||
DirectSecp256k1HdWallet::from_mnemonic(prefix, mnemonic.parse().unwrap())
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
wallet.try_derive_accounts().unwrap()[0].address,
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
|
||||
use crate::validator_api::error::ValidatorAPIError;
|
||||
use crate::validator_api::routes::{CORE_STATUS_COUNT, SINCE_ARG};
|
||||
use coconut_interface::{
|
||||
BlindSignRequestBody, BlindedSignatureResponse, ExecuteReleaseFundsRequestBody,
|
||||
ProposeReleaseFundsRequestBody, ProposeReleaseFundsResponse, VerificationKeyResponse,
|
||||
VerifyCredentialBody, VerifyCredentialResponse,
|
||||
};
|
||||
use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixNodeBond};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use url::Url;
|
||||
use validator_api_requests::coconut::{
|
||||
BlindSignRequestBody, BlindedSignatureResponse, CosmosAddressResponse,
|
||||
ExecuteReleaseFundsRequestBody, ProposeReleaseFundsRequestBody, ProposeReleaseFundsResponse,
|
||||
VerificationKeyResponse, VerifyCredentialBody, VerifyCredentialResponse,
|
||||
};
|
||||
use validator_api_requests::models::{
|
||||
CoreNodeStatusResponse, InclusionProbabilityResponse, MixNodeBondAnnotated,
|
||||
MixnodeStatusResponse, RewardEstimationResponse, StakeSaturationResponse, UptimeResponse,
|
||||
@@ -376,19 +376,6 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_cosmos_address(&self) -> Result<CosmosAddressResponse, ValidatorAPIError> {
|
||||
self.query_validator_api(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::COCONUT_ROUTES,
|
||||
routes::BANDWIDTH,
|
||||
routes::COCONUT_COSMOS_ADDRESS,
|
||||
],
|
||||
NO_PARAMS,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn verify_bandwidth_credential(
|
||||
&self,
|
||||
request_body: &VerifyCredentialBody,
|
||||
|
||||
@@ -17,7 +17,6 @@ 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 COCONUT_COSMOS_ADDRESS: &str = "cosmos-address";
|
||||
pub const COCONUT_VERIFY_BANDWIDTH_CREDENTIAL: &str = "verify-bandwidth-credential";
|
||||
pub const COCONUT_PROPOSE_RELEASE_FUNDS: &str = "propose-release-funds";
|
||||
pub const COCONUT_EXECUTE_RELEASE_FUNDS: &str = "execute-release-funds";
|
||||
|
||||
@@ -10,7 +10,7 @@ use error::CoconutInterfaceError;
|
||||
|
||||
pub use nymcoconut::*;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Getters, CopyGetters, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Serialize, Deserialize, Getters, CopyGetters, Clone, PartialEq)]
|
||||
pub struct Credential {
|
||||
#[getset(get = "pub")]
|
||||
n_params: u32,
|
||||
@@ -127,6 +127,171 @@ impl Bytable for Credential {
|
||||
|
||||
impl Base58 for Credential {}
|
||||
|
||||
#[derive(Serialize, Deserialize, Getters, CopyGetters)]
|
||||
pub struct VerifyCredentialBody {
|
||||
#[getset(get = "pub")]
|
||||
credential: Credential,
|
||||
#[getset(get = "pub")]
|
||||
proposal_id: u64,
|
||||
}
|
||||
|
||||
impl VerifyCredentialBody {
|
||||
pub fn new(credential: Credential, proposal_id: u64) -> VerifyCredentialBody {
|
||||
VerifyCredentialBody {
|
||||
credential,
|
||||
proposal_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct VerifyCredentialResponse {
|
||||
pub verification_result: bool,
|
||||
}
|
||||
|
||||
impl VerifyCredentialResponse {
|
||||
pub fn new(verification_result: bool) -> Self {
|
||||
VerifyCredentialResponse {
|
||||
verification_result,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All strings are base58 encoded representations of structs
|
||||
#[derive(Clone, 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,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn public_attributes(&self) -> Vec<Attribute> {
|
||||
self.public_attributes
|
||||
.iter()
|
||||
.map(|x| Attribute::try_from_bs58(x).unwrap())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct BlindedSignatureResponse {
|
||||
pub remote_key: [u8; 32],
|
||||
pub encrypted_signature: Vec<u8>,
|
||||
}
|
||||
|
||||
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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct VerificationKeyResponse {
|
||||
pub key: VerificationKey,
|
||||
}
|
||||
|
||||
impl VerificationKeyResponse {
|
||||
pub fn new(key: VerificationKey) -> VerificationKeyResponse {
|
||||
VerificationKeyResponse { key }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Getters, CopyGetters)]
|
||||
pub struct ProposeReleaseFundsRequestBody {
|
||||
#[getset(get = "pub")]
|
||||
credential: Credential,
|
||||
}
|
||||
|
||||
impl ProposeReleaseFundsRequestBody {
|
||||
pub fn new(credential: Credential) -> Self {
|
||||
ProposeReleaseFundsRequestBody { credential }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ProposeReleaseFundsResponse {
|
||||
pub proposal_id: u64,
|
||||
}
|
||||
|
||||
impl ProposeReleaseFundsResponse {
|
||||
pub fn new(proposal_id: u64) -> Self {
|
||||
ProposeReleaseFundsResponse { proposal_id }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Getters, CopyGetters)]
|
||||
pub struct ExecuteReleaseFundsRequestBody {
|
||||
#[getset(get = "pub")]
|
||||
proposal_id: u64,
|
||||
}
|
||||
|
||||
impl ExecuteReleaseFundsRequestBody {
|
||||
pub fn new(proposal_id: u64) -> Self {
|
||||
ExecuteReleaseFundsRequestBody { proposal_id }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
pub struct DepositData {
|
||||
deposit_info: String,
|
||||
identity_key: String,
|
||||
|
||||
@@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::deposit::DepositData;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
pub struct InstantiateMsg {
|
||||
pub multisig_addr: String,
|
||||
pub pool_addr: String,
|
||||
@@ -20,10 +20,10 @@ pub enum ExecuteMsg {
|
||||
ReleaseFunds { funds: Coin },
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum QueryMsg {}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct MigrateMsg {}
|
||||
|
||||
@@ -123,7 +123,7 @@ impl Display for Delegation {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
pub struct PagedMixDelegationsResponse {
|
||||
pub delegations: Vec<Delegation>,
|
||||
pub start_next_after: Option<(String, u64)>,
|
||||
@@ -138,7 +138,7 @@ impl PagedMixDelegationsResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
pub struct PagedDelegatorDelegationsResponse {
|
||||
pub delegations: Vec<Delegation>,
|
||||
pub start_next_after: Option<IdentityKey>,
|
||||
@@ -153,7 +153,7 @@ impl PagedDelegatorDelegationsResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
pub struct PagedAllDelegationsResponse {
|
||||
pub delegations: Vec<Delegation>,
|
||||
pub start_next_after: Option<(IdentityKey, Vec<u8>, u64)>,
|
||||
|
||||
@@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt::Display;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, PartialOrd, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize, JsonSchema)]
|
||||
pub struct Gateway {
|
||||
pub host: String,
|
||||
pub mix_port: u16,
|
||||
|
||||
@@ -59,7 +59,7 @@ pub(crate) mod string_rfc3339_offset_date_time {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, PartialOrd, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
|
||||
pub struct Interval {
|
||||
id: u32,
|
||||
#[serde(with = "string_rfc3339_offset_date_time")]
|
||||
|
||||
@@ -19,7 +19,7 @@ use std::fmt::Display;
|
||||
feature = "generate-ts",
|
||||
ts(export_to = "ts-packages/types/src/types/rust/RewardedSetNodeStatus.ts")
|
||||
)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Serialize, JsonSchema, PartialEq)]
|
||||
pub enum RewardedSetNodeStatus {
|
||||
Active,
|
||||
Standby,
|
||||
@@ -106,7 +106,7 @@ impl PendingUndelegate {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, PartialOrd, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize, JsonSchema)]
|
||||
pub struct MixNode {
|
||||
pub host: String,
|
||||
pub mix_port: u16,
|
||||
@@ -245,7 +245,7 @@ impl DelegatorRewardParams {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, JsonSchema, PartialEq, Eq, Serialize, Deserialize, Copy)]
|
||||
#[derive(Debug, Clone, JsonSchema, PartialEq, Serialize, Deserialize, Copy)]
|
||||
pub struct StoredNodeRewardResult {
|
||||
reward: Uint128,
|
||||
|
||||
|
||||
@@ -7,12 +7,12 @@ use crate::{Gateway, IdentityKey, MixNode};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
pub struct InstantiateMsg {
|
||||
pub rewarding_validator_address: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ExecuteMsg {
|
||||
UpdateRewardingValidatorAddress {
|
||||
@@ -32,6 +32,12 @@ pub enum ExecuteMsg {
|
||||
CompoundDelegatorReward {
|
||||
mix_identity: IdentityKey,
|
||||
},
|
||||
CompoundReward {
|
||||
operator: Option<String>,
|
||||
delegator: Option<String>,
|
||||
mix_identity: Option<IdentityKey>,
|
||||
proxy: Option<String>,
|
||||
},
|
||||
BondMixnode {
|
||||
mix_node: MixNode,
|
||||
owner_signature: String,
|
||||
@@ -112,7 +118,7 @@ pub enum ExecuteMsg {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum QueryMsg {
|
||||
GetCurrentOperatorCost {},
|
||||
@@ -205,6 +211,6 @@ pub enum QueryMsg {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct MigrateMsg {}
|
||||
|
||||
@@ -4,7 +4,7 @@ use cosmwasm_std::Uint128;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, JsonSchema, PartialEq, Eq, Serialize, Deserialize, Copy)]
|
||||
#[derive(Debug, Clone, JsonSchema, PartialEq, Serialize, Deserialize, Copy)]
|
||||
pub struct NodeEpochRewards {
|
||||
params: NodeRewardParams,
|
||||
result: StoredNodeRewardResult,
|
||||
@@ -105,7 +105,7 @@ impl NodeEpochRewards {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, JsonSchema, PartialEq, Eq, Serialize, Deserialize, Copy)]
|
||||
#[derive(Debug, Clone, JsonSchema, PartialEq, Serialize, Deserialize, Copy)]
|
||||
pub struct EpochRewardParams {
|
||||
epoch_reward_pool: Uint128,
|
||||
rewarded_set_size: Uint128,
|
||||
@@ -175,7 +175,7 @@ impl EpochRewardParams {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, JsonSchema, PartialEq, Eq, Serialize, Deserialize, Copy)]
|
||||
#[derive(Debug, Clone, JsonSchema, PartialEq, Serialize, Deserialize, Copy)]
|
||||
pub struct NodeRewardParams {
|
||||
reward_blockstamp: u64,
|
||||
uptime: Uint128,
|
||||
@@ -208,7 +208,7 @@ impl NodeRewardParams {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, JsonSchema, PartialEq, Eq, Serialize, Deserialize, Copy)]
|
||||
#[derive(Debug, Clone, JsonSchema, PartialEq, Serialize, Deserialize, Copy)]
|
||||
pub struct RewardParams {
|
||||
pub epoch: EpochRewardParams,
|
||||
pub node: NodeRewardParams,
|
||||
|
||||
@@ -27,7 +27,7 @@ impl LayerDistribution {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
pub struct ContractStateParams {
|
||||
// so currently interval_length is being unused and validator API performs rewarding
|
||||
// based on its own interval length config value. I guess that's fine for time being
|
||||
@@ -72,7 +72,7 @@ impl Display for ContractStateParams {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct RewardingResult {
|
||||
pub node_reward: Uint128,
|
||||
}
|
||||
@@ -124,21 +124,21 @@ pub type IdentityKey = String;
|
||||
pub type IdentityKeyRef<'a> = &'a str;
|
||||
pub type SphinxKey = String;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema)]
|
||||
pub struct PagedRewardedSetResponse {
|
||||
pub identities: Vec<(IdentityKey, RewardedSetNodeStatus)>,
|
||||
pub start_next_after: Option<IdentityKey>,
|
||||
pub at_height: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
pub struct RewardedSetUpdateDetails {
|
||||
pub refresh_rate_blocks: u64,
|
||||
pub last_refreshed_block: u64,
|
||||
pub current_height: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
pub struct IntervalRewardedSetHeightsResponse {
|
||||
pub interval_id: u32,
|
||||
pub heights: Vec<u64>,
|
||||
|
||||
@@ -44,7 +44,7 @@ pub enum ExecuteMsg {
|
||||
}
|
||||
|
||||
// We can also add this as a cw3 extension
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, JsonSchema, Debug)]
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum QueryMsg {
|
||||
/// Return ThresholdResponse
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::{Coin, Timestamp};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -11,7 +11,7 @@ pub mod events;
|
||||
pub mod messages;
|
||||
|
||||
pub fn one_ucoin() -> Coin {
|
||||
Coin::new(1, MIX_DENOM.base)
|
||||
Coin::new(1, DENOM)
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||
@@ -19,7 +19,7 @@ pub fn one_ucoin() -> Coin {
|
||||
feature = "generate-ts",
|
||||
ts(export_to = "ts-packages/types/src/types/rust/Period.ts")
|
||||
)]
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, JsonSchema)]
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, JsonSchema)]
|
||||
pub enum Period {
|
||||
Before,
|
||||
In(usize),
|
||||
|
||||
@@ -3,17 +3,17 @@ use mixnet_contract_common::{Gateway, IdentityKey, MixNode};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct InitMsg {
|
||||
pub mixnet_contract_address: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct MigrateMsg {}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, Default)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema, Default)]
|
||||
pub struct VestingSpecification {
|
||||
start_time: Option<u64>,
|
||||
period_seconds: Option<u64>,
|
||||
@@ -118,7 +118,7 @@ pub enum ExecuteMsg {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum QueryMsg {
|
||||
LockedCoins {
|
||||
|
||||
@@ -15,7 +15,6 @@ url = "2.2"
|
||||
coconut-interface = { path = "../coconut-interface" }
|
||||
crypto = { path = "../crypto", features = ["rand", "asymmetric", "symmetric", "hashing"] }
|
||||
network-defaults = { path = "../network-defaults" }
|
||||
validator-api-requests = { path = "../../validator-api/validator-api-requests" }
|
||||
validator-client = { path = "../client-libs/validator-client" }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
|
||||
use coconut_interface::{
|
||||
aggregate_signature_shares, aggregate_verification_keys, prove_bandwidth_credential, Attribute,
|
||||
BlindedSignature, Credential, Parameters, Signature, SignatureShare, VerificationKey,
|
||||
BlindSignRequestBody, BlindedSignature, 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 validator_api_requests::coconut::BlindSignRequestBody;
|
||||
|
||||
use crate::coconut::bandwidth::{BandwidthVoucher, PRIVATE_ATTRIBUTES, PUBLIC_ATTRIBUTES};
|
||||
use crate::coconut::params::{
|
||||
|
||||
@@ -15,7 +15,7 @@ use std::ops::Neg;
|
||||
use zeroize::Zeroize;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(test, derive(Clone, PartialEq, Eq))]
|
||||
#[cfg_attr(test, derive(Clone, PartialEq))]
|
||||
pub struct Ciphertexts {
|
||||
pub rr: [G1Projective; NUM_CHUNKS],
|
||||
pub ss: [G1Projective; NUM_CHUNKS],
|
||||
|
||||
@@ -335,7 +335,7 @@ pub fn keygen(params: &Params, mut rng: impl RngCore) -> (DecryptionKey, PublicK
|
||||
(dk, key_with_proof)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct PublicKey(pub(crate) G1Projective);
|
||||
|
||||
impl PublicKey {
|
||||
@@ -345,7 +345,7 @@ impl PublicKey {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub struct PublicKeyWithProof {
|
||||
pub(crate) key: PublicKey,
|
||||
pub(crate) proof: ProofOfDiscreteLog,
|
||||
|
||||
@@ -243,7 +243,7 @@ impl Zeroize for Tau {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
|
||||
pub struct Epoch(EpochStore);
|
||||
|
||||
impl Epoch {
|
||||
|
||||
@@ -68,7 +68,7 @@ impl<'a> Instance<'a> {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(test, derive(Clone, PartialEq, Eq))]
|
||||
#[cfg_attr(test, derive(Clone, PartialEq))]
|
||||
pub struct ProofOfChunking {
|
||||
y0: G1Projective,
|
||||
bb: Vec<G1Projective>,
|
||||
|
||||
@@ -14,7 +14,7 @@ const DISCRETE_LOG_DOMAIN: &[u8] =
|
||||
b"NYM_COCONUT_NIDKG_V01_CS01_WITH_BLS12381_XMD:SHA-256_SSWU_RO_PROOF_DISCRETE_LOG";
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub struct ProofOfDiscreteLog {
|
||||
pub(crate) rand_commitment: G1Projective,
|
||||
pub(crate) response: Scalar,
|
||||
|
||||
@@ -77,7 +77,7 @@ impl<'a> Instance<'a> {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(test, derive(Clone, PartialEq, Eq))]
|
||||
#[cfg_attr(test, derive(Clone, PartialEq))]
|
||||
pub struct ProofOfSecretSharing {
|
||||
ff: G1Projective,
|
||||
aa: G2Projective,
|
||||
|
||||
@@ -18,7 +18,7 @@ use std::collections::BTreeMap;
|
||||
use zeroize::Zeroize;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub struct Dealing {
|
||||
pub public_coefficients: PublicCoefficients,
|
||||
pub ciphertexts: Ciphertexts,
|
||||
|
||||
@@ -10,7 +10,7 @@ use rand_core::RngCore;
|
||||
use std::ops::{Add, Index, IndexMut};
|
||||
use zeroize::Zeroize;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct PublicCoefficients {
|
||||
pub(crate) coefficients: Vec<G2Projective>,
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use config::defaults::DEFAULT_NETWORK;
|
||||
use subtle_encoding::bech32;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Bech32Error {
|
||||
DecodeFailed(String),
|
||||
WrongPrefix(String),
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{
|
||||
DefaultNetworkDetails, DenomDetailsOwned, NymNetworkDetails, ValidatorDetails,
|
||||
MAINNET_DEFAULTS, QA_DEFAULTS, SANDBOX_DEFAULTS,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{collections::HashMap, fmt, str::FromStr};
|
||||
|
||||
use crate::{
|
||||
DefaultNetworkDetails, ValidatorDetails, MAINNET_DEFAULTS, QA_DEFAULTS, SANDBOX_DEFAULTS,
|
||||
};
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
@@ -15,97 +16,60 @@ pub enum NetworkDefaultsError {
|
||||
MalformedNetworkProvided(String),
|
||||
}
|
||||
|
||||
// the reason for allowing it is that this is just a temporary solution
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||
#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||
pub enum Network {
|
||||
QA,
|
||||
SANDBOX,
|
||||
MAINNET,
|
||||
CUSTOM { details: NymNetworkDetails },
|
||||
}
|
||||
|
||||
impl Network {
|
||||
pub fn new_custom(details: NymNetworkDetails) -> Self {
|
||||
Network::CUSTOM { details }
|
||||
}
|
||||
|
||||
pub fn details(&self) -> NymNetworkDetails {
|
||||
fn details(&self) -> &DefaultNetworkDetails<'_> {
|
||||
match self {
|
||||
Self::QA => (&*QA_DEFAULTS).into(),
|
||||
Self::SANDBOX => (&*SANDBOX_DEFAULTS).into(),
|
||||
Self::MAINNET => (&*MAINNET_DEFAULTS).into(),
|
||||
// I dislike the clone here, but for compatibility reasons we cannot define other networks with `NymNetworkDetails` directly yet
|
||||
Self::CUSTOM { details } => details.clone(),
|
||||
Self::QA => &QA_DEFAULTS,
|
||||
Self::SANDBOX => &SANDBOX_DEFAULTS,
|
||||
Self::MAINNET => &MAINNET_DEFAULTS,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bech32_prefix(&self) -> String {
|
||||
self.details().chain_details.bech32_account_prefix
|
||||
pub fn bech32_prefix(&self) -> &str {
|
||||
self.details().bech32_prefix
|
||||
}
|
||||
|
||||
pub fn mix_denom(&self) -> DenomDetailsOwned {
|
||||
self.details().chain_details.mix_denom
|
||||
pub fn denom(&self) -> &str {
|
||||
self.details().denom
|
||||
}
|
||||
|
||||
pub fn stake_denom(&self) -> DenomDetailsOwned {
|
||||
self.details().chain_details.stake_denom
|
||||
pub fn mixnet_contract_address(&self) -> &str {
|
||||
self.details().mixnet_contract_address
|
||||
}
|
||||
|
||||
pub fn base_mix_denom(&self) -> String {
|
||||
self.details().chain_details.mix_denom.base
|
||||
pub fn vesting_contract_address(&self) -> &str {
|
||||
self.details().vesting_contract_address
|
||||
}
|
||||
|
||||
pub fn base_stake_denom(&self) -> String {
|
||||
self.details().chain_details.stake_denom.base
|
||||
pub fn bandwidth_claim_contract_address(&self) -> &str {
|
||||
self.details().bandwidth_claim_contract_address
|
||||
}
|
||||
|
||||
pub fn mixnet_contract_address(&self) -> Option<String> {
|
||||
self.details().contracts.mixnet_contract_address
|
||||
pub fn coconut_bandwidth_contract_address(&self) -> &str {
|
||||
self.details().coconut_bandwidth_contract_address
|
||||
}
|
||||
|
||||
pub fn vesting_contract_address(&self) -> Option<String> {
|
||||
self.details().contracts.vesting_contract_address
|
||||
pub fn multisig_contract_address(&self) -> &str {
|
||||
self.details().multisig_contract_address
|
||||
}
|
||||
|
||||
pub fn bandwidth_claim_contract_address(&self) -> Option<String> {
|
||||
self.details().contracts.bandwidth_claim_contract_address
|
||||
}
|
||||
|
||||
pub fn coconut_bandwidth_contract_address(&self) -> Option<String> {
|
||||
self.details().contracts.coconut_bandwidth_contract_address
|
||||
}
|
||||
|
||||
pub fn multisig_contract_address(&self) -> Option<String> {
|
||||
self.details().contracts.multisig_contract_address
|
||||
}
|
||||
|
||||
pub fn validators(&self) -> Vec<ValidatorDetails> {
|
||||
self.details().endpoints
|
||||
}
|
||||
|
||||
// only used in mixnet contract tests, but I don't want to be messing with that code now
|
||||
pub fn rewarding_validator_address(&self) -> &str {
|
||||
match self {
|
||||
Network::QA => crate::qa::REWARDING_VALIDATOR_ADDRESS,
|
||||
Network::SANDBOX => crate::sandbox::REWARDING_VALIDATOR_ADDRESS,
|
||||
Network::MAINNET => crate::mainnet::REWARDING_VALIDATOR_ADDRESS,
|
||||
Network::CUSTOM { .. } => {
|
||||
panic!("rewarding validator address is unavailable for a custom network")
|
||||
}
|
||||
}
|
||||
self.details().rewarding_validator_address
|
||||
}
|
||||
|
||||
// this should be handled differently, but I don't want to break compatibility
|
||||
pub fn statistics_service_url(&self) -> &str {
|
||||
match self {
|
||||
Network::MAINNET => crate::mainnet::STATISTICS_SERVICE_DOMAIN_ADDRESS,
|
||||
Network::SANDBOX => crate::mainnet::STATISTICS_SERVICE_DOMAIN_ADDRESS,
|
||||
Network::QA => crate::mainnet::STATISTICS_SERVICE_DOMAIN_ADDRESS,
|
||||
Network::CUSTOM { .. } => {
|
||||
panic!("statistics service url is unavailable for a custom network")
|
||||
}
|
||||
}
|
||||
self.details().statistics_service_url
|
||||
}
|
||||
|
||||
pub fn validators(&self) -> impl Iterator<Item = &ValidatorDetails> {
|
||||
self.details().validators.iter()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +94,6 @@ impl fmt::Display for Network {
|
||||
Network::QA => f.write_str("QA"),
|
||||
Network::SANDBOX => f.write_str("Sandbox"),
|
||||
Network::MAINNET => f.write_str("Mainnet"),
|
||||
Network::CUSTOM { .. } => f.write_str("Custom"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -138,8 +101,7 @@ impl fmt::Display for Network {
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
|
||||
pub struct NetworkDetails {
|
||||
bech32_prefix: String,
|
||||
mix_denom: DenomDetailsOwned,
|
||||
stake_denom: DenomDetailsOwned,
|
||||
denom: String,
|
||||
mixnet_contract_address: String,
|
||||
vesting_contract_address: String,
|
||||
bandwidth_claim_contract_address: String,
|
||||
@@ -147,12 +109,11 @@ pub struct NetworkDetails {
|
||||
validators: Vec<ValidatorDetails>,
|
||||
}
|
||||
|
||||
impl From<&DefaultNetworkDetails> for NetworkDetails {
|
||||
fn from(details: &DefaultNetworkDetails) -> Self {
|
||||
impl From<&DefaultNetworkDetails<'_>> for NetworkDetails {
|
||||
fn from(details: &DefaultNetworkDetails<'_>) -> Self {
|
||||
NetworkDetails {
|
||||
bech32_prefix: details.bech32_prefix.into(),
|
||||
mix_denom: details.mix_denom.into(),
|
||||
stake_denom: details.stake_denom.into(),
|
||||
denom: details.denom.into(),
|
||||
mixnet_contract_address: details.mixnet_contract_address.into(),
|
||||
vesting_contract_address: details.vesting_contract_address.into(),
|
||||
bandwidth_claim_contract_address: details.bandwidth_claim_contract_address.into(),
|
||||
@@ -162,37 +123,6 @@ impl From<&DefaultNetworkDetails> for NetworkDetails {
|
||||
}
|
||||
}
|
||||
|
||||
// this also has to exist for compatibility reasons since I don't want to be touching the wallet now
|
||||
impl From<NymNetworkDetails> for NetworkDetails {
|
||||
fn from(details: NymNetworkDetails) -> Self {
|
||||
NetworkDetails {
|
||||
bech32_prefix: details.chain_details.bech32_account_prefix,
|
||||
mix_denom: details.chain_details.mix_denom,
|
||||
stake_denom: details.chain_details.stake_denom,
|
||||
mixnet_contract_address: details
|
||||
.contracts
|
||||
.mixnet_contract_address
|
||||
.unwrap_or_default(),
|
||||
vesting_contract_address: details
|
||||
.contracts
|
||||
.vesting_contract_address
|
||||
.unwrap_or_default(),
|
||||
bandwidth_claim_contract_address: details
|
||||
.contracts
|
||||
.bandwidth_claim_contract_address
|
||||
.unwrap_or_default(),
|
||||
statistics_service_url: "".to_string(),
|
||||
validators: details.endpoints,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkDetails {
|
||||
pub fn base_mix_denom(&self) -> &str {
|
||||
&self.mix_denom.base
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
|
||||
pub struct SupportedNetworks {
|
||||
networks: HashMap<Network, NetworkDetails>,
|
||||
@@ -203,10 +133,7 @@ impl SupportedNetworks {
|
||||
SupportedNetworks {
|
||||
networks: support
|
||||
.into_iter()
|
||||
.map(|n| {
|
||||
let details = n.details().into();
|
||||
(n, details)
|
||||
})
|
||||
.map(|n| (n, n.details().into()))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
@@ -217,10 +144,10 @@ impl SupportedNetworks {
|
||||
.map(|network_details| network_details.bech32_prefix.as_str())
|
||||
}
|
||||
|
||||
pub fn base_mix_denom(&self, network: Network) -> Option<&str> {
|
||||
pub fn denom(&self, network: Network) -> Option<&str> {
|
||||
self.networks
|
||||
.get(&network)
|
||||
.map(|network_details| network_details.base_mix_denom())
|
||||
.map(|network_details| network_details.denom.as_str())
|
||||
}
|
||||
|
||||
pub fn mixnet_contract_address(&self, network: Network) -> Option<&str> {
|
||||
|
||||
@@ -17,228 +17,78 @@ pub mod sandbox;
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(network = "mainnet")] {
|
||||
pub const DEFAULT_NETWORK: all::Network = all::Network::MAINNET;
|
||||
pub const MIX_DENOM: DenomDetails = mainnet::MIX_DENOM;
|
||||
pub const STAKE_DENOM: DenomDetails = mainnet::STAKE_DENOM;
|
||||
pub const DENOM: &str = mainnet::DENOM;
|
||||
pub const STAKE_DENOM: &str = mainnet::STAKE_DENOM;
|
||||
|
||||
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = mainnet::_ETH_CONTRACT_ADDRESS;
|
||||
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = mainnet::_ETH_ERC20_CONTRACT_ADDRESS;
|
||||
|
||||
} else if #[cfg(network = "qa")] {
|
||||
pub const DEFAULT_NETWORK: all::Network = all::Network::QA;
|
||||
pub const MIX_DENOM: DenomDetails = qa::MIX_DENOM;
|
||||
pub const STAKE_DENOM: DenomDetails = qa::STAKE_DENOM;
|
||||
pub const DENOM: &str = qa::DENOM;
|
||||
pub const STAKE_DENOM: &str = qa::STAKE_DENOM;
|
||||
|
||||
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = qa::_ETH_CONTRACT_ADDRESS;
|
||||
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = qa::_ETH_ERC20_CONTRACT_ADDRESS;
|
||||
|
||||
} else if #[cfg(network = "sandbox")] {
|
||||
pub const DEFAULT_NETWORK: all::Network = all::Network::SANDBOX;
|
||||
pub const MIX_DENOM: DenomDetails = sandbox::MIX_DENOM;
|
||||
pub const STAKE_DENOM: DenomDetails = sandbox::STAKE_DENOM;
|
||||
pub const DENOM: &str = sandbox::DENOM;
|
||||
pub const STAKE_DENOM: &str = sandbox::STAKE_DENOM;
|
||||
|
||||
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = sandbox::_ETH_CONTRACT_ADDRESS;
|
||||
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = sandbox::_ETH_ERC20_CONTRACT_ADDRESS;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||
pub struct ChainDetails {
|
||||
pub bech32_account_prefix: String,
|
||||
pub mix_denom: DenomDetailsOwned,
|
||||
pub stake_denom: DenomDetailsOwned,
|
||||
}
|
||||
|
||||
// by default we assume the same defaults as mainnet, i.e. same prefixes and denoms
|
||||
impl Default for ChainDetails {
|
||||
fn default() -> Self {
|
||||
ChainDetails {
|
||||
bech32_account_prefix: mainnet::BECH32_PREFIX.into(),
|
||||
mix_denom: mainnet::MIX_DENOM.into(),
|
||||
stake_denom: mainnet::STAKE_DENOM.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||
pub struct NymContracts {
|
||||
pub mixnet_contract_address: Option<String>,
|
||||
pub vesting_contract_address: Option<String>,
|
||||
pub bandwidth_claim_contract_address: Option<String>,
|
||||
pub coconut_bandwidth_contract_address: Option<String>,
|
||||
pub multisig_contract_address: Option<String>,
|
||||
}
|
||||
|
||||
// I wanted to use the simpler `NetworkDetails` name, but there's a clash
|
||||
// with `NetworkDetails` defined in all.rs...
|
||||
#[derive(Clone, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||
pub struct NymNetworkDetails {
|
||||
pub chain_details: ChainDetails,
|
||||
pub endpoints: Vec<ValidatorDetails>,
|
||||
pub contracts: NymContracts,
|
||||
}
|
||||
|
||||
impl NymNetworkDetails {
|
||||
pub fn new() -> Self {
|
||||
NymNetworkDetails::default()
|
||||
}
|
||||
|
||||
pub fn new_qa() -> Self {
|
||||
(&*QA_DEFAULTS).into()
|
||||
}
|
||||
|
||||
pub fn new_sandbox() -> Self {
|
||||
(&*SANDBOX_DEFAULTS).into()
|
||||
}
|
||||
|
||||
pub fn new_mainnet() -> Self {
|
||||
(&*MAINNET_DEFAULTS).into()
|
||||
}
|
||||
|
||||
pub fn current_default() -> Self {
|
||||
// backwards compatibility reasons
|
||||
DEFAULT_NETWORK.details()
|
||||
}
|
||||
|
||||
pub fn with_bech32_account_prefix<S: Into<String>>(mut self, prefix: S) -> Self {
|
||||
self.chain_details.bech32_account_prefix = prefix.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_mix_denom(mut self, mix_denom: DenomDetailsOwned) -> Self {
|
||||
self.chain_details.mix_denom = mix_denom;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_stake_denom(mut self, stake_denom: DenomDetailsOwned) -> Self {
|
||||
self.chain_details.stake_denom = stake_denom;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_base_mix_denom<S: Into<String>>(mut self, base_mix_denom: S) -> Self {
|
||||
self.chain_details.mix_denom = DenomDetailsOwned::base_only(base_mix_denom.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_base_stake_denom<S: Into<String>>(mut self, base_stake_denom: S) -> Self {
|
||||
self.chain_details.stake_denom = DenomDetailsOwned::base_only(base_stake_denom.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_validator_endpoint(mut self, endpoint: ValidatorDetails) -> Self {
|
||||
self.endpoints.push(endpoint);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_mixnet_contract<S: Into<String>>(mut self, contract: Option<S>) -> Self {
|
||||
self.contracts.mixnet_contract_address = contract.map(Into::into);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_vesting_contract<S: Into<String>>(mut self, contract: Option<S>) -> Self {
|
||||
self.contracts.vesting_contract_address = contract.map(Into::into);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_bandwidth_claim_contract<S: Into<String>>(mut self, contract: Option<S>) -> Self {
|
||||
self.contracts.bandwidth_claim_contract_address = contract.map(Into::into);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_coconut_bandwidth_contract<S: Into<String>>(mut self, contract: Option<S>) -> Self {
|
||||
self.contracts.coconut_bandwidth_contract_address = contract.map(Into::into);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_multisig_contract<S: Into<String>>(mut self, contract: Option<S>) -> Self {
|
||||
self.contracts.multisig_contract_address = contract.map(Into::into);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
// This conversion only exists for convenience reasons until
|
||||
// we can completely phase out `DefaultNetworkDetails`
|
||||
impl<'a> From<&'a DefaultNetworkDetails> for NymNetworkDetails {
|
||||
fn from(details: &'a DefaultNetworkDetails) -> Self {
|
||||
fn parse_optional_str(raw: &str) -> Option<String> {
|
||||
if raw.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(raw.into())
|
||||
}
|
||||
}
|
||||
|
||||
NymNetworkDetails {
|
||||
chain_details: ChainDetails {
|
||||
bech32_account_prefix: details.bech32_prefix.into(),
|
||||
mix_denom: details.mix_denom.into(),
|
||||
stake_denom: details.stake_denom.into(),
|
||||
},
|
||||
endpoints: details.validators.clone(),
|
||||
contracts: NymContracts {
|
||||
mixnet_contract_address: parse_optional_str(details.mixnet_contract_address),
|
||||
vesting_contract_address: parse_optional_str(details.vesting_contract_address),
|
||||
bandwidth_claim_contract_address: parse_optional_str(
|
||||
details.bandwidth_claim_contract_address,
|
||||
),
|
||||
coconut_bandwidth_contract_address: parse_optional_str(
|
||||
details.coconut_bandwidth_contract_address,
|
||||
),
|
||||
multisig_contract_address: parse_optional_str(details.multisig_contract_address),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Since these are lazily constructed, we can afford to switch some of them to stronger types in the
|
||||
// future. If we do this, and also get rid of the references we could potentially unify with
|
||||
// `NetworkDetails`.
|
||||
pub struct DefaultNetworkDetails {
|
||||
bech32_prefix: &'static str,
|
||||
mix_denom: DenomDetails,
|
||||
stake_denom: DenomDetails,
|
||||
mixnet_contract_address: &'static str,
|
||||
vesting_contract_address: &'static str,
|
||||
bandwidth_claim_contract_address: &'static str,
|
||||
coconut_bandwidth_contract_address: &'static str,
|
||||
multisig_contract_address: &'static str,
|
||||
#[allow(dead_code)]
|
||||
rewarding_validator_address: &'static str,
|
||||
statistics_service_url: &'static str,
|
||||
#[derive(Debug)]
|
||||
pub struct DefaultNetworkDetails<'a> {
|
||||
bech32_prefix: &'a str,
|
||||
denom: &'a str,
|
||||
mixnet_contract_address: &'a str,
|
||||
vesting_contract_address: &'a str,
|
||||
bandwidth_claim_contract_address: &'a str,
|
||||
coconut_bandwidth_contract_address: &'a str,
|
||||
multisig_contract_address: &'a str,
|
||||
rewarding_validator_address: &'a str,
|
||||
statistics_service_url: &'a str,
|
||||
validators: Vec<ValidatorDetails>,
|
||||
}
|
||||
|
||||
static MAINNET_DEFAULTS: Lazy<DefaultNetworkDetails> = Lazy::new(|| DefaultNetworkDetails {
|
||||
bech32_prefix: mainnet::BECH32_PREFIX,
|
||||
mix_denom: mainnet::MIX_DENOM,
|
||||
stake_denom: mainnet::STAKE_DENOM,
|
||||
mixnet_contract_address: mainnet::MIXNET_CONTRACT_ADDRESS,
|
||||
vesting_contract_address: mainnet::VESTING_CONTRACT_ADDRESS,
|
||||
bandwidth_claim_contract_address: mainnet::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
|
||||
coconut_bandwidth_contract_address: mainnet::COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
|
||||
multisig_contract_address: mainnet::MULTISIG_CONTRACT_ADDRESS,
|
||||
rewarding_validator_address: mainnet::REWARDING_VALIDATOR_ADDRESS,
|
||||
statistics_service_url: mainnet::STATISTICS_SERVICE_DOMAIN_ADDRESS,
|
||||
validators: mainnet::validators(),
|
||||
});
|
||||
static MAINNET_DEFAULTS: Lazy<DefaultNetworkDetails<'static>> =
|
||||
Lazy::new(|| DefaultNetworkDetails {
|
||||
bech32_prefix: mainnet::BECH32_PREFIX,
|
||||
denom: mainnet::DENOM,
|
||||
mixnet_contract_address: mainnet::MIXNET_CONTRACT_ADDRESS,
|
||||
vesting_contract_address: mainnet::VESTING_CONTRACT_ADDRESS,
|
||||
bandwidth_claim_contract_address: mainnet::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
|
||||
coconut_bandwidth_contract_address: mainnet::COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
|
||||
multisig_contract_address: mainnet::MULTISIG_CONTRACT_ADDRESS,
|
||||
rewarding_validator_address: mainnet::REWARDING_VALIDATOR_ADDRESS,
|
||||
statistics_service_url: mainnet::STATISTICS_SERVICE_DOMAIN_ADDRESS,
|
||||
validators: mainnet::validators(),
|
||||
});
|
||||
|
||||
static SANDBOX_DEFAULTS: Lazy<DefaultNetworkDetails> = Lazy::new(|| DefaultNetworkDetails {
|
||||
bech32_prefix: sandbox::BECH32_PREFIX,
|
||||
mix_denom: sandbox::MIX_DENOM,
|
||||
stake_denom: sandbox::STAKE_DENOM,
|
||||
mixnet_contract_address: sandbox::MIXNET_CONTRACT_ADDRESS,
|
||||
vesting_contract_address: sandbox::VESTING_CONTRACT_ADDRESS,
|
||||
bandwidth_claim_contract_address: sandbox::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
|
||||
coconut_bandwidth_contract_address: sandbox::COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
|
||||
multisig_contract_address: sandbox::MULTISIG_CONTRACT_ADDRESS,
|
||||
rewarding_validator_address: sandbox::REWARDING_VALIDATOR_ADDRESS,
|
||||
statistics_service_url: sandbox::STATISTICS_SERVICE_DOMAIN_ADDRESS,
|
||||
validators: sandbox::validators(),
|
||||
});
|
||||
static SANDBOX_DEFAULTS: Lazy<DefaultNetworkDetails<'static>> =
|
||||
Lazy::new(|| DefaultNetworkDetails {
|
||||
bech32_prefix: sandbox::BECH32_PREFIX,
|
||||
denom: sandbox::DENOM,
|
||||
mixnet_contract_address: sandbox::MIXNET_CONTRACT_ADDRESS,
|
||||
vesting_contract_address: sandbox::VESTING_CONTRACT_ADDRESS,
|
||||
bandwidth_claim_contract_address: sandbox::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
|
||||
coconut_bandwidth_contract_address: sandbox::COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
|
||||
multisig_contract_address: sandbox::MULTISIG_CONTRACT_ADDRESS,
|
||||
rewarding_validator_address: sandbox::REWARDING_VALIDATOR_ADDRESS,
|
||||
statistics_service_url: sandbox::STATISTICS_SERVICE_DOMAIN_ADDRESS,
|
||||
validators: sandbox::validators(),
|
||||
});
|
||||
|
||||
static QA_DEFAULTS: Lazy<DefaultNetworkDetails> = Lazy::new(|| DefaultNetworkDetails {
|
||||
static QA_DEFAULTS: Lazy<DefaultNetworkDetails<'static>> = Lazy::new(|| DefaultNetworkDetails {
|
||||
bech32_prefix: qa::BECH32_PREFIX,
|
||||
mix_denom: qa::MIX_DENOM,
|
||||
stake_denom: qa::STAKE_DENOM,
|
||||
denom: qa::DENOM,
|
||||
mixnet_contract_address: qa::MIXNET_CONTRACT_ADDRESS,
|
||||
vesting_contract_address: qa::VESTING_CONTRACT_ADDRESS,
|
||||
bandwidth_claim_contract_address: qa::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
|
||||
@@ -249,74 +99,27 @@ static QA_DEFAULTS: Lazy<DefaultNetworkDetails> = Lazy::new(|| DefaultNetworkDet
|
||||
validators: qa::validators(),
|
||||
});
|
||||
|
||||
#[derive(Debug, Copy, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||
pub struct DenomDetails {
|
||||
pub base: &'static str,
|
||||
pub display: &'static str,
|
||||
// i.e. display_amount * 10^display_exponent = base_amount
|
||||
pub display_exponent: u32,
|
||||
}
|
||||
|
||||
impl DenomDetails {
|
||||
pub const fn new(base: &'static str, display: &'static str, display_exponent: u32) -> Self {
|
||||
DenomDetails {
|
||||
base,
|
||||
display,
|
||||
display_exponent,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||
pub struct DenomDetailsOwned {
|
||||
pub base: String,
|
||||
pub display: String,
|
||||
// i.e. display_amount * 10^display_exponent = base_amount
|
||||
pub display_exponent: u32,
|
||||
}
|
||||
|
||||
impl From<DenomDetails> for DenomDetailsOwned {
|
||||
fn from(details: DenomDetails) -> Self {
|
||||
DenomDetailsOwned {
|
||||
base: details.base.to_owned(),
|
||||
display: details.display.to_owned(),
|
||||
display_exponent: details.display_exponent,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DenomDetailsOwned {
|
||||
pub fn base_only(base: String) -> Self {
|
||||
DenomDetailsOwned {
|
||||
base: base.clone(),
|
||||
display: base,
|
||||
display_exponent: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||
pub struct ValidatorDetails {
|
||||
// it is assumed those values are always valid since they're being provided in our defaults file
|
||||
pub nymd_url: String,
|
||||
// Right now api_url is optional as we are not running the api reliably on all validators
|
||||
// however, later on it should be a mandatory field
|
||||
pub api_url: Option<String>,
|
||||
// TODO: I'd argue this one should also have a field like `gas_price` since its a validator-specific setting
|
||||
}
|
||||
|
||||
impl ValidatorDetails {
|
||||
pub fn new<S: Into<String>>(nymd_url: S, api_url: Option<S>) -> Self {
|
||||
pub fn new(nymd_url: &str, api_url: Option<&str>) -> Self {
|
||||
ValidatorDetails {
|
||||
nymd_url: nymd_url.into(),
|
||||
api_url: api_url.map(Into::into),
|
||||
nymd_url: nymd_url.to_string(),
|
||||
api_url: api_url.map(ToString::to_string),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_nymd_only<S: Into<String>>(nymd_url: S) -> Self {
|
||||
pub fn new_with_name(nymd_url: &str, api_url: Option<&str>) -> Self {
|
||||
ValidatorDetails {
|
||||
nymd_url: nymd_url.into(),
|
||||
api_url: None,
|
||||
nymd_url: nymd_url.to_string(),
|
||||
api_url: api_url.map(ToString::to_string),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,7 +146,6 @@ pub fn default_statistics_service_url() -> Url {
|
||||
pub fn default_nymd_endpoints() -> Vec<Url> {
|
||||
DEFAULT_NETWORK
|
||||
.validators()
|
||||
.iter()
|
||||
.map(ValidatorDetails::nymd_url)
|
||||
.collect()
|
||||
}
|
||||
@@ -351,7 +153,6 @@ pub fn default_nymd_endpoints() -> Vec<Url> {
|
||||
pub fn default_api_endpoints() -> Vec<Url> {
|
||||
DEFAULT_NETWORK
|
||||
.validators()
|
||||
.iter()
|
||||
.filter_map(ValidatorDetails::api_url)
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{DenomDetails, ValidatorDetails};
|
||||
use crate::ValidatorDetails;
|
||||
|
||||
pub(crate) const BECH32_PREFIX: &str = "n";
|
||||
|
||||
pub const MIX_DENOM: DenomDetails = DenomDetails::new("unym", "nym", 6);
|
||||
pub const STAKE_DENOM: DenomDetails = DenomDetails::new("unyx", "nyx", 6);
|
||||
pub const DENOM: &str = "unym";
|
||||
pub const STAKE_DENOM: &str = "unyx";
|
||||
|
||||
pub(crate) const MIXNET_CONTRACT_ADDRESS: &str =
|
||||
"n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjyvg3g";
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{DenomDetails, ValidatorDetails};
|
||||
use crate::ValidatorDetails;
|
||||
|
||||
pub(crate) const BECH32_PREFIX: &str = "n";
|
||||
|
||||
pub const MIX_DENOM: DenomDetails = DenomDetails::new("unym", "nym", 6);
|
||||
pub const STAKE_DENOM: DenomDetails = DenomDetails::new("unyx", "nyx", 6);
|
||||
pub const DENOM: &str = "unym";
|
||||
pub const STAKE_DENOM: &str = "unyx";
|
||||
|
||||
pub(crate) const MIXNET_CONTRACT_ADDRESS: &str =
|
||||
"n1suhgf5svhu4usrurvxzlgn54ksxmn8gljarjtxqnapv8kjnp4nrsd3qaep";
|
||||
@@ -23,7 +22,7 @@ pub(crate) const _ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] =
|
||||
hex_literal::hex!("0000000000000000000000000000000000000000");
|
||||
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "n1tfzd4qz3a45u8p4mr5zmzv66457uwjgcl05jdq";
|
||||
|
||||
pub(crate) const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "http://0.0.0.0";
|
||||
pub(crate) const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "";
|
||||
pub(crate) fn validators() -> Vec<ValidatorDetails> {
|
||||
vec![ValidatorDetails::new(
|
||||
"https://qa-validator.nymtech.net",
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{DenomDetails, ValidatorDetails};
|
||||
use crate::ValidatorDetails;
|
||||
|
||||
pub(crate) const BECH32_PREFIX: &str = "nymt";
|
||||
|
||||
pub const MIX_DENOM: DenomDetails = DenomDetails::new("unymt", "nymt", 6);
|
||||
pub const STAKE_DENOM: DenomDetails = DenomDetails::new("unyxt", "nyxt", 6);
|
||||
pub const DENOM: &str = "unymt";
|
||||
pub const STAKE_DENOM: &str = "unyxt";
|
||||
|
||||
pub(crate) const MIXNET_CONTRACT_ADDRESS: &str = "nymt1ghd753shjuwexxywmgs4xz7x2q732vcnstz02j";
|
||||
pub(crate) const VESTING_CONTRACT_ADDRESS: &str = "nymt14ejqjyq8um4p3xfqj74yld5waqljf88fn549lh";
|
||||
@@ -21,7 +20,7 @@ pub(crate) const _ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] =
|
||||
hex_literal::hex!("E8883BAeF3869e14E4823F46662e81D4F7d2A81F");
|
||||
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "nymt1jh0s6qu6tuw9ut438836mmn7f3f2wencrnmdj4";
|
||||
|
||||
pub(crate) const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "http://0.0.0.0";
|
||||
pub(crate) const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "";
|
||||
pub(crate) fn validators() -> Vec<ValidatorDetails> {
|
||||
vec![ValidatorDetails::new(
|
||||
"https://sandbox-validator.nymtech.net",
|
||||
|
||||
@@ -20,7 +20,7 @@ pub type EphemeralKey = Scalar;
|
||||
|
||||
/// Two G1 points representing ElGamal ciphertext
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub struct Ciphertext(pub(crate) G1Projective, pub(crate) G1Projective);
|
||||
|
||||
impl TryFrom<&[u8]> for Ciphertext {
|
||||
@@ -73,7 +73,7 @@ impl Ciphertext {
|
||||
|
||||
/// PrivateKey used in the ElGamal encryption scheme to recover the plaintext
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub struct PrivateKey(pub(crate) Scalar);
|
||||
|
||||
impl PrivateKey {
|
||||
@@ -121,7 +121,7 @@ impl Base58 for PrivateKey {}
|
||||
// TODO: perhaps be more explicit and apart from gamma also store generator and group order?
|
||||
/// PublicKey used in the ElGamal encryption scheme to produce the ciphertext
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub struct PublicKey(G1Projective);
|
||||
|
||||
impl PublicKey {
|
||||
|
||||
@@ -23,7 +23,7 @@ use crate::Attribute;
|
||||
type ChallengeDigest = Sha256;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub struct ProofCmCs {
|
||||
challenge: Scalar,
|
||||
response_opening: Scalar,
|
||||
@@ -327,7 +327,7 @@ impl ProofCmCs {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct ProofKappaZeta {
|
||||
// c
|
||||
challenge: Scalar,
|
||||
|
||||
@@ -25,7 +25,7 @@ use crate::utils::{hash_g1, try_deserialize_g1_projective};
|
||||
// TODO NAMING: double check this one
|
||||
// Lambda
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub struct BlindSignRequest {
|
||||
// cm
|
||||
commitment: G1Projective,
|
||||
|
||||
@@ -23,7 +23,7 @@ use crate::utils::{
|
||||
use crate::Base58;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub struct SecretKey {
|
||||
pub(crate) x: Scalar,
|
||||
pub(crate) ys: Vec<Scalar>,
|
||||
@@ -114,7 +114,7 @@ impl Base58 for SecretKey {}
|
||||
|
||||
// TODO: perhaps change points to affine representation
|
||||
// to make verification slightly more efficient?
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct VerificationKey {
|
||||
// TODO add gen2 as per the paper or imply it from the fact library is using bls381?
|
||||
pub(crate) alpha: G2Projective,
|
||||
@@ -351,7 +351,7 @@ impl Bytable for VerificationKey {
|
||||
impl Base58 for VerificationKey {}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub struct KeyPair {
|
||||
secret_key: SecretKey,
|
||||
verification_key: VerificationKey,
|
||||
|
||||
@@ -28,7 +28,7 @@ pub mod verification;
|
||||
pub type SignerIndex = u64;
|
||||
|
||||
// (h, s)
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct Signature(pub(crate) G1Projective, pub(crate) G1Projective);
|
||||
|
||||
pub type PartialSignature = Signature;
|
||||
@@ -103,7 +103,7 @@ impl Bytable for Signature {
|
||||
impl Base58 for Signature {}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub struct BlindedSignature(G1Projective, G1Projective);
|
||||
|
||||
impl Bytable for BlindedSignature {
|
||||
|
||||
@@ -20,7 +20,7 @@ use crate::Attribute;
|
||||
|
||||
// TODO NAMING: this whole thing
|
||||
// Theta
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Theta {
|
||||
// blinded_message (kappa)
|
||||
pub blinded_message: G2Projective,
|
||||
|
||||
@@ -45,7 +45,7 @@ pub mod set;
|
||||
/// Both of those concepts as well as their structures, i.e. `Set` and `Fragment`
|
||||
/// are further explained in the respective files.
|
||||
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum ChunkingError {
|
||||
InvalidPayloadLengthError,
|
||||
TooBigMessageToSplit,
|
||||
|
||||
@@ -46,7 +46,7 @@ impl FramedSphinxPacket {
|
||||
// Contains any metadata that might be useful for sending between mix nodes.
|
||||
// TODO: in theory all those data could be put in a single `u8` by setting appropriate bits,
|
||||
// but would that really be worth it?
|
||||
#[derive(Debug, Default, PartialEq, Eq, Copy, Clone)]
|
||||
#[derive(Debug, Default, PartialEq, Copy, Clone)]
|
||||
pub struct Header {
|
||||
/// Represents type and consequently size of the included SphinxPacket.
|
||||
pub(crate) packet_size: PacketSize,
|
||||
|
||||
@@ -7,7 +7,7 @@ use std::convert::TryFrom;
|
||||
pub struct InvalidPacketMode;
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum PacketMode {
|
||||
/// Represents 'normal' packet sent through the network that should be delayed by an appropriate
|
||||
/// value at each hop.
|
||||
|
||||
@@ -21,7 +21,7 @@ const EXTENDED_PACKET_SIZE: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE + 32 * 1
|
||||
pub struct InvalidPacketSize;
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum PacketSize {
|
||||
// for example instant messaging use case
|
||||
RegularPacket = 1,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::cmp::Ordering;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum MessageError {
|
||||
NoData,
|
||||
IndexTooShort,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::ConnectionId;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum ResponseError {
|
||||
ConnectionIdTooShort,
|
||||
NoData,
|
||||
|
||||
@@ -18,4 +18,4 @@ sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "chrono"]}
|
||||
thiserror = "1"
|
||||
tokio = { version = "1.19.1", features = [ "time" ] }
|
||||
|
||||
network-defaults = { path = "../network-defaults" }
|
||||
network-defaults = { path = "../network-defaults" }
|
||||
@@ -26,7 +26,6 @@ use validator_client::nymd::{Coin, CosmosCoin};
|
||||
EnumString,
|
||||
EnumVariantNames,
|
||||
PartialEq,
|
||||
Eq,
|
||||
JsonSchema,
|
||||
)]
|
||||
#[serde(rename_all = "UPPERCASE")]
|
||||
@@ -60,7 +59,7 @@ impl TryFrom<CosmosDenom> for CurrencyDenom {
|
||||
type Error = TypesError;
|
||||
|
||||
fn try_from(value: CosmosDenom) -> Result<Self, Self::Error> {
|
||||
CurrencyDenom::parse(value.as_ref())
|
||||
CurrencyDenom::parse(&value.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +68,7 @@ impl TryFrom<CosmosDenom> for CurrencyDenom {
|
||||
feature = "generate-ts",
|
||||
ts(export_to = "ts-packages/types/src/types/rust/CurrencyStringMajorAmount.ts")
|
||||
)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
pub struct MajorAmountString(String); // see https://github.com/Aleph-Alpha/ts-rs/issues/51 for exporting type aliases
|
||||
|
||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||
@@ -78,7 +77,7 @@ pub struct MajorAmountString(String); // see https://github.com/Aleph-Alpha/ts-r
|
||||
ts(export_to = "ts-packages/types/src/types/rust/Currency.ts")
|
||||
)]
|
||||
// #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
pub struct MajorCurrencyAmount {
|
||||
// temporarly going back to original impl to speed up merge
|
||||
pub amount: MajorAmountString,
|
||||
|
||||
@@ -14,7 +14,7 @@ use crate::error::TypesError;
|
||||
feature = "generate-ts",
|
||||
ts(export_to = "ts-packages/types/src/types/rust/Delegation.ts")
|
||||
)]
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema)]
|
||||
pub struct Delegation {
|
||||
pub owner: String,
|
||||
pub node_identity: String,
|
||||
@@ -52,7 +52,7 @@ impl TryFrom<MixnetContractDelegation> for Delegation {
|
||||
feature = "generate-ts",
|
||||
ts(export_to = "ts-packages/types/src/types/rust/DelegationRecord.ts")
|
||||
)]
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema)]
|
||||
pub struct DelegationRecord {
|
||||
pub amount: MajorCurrencyAmount,
|
||||
pub block_height: u64,
|
||||
@@ -88,7 +88,7 @@ pub struct DelegationWithEverything {
|
||||
feature = "generate-ts",
|
||||
ts(export_to = "ts-packages/types/src/types/rust/DelegationResult.ts")
|
||||
)]
|
||||
#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Eq, Debug)]
|
||||
#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Debug)]
|
||||
pub struct DelegationResult {
|
||||
source_address: String,
|
||||
target_address: String,
|
||||
@@ -127,7 +127,7 @@ impl TryFrom<MixnetContractDelegation> for DelegationResult {
|
||||
feature = "generate-ts",
|
||||
ts(export_to = "ts-packages/types/src/types/rust/DelegationEventKind.ts")
|
||||
)]
|
||||
#[derive(Clone, Deserialize, Serialize, PartialEq, Eq, JsonSchema, Debug)]
|
||||
#[derive(Clone, Deserialize, Serialize, PartialEq, JsonSchema, Debug)]
|
||||
pub enum DelegationEventKind {
|
||||
Delegate,
|
||||
Undelegate,
|
||||
@@ -138,7 +138,7 @@ pub enum DelegationEventKind {
|
||||
feature = "generate-ts",
|
||||
ts(export_to = "ts-packages/types/src/types/rust/DelegationEvent.ts")
|
||||
)]
|
||||
#[derive(Clone, Deserialize, Serialize, PartialEq, Eq, JsonSchema, Debug)]
|
||||
#[derive(Clone, Deserialize, Serialize, PartialEq, JsonSchema, Debug)]
|
||||
pub struct DelegationEvent {
|
||||
pub kind: DelegationEventKind,
|
||||
pub node_identity: String,
|
||||
@@ -181,7 +181,7 @@ impl TryFrom<ContractDelegationEvent> for DelegationEvent {
|
||||
feature = "generate-ts",
|
||||
ts(export_to = "ts-packages/types/src/types/rust/PendingUndelegate.ts")
|
||||
)]
|
||||
#[derive(Deserialize, Serialize, PartialEq, Eq, JsonSchema, Clone, Debug)]
|
||||
#[derive(Deserialize, Serialize, PartialEq, JsonSchema, Clone, Debug)]
|
||||
pub struct PendingUndelegate {
|
||||
mix_identity: String,
|
||||
delegate: String,
|
||||
|
||||
@@ -51,8 +51,6 @@ pub enum TypesError {
|
||||
#[from]
|
||||
source: cosmwasm_std::DecimalRangeExceeded,
|
||||
},
|
||||
#[error("No validator API URL configured")]
|
||||
NoValidatorApiUrlConfigured,
|
||||
#[error("{0} is not a valid amount string")]
|
||||
InvalidAmount(String),
|
||||
#[error("{0} is not a valid denomination string")]
|
||||
@@ -80,7 +78,6 @@ impl From<ValidatorClientError> for TypesError {
|
||||
ValidatorClientError::ValidatorAPIError { source } => source.into(),
|
||||
ValidatorClientError::MalformedUrlProvided(e) => e.into(),
|
||||
ValidatorClientError::NymdError(e) => e.into(),
|
||||
ValidatorClientError::NoAPIUrlAvailable => TypesError::NoValidatorApiUrlConfigured,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,84 +1,18 @@
|
||||
use crate::currency::MajorCurrencyAmount;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use validator_client::nymd::Fee;
|
||||
|
||||
#[cfg(feature = "generate-ts")]
|
||||
use ts_rs::{Dependency, TS};
|
||||
use crate::currency::MajorCurrencyAmount;
|
||||
|
||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||
#[cfg_attr(
|
||||
feature = "generate-ts",
|
||||
ts(export_to = "ts-packages/types/src/types/rust/FeeDetails.ts")
|
||||
)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct FeeDetails {
|
||||
// expected to be used by the wallet in order to display detailed fee information to the user
|
||||
pub amount: Option<MajorCurrencyAmount>,
|
||||
#[cfg_attr(feature = "generate-ts", ts(skip))]
|
||||
pub fee: Fee,
|
||||
}
|
||||
|
||||
#[cfg(feature = "generate-ts")]
|
||||
impl TS for FeeDetails {
|
||||
const EXPORT_TO: Option<&'static str> = Some("ts-packages/types/src/types/rust/FeeDetails.ts");
|
||||
|
||||
fn decl() -> String {
|
||||
format!("type {} = {};", Self::name(), Self::inline())
|
||||
}
|
||||
|
||||
fn name() -> String {
|
||||
"FeeDetails".into()
|
||||
}
|
||||
|
||||
fn inline() -> String {
|
||||
"{ amount: MajorCurrencyAmount | null, fee: Fee }".into()
|
||||
}
|
||||
|
||||
fn dependencies() -> Vec<Dependency> {
|
||||
vec![
|
||||
Dependency::from_ty::<MajorCurrencyAmount>()
|
||||
.expect("TS was incorrectly defined on `CurrencyDenom`"),
|
||||
Dependency::from_ty::<ts_type_helpers::Fee>()
|
||||
.expect("TS was incorrectly defined on `ts_type_helpers::Fee`"),
|
||||
]
|
||||
}
|
||||
|
||||
fn transparent() -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// this should really be sealed and NEVER EVER used as "normal" types,
|
||||
// but due to our typescript requirements, we have to expose it to generate
|
||||
// the types...
|
||||
#[cfg(feature = "generate-ts")]
|
||||
pub mod ts_type_helpers {
|
||||
use serde::{Deserialize, Serialize};
|
||||
use validator_client::nymd::GasAdjustment;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, ts_rs::TS)]
|
||||
#[ts(export_to = "ts-packages/types/src/types/rust/Fee.ts")]
|
||||
pub enum Fee {
|
||||
Manual(CosmosFee),
|
||||
Auto(Option<GasAdjustment>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, ts_rs::TS)]
|
||||
#[ts(export_to = "ts-packages/types/src/types/rust/CosmosFee.ts")]
|
||||
// this should corresponds to cosmrs::tx::Fee
|
||||
// IMPORTANT NOTE: this should work as of cosmrs 0.7.1 due to their `FromStr` implementations
|
||||
// on the type. The below struct might have to get readjusted if we update cosmrs!!
|
||||
pub struct CosmosFee {
|
||||
amount: Vec<Coin>,
|
||||
gas_limit: u64,
|
||||
payer: Option<String>,
|
||||
granter: Option<String>,
|
||||
}
|
||||
|
||||
// Note: I've got a feeling this one will bite us hard at some point...
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, ts_rs::TS)]
|
||||
#[ts(export_to = "ts-packages/types/src/types/rust/Coin.ts")]
|
||||
// this should corresponds to cosmrs::Coin
|
||||
// IMPORTANT NOTE: this should work as of cosmrs 0.7.1 due to their `FromStr` implementations
|
||||
// on the type. The below struct might have to get readjusted if we update cosmrs!!
|
||||
pub struct Coin {
|
||||
denom: String,
|
||||
// this is not entirely true, but for the purposes
|
||||
// of ts_rs, it's sufficient for the time being
|
||||
amount: u64,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize};
|
||||
feature = "generate-ts",
|
||||
ts(export_to = "ts-packages/types/src/types/rust/Gateway.ts")
|
||||
)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, PartialOrd, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize, JsonSchema)]
|
||||
pub struct Gateway {
|
||||
pub host: String,
|
||||
pub mix_port: u16,
|
||||
@@ -52,7 +52,7 @@ impl From<MixnetContractGateway> for Gateway {
|
||||
feature = "generate-ts",
|
||||
ts(export_to = "ts-packages/types/src/types/rust/GatewayBond.ts")
|
||||
)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
pub struct GatewayBond {
|
||||
pub pledge_amount: MajorCurrencyAmount,
|
||||
pub owner: String,
|
||||
|
||||
@@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize};
|
||||
feature = "generate-ts",
|
||||
ts(export_to = "ts-packages/types/src/types/rust/Mixnode.ts")
|
||||
)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, PartialOrd, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize, JsonSchema)]
|
||||
pub struct MixNode {
|
||||
pub host: String,
|
||||
pub mix_port: u16,
|
||||
@@ -56,7 +56,7 @@ impl From<MixnetContractMixNode> for MixNode {
|
||||
feature = "generate-ts",
|
||||
ts(export_to = "ts-packages/types/src/types/rust/MixNodeBond.ts")
|
||||
)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
pub struct MixNodeBond {
|
||||
pub pledge_amount: MajorCurrencyAmount,
|
||||
pub total_delegation: MajorCurrencyAmount,
|
||||
|
||||
@@ -62,7 +62,7 @@ pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Respon
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use bandwidth_claim_contract::payment::PagedPaymentResponse;
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
|
||||
use cosmwasm_std::{coins, from_binary};
|
||||
|
||||
@@ -91,11 +91,11 @@ pub mod tests {
|
||||
|
||||
// Contract balance should match what we initialized it as
|
||||
assert_eq!(
|
||||
coins(0, MIX_DENOM.base),
|
||||
coins(0, DENOM),
|
||||
vec![deps
|
||||
.as_ref()
|
||||
.querier
|
||||
.query_balance(env.contract.address, MIX_DENOM.base)
|
||||
.query_balance(env.contract.address, DENOM)
|
||||
.unwrap()]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ use bandwidth_claim_contract::payment::Payment;
|
||||
const PREFIX_PAYMENTS: &[u8] = b"payments";
|
||||
const PREFIX_STATUS: &[u8] = b"status";
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
pub enum Status {
|
||||
Unchecked,
|
||||
Checked,
|
||||
|
||||
@@ -63,10 +63,11 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::support::tests::helpers::*;
|
||||
use coconut_bandwidth_contract_common::deposit::DepositData;
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
|
||||
use cosmwasm_std::{coins, Addr};
|
||||
use cw_multi_test::Executor;
|
||||
use serde::de::Unexpected::Str;
|
||||
|
||||
#[test]
|
||||
fn initialize_contract() {
|
||||
@@ -83,20 +84,20 @@ mod tests {
|
||||
|
||||
// Contract balance should be 0
|
||||
assert_eq!(
|
||||
coins(0, MIX_DENOM.base),
|
||||
coins(0, DENOM),
|
||||
vec![deps
|
||||
.as_ref()
|
||||
.querier
|
||||
.query_balance(env.contract.address, MIX_DENOM.base)
|
||||
.query_balance(env.contract.address, DENOM)
|
||||
.unwrap()]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deposit_and_release() {
|
||||
let init_funds = coins(10, MIX_DENOM.base);
|
||||
let deposit_funds = coins(1, MIX_DENOM.base);
|
||||
let release_funds = coins(2, MIX_DENOM.base);
|
||||
let init_funds = coins(10, DENOM);
|
||||
let deposit_funds = coins(1, DENOM);
|
||||
let release_funds = coins(2, DENOM);
|
||||
let mut app = mock_app(&init_funds);
|
||||
let multisig_addr = String::from(MULTISIG_CONTRACT);
|
||||
let pool_addr = String::from(POOL_CONTRACT);
|
||||
@@ -156,7 +157,7 @@ mod tests {
|
||||
&[],
|
||||
)
|
||||
.unwrap();
|
||||
let pool_bal = app.wrap().query_balance(pool_addr, MIX_DENOM.base).unwrap();
|
||||
let pool_bal = app.wrap().query_balance(pool_addr, DENOM).unwrap();
|
||||
assert_eq!(pool_bal, deposit_funds[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use cosmwasm_std::StdError;
|
||||
use cw_controllers::AdminError;
|
||||
use thiserror::Error;
|
||||
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
|
||||
/// Custom errors for contract failure conditions.
|
||||
///
|
||||
@@ -22,7 +22,7 @@ pub enum ContractError {
|
||||
#[error("No coin was sent for voucher")]
|
||||
NoCoin,
|
||||
|
||||
#[error("Wrong coin denomination, you must send {}", MIX_DENOM.base)]
|
||||
#[error("Wrong coin denomination, you must send {}", DENOM)]
|
||||
WrongDenom,
|
||||
|
||||
#[error("There aren't enough funds in the contract")]
|
||||
|
||||
@@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
pub const ADMIN: Admin = Admin::new("admin");
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, JsonSchema, Debug)]
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
|
||||
pub struct Config {
|
||||
pub multisig_addr: Addr,
|
||||
pub pool_addr: Addr,
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#[cfg(test)]
|
||||
pub mod helpers {
|
||||
pub const OWNER: &str = "admin0001";
|
||||
pub const SOMEBODY: &str = "somebody";
|
||||
pub const MULTISIG_CONTRACT: &str = "multisig contract address";
|
||||
pub const POOL_CONTRACT: &str = "mix pool contract address";
|
||||
|
||||
@@ -22,7 +23,7 @@ pub mod helpers {
|
||||
let env = mock_env();
|
||||
let info = mock_info("creator", &[]);
|
||||
instantiate(deps.as_mut(), env.clone(), info, msg).unwrap();
|
||||
deps
|
||||
return deps;
|
||||
}
|
||||
|
||||
pub fn mock_app(init_funds: &[Coin]) -> App {
|
||||
|
||||
@@ -11,7 +11,7 @@ use coconut_bandwidth_contract_common::events::{
|
||||
DEPOSITED_FUNDS_EVENT_TYPE, DEPOSIT_ENCRYPTION_KEY, DEPOSIT_IDENTITY_KEY, DEPOSIT_INFO,
|
||||
DEPOSIT_VALUE,
|
||||
};
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
|
||||
pub(crate) fn deposit_funds(
|
||||
_deps: DepsMut<'_>,
|
||||
@@ -25,7 +25,7 @@ pub(crate) fn deposit_funds(
|
||||
if info.funds.len() > 1 {
|
||||
return Err(ContractError::MultipleDenoms);
|
||||
}
|
||||
if info.funds[0].denom != MIX_DENOM.base {
|
||||
if info.funds[0].denom != DENOM {
|
||||
return Err(ContractError::WrongDenom);
|
||||
}
|
||||
|
||||
@@ -45,12 +45,10 @@ pub(crate) fn release_funds(
|
||||
info: MessageInfo,
|
||||
funds: Coin,
|
||||
) -> Result<Response, ContractError> {
|
||||
if funds.denom != MIX_DENOM.base {
|
||||
if funds.denom != DENOM {
|
||||
return Err(ContractError::WrongDenom);
|
||||
}
|
||||
let current_balance = deps
|
||||
.querier
|
||||
.query_balance(env.contract.address, MIX_DENOM.base)?;
|
||||
let current_balance = deps.querier.query_balance(env.contract.address, DENOM)?;
|
||||
if funds.amount > current_balance.amount {
|
||||
return Err(ContractError::NotEnoughFunds);
|
||||
}
|
||||
@@ -92,7 +90,7 @@ mod tests {
|
||||
Err(ContractError::NoCoin)
|
||||
);
|
||||
|
||||
let coin = Coin::new(1000000, MIX_DENOM.base);
|
||||
let coin = Coin::new(1000000, DENOM);
|
||||
let second_coin = Coin::new(1000000, "some_denom");
|
||||
|
||||
let info = mock_info("requester", &[coin, second_coin.clone()]);
|
||||
@@ -122,7 +120,7 @@ mod tests {
|
||||
verification_key.clone(),
|
||||
encryption_key.clone(),
|
||||
);
|
||||
let coin = Coin::new(deposit_value, MIX_DENOM.base);
|
||||
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();
|
||||
@@ -171,7 +169,7 @@ mod tests {
|
||||
let mut deps = helpers::init_contract();
|
||||
let env = mock_env();
|
||||
let invalid_admin = "invalid admin";
|
||||
let funds = Coin::new(1, MIX_DENOM.base);
|
||||
let funds = Coin::new(1, DENOM);
|
||||
|
||||
let err = release_funds(
|
||||
deps.as_mut(),
|
||||
@@ -207,7 +205,7 @@ mod tests {
|
||||
fn valid_release() {
|
||||
let mut deps = helpers::init_contract();
|
||||
let env = mock_env();
|
||||
let coin = Coin::new(1, MIX_DENOM.base);
|
||||
let coin = Coin::new(1, DENOM);
|
||||
|
||||
deps.querier
|
||||
.update_balance(env.contract.address.clone(), vec![coin.clone()]);
|
||||
|
||||
@@ -107,6 +107,19 @@ pub fn execute(
|
||||
msg: ExecuteMsg,
|
||||
) -> Result<Response, ContractError> {
|
||||
match msg {
|
||||
ExecuteMsg::CompoundReward {
|
||||
operator,
|
||||
delegator,
|
||||
mix_identity,
|
||||
proxy,
|
||||
} => crate::rewards::transactions::try_compound_reward(
|
||||
deps,
|
||||
env,
|
||||
operator,
|
||||
delegator,
|
||||
mix_identity,
|
||||
proxy,
|
||||
),
|
||||
ExecuteMsg::UpdateRewardingValidatorAddress { address } => {
|
||||
try_update_rewarding_validator_address(deps, info, address)
|
||||
}
|
||||
@@ -275,7 +288,7 @@ pub fn execute(
|
||||
)
|
||||
}
|
||||
ExecuteMsg::ReconcileDelegations {} => {
|
||||
crate::delegations::transactions::try_reconcile_all_delegation_events(deps, info)
|
||||
crate::delegations::transactions::try_reconcile_all_delegation_events(deps)
|
||||
}
|
||||
ExecuteMsg::CheckpointMixnodes {} => {
|
||||
crate::mixnodes::transactions::try_checkpoint_mixnodes(
|
||||
@@ -443,6 +456,7 @@ pub fn query(deps: Deps<'_>, env: Env, msg: QueryMsg) -> Result<QueryResponse, C
|
||||
Ok(query_res?)
|
||||
}
|
||||
|
||||
|
||||
#[entry_point]
|
||||
pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
|
||||
Ok(Default::default())
|
||||
@@ -452,7 +466,7 @@ pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Respon
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use crate::support::tests;
|
||||
use config::defaults::{DEFAULT_NETWORK, MIX_DENOM};
|
||||
use config::defaults::{DEFAULT_NETWORK, DENOM};
|
||||
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
|
||||
use cosmwasm_std::{coins, from_binary};
|
||||
use mixnet_contract_common::PagedMixnodeResponse;
|
||||
@@ -484,7 +498,7 @@ pub mod tests {
|
||||
|
||||
// Contract balance should match what we initialized it as
|
||||
assert_eq!(
|
||||
coins(0, MIX_DENOM.base),
|
||||
coins(0, DENOM),
|
||||
tests::queries::query_contract_balance(env.contract.address, deps)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ pub(crate) fn query_mixnode_delegations_paged(
|
||||
pub(crate) mod tests {
|
||||
use super::*;
|
||||
use crate::support::tests::test_helpers;
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::{coin, Addr, Storage};
|
||||
use rand::Rng;
|
||||
|
||||
@@ -385,7 +385,7 @@ pub(crate) mod tests {
|
||||
let delegation = Delegation::new(
|
||||
delegation_owner.clone(),
|
||||
node_identity.clone(),
|
||||
coin(1234, MIX_DENOM.base),
|
||||
coin(1234, DENOM),
|
||||
1234,
|
||||
None,
|
||||
);
|
||||
@@ -433,7 +433,7 @@ pub(crate) mod tests {
|
||||
let delegation = Delegation::new(
|
||||
delegation_owner2,
|
||||
node_identity1.clone(),
|
||||
coin(1234, MIX_DENOM.base),
|
||||
coin(1234, DENOM),
|
||||
1234,
|
||||
None,
|
||||
);
|
||||
@@ -460,7 +460,7 @@ pub(crate) mod tests {
|
||||
let delegation = Delegation::new(
|
||||
delegation_owner1.clone(),
|
||||
node_identity2,
|
||||
coin(1234, MIX_DENOM.base),
|
||||
coin(1234, DENOM),
|
||||
1234,
|
||||
None,
|
||||
);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user