Compare commits
135 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3c82d58343 | |||
| 1f05e956fb | |||
| dbfe9a0b92 | |||
| eb3ed98f94 | |||
| 9d6a4ea99d | |||
| 5701ea5c02 | |||
| e3cd1f7eb7 | |||
| 080616a461 | |||
| 2a0ccf30f9 | |||
| cef9e17796 | |||
| 4d0b5b34ec | |||
| 6af0dbd1da | |||
| 2004148710 | |||
| 1e805be5ad | |||
| 7a25e600b3 | |||
| 1fd7d54715 | |||
| 43a6e62050 | |||
| 39fb131d95 | |||
| 9533c2440a | |||
| aab2be1fbd | |||
| 448dcbeaa8 | |||
| 29b07b4904 | |||
| cceb7a40bd | |||
| fb4b32359d | |||
| 7ca92cc487 | |||
| 15d612eff6 | |||
| 021c2d14f2 | |||
| 3b85927a90 | |||
| b386388b82 | |||
| 7941b7099f | |||
| 6604d927c5 | |||
| 4fedf05b64 | |||
| fa00f85a31 | |||
| abf5a2d307 | |||
| 8e0000cb0b | |||
| cc27911671 | |||
| b598f1d1db | |||
| d4f10c1d68 | |||
| 1d7ff40d02 | |||
| 72703b36e1 | |||
| ecf7a40010 | |||
| 272e9187d2 | |||
| 69a1f3773c | |||
| 15c97b1cae | |||
| 2660ef59f7 | |||
| 12a06d9dfe | |||
| 6399cd24c8 | |||
| f30b5162e8 | |||
| 229329ae4c | |||
| a3bb5e466d | |||
| 65d893a70b | |||
| e0944e5238 | |||
| b451d4b709 | |||
| 1507e48158 | |||
| 6e7a7ed4a6 | |||
| af4801ac47 | |||
| b748c55d4e | |||
| 84e5bfc286 | |||
| 96bd9ecf49 | |||
| 092851976f | |||
| 9da1f82cca | |||
| 8c60927fe2 | |||
| ec5ef1db56 | |||
| 5dee6dd44f | |||
| aa6f5ad664 | |||
| 201b5cc56f | |||
| 510553a697 | |||
| b81967c9f5 | |||
| fadff7888b | |||
| 24854f9254 | |||
| 8ea7726e81 | |||
| ea32a897b2 | |||
| 5d7a14c5ab | |||
| cad68b8d6c | |||
| 1d125ed97f | |||
| 36d4ec5a72 | |||
| 44981b8621 | |||
| bd68797432 | |||
| 636759789c | |||
| c03a859223 | |||
| b269cdae31 | |||
| 2177a396b9 | |||
| 4c50dd64f4 | |||
| be9d3a48bb | |||
| 37d890c634 | |||
| 6287583f4b | |||
| c7760c6c10 | |||
| 2c0058c477 | |||
| 02fb2e56ca | |||
| 8b2c72eb91 | |||
| 805eb31728 | |||
| 22d4c89e48 | |||
| 28d5ac92b3 | |||
| a2e678587c | |||
| 0ac7bb5f03 | |||
| 7f45cbd5df | |||
| 8ce709bbb4 | |||
| 46db139f79 | |||
| 069c5bf332 | |||
| 54a4653e7d | |||
| ea1f689c71 | |||
| 3d60299b22 | |||
| 4d9dfac812 | |||
| 0012294dc0 | |||
| 5b5063676f | |||
| 833556020d | |||
| 0cdb68bcf3 | |||
| aa00eb70d5 | |||
| a882d10848 | |||
| c03a58ae9a | |||
| 2caf79fba0 | |||
| eda1822653 | |||
| 0f1ff5ffd2 | |||
| 9512fc34f0 | |||
| 75348922fc | |||
| 938eb2d0f0 | |||
| ede51fa589 | |||
| 7e0711ce12 | |||
| 822f40239f | |||
| 31149e6ba1 | |||
| ba233b6016 | |||
| 3d17ab6a4b | |||
| 492f1dd199 | |||
| 172399f792 | |||
| 22407c2911 | |||
| bdace0f9cb | |||
| 15bbba590b | |||
| a72264c685 | |||
| 2612cca708 | |||
| fc16d1c839 | |||
| f22bb282ab | |||
| d907b6b81a | |||
| 1903938035 | |||
| bb646c4f6a | |||
| 4c65ef3a2f |
@@ -9,28 +9,14 @@ on:
|
||||
- 'explorer/**'
|
||||
|
||||
jobs:
|
||||
matrix_prep:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||
steps:
|
||||
# creates the matrix strategy from build_matrix_includes.json
|
||||
- uses: actions/checkout@v2
|
||||
- id: set-matrix
|
||||
uses: JoshuaTheMiller/conditional-build-matrix@main
|
||||
with:
|
||||
inputFile: '.github/workflows/build_matrix_includes.json'
|
||||
filter: '[?runOnEvent==`${{ github.event_name }}` || runOnEvent==`always`]'
|
||||
build:
|
||||
needs: matrix_prep
|
||||
strategy:
|
||||
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
|
||||
runs-on: ${{ matrix.os }}
|
||||
continue-on-error: ${{ matrix.rust == 'nightly' || matrix.rust == 'beta' || matrix.os == 'windows-latest' }}
|
||||
runs-on: [ self-hosted, custom-linux-exoscale ]
|
||||
# Enable sccache via environment variable
|
||||
env:
|
||||
RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
|
||||
steps:
|
||||
- name: Install Dependencies (Linux)
|
||||
run: sudo apt-get update && sudo apt-get install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools
|
||||
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v2
|
||||
@@ -39,7 +25,7 @@ jobs:
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ matrix.rust }}
|
||||
toolchain: stable
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
@@ -53,7 +39,7 @@ jobs:
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --all
|
||||
args: --all --all-features
|
||||
|
||||
- name: Check formatting
|
||||
uses: actions-rs/cargo@v1
|
||||
@@ -63,25 +49,16 @@ jobs:
|
||||
|
||||
- uses: actions-rs/clippy-check@v1
|
||||
name: Clippy checks
|
||||
# if: matrix.os == 'ubuntu-latest' && matrix.rust == 'stable'
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --all-features
|
||||
|
||||
- name: Run clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.rust != 'nightly' }}
|
||||
with:
|
||||
command: clippy
|
||||
args: -- -D warnings
|
||||
|
||||
# COCONUT stuff
|
||||
- name: Reclaim some disk space (because Windows is being annoying)
|
||||
uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
with:
|
||||
command: clean
|
||||
|
||||
- name: Build all binaries with coconut enabled
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
@@ -96,7 +73,6 @@ jobs:
|
||||
|
||||
- name: Run clippy with coconut enabled
|
||||
uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.rust != 'nightly' }}
|
||||
with:
|
||||
command: clippy
|
||||
args: --features=coconut -- -D warnings
|
||||
args: --features=coconut -- -D warnings
|
||||
|
||||
@@ -10,41 +10,10 @@
|
||||
"rust":"stable",
|
||||
"runOnEvent":"pull_request"
|
||||
},
|
||||
|
||||
{
|
||||
"os":"macos-latest",
|
||||
"rust":"stable",
|
||||
"runOnEvent":"pull_request"
|
||||
},
|
||||
|
||||
{
|
||||
"os":"ubuntu-latest",
|
||||
"rust":"beta",
|
||||
"runOnEvent":"pull_request"
|
||||
},
|
||||
{
|
||||
"os":"windows-latest",
|
||||
"rust":"beta",
|
||||
"runOnEvent":"pull_request"
|
||||
},
|
||||
{
|
||||
"os":"macos-latest",
|
||||
"rust":"beta",
|
||||
"runOnEvent":"pull_request"
|
||||
},
|
||||
|
||||
{
|
||||
"os":"ubuntu-latest",
|
||||
"rust":"nightly",
|
||||
"runOnEvent":"pull_request"
|
||||
},
|
||||
{
|
||||
"os":"windows-latest",
|
||||
"rust":"nightly",
|
||||
"runOnEvent":"pull_request"
|
||||
},
|
||||
{
|
||||
"os":"macos-latest",
|
||||
"rust":"nightly",
|
||||
"runOnEvent":"pull_request"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
@@ -41,9 +41,10 @@ jobs:
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Keybase - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files/messages
|
||||
working-directory: .github/workflows/support-files
|
||||
- name: Keybase - Send Notification
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: network-explorer
|
||||
NYM_PROJECT_NAME: "Network Explorer"
|
||||
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
|
||||
NYM_CI_WWW_LOCATION: "network-explorer-${{ env.GITHUB_REF_SLUG }}"
|
||||
@@ -56,4 +57,4 @@ jobs:
|
||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||
uses: docker://keybaseio/client:stable-node
|
||||
with:
|
||||
args: .github/workflows/support-files/messages/entry_point_notifications.sh
|
||||
args: .github/workflows/support-files/notifications/entry_point.sh
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
name: Nightly builds
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '14 4 * * *'
|
||||
jobs:
|
||||
matrix_prep:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||
steps:
|
||||
# creates the matrix strategy from nightly_build_matrix_includes.json
|
||||
- uses: actions/checkout@v2
|
||||
- id: set-matrix
|
||||
uses: JoshuaTheMiller/conditional-build-matrix@main
|
||||
with:
|
||||
inputFile: '.github/workflows/nightly_build_matrix_includes.json'
|
||||
filter: '[?runOnEvent==`${{ github.event_name }}` || runOnEvent==`always`]'
|
||||
build:
|
||||
needs: matrix_prep
|
||||
strategy:
|
||||
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
|
||||
runs-on: ${{ matrix.os }}
|
||||
continue-on-error: ${{ matrix.rust == 'nightly' || matrix.rust == 'beta' || matrix.rust == 'stable' }}
|
||||
steps:
|
||||
- name: Install Dependencies (Linux)
|
||||
run: sudo apt-get update && sudo apt-get install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ matrix.rust }}
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Build all binaries
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --all
|
||||
|
||||
- name: Run all tests
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --all
|
||||
|
||||
- name: Check formatting
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
|
||||
- uses: actions-rs/clippy-check@v1
|
||||
name: Clippy checks
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --all-features
|
||||
|
||||
- name: Run clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.rust != 'nightly' }}
|
||||
with:
|
||||
command: clippy
|
||||
args: -- -D warnings
|
||||
|
||||
# COCONUT stuff
|
||||
- name: Reclaim some disk space (because Windows is being annoying)
|
||||
uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
with:
|
||||
command: clean
|
||||
|
||||
- name: Build all binaries with coconut enabled
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --all --features=coconut
|
||||
|
||||
- name: Run all tests with coconut enabled
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --all --features=coconut
|
||||
|
||||
- name: Run clippy with coconut enabled
|
||||
uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.rust != 'nightly' }}
|
||||
with:
|
||||
command: clippy
|
||||
args: --features=coconut -- -D warnings
|
||||
notification:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Collect jobs status
|
||||
uses: technote-space/workflow-conclusion-action@v2
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v2
|
||||
- name: Keybase - Node Install
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
- name: Keybase - Send Notification
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: nightly
|
||||
NYM_PROJECT_NAME: "Nym nightly build"
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||
GIT_BRANCH: "${GITHUB_REF##*/}"
|
||||
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
|
||||
KEYBASE_NYMBOT_PAPERKEY: "${{ secrets.KEYBASE_NYMBOT_PAPERKEY }}"
|
||||
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMBOT_TEAM }}"
|
||||
KEYBASE_NYM_CHANNEL: "ci-nightly"
|
||||
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
|
||||
uses: docker://keybaseio/client:stable-node
|
||||
with:
|
||||
args: .github/workflows/support-files/notifications/entry_point.sh
|
||||
@@ -0,0 +1,50 @@
|
||||
[
|
||||
{
|
||||
"os":"ubuntu-latest",
|
||||
"rust":"stable",
|
||||
"runOnEvent":"schedule"
|
||||
},
|
||||
|
||||
{
|
||||
"os":"windows-latest",
|
||||
"rust":"stable",
|
||||
"runOnEvent":"schedule"
|
||||
},
|
||||
{
|
||||
"os":"macos-latest",
|
||||
"rust":"stable",
|
||||
"runOnEvent":"schedule"
|
||||
},
|
||||
|
||||
{
|
||||
"os":"ubuntu-latest",
|
||||
"rust":"beta",
|
||||
"runOnEvent":"schedule"
|
||||
},
|
||||
{
|
||||
"os":"windows-latest",
|
||||
"rust":"beta",
|
||||
"runOnEvent":"schedule"
|
||||
},
|
||||
{
|
||||
"os":"macos-latest",
|
||||
"rust":"beta",
|
||||
"runOnEvent":"schedule"
|
||||
},
|
||||
|
||||
{
|
||||
"os":"ubuntu-latest",
|
||||
"rust":"nightly",
|
||||
"runOnEvent":"schedule"
|
||||
},
|
||||
{
|
||||
"os":"windows-latest",
|
||||
"rust":"nightly",
|
||||
"runOnEvent":"schedule"
|
||||
},
|
||||
{
|
||||
"os":"macos-latest",
|
||||
"rust":"nightly",
|
||||
"runOnEvent":"schedule"
|
||||
}
|
||||
]
|
||||
@@ -10,7 +10,10 @@ on:
|
||||
|
||||
jobs:
|
||||
nym-wallet-types:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: [ self-hosted, custom-linux-exoscale ]
|
||||
# Enable sccache
|
||||
env:
|
||||
RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
steps:
|
||||
- name: Prepare
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
KEYBASE_NYM_CHANNEL=
|
||||
KEYBASE_NYMBOT_USERNAME=
|
||||
KEYBASE_NYMBOT_PAPERKEY=
|
||||
|
||||
NYM_NOTIFICATION_KIND=nightly
|
||||
NYM_PROJECT_NAME=Nightly Build
|
||||
|
||||
#----------------------------------------------------------------
|
||||
# Custom GitHub Actions mock env vars
|
||||
IS_SUCCESS=true
|
||||
|
||||
#----------------------------------------------------------------
|
||||
# GitHub Actions context mock env vars
|
||||
GITHUB_SHA=abcdef
|
||||
GITHUB_RUN_ID=123456
|
||||
GITHUB_REPOSITORY=nymtech/nym
|
||||
GITHUB_SERVER_URL=https://github.com
|
||||
GIT_BRANCH_NAME=feature/testing-support-files
|
||||
GIT_BRANCH=feature/testing-support-files
|
||||
GIT_COMMIT_MESSAGE=This is the commit message
|
||||
GITHUB_ACTOR=octocat
|
||||
|
||||
# add a Personal Access Token (PAT) generated from GitHub here for use in testing
|
||||
GITHUB_TOKEN=
|
||||
|
||||
#----------------------------------------------------------------
|
||||
# Network Explorer
|
||||
NYM_CI_WWW_LOCATION=some-branch
|
||||
NYM_CI_WWW_BASE=example.com
|
||||
|
||||
#----------------------------------------------------------------
|
||||
# Nightly builds
|
||||
WORKFLOW_CONCLUSION=success
|
||||
|
||||
SHOW_DEBUG=true
|
||||
@@ -0,0 +1,5 @@
|
||||
node_modules
|
||||
.idea
|
||||
|
||||
# don't commit the lock file to avoid cross-platform issues
|
||||
package-lock.json
|
||||
@@ -0,0 +1 @@
|
||||
16
|
||||
@@ -0,0 +1,58 @@
|
||||
# GitHub Actions Support Files
|
||||
|
||||
This is a collection of scripts and files to support GitHub Actions.
|
||||
|
||||
## Sending Notifications
|
||||
|
||||
These scripts send CI notifications to Keybase by creating messages from templates and env vars passed from GitHub Actions.
|
||||
|
||||
### Adding notifications to a GitHub Action
|
||||
|
||||
```
|
||||
jobs:
|
||||
build:
|
||||
...
|
||||
- name: Notifications - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files/notifications
|
||||
- name: Notifications - Send
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: "my-component"
|
||||
GIT_BRANCH: "${GITHUB_REF##*/}"
|
||||
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
|
||||
KEYBASE_NYMBOT_PAPERKEY: "${{ secrets.KEYBASE_NYMBOT_PAPERKEY }}"
|
||||
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMBOT_TEAM }}"
|
||||
KEYBASE_NYM_CHANNEL: "ci-network-explorer"
|
||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||
uses: docker://keybaseio/client:stable-node
|
||||
with:
|
||||
args: .github/workflows/support-files/notifications/entry_point.sh
|
||||
```
|
||||
|
||||
Notifications are run by adding the snippet above to a GitHub Action, and:
|
||||
|
||||
1. Installing node packages needed at run time
|
||||
2. Set the env vars as required:
|
||||
- `NYM_NOTIFICATION_KIND` matches the directory in `.github/workflows/support-files/${NYM_NOTIFICATION_KIND}` to provide the templates and extra scripting in `index.js`
|
||||
- Keybase credentials, channel and other env vars for the status of the build and repo
|
||||
3. Replacing the default entry point shell script on the `keybaseio/client:stable-node` docker image to run `.github/workflows/support-files/notifications/entry_point.sh`
|
||||
|
||||
### Running locally
|
||||
|
||||
You will need:
|
||||
- Node 16 LTS
|
||||
- npm
|
||||
|
||||
Copy `.github/workflows/support-files/.env.example` to `.github/workflows/support-files/.env` and valid Keybase credentials.
|
||||
|
||||
Then run `npm install` to get dependencies.
|
||||
|
||||
Start development mode for the notification type you want either by passing the value as an env var called `NYM_NOTIFICATION_KIND` or set the `.env` file values correctly.
|
||||
|
||||
```bash
|
||||
cd .github/workflows/support-files
|
||||
npm install
|
||||
cp .env.example .env
|
||||
vi .env
|
||||
npm run dev
|
||||
```
|
||||
@@ -0,0 +1 @@
|
||||
require('./notifications/send_message');
|
||||
@@ -1,2 +0,0 @@
|
||||
node_modules
|
||||
.idea
|
||||
@@ -1,69 +0,0 @@
|
||||
const Bot = require('keybase-bot');
|
||||
const Handlebars = require('handlebars');
|
||||
const fs = require('fs');
|
||||
|
||||
async function main() {
|
||||
const data = { env: process.env };
|
||||
// const data = { ...PASTE TEST DATA HERE ... }; // -- DEV: uncomment to set test data
|
||||
|
||||
// validation of environment
|
||||
if(!(process.env.NYM_PROJECT_NAME || data.env.NYM_PROJECT_NAME)) {
|
||||
throw new Error('Please set env var NYM_PROJECT_NAME with the project name for displaying in notification messages');
|
||||
}
|
||||
const keybaseChannel = process.env.KEYBASE_NYM_CHANNEL || data.env.KEYBASE_NYM_CHANNEL;
|
||||
if(!keybaseChannel) {
|
||||
throw new Error('Please set env var KEYBASE_NYM_CHANNEL with the channel name for the notification message');
|
||||
}
|
||||
|
||||
// extract the git branch name
|
||||
const GIT_BRANCH_NAME = (process.env.GITHUB_REF || data.env.GITHUB_REF).split('/').slice(2).join('/');
|
||||
|
||||
data.env.GIT_BRANCH_NAME = GIT_BRANCH_NAME;
|
||||
const source = fs
|
||||
.readFileSync(process.env.IS_SUCCESS === 'true' ? 'success' : 'failure')
|
||||
.toString();
|
||||
const template = Handlebars.compile(source);
|
||||
const result = template(data);
|
||||
|
||||
// -- DEV: uncomment to show what is available in the handlebars template / show the result
|
||||
// console.dir({ data }, { depth: null });
|
||||
// console.log(result);
|
||||
|
||||
const bot = new Bot();
|
||||
try {
|
||||
const username = process.env.KEYBASE_NYMBOT_USERNAME;
|
||||
const paperkey = process.env.KEYBASE_NYMBOT_PAPERKEY;
|
||||
|
||||
if(!username) {
|
||||
throw new Error('Username is not defined. Please set env var KEYBASE_NYMBOT_USERNAME');
|
||||
}
|
||||
if(!paperkey) {
|
||||
throw new Error('Paperkey is not defined. Please set env var KEYBASE_NYMBOT_PAPERKEY');
|
||||
}
|
||||
|
||||
console.log(`Initialising keybase with user "${username}" and key: "${'*'.repeat(paperkey.length)}"...`);
|
||||
await bot.init(username, paperkey, { verbose: false });
|
||||
|
||||
const channel = {
|
||||
name: 'nymtech_bot',
|
||||
membersType: 'team',
|
||||
topicName: keybaseChannel,
|
||||
topic_type: 'CHAT',
|
||||
};
|
||||
const message = {
|
||||
body: result,
|
||||
};
|
||||
|
||||
console.log(`Sending to ${channel.name}#${channel.topicName}...`);
|
||||
await bot.chat.send(channel, message);
|
||||
|
||||
console.log('Message sent!');
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
process.exitCode = -1;
|
||||
} finally {
|
||||
await bot.deinit();
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -0,0 +1,29 @@
|
||||
const Handlebars = require('handlebars');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
async function addToContextAndValidate(context) {
|
||||
if (!context.env.NYM_CI_WWW_LOCATION) {
|
||||
throw new Error('Please ensure the env var NYM_CI_WWW_LOCATION is set');
|
||||
}
|
||||
if (!context.env.NYM_CI_WWW_BASE) {
|
||||
throw new Error('Please ensure the env var NYM_CI_WWW_BASE is set');
|
||||
}
|
||||
}
|
||||
|
||||
async function getMessageBody(context) {
|
||||
const source = fs
|
||||
.readFileSync(
|
||||
context.env.IS_SUCCESS === 'true'
|
||||
? path.resolve(__dirname, 'templates', 'success')
|
||||
: path.resolve(__dirname, 'templates', 'failure'),
|
||||
)
|
||||
.toString();
|
||||
const template = Handlebars.compile(source);
|
||||
return template(context);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
addToContextAndValidate,
|
||||
getMessageBody,
|
||||
};
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||
|
||||
Commit message:
|
||||
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
|
||||
```
|
||||
{{ env.GIT_COMMIT_MESSAGE }}
|
||||
```
|
||||
@@ -0,0 +1,162 @@
|
||||
const Handlebars = require('handlebars');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { Octokit, App } = require('octokit');
|
||||
|
||||
async function addToContextAndValidate(context) {
|
||||
if (!context.env.WORKFLOW_CONCLUSION) {
|
||||
throw new Error('Please ensure the env var WORKFLOW_CONCLUSION is set');
|
||||
}
|
||||
if (!context.env.GITHUB_TOKEN) {
|
||||
throw new Error('Please ensure the env var GITHUB_TOKEN is set');
|
||||
}
|
||||
if (!context.env.GITHUB_RUN_ID) {
|
||||
throw new Error('Please ensure the env var GITHUB_RUN_ID is set');
|
||||
}
|
||||
if (!context.env.GITHUB_REPOSITORY) {
|
||||
throw new Error('Please ensure the env var GITHUB_REPOSITORY is set');
|
||||
}
|
||||
}
|
||||
|
||||
async function getMessageBody(context) {
|
||||
const source = fs
|
||||
.readFileSync(
|
||||
context.env.WORKFLOW_CONCLUSION === 'success'
|
||||
? path.resolve(__dirname, 'templates', 'success')
|
||||
: path.resolve(__dirname, 'templates', 'failure'),
|
||||
)
|
||||
.toString();
|
||||
const template = Handlebars.compile(source);
|
||||
|
||||
// get job details from GitHub API
|
||||
const octokit = new Octokit({ auth: context.env.GITHUB_TOKEN });
|
||||
const [owner, repo] = context.env.GITHUB_REPOSITORY.split('/');
|
||||
const {
|
||||
data: { jobs },
|
||||
} = await octokit.rest.actions.listJobsForWorkflowRun({
|
||||
run_id: context.env.GITHUB_RUN_ID,
|
||||
owner,
|
||||
repo,
|
||||
});
|
||||
|
||||
// uncomment this to see what is available for each job
|
||||
if(process.env.SHOW_DEBUG) {
|
||||
console.dir(jobs, { depth: null });
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
a sample of the response is:
|
||||
|
||||
{
|
||||
total_count: 10,
|
||||
jobs: [
|
||||
{
|
||||
id: 5182940024,
|
||||
run_id: 1840752095,
|
||||
run_url: 'https://api.github.com/repos/nymtech/nym/actions/runs/1840752095',
|
||||
run_attempt: 1,
|
||||
node_id: 'CR_kwDODdjOis8AAAABNO1jeA',
|
||||
head_sha: 'aa00eb70d57751bfa556bd3602df87c7473367fc',
|
||||
url: 'https://api.github.com/repos/nymtech/nym/actions/jobs/5182940024',
|
||||
html_url: 'https://github.com/nymtech/nym/runs/5182940024?check_suite_focus=true',
|
||||
status: 'completed',
|
||||
conclusion: 'success',
|
||||
started_at: '2022-02-14T11:28:34Z',
|
||||
completed_at: '2022-02-14T11:28:38Z',
|
||||
name: 'matrix_prep',
|
||||
steps: [
|
||||
{
|
||||
name: 'Set up job',
|
||||
status: 'completed',
|
||||
conclusion: 'success',
|
||||
number: 1,
|
||||
started_at: '2022-02-14T13:28:34.000+02:00',
|
||||
completed_at: '2022-02-14T13:28:36.000+02:00'
|
||||
},
|
||||
{
|
||||
name: 'Run actions/checkout@v2',
|
||||
status: 'completed',
|
||||
conclusion: 'success',
|
||||
number: 2,
|
||||
started_at: '2022-02-14T13:28:36.000+02:00',
|
||||
completed_at: '2022-02-14T13:28:37.000+02:00'
|
||||
},
|
||||
...
|
||||
],
|
||||
check_run_url: 'https://api.github.com/repos/nymtech/nym/check-runs/5182940024',
|
||||
labels: [ 'ubuntu-latest' ],
|
||||
runner_id: 1,
|
||||
runner_name: 'Hosted Agent',
|
||||
runner_group_id: 2,
|
||||
runner_group_name: 'GitHub Actions'
|
||||
},
|
||||
{
|
||||
id: 5182943473,
|
||||
run_id: 1840752095,
|
||||
run_url: 'https://api.github.com/repos/nymtech/nym/actions/runs/1840752095',
|
||||
run_attempt: 1,
|
||||
node_id: 'CR_kwDODdjOis8AAAABNO1w8Q',
|
||||
head_sha: 'aa00eb70d57751bfa556bd3602df87c7473367fc',
|
||||
url: 'https://api.github.com/repos/nymtech/nym/actions/jobs/5182943473',
|
||||
html_url: 'https://github.com/nymtech/nym/runs/5182943473?check_suite_focus=true',
|
||||
status: 'completed',
|
||||
conclusion: 'failure',
|
||||
started_at: '2022-02-14T11:29:04Z',
|
||||
completed_at: '2022-02-14T11:55:45Z',
|
||||
name: 'build (macos-latest, stable, schedule)',
|
||||
steps: [
|
||||
{
|
||||
name: 'Set up job',
|
||||
status: 'completed',
|
||||
conclusion: 'success',
|
||||
number: 1,
|
||||
started_at: '2022-02-14T13:29:04.000+02:00',
|
||||
completed_at: '2022-02-14T13:29:26.000+02:00'
|
||||
},
|
||||
{
|
||||
name: 'Install Dependencies (Linux)',
|
||||
status: 'completed',
|
||||
conclusion: 'skipped',
|
||||
number: 2,
|
||||
started_at: '2022-02-14T13:29:26.000+02:00',
|
||||
completed_at: '2022-02-14T13:29:26.000+02:00'
|
||||
},
|
||||
{
|
||||
name: 'Keybase - Send Notification',
|
||||
status: 'completed',
|
||||
conclusion: 'failure',
|
||||
number: 15,
|
||||
started_at: '2022-02-14T13:55:44.000+02:00',
|
||||
completed_at: '2022-02-14T13:55:44.000+02:00'
|
||||
},
|
||||
],
|
||||
check_run_url: 'https://api.github.com/repos/nymtech/nym/check-runs/5182943473',
|
||||
labels: [ 'macos-latest' ],
|
||||
runner_id: 4,
|
||||
runner_name: 'GitHub Actions 4',
|
||||
runner_group_id: 2,
|
||||
runner_group_name: 'GitHub Actions'
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
*/
|
||||
|
||||
const jobResults = jobs
|
||||
.map((job) => {
|
||||
const icon = job.conclusion === 'success' ? '🟩' : '🟥';
|
||||
|
||||
// each job is converted into formatted markdown text
|
||||
return `${icon} ${job.conclusion}: ${job.name} - ${job.html_url}`;
|
||||
})
|
||||
// and join with newlines for display in the template
|
||||
.join('\n');
|
||||
|
||||
return template({ ...context, jobResults });
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
addToContextAndValidate,
|
||||
getMessageBody,
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||
> 🔴 **FAILURE** :cry:
|
||||
> `when` {{ timestamp }}
|
||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||
|
||||
{{ jobResults }}
|
||||
@@ -0,0 +1,9 @@
|
||||
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||
> ✅ **SUCCESS**
|
||||
> `when` {{ timestamp }}
|
||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||
|
||||
{{ jobResults }}
|
||||
@@ -0,0 +1,153 @@
|
||||
require('dotenv').config();
|
||||
|
||||
const Bot = require('keybase-bot');
|
||||
|
||||
let context = {
|
||||
kinds: ['network-explorer', 'nightly'],
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate that all required env and context vars are available
|
||||
*/
|
||||
function validateContext() {
|
||||
if (!context.env.NYM_NOTIFICATION_KIND) {
|
||||
throw new Error(
|
||||
'Please set env var NYM_NOTIFICATION_KIND with the project kind that matches a directory in ".github/workflows/support-files"',
|
||||
);
|
||||
}
|
||||
if (!context.kinds.includes(context.env.NYM_NOTIFICATION_KIND)) {
|
||||
throw new Error(`Env var NYM_NOTIFICATION_KIND is not in ${context.kinds}`);
|
||||
}
|
||||
if (!context.env.NYM_PROJECT_NAME) {
|
||||
throw new Error(
|
||||
'Please set env var NYM_PROJECT_NAME with the project name for displaying in notification messages',
|
||||
);
|
||||
}
|
||||
if (!context.env.KEYBASE_NYM_CHANNEL) {
|
||||
throw new Error(
|
||||
'Please set env var KEYBASE_NYM_CHANNEL with the channel name for the notification message',
|
||||
);
|
||||
}
|
||||
if (!context.env.KEYBASE_NYMBOT_USERNAME) {
|
||||
throw new Error(
|
||||
'Username is not defined. Please set env var KEYBASE_NYMBOT_USERNAME',
|
||||
);
|
||||
}
|
||||
if (!context.env.KEYBASE_NYMBOT_PAPERKEY) {
|
||||
throw new Error(
|
||||
'Paperkey is not defined. Please set env var KEYBASE_NYMBOT_PAPERKEY',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a context that will be available in the templates for rendering notifications
|
||||
*/
|
||||
function createTemplateContext() {
|
||||
const options = { dateStyle: 'full', timeStyle: 'long' };
|
||||
context.timestamp = new Date().toLocaleString(undefined, options);
|
||||
|
||||
// add environment to template context and validate
|
||||
context.env = process.env;
|
||||
try {
|
||||
validateContext();
|
||||
} catch (e) {
|
||||
if(process.env.SHOW_DEBUG) {
|
||||
// recursively print the context for easy debugging and rethrow the error
|
||||
console.dir({ context }, { depth: null });
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
context.kind = context.env.NYM_NOTIFICATION_KIND;
|
||||
|
||||
context.keybase = {
|
||||
channel: context.env.KEYBASE_NYM_CHANNEL,
|
||||
username: context.env.KEYBASE_NYMBOT_USERNAME,
|
||||
paperkey: context.env.KEYBASE_NYMBOT_PAPERKEY,
|
||||
};
|
||||
|
||||
if (!context.env.GIT_BRANCH_NAME) {
|
||||
context.env.GIT_BRANCH_NAME = context.env.GITHUB_REF.split('/')
|
||||
.slice(2)
|
||||
.join('/');
|
||||
}
|
||||
|
||||
context.status = process.env.IS_SUCCESS === 'true' ? 'success' : 'failure';
|
||||
}
|
||||
|
||||
async function sendKeybaseMessage(messageBody) {
|
||||
const bot = new Bot();
|
||||
try {
|
||||
console.log(
|
||||
`Initialising keybase with user "${
|
||||
context.keybase.username
|
||||
}" and key: "${'*'.repeat(context.keybase.paperkey.length)}"...`,
|
||||
);
|
||||
await bot.init(context.keybase.username, context.keybase.paperkey, {
|
||||
verbose: false,
|
||||
});
|
||||
|
||||
const channel = {
|
||||
name: 'nymtech_bot',
|
||||
membersType: 'team',
|
||||
topicName: context.keybase.channel,
|
||||
topic_type: 'CHAT',
|
||||
};
|
||||
const message = {
|
||||
body: messageBody,
|
||||
};
|
||||
|
||||
console.log(`Sending to ${channel.name}#${channel.topicName}...`);
|
||||
await bot.chat.send(channel, message);
|
||||
|
||||
console.log('Message sent!');
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
process.exitCode = -1;
|
||||
} finally {
|
||||
await bot.deinit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the `kind` set in the context to process the context and generate a notification message
|
||||
* @returns {Promise<string>} A string notification message body
|
||||
*/
|
||||
async function processKindScript() {
|
||||
const script = require(`../${context.kind}`);
|
||||
if (!script.addToContextAndValidate) {
|
||||
throw new Error(
|
||||
`"./${context.kind}/index.js" does not export a method called "async addToContextAndValidate(context)"`,
|
||||
);
|
||||
}
|
||||
if (!script.getMessageBody) {
|
||||
throw new Error(
|
||||
`"./${context.kind}/index.js" does not export a method called "async getMessageBody(context)"`,
|
||||
);
|
||||
}
|
||||
|
||||
// call the script to modify and validate the context
|
||||
await script.addToContextAndValidate(context);
|
||||
|
||||
// let the script create a message body and return the result as a string for sending
|
||||
return await script.getMessageBody(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* The main function, as async so that await syntax is available
|
||||
*/
|
||||
async function main() {
|
||||
createTemplateContext();
|
||||
console.log(`Sending notification for kind "${context.kind}"...`);
|
||||
const messageBody = await processKindScript();
|
||||
if(process.env.SHOW_DEBUG) {
|
||||
console.log('-----------------------------------------');
|
||||
console.log(messageBody);
|
||||
console.log('-----------------------------------------');
|
||||
}
|
||||
await sendKeybaseMessage(messageBody);
|
||||
}
|
||||
|
||||
// call main function and let NodeJS handle the promise
|
||||
main();
|
||||
+5
-2
@@ -4,11 +4,14 @@
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"format": "prettier --write send_message.js"
|
||||
"dev": "node dev.js",
|
||||
"format": "prettier --write **/*.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"dotenv": "^16.0.0",
|
||||
"handlebars": "^4.7.7",
|
||||
"keybase-bot": "^3.6.1"
|
||||
"keybase-bot": "^3.6.1",
|
||||
"octokit": "^1.7.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "2.3.2"
|
||||
Generated
+758
-484
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,9 @@
|
||||
all: clippy-all test wasm fmt
|
||||
happy: clippy-happy test fmt
|
||||
test: build clippy-all cargo-test wasm fmt
|
||||
happy: fmt clippy-happy test
|
||||
clippy-all: clippy-all-main clippy-all-contracts clippy-all-wallet
|
||||
clippy-happy: clippy-happy-main clippy-happy-contracts clippy-happy-wallet
|
||||
test: test-main test-contracts test-wallet
|
||||
cargo-test: test-main test-contracts test-wallet
|
||||
build: build-main build-contracts build-wallet
|
||||
fmt: fmt-main fmt-contracts fmt-wallet
|
||||
|
||||
clippy-happy-main:
|
||||
@@ -32,6 +33,15 @@ test-contracts:
|
||||
test-wallet:
|
||||
cargo test --manifest-path nym-wallet/Cargo.toml --all-features
|
||||
|
||||
build-main:
|
||||
cargo build --all
|
||||
|
||||
build-contracts:
|
||||
cargo build --manifest-path contracts/Cargo.toml --all
|
||||
|
||||
build-wallet:
|
||||
cargo build --manifest-path nym-wallet/Cargo.toml --all
|
||||
|
||||
fmt-main:
|
||||
cargo fmt --all
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crypto::generic_array::typenum::Unsigned;
|
||||
use log::*;
|
||||
use nymsphinx::anonymous_replies::{
|
||||
encryption_key::EncryptionKeyDigest, encryption_key::Unsigned, SurbEncryptionKey,
|
||||
SurbEncryptionKeySize,
|
||||
encryption_key::EncryptionKeyDigest, SurbEncryptionKey, SurbEncryptionKeySize,
|
||||
};
|
||||
use std::path::Path;
|
||||
|
||||
@@ -43,7 +43,7 @@ impl ReplyKeyStorage {
|
||||
// if this fails it means we have some database corruption and we
|
||||
// absolutely can't continue
|
||||
|
||||
if key_bytes_ref.len() != SurbEncryptionKeySize::to_usize() {
|
||||
if key_bytes_ref.len() != SurbEncryptionKeySize::USIZE {
|
||||
error!("REPLY KEY STORAGE DATA CORRUPTION - ENCRYPTION KEY HAS INVALID LENGTH");
|
||||
panic!("REPLY KEY STORAGE DATA CORRUPTION - ENCRYPTION KEY HAS INVALID LENGTH");
|
||||
}
|
||||
|
||||
@@ -121,12 +121,16 @@ impl<T: NymConfig> Config<T> {
|
||||
self.client.testnet_mode = testnet_mode;
|
||||
}
|
||||
|
||||
pub fn with_gateway_id<S: Into<String>>(&mut self, id: S) {
|
||||
self.client.gateway_id = id.into();
|
||||
pub fn with_gateway_endpoint<S: Into<String>>(&mut self, id: S, owner: S, listener: S) {
|
||||
self.client.gateway_endpoint = GatewayEndpoint {
|
||||
gateway_id: id.into(),
|
||||
gateway_owner: owner.into(),
|
||||
gateway_listener: listener.into(),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn with_gateway_listener<S: Into<String>>(&mut self, gateway_listener: S) {
|
||||
self.client.gateway_listener = gateway_listener.into();
|
||||
pub fn with_gateway_id<S: Into<String>>(&mut self, id: S) {
|
||||
self.client.gateway_endpoint.gateway_id = id.into();
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
@@ -198,11 +202,15 @@ impl<T: NymConfig> Config<T> {
|
||||
}
|
||||
|
||||
pub fn get_gateway_id(&self) -> String {
|
||||
self.client.gateway_id.clone()
|
||||
self.client.gateway_endpoint.gateway_id.clone()
|
||||
}
|
||||
|
||||
pub fn get_gateway_owner(&self) -> String {
|
||||
self.client.gateway_endpoint.gateway_owner.clone()
|
||||
}
|
||||
|
||||
pub fn get_gateway_listener(&self) -> String {
|
||||
self.client.gateway_listener.clone()
|
||||
self.client.gateway_endpoint.gateway_listener.clone()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
@@ -272,6 +280,19 @@ impl<T: NymConfig> Default for Config<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||
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.
|
||||
gateway_id: String,
|
||||
|
||||
/// Address of the gateway owner to which the client should send messages.
|
||||
gateway_owner: String,
|
||||
|
||||
/// Address of the gateway listener to which all client requests should be sent.
|
||||
gateway_listener: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
pub struct Client<T> {
|
||||
/// Version of the client for which this configuration was created.
|
||||
@@ -313,12 +334,8 @@ pub struct Client<T> {
|
||||
/// sent but not received back.
|
||||
reply_encryption_key_store_path: PathBuf,
|
||||
|
||||
/// 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.
|
||||
gateway_id: String,
|
||||
|
||||
/// Address of the gateway listener to which all client requests should be sent.
|
||||
gateway_listener: String,
|
||||
/// Information regarding how the client should send data to gateway.
|
||||
gateway_endpoint: GatewayEndpoint,
|
||||
|
||||
/// Path to directory containing public/private keys used for bandwidth token purchase.
|
||||
/// Those are saved in case of emergency, to be able to reclaim bandwidth tokens.
|
||||
@@ -357,8 +374,7 @@ impl<T: NymConfig> Default for Client<T> {
|
||||
gateway_shared_key_file: Default::default(),
|
||||
ack_key_file: Default::default(),
|
||||
reply_encryption_key_store_path: Default::default(),
|
||||
gateway_id: "".to_string(),
|
||||
gateway_listener: "".to_string(),
|
||||
gateway_endpoint: Default::default(),
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
backup_bandwidth_token_keys_dir: Default::default(),
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
|
||||
+12
-12
@@ -2441,9 +2441,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.14.7",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz",
|
||||
"integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==",
|
||||
"version": "1.14.8",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
|
||||
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -6085,9 +6085,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/url-parse": {
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.4.tgz",
|
||||
"integrity": "sha512-ITeAByWWoqutFClc/lRZnFplgXgEZr3WJ6XngMM/N9DMIm4K8zXPCZ1Jdu0rERwO84w1WC5wkle2ubwTA4NTBg==",
|
||||
"version": "1.5.7",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.7.tgz",
|
||||
"integrity": "sha512-HxWkieX+STA38EDk7CE9MEryFeHCKzgagxlGvsdS7WBImq9Mk+PGwiT56w82WI3aicwJA8REp42Cxo98c8FZMA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"querystringify": "^2.1.1",
|
||||
@@ -8853,9 +8853,9 @@
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.14.7",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz",
|
||||
"integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==",
|
||||
"version": "1.14.8",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
|
||||
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==",
|
||||
"dev": true
|
||||
},
|
||||
"for-in": {
|
||||
@@ -11733,9 +11733,9 @@
|
||||
}
|
||||
},
|
||||
"url-parse": {
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.4.tgz",
|
||||
"integrity": "sha512-ITeAByWWoqutFClc/lRZnFplgXgEZr3WJ6XngMM/N9DMIm4K8zXPCZ1Jdu0rERwO84w1WC5wkle2ubwTA4NTBg==",
|
||||
"version": "1.5.7",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.7.tgz",
|
||||
"integrity": "sha512-HxWkieX+STA38EDk7CE9MEryFeHCKzgagxlGvsdS7WBImq9Mk+PGwiT56w82WI3aicwJA8REp42Cxo98c8FZMA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"querystringify": "^2.1.1",
|
||||
|
||||
@@ -59,12 +59,6 @@ eth_endpoint = '{{ client.eth_endpoint }}'
|
||||
|
||||
##### additional client config options #####
|
||||
|
||||
# ID of the gateway from which the client should be fetching messages.
|
||||
gateway_id = '{{ client.gateway_id }}'
|
||||
|
||||
# Address of the gateway listener to which all client requests should be sent.
|
||||
gateway_listener = '{{ client.gateway_listener }}'
|
||||
|
||||
# A gateway specific, optional, base58 stringified shared key used for
|
||||
# communication with particular gateway.
|
||||
gateway_shared_key_file = '{{ client.gateway_shared_key_file }}'
|
||||
@@ -78,6 +72,17 @@ ack_key_file = '{{ client.ack_key_file }}'
|
||||
# Absolute path to the home Nym Clients directory.
|
||||
nym_root_directory = '{{ client.nym_root_directory }}'
|
||||
|
||||
[client.gateway_endpoint]
|
||||
# ID of the gateway from which the client should be fetching messages.
|
||||
gateway_id = '{{ client.gateway_endpoint.gateway_id }}'
|
||||
|
||||
# Address of the gateway owner to which the client should send messages.
|
||||
gateway_owner = '{{ client.gateway_endpoint.gateway_owner }}'
|
||||
|
||||
# Address of the gateway listener to which all client requests should be sent.
|
||||
gateway_listener = '{{ client.gateway_endpoint.gateway_listener }}'
|
||||
|
||||
|
||||
|
||||
##### socket config options #####
|
||||
|
||||
|
||||
@@ -160,6 +160,10 @@ impl NymClient {
|
||||
if gateway_id.is_empty() {
|
||||
panic!("The identity of the gateway is unknown - did you run `nym-client` init?")
|
||||
}
|
||||
let gateway_owner = self.config.get_base().get_gateway_owner();
|
||||
if gateway_owner.is_empty() {
|
||||
panic!("The owner of the gateway is unknown - did you run `nym-client` init?")
|
||||
}
|
||||
let gateway_address = self.config.get_base().get_gateway_listener();
|
||||
if gateway_address.is_empty() {
|
||||
panic!("The address of the gateway is unknown - did you run `nym-client` init?")
|
||||
@@ -185,6 +189,7 @@ impl NymClient {
|
||||
gateway_address,
|
||||
self.key_manager.identity_keypair(),
|
||||
gateway_identity,
|
||||
gateway_owner,
|
||||
Some(self.key_manager.gateway_shared_key()),
|
||||
mixnet_message_sender,
|
||||
ack_sender,
|
||||
|
||||
@@ -136,6 +136,7 @@ async fn register_with_gateway(
|
||||
let mut gateway_client = GatewayClient::new_init(
|
||||
gateway.clients_address(),
|
||||
gateway.identity_key,
|
||||
gateway.owner.clone(),
|
||||
our_identity.clone(),
|
||||
timeout,
|
||||
);
|
||||
@@ -255,15 +256,14 @@ pub async fn execute(matches: ArgMatches<'static>) {
|
||||
chosen_gateway_id,
|
||||
)
|
||||
.await;
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_id(gateway_details.identity_key.to_base58_string());
|
||||
let shared_keys =
|
||||
register_with_gateway(&gateway_details, key_manager.identity_keypair()).await;
|
||||
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_listener(gateway_details.clients_address());
|
||||
config.get_base_mut().with_gateway_endpoint(
|
||||
gateway_details.identity_key.to_base58_string(),
|
||||
gateway_details.owner.clone(),
|
||||
gateway_details.clients_address(),
|
||||
);
|
||||
key_manager.insert_gateway_shared_key(shared_keys);
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
|
||||
@@ -58,7 +58,7 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches<'_>) -> C
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
if let Some(eth_endpoint) = matches.value_of(ETH_ENDPOINT_ARG_NAME) {
|
||||
config.get_base_mut().with_eth_endpoint(eth_endpoint);
|
||||
} else {
|
||||
} else if !cfg!(feature = "eth") {
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_eth_endpoint(DEFAULT_ETH_ENDPOINT);
|
||||
@@ -66,7 +66,7 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches<'_>) -> C
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
if let Some(eth_private_key) = matches.value_of(ETH_PRIVATE_KEY_ARG_NAME) {
|
||||
config.get_base_mut().with_eth_private_key(eth_private_key);
|
||||
} else {
|
||||
} else if !cfg!(feature = "eth") {
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY);
|
||||
|
||||
@@ -59,12 +59,6 @@ eth_endpoint = '{{ client.eth_endpoint }}'
|
||||
|
||||
##### additional client config options #####
|
||||
|
||||
# ID of the gateway from which the client should be fetching messages.
|
||||
gateway_id = '{{ client.gateway_id }}'
|
||||
|
||||
# Address of the gateway listener to which all client requests should be sent.
|
||||
gateway_listener = '{{ client.gateway_listener }}'
|
||||
|
||||
# A gateway specific, optional, base58 stringified shared key used for
|
||||
# communication with particular gateway.
|
||||
gateway_shared_key_file = '{{ client.gateway_shared_key_file }}'
|
||||
@@ -72,12 +66,22 @@ gateway_shared_key_file = '{{ client.gateway_shared_key_file }}'
|
||||
# Path to file containing key used for encrypting and decrypting the content of an
|
||||
# acknowledgement so that nobody besides the client knows which packet it refers to.
|
||||
ack_key_file = '{{ client.ack_key_file }}'
|
||||
|
||||
|
||||
##### advanced configuration options #####
|
||||
|
||||
# Absolute path to the home Nym Clients directory.
|
||||
nym_root_directory = '{{ client.nym_root_directory }}'
|
||||
|
||||
[client.gateway_endpoint]
|
||||
# ID of the gateway from which the client should be fetching messages.
|
||||
gateway_id = '{{ client.gateway_endpoint.gateway_id }}'
|
||||
|
||||
# Address of the gateway owner to which the client should send messages.
|
||||
gateway_owner = '{{ client.gateway_endpoint.gateway_owner }}'
|
||||
|
||||
# Address of the gateway listener to which all client requests should be sent.
|
||||
gateway_listener = '{{ client.gateway_endpoint.gateway_listener }}'
|
||||
|
||||
|
||||
##### socket config options #####
|
||||
|
||||
|
||||
@@ -148,6 +148,10 @@ impl NymClient {
|
||||
if gateway_id.is_empty() {
|
||||
panic!("The identity of the gateway is unknown - did you run `nym-client` init?")
|
||||
}
|
||||
let gateway_owner = self.config.get_base().get_gateway_owner();
|
||||
if gateway_owner.is_empty() {
|
||||
panic!("The owner of the gateway is unknown - did you run `nym-client` init?")
|
||||
}
|
||||
let gateway_address = self.config.get_base().get_gateway_listener();
|
||||
if gateway_address.is_empty() {
|
||||
panic!("The address of the gateway is unknown - did you run `nym-client` init?")
|
||||
@@ -173,6 +177,7 @@ impl NymClient {
|
||||
gateway_address,
|
||||
self.key_manager.identity_keypair(),
|
||||
gateway_identity,
|
||||
gateway_owner,
|
||||
Some(self.key_manager.gateway_shared_key()),
|
||||
mixnet_message_sender,
|
||||
ack_sender,
|
||||
|
||||
@@ -136,6 +136,7 @@ async fn register_with_gateway(
|
||||
let mut gateway_client = GatewayClient::new_init(
|
||||
gateway.clients_address(),
|
||||
gateway.identity_key,
|
||||
gateway.owner.clone(),
|
||||
our_identity.clone(),
|
||||
timeout,
|
||||
);
|
||||
@@ -256,15 +257,14 @@ pub async fn execute(matches: ArgMatches<'static>) {
|
||||
chosen_gateway_id,
|
||||
)
|
||||
.await;
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_id(gateway_details.identity_key.to_base58_string());
|
||||
let shared_keys =
|
||||
register_with_gateway(&gateway_details, key_manager.identity_keypair()).await;
|
||||
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_listener(gateway_details.clients_address());
|
||||
config.get_base_mut().with_gateway_endpoint(
|
||||
gateway_details.identity_key.to_base58_string(),
|
||||
gateway_details.owner.clone(),
|
||||
gateway_details.clients_address(),
|
||||
);
|
||||
key_manager.insert_gateway_shared_key(shared_keys);
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
|
||||
@@ -54,7 +54,7 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches<'_>) -> C
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
if let Some(eth_endpoint) = matches.value_of(ETH_ENDPOINT_ARG_NAME) {
|
||||
config.get_base_mut().with_eth_endpoint(eth_endpoint);
|
||||
} else {
|
||||
} else if !cfg!(feature = "eth") {
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_eth_endpoint(DEFAULT_ETH_ENDPOINT);
|
||||
@@ -62,7 +62,7 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches<'_>) -> C
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
if let Some(eth_private_key) = matches.value_of(ETH_PRIVATE_KEY_ARG_NAME) {
|
||||
config.get_base_mut().with_eth_private_key(eth_private_key);
|
||||
} else {
|
||||
} else if !cfg!(feature = "eth") {
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY);
|
||||
|
||||
Generated
+17
-7
@@ -11,6 +11,7 @@
|
||||
"@tauri-apps/api": "^1.0.0-beta.4",
|
||||
"compression": "^1.7.1",
|
||||
"polka": "next",
|
||||
"qrious": "^4.0.2",
|
||||
"sirv": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -6758,6 +6759,11 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/qrious": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/qrious/-/qrious-4.0.2.tgz",
|
||||
"integrity": "sha512-xWPJIrK1zu5Ypn898fBp8RHkT/9ibquV2Kv24S/JY9VYEhMBMKur1gHVsOiNUh7PHP9uCgejjpZUHUIXXKoU/g=="
|
||||
},
|
||||
"node_modules/query-string": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz",
|
||||
@@ -7579,11 +7585,10 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/simple-get": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz",
|
||||
"integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==",
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz",
|
||||
"integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"decompress-response": "^4.2.0",
|
||||
"once": "^1.3.1",
|
||||
@@ -13474,6 +13479,11 @@
|
||||
"escape-goat": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"qrious": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/qrious/-/qrious-4.0.2.tgz",
|
||||
"integrity": "sha512-xWPJIrK1zu5Ypn898fBp8RHkT/9ibquV2Kv24S/JY9VYEhMBMKur1gHVsOiNUh7PHP9uCgejjpZUHUIXXKoU/g=="
|
||||
},
|
||||
"query-string": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz",
|
||||
@@ -14036,9 +14046,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"simple-get": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz",
|
||||
"integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==",
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz",
|
||||
"integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"decompress-response": "^4.2.0",
|
||||
|
||||
@@ -1813,7 +1813,7 @@ decompress-response@^3.2.0, decompress-response@^3.3.0:
|
||||
|
||||
decompress-response@^4.2.0:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz"
|
||||
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-4.2.1.tgz#414023cc7a302da25ce2ec82d0d5238ccafd8986"
|
||||
integrity sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==
|
||||
dependencies:
|
||||
mimic-response "^2.0.0"
|
||||
@@ -3130,7 +3130,7 @@ mimic-response@^1.0.0, mimic-response@^1.0.1:
|
||||
|
||||
mimic-response@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz"
|
||||
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43"
|
||||
integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==
|
||||
|
||||
mimic-response@^3.1.0:
|
||||
@@ -4056,13 +4056,13 @@ signal-exit@^3.0.0, signal-exit@^3.0.2:
|
||||
|
||||
simple-concat@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz"
|
||||
resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f"
|
||||
integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==
|
||||
|
||||
simple-get@^3.0.3, simple-get@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz"
|
||||
integrity sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-3.1.1.tgz#cc7ba77cfbe761036fbfce3d021af25fc5584d55"
|
||||
integrity sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==
|
||||
dependencies:
|
||||
decompress-response "^4.2.0"
|
||||
once "^1.3.1"
|
||||
@@ -4673,7 +4673,7 @@ wrap-ansi@^7.0.0:
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
||||
|
||||
write-file-atomic@^3.0.0:
|
||||
|
||||
+19
-16
@@ -22,7 +22,10 @@
|
||||
"webpack-dev-server": "^3.11.0"
|
||||
}
|
||||
},
|
||||
"../pkg": {},
|
||||
"../pkg": {
|
||||
"name": "@nymproject/nym-client-wasm",
|
||||
"version": "0.0.1"
|
||||
},
|
||||
"node_modules/@nymproject/nym-client-wasm": {
|
||||
"resolved": "../pkg",
|
||||
"link": true
|
||||
@@ -2351,9 +2354,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz",
|
||||
"integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==",
|
||||
"version": "1.14.8",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
|
||||
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -5859,9 +5862,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/url-parse": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.1.tgz",
|
||||
"integrity": "sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==",
|
||||
"version": "1.5.7",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.7.tgz",
|
||||
"integrity": "sha512-HxWkieX+STA38EDk7CE9MEryFeHCKzgagxlGvsdS7WBImq9Mk+PGwiT56w82WI3aicwJA8REp42Cxo98c8FZMA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"querystringify": "^2.1.1",
|
||||
@@ -6500,9 +6503,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
|
||||
"integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz",
|
||||
"integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"async-limiter": "~1.0.0"
|
||||
@@ -8542,9 +8545,9 @@
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz",
|
||||
"integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==",
|
||||
"version": "1.14.8",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
|
||||
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==",
|
||||
"dev": true
|
||||
},
|
||||
"for-in": {
|
||||
@@ -11399,9 +11402,9 @@
|
||||
}
|
||||
},
|
||||
"url-parse": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.1.tgz",
|
||||
"integrity": "sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==",
|
||||
"version": "1.5.7",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.7.tgz",
|
||||
"integrity": "sha512-HxWkieX+STA38EDk7CE9MEryFeHCKzgagxlGvsdS7WBImq9Mk+PGwiT56w82WI3aicwJA8REp42Cxo98c8FZMA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"querystringify": "^2.1.1",
|
||||
|
||||
+510
-629
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@
|
||||
"@testing-library/react": "^9.5.0",
|
||||
"@testing-library/user-event": "^7.2.1",
|
||||
"bootstrap": "^4.5.0",
|
||||
"node-sass": "^4.14.1",
|
||||
"node-sass": "^7.0.0",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-scripts": "^4.0.0",
|
||||
|
||||
@@ -127,6 +127,7 @@ impl NymClient {
|
||||
gateway.clients_address(),
|
||||
Arc::clone(&client.identity),
|
||||
gateway.identity_key,
|
||||
gateway.owner.clone(),
|
||||
None,
|
||||
mixnet_messages_sender,
|
||||
ack_sender,
|
||||
|
||||
@@ -23,6 +23,7 @@ credentials = { path = "../../credentials" }
|
||||
crypto = { path = "../../crypto" }
|
||||
gateway-requests = { path = "../../../gateway/gateway-requests" }
|
||||
nymsphinx = { path = "../../nymsphinx" }
|
||||
pemstore = { path = "../../pemstore" }
|
||||
coconut-interface = { path = "../../coconut-interface", optional = true }
|
||||
network-defaults = { path = "../../network-defaults" }
|
||||
|
||||
|
||||
@@ -16,22 +16,27 @@ use crypto::asymmetric::identity::PublicKey;
|
||||
use network_defaults::BANDWIDTH_VALUE;
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use network_defaults::{
|
||||
eth_contract::ETH_JSON_ABI, ETH_BURN_FUNCTION_NAME, ETH_CONTRACT_ADDRESS, ETH_MIN_BLOCK_DEPTH,
|
||||
TOKENS_TO_BURN,
|
||||
eth_contract::ETH_ERC20_JSON_ABI, eth_contract::ETH_JSON_ABI, 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;
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use std::io::Write;
|
||||
use std::io::{Read, Write};
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use std::str::FromStr;
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use web3::{
|
||||
contract::{Contract, Options},
|
||||
ethabi::Token,
|
||||
signing::{Key, SecretKeyRef},
|
||||
transports::Http,
|
||||
types::{Address, Bytes, U256, U64},
|
||||
types::{Address, U256, U64},
|
||||
Web3,
|
||||
};
|
||||
|
||||
@@ -50,6 +55,19 @@ pub fn eth_contract(web3: Web3<Http>) -> Contract<Http> {
|
||||
.expect("Invalid json abi")
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
pub fn eth_erc20_contract(web3: Web3<Http>) -> Contract<Http> {
|
||||
Contract::from_json(
|
||||
web3.eth(),
|
||||
Address::from(ETH_ERC20_CONTRACT_ADDRESS),
|
||||
json::parse(ETH_ERC20_JSON_ABI)
|
||||
.expect("Invalid json abi")
|
||||
.dump()
|
||||
.as_bytes(),
|
||||
)
|
||||
.expect("Invalid json abi")
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BandwidthController {
|
||||
#[cfg(feature = "coconut")]
|
||||
@@ -59,6 +77,8 @@ pub struct BandwidthController {
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
contract: Contract<Http>,
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
erc20_contract: Contract<Http>,
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
eth_private_key: SecretKey,
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
backup_bandwidth_token_keys_dir: std::path::PathBuf,
|
||||
@@ -84,12 +104,14 @@ impl BandwidthController {
|
||||
Http::new(ð_endpoint).map_err(|_| GatewayClientError::InvalidURL(eth_endpoint))?;
|
||||
let web3 = web3::Web3::new(transport);
|
||||
// Fail early, on invalid abi
|
||||
let contract = eth_contract(web3);
|
||||
let contract = eth_contract(web3.clone());
|
||||
let erc20_contract = eth_erc20_contract(web3);
|
||||
let eth_private_key = secp256k1::SecretKey::from_str(ð_private_key)
|
||||
.map_err(|_| GatewayClientError::InvalidEthereumPrivateKey)?;
|
||||
|
||||
Ok(BandwidthController {
|
||||
contract,
|
||||
erc20_contract,
|
||||
eth_private_key,
|
||||
backup_bandwidth_token_keys_dir,
|
||||
})
|
||||
@@ -107,6 +129,45 @@ impl BandwidthController {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
fn restore_keypair(&self) -> Result<identity::KeyPair, GatewayClientError> {
|
||||
std::fs::create_dir_all(&self.backup_bandwidth_token_keys_dir)?;
|
||||
let file = std::fs::read_dir(&self.backup_bandwidth_token_keys_dir)?
|
||||
.find(|entry| {
|
||||
entry
|
||||
.as_ref()
|
||||
.map(|entry| entry.path().is_file())
|
||||
.unwrap_or(false)
|
||||
})
|
||||
.unwrap_or_else(|| Err(std::io::Error::from(std::io::ErrorKind::NotFound)))?;
|
||||
let file_path = file.path();
|
||||
let pub_key = file_path
|
||||
.file_name()
|
||||
.ok_or_else(|| std::io::Error::from(std::io::ErrorKind::NotFound))?
|
||||
.to_str()
|
||||
.ok_or_else(|| std::io::Error::from(std::io::ErrorKind::NotFound))?;
|
||||
let mut priv_key = vec![];
|
||||
std::fs::File::open(file_path.clone())?.read_to_end(&mut priv_key)?;
|
||||
Ok(identity::KeyPair::from_keys(
|
||||
identity::PrivateKey::from_bytes(&priv_key).unwrap(),
|
||||
identity::PublicKey::from_base58_string(pub_key).unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
fn mark_keypair_as_spent(&self, keypair: &identity::KeyPair) -> Result<(), GatewayClientError> {
|
||||
let mut spent_dir = self.backup_bandwidth_token_keys_dir.clone();
|
||||
spent_dir.push("spent");
|
||||
std::fs::create_dir_all(&spent_dir)?;
|
||||
let file_path_old = self
|
||||
.backup_bandwidth_token_keys_dir
|
||||
.join(keypair.public_key().to_base58_string());
|
||||
let file_path_new = spent_dir.join(keypair.public_key().to_base58_string());
|
||||
std::fs::rename(file_path_old, file_path_new)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "coconut")]
|
||||
pub async fn prepare_coconut_credential(
|
||||
&self,
|
||||
@@ -145,17 +206,25 @@ impl BandwidthController {
|
||||
pub async fn prepare_token_credential(
|
||||
&self,
|
||||
gateway_identity: PublicKey,
|
||||
gateway_owner: String,
|
||||
) -> Result<TokenCredential, GatewayClientError> {
|
||||
let mut rng = OsRng;
|
||||
|
||||
let kp = identity::KeyPair::new(&mut rng);
|
||||
self.backup_keypair(&kp)?;
|
||||
let kp = match self.restore_keypair() {
|
||||
Ok(kp) => kp,
|
||||
Err(_) => {
|
||||
let mut rng = OsRng;
|
||||
let kp = identity::KeyPair::new(&mut rng);
|
||||
self.backup_keypair(&kp)?;
|
||||
kp
|
||||
}
|
||||
};
|
||||
|
||||
let verification_key = *kp.public_key();
|
||||
let signed_verification_key = kp.private_key().sign(&verification_key.to_bytes());
|
||||
self.buy_token_credential(verification_key, signed_verification_key)
|
||||
self.buy_token_credential(verification_key, signed_verification_key, gateway_owner)
|
||||
.await?;
|
||||
|
||||
self.mark_keypair_as_spent(&kp)?;
|
||||
|
||||
let message: Vec<u8> = verification_key
|
||||
.to_bytes()
|
||||
.iter()
|
||||
@@ -177,28 +246,109 @@ impl BandwidthController {
|
||||
&self,
|
||||
verification_key: PublicKey,
|
||||
signed_verification_key: identity::Signature,
|
||||
gateway_owner: String,
|
||||
) -> Result<(), GatewayClientError> {
|
||||
// 0 means a transaction failure, 1 means success
|
||||
let confirmations = if cfg!(debug_assertions) {
|
||||
1
|
||||
} else {
|
||||
ETH_MIN_BLOCK_DEPTH
|
||||
};
|
||||
// 15 seconds per confirmation block + 10 seconds of network overhead
|
||||
// 15 seconds per confirmation block + 10 seconds of network overhead + 20 seconds of wait for kill
|
||||
log::info!(
|
||||
"Waiting for Ethereum transaction. This should take about {} seconds",
|
||||
confirmations * 15 + 10
|
||||
(confirmations + 1) * 15 + 30
|
||||
);
|
||||
let mut options = Options::default();
|
||||
let estimation = self
|
||||
.erc20_contract
|
||||
.estimate_gas(
|
||||
ETH_ERC20_APPROVE_FUNCTION_NAME,
|
||||
(
|
||||
Token::Address(Address::from(ETH_CONTRACT_ADDRESS)),
|
||||
Token::Uint(U256::from(UTOKENS_TO_BURN)),
|
||||
),
|
||||
SecretKeyRef::from(&self.eth_private_key).address(),
|
||||
options.clone(),
|
||||
)
|
||||
.await?;
|
||||
options.gas = Some(estimation);
|
||||
log::info!("Calling ERC20 approve in 10 seconds with an estimated gas of {}. Kill the process if you want to abort", estimation);
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
if let Err(err) = fluvio_wasm_timer::Delay::new(std::time::Duration::from_secs(10)).await {
|
||||
log::error!(
|
||||
"the timer has gone away while waiting for possible kill! - {}",
|
||||
err
|
||||
);
|
||||
}
|
||||
let recipt = self
|
||||
.erc20_contract
|
||||
.signed_call_with_confirmations(
|
||||
ETH_ERC20_APPROVE_FUNCTION_NAME,
|
||||
(
|
||||
Token::Address(Address::from(ETH_CONTRACT_ADDRESS)),
|
||||
Token::Uint(U256::from(UTOKENS_TO_BURN)),
|
||||
),
|
||||
options,
|
||||
1, // One confirmation is enough, as we'll be consuming the approved token next anyway
|
||||
&self.eth_private_key,
|
||||
)
|
||||
.await?;
|
||||
if Some(U64::from(0u64)) == recipt.status {
|
||||
return Err(GatewayClientError::BurnTokenError(
|
||||
web3::Error::InvalidResponse(format!(
|
||||
"Approve transaction status is 0 (failure): {:?}",
|
||||
recipt.logs,
|
||||
)),
|
||||
));
|
||||
} else {
|
||||
log::info!(
|
||||
"Approved {} tokens for bandwidth use on Ethereum",
|
||||
TOKENS_TO_BURN
|
||||
);
|
||||
}
|
||||
|
||||
let mut options = Options::default();
|
||||
let estimation = self
|
||||
.contract
|
||||
.estimate_gas(
|
||||
ETH_BURN_FUNCTION_NAME,
|
||||
(
|
||||
Token::Uint(U256::from(UTOKENS_TO_BURN)),
|
||||
Token::Uint(U256::from(&verification_key.to_bytes())),
|
||||
Token::Bytes(signed_verification_key.to_bytes().to_vec()),
|
||||
Token::String(gateway_owner.clone()),
|
||||
),
|
||||
SecretKeyRef::from(&self.eth_private_key).address(),
|
||||
options.clone(),
|
||||
)
|
||||
.await?;
|
||||
options.gas = Some(estimation);
|
||||
log::info!("Generating bandwidth on ETH contract in 10 seconds with an estimated gas of {}. \
|
||||
Kill the process if you want to abort. Keep in mind that if you abort now, you'll still have \
|
||||
some tokens approved for bandwidth spending from the previous action. \
|
||||
If you don't want that, you'll need to manually decreaseAllowance to revert the approval.", estimation);
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
if let Err(err) = fluvio_wasm_timer::Delay::new(std::time::Duration::from_secs(10)).await {
|
||||
log::error!(
|
||||
"the timer has gone away while waiting for possible kill! - {}",
|
||||
err
|
||||
);
|
||||
}
|
||||
let recipt = self
|
||||
.contract
|
||||
.signed_call_with_confirmations(
|
||||
ETH_BURN_FUNCTION_NAME,
|
||||
(
|
||||
U256::from(TOKENS_TO_BURN),
|
||||
U256::from(&verification_key.to_bytes()),
|
||||
Bytes(signed_verification_key.to_bytes().to_vec()),
|
||||
Token::Uint(U256::from(UTOKENS_TO_BURN)),
|
||||
Token::Uint(U256::from(&verification_key.to_bytes())),
|
||||
Token::Bytes(signed_verification_key.to_bytes().to_vec()),
|
||||
Token::String(gateway_owner),
|
||||
),
|
||||
Options::default(),
|
||||
options,
|
||||
confirmations,
|
||||
&self.eth_private_key,
|
||||
)
|
||||
@@ -236,6 +386,15 @@ mod tests {
|
||||
eth_contract(web3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_erc20_contract() {
|
||||
let transport =
|
||||
Http::new("https://rinkeby.infura.io/v3/00000000000000000000000000000000").unwrap();
|
||||
let web3 = web3::Web3::new(transport);
|
||||
// test no panic occurs
|
||||
eth_erc20_contract(web3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_event_name_constant_against_abi() {
|
||||
let transport =
|
||||
|
||||
@@ -20,6 +20,7 @@ use gateway_requests::iv::IV;
|
||||
use gateway_requests::registration::handshake::{client_handshake, SharedKeys};
|
||||
use gateway_requests::{BinaryRequest, ClientControlRequest, ServerResponse};
|
||||
use log::*;
|
||||
use network_defaults::{REMAINING_BANDWIDTH_THRESHOLD, TOKENS_TO_BURN};
|
||||
use nymsphinx::forwarding::packet::MixPacket;
|
||||
use rand::rngs::OsRng;
|
||||
use std::convert::TryFrom;
|
||||
@@ -44,6 +45,7 @@ pub struct GatewayClient {
|
||||
bandwidth_remaining: i64,
|
||||
gateway_address: String,
|
||||
gateway_identity: identity::PublicKey,
|
||||
gateway_owner: String,
|
||||
local_identity: Arc<identity::KeyPair>,
|
||||
shared_key: Option<Arc<SharedKeys>>,
|
||||
connection: SocketState,
|
||||
@@ -68,6 +70,7 @@ impl GatewayClient {
|
||||
gateway_address: String,
|
||||
local_identity: Arc<identity::KeyPair>,
|
||||
gateway_identity: identity::PublicKey,
|
||||
gateway_owner: String,
|
||||
shared_key: Option<Arc<SharedKeys>>,
|
||||
mixnet_message_sender: MixnetMessageSender,
|
||||
ack_sender: AcknowledgementSender,
|
||||
@@ -80,6 +83,7 @@ impl GatewayClient {
|
||||
bandwidth_remaining: 0,
|
||||
gateway_address,
|
||||
gateway_identity,
|
||||
gateway_owner,
|
||||
local_identity,
|
||||
shared_key,
|
||||
connection: SocketState::NotConnected,
|
||||
@@ -112,6 +116,7 @@ impl GatewayClient {
|
||||
pub fn new_init(
|
||||
gateway_address: String,
|
||||
gateway_identity: identity::PublicKey,
|
||||
gateway_owner: String,
|
||||
local_identity: Arc<identity::KeyPair>,
|
||||
response_timeout_duration: Duration,
|
||||
) -> Self {
|
||||
@@ -129,6 +134,7 @@ impl GatewayClient {
|
||||
bandwidth_remaining: 0,
|
||||
gateway_address,
|
||||
gateway_identity,
|
||||
gateway_owner,
|
||||
local_identity,
|
||||
shared_key: None,
|
||||
connection: SocketState::NotConnected,
|
||||
@@ -548,6 +554,8 @@ impl GatewayClient {
|
||||
return self.try_claim_testnet_bandwidth().await;
|
||||
}
|
||||
|
||||
let _gateway_owner = self.gateway_owner.clone();
|
||||
|
||||
#[cfg(feature = "coconut")]
|
||||
let credential = self
|
||||
.bandwidth_controller
|
||||
@@ -560,7 +568,7 @@ impl GatewayClient {
|
||||
.bandwidth_controller
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.prepare_token_credential(self.gateway_identity)
|
||||
.prepare_token_credential(self.gateway_identity, _gateway_owner)
|
||||
.await?;
|
||||
|
||||
#[cfg(feature = "coconut")]
|
||||
@@ -584,15 +592,10 @@ impl GatewayClient {
|
||||
return Err(GatewayClientError::NotAuthenticated);
|
||||
}
|
||||
if self.estimate_required_bandwidth(&packets) > self.bandwidth_remaining {
|
||||
// Try to claim more bandwidth first, and return an error only if that is still not
|
||||
// enough (the current granularity for bandwidth should be sufficient)
|
||||
self.claim_bandwidth().await?;
|
||||
if self.estimate_required_bandwidth(&packets) > self.bandwidth_remaining {
|
||||
return Err(GatewayClientError::NotEnoughBandwidth(
|
||||
self.estimate_required_bandwidth(&packets),
|
||||
self.bandwidth_remaining,
|
||||
));
|
||||
}
|
||||
return Err(GatewayClientError::NotEnoughBandwidth(
|
||||
self.estimate_required_bandwidth(&packets),
|
||||
self.bandwidth_remaining,
|
||||
));
|
||||
}
|
||||
if !self.connection.is_established() {
|
||||
return Err(GatewayClientError::ConnectionNotEstablished);
|
||||
@@ -659,15 +662,10 @@ impl GatewayClient {
|
||||
return Err(GatewayClientError::NotAuthenticated);
|
||||
}
|
||||
if (mix_packet.sphinx_packet().len() as i64) > self.bandwidth_remaining {
|
||||
// Try to claim more bandwidth first, and return an error only if that is still not
|
||||
// enough
|
||||
self.claim_bandwidth().await?;
|
||||
if (mix_packet.sphinx_packet().len() as i64) > self.bandwidth_remaining {
|
||||
return Err(GatewayClientError::NotEnoughBandwidth(
|
||||
mix_packet.sphinx_packet().len() as i64,
|
||||
self.bandwidth_remaining,
|
||||
));
|
||||
}
|
||||
return Err(GatewayClientError::NotEnoughBandwidth(
|
||||
mix_packet.sphinx_packet().len() as i64,
|
||||
self.bandwidth_remaining,
|
||||
));
|
||||
}
|
||||
if !self.connection.is_established() {
|
||||
return Err(GatewayClientError::ConnectionNotEstablished);
|
||||
@@ -737,6 +735,12 @@ impl GatewayClient {
|
||||
}
|
||||
let shared_key = self.perform_initial_authentication().await?;
|
||||
|
||||
if self.bandwidth_remaining < REMAINING_BANDWIDTH_THRESHOLD {
|
||||
info!("Claiming more bandwidth for your tokens. This will use {} token(s) from your wallet. \
|
||||
Stop the process now if you don't want that to happen.", TOKENS_TO_BURN);
|
||||
self.claim_bandwidth().await?;
|
||||
}
|
||||
|
||||
// this call is NON-blocking
|
||||
self.start_listening_for_mixnet_messages()?;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ use tungstenite::Error as WsError;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use wasm_bindgen::JsValue;
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
use web3::Error as Web3Error;
|
||||
use web3::{contract::Error as Web3ContractError, Error as Web3Error};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum GatewayClientError {
|
||||
@@ -27,13 +27,17 @@ pub enum GatewayClientError {
|
||||
NetworkErrorWasm(JsValue),
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
#[error("Could not backup keypair - {0}")]
|
||||
#[error("Keypair IO error - {0}")]
|
||||
IOError(#[from] std::io::Error),
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
#[error("Could not burn ERC20 token in Ethereum smart contract - {0}")]
|
||||
BurnTokenError(#[from] Web3Error),
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
#[error("Could not run web3 contract - {0}")]
|
||||
Web3ContractError(#[from] Web3ContractError),
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
#[error("Invalid Ethereum private key")]
|
||||
InvalidEthereumPrivateKey,
|
||||
|
||||
@@ -39,7 +39,8 @@ flate2 = { version = "1.0.20", optional = true }
|
||||
sha2 = { version = "0.9.5", optional = true }
|
||||
itertools = { version = "0.10", optional = true }
|
||||
cosmwasm-std = { version = "1.0.0-beta3", optional = true }
|
||||
ts-rs = { version = "5.1", optional = true }
|
||||
# Leaving it as * so that it inherits whatever the wallet is using
|
||||
ts-rs = { version = "*", optional = true }
|
||||
|
||||
[features]
|
||||
nymd-client = [
|
||||
|
||||
@@ -35,6 +35,7 @@ pub struct Config {
|
||||
nymd_url: Url,
|
||||
mixnet_contract_address: Option<cosmrs::AccountId>,
|
||||
vesting_contract_address: Option<cosmrs::AccountId>,
|
||||
erc20_bridge_contract_address: Option<cosmrs::AccountId>,
|
||||
|
||||
mixnode_page_limit: Option<u32>,
|
||||
gateway_page_limit: Option<u32>,
|
||||
@@ -50,12 +51,14 @@ impl Config {
|
||||
api_url: Url,
|
||||
mixnet_contract_address: Option<cosmrs::AccountId>,
|
||||
vesting_contract_address: Option<cosmrs::AccountId>,
|
||||
erc20_bridge_contract_address: Option<cosmrs::AccountId>,
|
||||
) -> Self {
|
||||
Config {
|
||||
network,
|
||||
nymd_url,
|
||||
mixnet_contract_address,
|
||||
vesting_contract_address,
|
||||
erc20_bridge_contract_address,
|
||||
api_url,
|
||||
mixnode_page_limit: None,
|
||||
gateway_page_limit: None,
|
||||
@@ -90,6 +93,7 @@ pub struct Client<C> {
|
||||
network: network_defaults::all::Network,
|
||||
mixnet_contract_address: Option<cosmrs::AccountId>,
|
||||
vesting_contract_address: Option<cosmrs::AccountId>,
|
||||
erc20_bridge_contract_address: Option<cosmrs::AccountId>,
|
||||
mnemonic: Option<bip39::Mnemonic>,
|
||||
|
||||
mixnode_page_limit: Option<u32>,
|
||||
@@ -114,6 +118,7 @@ impl Client<SigningNymdClient> {
|
||||
config.nymd_url.as_str(),
|
||||
config.mixnet_contract_address.clone(),
|
||||
config.vesting_contract_address.clone(),
|
||||
config.erc20_bridge_contract_address.clone(),
|
||||
mnemonic.clone(),
|
||||
None,
|
||||
)?;
|
||||
@@ -122,6 +127,7 @@ impl Client<SigningNymdClient> {
|
||||
network: config.network,
|
||||
mixnet_contract_address: config.mixnet_contract_address,
|
||||
vesting_contract_address: config.vesting_contract_address,
|
||||
erc20_bridge_contract_address: config.erc20_bridge_contract_address,
|
||||
mnemonic: Some(mnemonic),
|
||||
mixnode_page_limit: config.mixnode_page_limit,
|
||||
gateway_page_limit: config.gateway_page_limit,
|
||||
@@ -138,6 +144,7 @@ impl Client<SigningNymdClient> {
|
||||
new_endpoint.as_ref(),
|
||||
self.mixnet_contract_address.clone(),
|
||||
self.vesting_contract_address.clone(),
|
||||
self.erc20_bridge_contract_address.clone(),
|
||||
self.mnemonic.clone().unwrap(),
|
||||
None,
|
||||
)?;
|
||||
@@ -159,12 +166,24 @@ impl Client<QueryNymdClient> {
|
||||
cosmrs::AccountId::from_str(network_defaults::DEFAULT_VESTING_CONTRACT_ADDRESS)
|
||||
.unwrap()
|
||||
})),
|
||||
Some(
|
||||
config
|
||||
.erc20_bridge_contract_address
|
||||
.clone()
|
||||
.unwrap_or_else(|| {
|
||||
cosmrs::AccountId::from_str(
|
||||
network_defaults::DEFAULT_BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
),
|
||||
)?;
|
||||
|
||||
Ok(Client {
|
||||
network: config.network,
|
||||
mixnet_contract_address: config.mixnet_contract_address,
|
||||
vesting_contract_address: config.vesting_contract_address,
|
||||
erc20_bridge_contract_address: config.erc20_bridge_contract_address,
|
||||
mnemonic: None,
|
||||
mixnode_page_limit: config.mixnode_page_limit,
|
||||
gateway_page_limit: config.gateway_page_limit,
|
||||
@@ -180,6 +199,7 @@ impl Client<QueryNymdClient> {
|
||||
new_endpoint.as_ref(),
|
||||
self.mixnet_contract_address.clone(),
|
||||
self.vesting_contract_address.clone(),
|
||||
self.erc20_bridge_contract_address.clone(),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -232,7 +252,7 @@ impl<C> Client<C> {
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
Ok(self.nymd.get_mixnet_contract_version().await?)
|
||||
self.nymd.get_mixnet_contract_version().await
|
||||
}
|
||||
|
||||
pub async fn get_rewarding_status(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nymd::cosmwasm_client::helpers::create_pagination;
|
||||
use crate::nymd::cosmwasm_client::helpers::{create_pagination, next_page_key};
|
||||
use crate::nymd::cosmwasm_client::types::{
|
||||
Account, Code, CodeDetails, Contract, ContractCodeHistoryEntry, ContractCodeId,
|
||||
SequenceResponse, SimulateResponse,
|
||||
@@ -150,8 +150,8 @@ pub trait CosmWasmClient: rpc::Client {
|
||||
.await?;
|
||||
|
||||
raw_balances.append(&mut res.balances);
|
||||
if let Some(pagination_info) = res.pagination {
|
||||
pagination = Some(create_pagination(pagination_info.next_key))
|
||||
if let Some(next_key) = next_page_key(res.pagination) {
|
||||
pagination = Some(create_pagination(next_key))
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -182,8 +182,8 @@ pub trait CosmWasmClient: rpc::Client {
|
||||
.await?;
|
||||
|
||||
supply.append(&mut res.supply);
|
||||
if let Some(pagination_info) = res.pagination {
|
||||
pagination = Some(create_pagination(pagination_info.next_key))
|
||||
if let Some(next_key) = next_page_key(res.pagination) {
|
||||
pagination = Some(create_pagination(next_key))
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -274,8 +274,8 @@ pub trait CosmWasmClient: rpc::Client {
|
||||
.await?;
|
||||
|
||||
raw_codes.append(&mut res.code_infos);
|
||||
if let Some(pagination_info) = res.pagination {
|
||||
pagination = Some(create_pagination(pagination_info.next_key))
|
||||
if let Some(next_key) = next_page_key(res.pagination) {
|
||||
pagination = Some(create_pagination(next_key))
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -319,8 +319,8 @@ pub trait CosmWasmClient: rpc::Client {
|
||||
.await?;
|
||||
|
||||
raw_contracts.append(&mut res.contracts);
|
||||
if let Some(pagination_info) = res.pagination {
|
||||
pagination = Some(create_pagination(pagination_info.next_key))
|
||||
if let Some(next_key) = next_page_key(res.pagination) {
|
||||
pagination = Some(create_pagination(next_key))
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -375,8 +375,8 @@ pub trait CosmWasmClient: rpc::Client {
|
||||
.await?;
|
||||
|
||||
raw_entries.append(&mut res.entries);
|
||||
if let Some(pagination_info) = res.pagination {
|
||||
pagination = Some(create_pagination(pagination_info.next_key))
|
||||
if let Some(next_key) = next_page_key(res.pagination) {
|
||||
pagination = Some(create_pagination(next_key))
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nymd::error::NymdError;
|
||||
use cosmrs::proto::cosmos::base::query::v1beta1::PageRequest;
|
||||
use cosmrs::proto::cosmos::base::query::v1beta1::{PageRequest, PageResponse};
|
||||
use cosmrs::rpc::endpoint::broadcast;
|
||||
use flate2::write::GzEncoder;
|
||||
use flate2::Compression;
|
||||
@@ -53,3 +53,15 @@ pub(crate) fn create_pagination(key: Vec<u8>) -> PageRequest {
|
||||
count_total: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn next_page_key(pagination_info: Option<PageResponse>) -> Option<Vec<u8>> {
|
||||
if let Some(next_page_info) = pagination_info {
|
||||
// it turns out, even though `PageResponse` is always returned wrapped in an `Option`,
|
||||
// the `next_key` can still be empty, so check whether we actually need to perform another call
|
||||
if !next_page_info.next_key.is_empty() {
|
||||
return Some(next_page_info.next_key);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ pub struct NymdClient<C> {
|
||||
client: C,
|
||||
mixnet_contract_address: Option<AccountId>,
|
||||
vesting_contract_address: Option<AccountId>,
|
||||
erc20_bridge_contract_address: Option<AccountId>,
|
||||
client_address: Option<Vec<AccountId>>,
|
||||
custom_gas_limits: HashMap<Operation, Gas>,
|
||||
simulated_gas_multiplier: f32,
|
||||
@@ -62,6 +63,7 @@ impl NymdClient<QueryNymdClient> {
|
||||
endpoint: U,
|
||||
mixnet_contract_address: Option<AccountId>,
|
||||
vesting_contract_address: Option<AccountId>,
|
||||
erc20_bridge_contract_address: Option<AccountId>,
|
||||
) -> Result<NymdClient<QueryNymdClient>, NymdError>
|
||||
where
|
||||
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
|
||||
@@ -70,6 +72,7 @@ impl NymdClient<QueryNymdClient> {
|
||||
client: QueryNymdClient::new(endpoint)?,
|
||||
mixnet_contract_address,
|
||||
vesting_contract_address,
|
||||
erc20_bridge_contract_address,
|
||||
client_address: None,
|
||||
custom_gas_limits: Default::default(),
|
||||
simulated_gas_multiplier: DEFAULT_SIMULATED_GAS_MULTIPLIER,
|
||||
@@ -83,6 +86,7 @@ impl NymdClient<SigningNymdClient> {
|
||||
endpoint: U,
|
||||
mixnet_contract_address: Option<AccountId>,
|
||||
vesting_contract_address: Option<AccountId>,
|
||||
erc20_bridge_contract_address: Option<AccountId>,
|
||||
signer: DirectSecp256k1HdWallet,
|
||||
gas_price: Option<GasPrice>,
|
||||
) -> Result<NymdClient<SigningNymdClient>, NymdError>
|
||||
@@ -99,6 +103,7 @@ impl NymdClient<SigningNymdClient> {
|
||||
client: SigningNymdClient::connect_with_signer(endpoint, signer, gas_price)?,
|
||||
mixnet_contract_address,
|
||||
vesting_contract_address,
|
||||
erc20_bridge_contract_address,
|
||||
client_address: Some(client_address),
|
||||
custom_gas_limits: Default::default(),
|
||||
simulated_gas_multiplier: DEFAULT_SIMULATED_GAS_MULTIPLIER,
|
||||
@@ -110,6 +115,7 @@ impl NymdClient<SigningNymdClient> {
|
||||
endpoint: U,
|
||||
mixnet_contract_address: Option<AccountId>,
|
||||
vesting_contract_address: Option<AccountId>,
|
||||
erc20_bridge_contract_address: Option<AccountId>,
|
||||
mnemonic: bip39::Mnemonic,
|
||||
gas_price: Option<GasPrice>,
|
||||
) -> Result<NymdClient<SigningNymdClient>, NymdError>
|
||||
@@ -128,6 +134,7 @@ impl NymdClient<SigningNymdClient> {
|
||||
client: SigningNymdClient::connect_with_signer(endpoint, wallet, gas_price)?,
|
||||
mixnet_contract_address,
|
||||
vesting_contract_address,
|
||||
erc20_bridge_contract_address,
|
||||
client_address: Some(client_address),
|
||||
custom_gas_limits: Default::default(),
|
||||
simulated_gas_multiplier: DEFAULT_SIMULATED_GAS_MULTIPLIER,
|
||||
@@ -148,6 +155,12 @@ impl<C> NymdClient<C> {
|
||||
.ok_or(NymdError::NoContractAddressAvailable)
|
||||
}
|
||||
|
||||
pub fn erc20_bridge_contract_address(&self) -> Result<&AccountId, NymdError> {
|
||||
self.erc20_bridge_contract_address
|
||||
.as_ref()
|
||||
.ok_or(NymdError::NoContractAddressAvailable)
|
||||
}
|
||||
|
||||
// now the question is as follows: will denom always be in the format of `u{prefix}`?
|
||||
pub fn denom(&self) -> Result<Denom, NymdError> {
|
||||
Ok(format!("u{}", self.mixnet_contract_address()?.prefix())
|
||||
|
||||
@@ -6,8 +6,10 @@ use crate::nymd::error::NymdError;
|
||||
use crate::nymd::NymdClient;
|
||||
use async_trait::async_trait;
|
||||
use cosmwasm_std::{Coin, Timestamp};
|
||||
use vesting_contract::vesting::{Account, PledgeData};
|
||||
use vesting_contract_common::messages::QueryMsg as VestingQueryMsg;
|
||||
use vesting_contract::vesting::Account;
|
||||
use vesting_contract_common::{
|
||||
messages::QueryMsg as VestingQueryMsg, OriginalVestingResponse, Period, PledgeData,
|
||||
};
|
||||
|
||||
#[async_trait]
|
||||
pub trait VestingQueryClient {
|
||||
@@ -43,7 +45,10 @@ pub trait VestingQueryClient {
|
||||
async fn vesting_end_time(&self, vesting_account_address: &str)
|
||||
-> Result<Timestamp, NymdError>;
|
||||
|
||||
async fn original_vesting(&self, vesting_account_address: &str) -> Result<Coin, NymdError>;
|
||||
async fn original_vesting(
|
||||
&self,
|
||||
vesting_account_address: &str,
|
||||
) -> Result<OriginalVestingResponse, NymdError>;
|
||||
|
||||
async fn delegated_free(
|
||||
&self,
|
||||
@@ -60,6 +65,10 @@ pub trait VestingQueryClient {
|
||||
async fn get_account(&self, address: &str) -> Result<Account, NymdError>;
|
||||
async fn get_mixnode_pledge(&self, address: &str) -> Result<Option<PledgeData>, NymdError>;
|
||||
async fn get_gateway_pledge(&self, address: &str) -> Result<Option<PledgeData>, NymdError>;
|
||||
async fn get_current_vesting_period(
|
||||
&self,
|
||||
vesting_account_address: &str,
|
||||
) -> Result<Period, NymdError>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -142,7 +151,10 @@ impl<C: CosmWasmClient + Sync + Send> VestingQueryClient for NymdClient<C> {
|
||||
.await
|
||||
}
|
||||
|
||||
async fn original_vesting(&self, vesting_account_address: &str) -> Result<Coin, NymdError> {
|
||||
async fn original_vesting(
|
||||
&self,
|
||||
vesting_account_address: &str,
|
||||
) -> Result<OriginalVestingResponse, NymdError> {
|
||||
let request = VestingQueryMsg::GetOriginalVesting {
|
||||
vesting_account_address: vesting_account_address.to_string(),
|
||||
};
|
||||
@@ -203,4 +215,13 @@ impl<C: CosmWasmClient + Sync + Send> VestingQueryClient for NymdClient<C> {
|
||||
.query_contract_smart(self.vesting_contract_address()?, &request)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_current_vesting_period(&self, address: &str) -> Result<Period, NymdError> {
|
||||
let request = VestingQueryMsg::GetCurrentVestingPeriod {
|
||||
address: address.to_string(),
|
||||
};
|
||||
self.client
|
||||
.query_contract_smart(self.vesting_contract_address()?, &request)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,11 @@ use vesting_contract_common::messages::{ExecuteMsg as VestingExecuteMsg, Vesting
|
||||
|
||||
#[async_trait]
|
||||
pub trait VestingSigningClient {
|
||||
async fn vesting_update_mixnode_config(
|
||||
&self,
|
||||
profix_margin_percent: u8,
|
||||
) -> Result<ExecuteResult, NymdError>;
|
||||
|
||||
async fn update_mixnet_address(&self, address: &str) -> Result<ExecuteResult, NymdError>;
|
||||
|
||||
async fn vesting_bond_gateway(
|
||||
@@ -316,4 +321,24 @@ impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NymdClient
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn vesting_update_mixnode_config(
|
||||
&self,
|
||||
profit_margin_percent: u8,
|
||||
) -> Result<ExecuteResult, NymdError> {
|
||||
let fee = self.operation_fee(Operation::UpdateMixnodeConfig);
|
||||
let req = VestingExecuteMsg::UpdateMixnodeConfig {
|
||||
profit_margin_percent,
|
||||
};
|
||||
self.client
|
||||
.execute(
|
||||
self.address(),
|
||||
self.vesting_contract_address()?,
|
||||
&req,
|
||||
fee,
|
||||
"VestingContract::UpdateMixnetConfig",
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,8 @@ cosmwasm-std = "1.0.0-beta3"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_repr = "0.1"
|
||||
schemars = "0.8"
|
||||
ts-rs = { version = "5.1", optional = true }
|
||||
# Leaving it as * so that it inherits whatever the wallet is using
|
||||
ts-rs = { version = "*", optional = true }
|
||||
thiserror = "1.0"
|
||||
network-defaults = { path = "../../network-defaults" }
|
||||
fixed = { version = "1.1", features = ["serde"] }
|
||||
|
||||
@@ -52,6 +52,8 @@ pub const NEW_MIXNODE_ACTIVE_SET_SIZE_KEY: &str = "new_mixnode_active_set_size";
|
||||
pub const INTERVAL_ID_KEY: &str = "interval_id";
|
||||
pub const TOTAL_MIXNODE_REWARD_KEY: &str = "total_node_reward";
|
||||
pub const OPERATOR_REWARD_KEY: &str = "operator_reward";
|
||||
pub const TOTAL_PLEDGE_KEY: &str = "pledge";
|
||||
pub const TOTAL_DELEGATIONS_KEY: &str = "delegated";
|
||||
pub const LAMBDA_KEY: &str = "lambda";
|
||||
pub const SIGMA_KEY: &str = "sigma";
|
||||
pub const DISTRIBUTED_DELEGATION_REWARDS_KEY: &str = "distributed_delegation_rewards";
|
||||
@@ -271,10 +273,13 @@ pub fn new_zero_uptime_mix_operator_rewarding_event(
|
||||
.add_attribute(NO_REWARD_REASON_KEY, ZERO_UPTIME_VALUE)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new_mix_operator_rewarding_event(
|
||||
interval_id: u32,
|
||||
identity: IdentityKeyRef<'_>,
|
||||
node_reward_result: NodeRewardResult,
|
||||
node_pledge: Uint128,
|
||||
node_delegation: Uint128,
|
||||
operator_reward: Uint128,
|
||||
delegation_rewards_distributed: Uint128,
|
||||
further_delegations: bool,
|
||||
@@ -282,6 +287,8 @@ pub fn new_mix_operator_rewarding_event(
|
||||
Event::new(OPERATOR_REWARDING_EVENT_TYPE)
|
||||
.add_attribute(INTERVAL_ID_KEY, interval_id.to_string())
|
||||
.add_attribute(NODE_IDENTITY_KEY, identity)
|
||||
.add_attribute(TOTAL_PLEDGE_KEY, node_pledge)
|
||||
.add_attribute(TOTAL_DELEGATIONS_KEY, node_delegation)
|
||||
.add_attribute(
|
||||
TOTAL_MIXNODE_REWARD_KEY,
|
||||
node_reward_result.reward().to_string(),
|
||||
|
||||
@@ -23,6 +23,10 @@ pub enum ExecuteMsg {
|
||||
UpdateMixnodeConfig {
|
||||
profit_margin_percent: u8,
|
||||
},
|
||||
UpdateMixnodeConfigOnBehalf {
|
||||
profit_margin_percent: u8,
|
||||
owner: String,
|
||||
},
|
||||
BondGateway {
|
||||
gateway: Gateway,
|
||||
owner_signature: String,
|
||||
|
||||
@@ -11,4 +11,5 @@ mixnet-contract-common = { path = "../mixnet-contract" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
schemars = "0.8"
|
||||
cw-storage-plus = "0.11.1"
|
||||
config = {path = "../../config"}
|
||||
config = { path = "../../config" }
|
||||
ts-rs = { version = "*", optional = true }
|
||||
|
||||
@@ -15,6 +15,7 @@ pub const VESTING_GATEWAY_BONDING_EVENT_TYPE: &str = "vesting_gateway_bonding";
|
||||
pub const VESTING_GATEWAY_UNBONDING_EVENT_TYPE: &str = "vesting_gateway_unbonding";
|
||||
pub const VESTING_MIXNODE_BONDING_EVENT_TYPE: &str = "vesting_mixnode_bonding";
|
||||
pub const VESTING_MIXNODE_UNBONDING_EVENT_TYPE: &str = "vesting_mixnode_unbonding";
|
||||
pub const VESTING_UPDATE_MIXNODE_CONFIG_EVENT_TYPE: &str = "vesting_update_mixnode_config";
|
||||
|
||||
pub const TRACK_MIXNODE_UNBOND_EVENT_TYPE: &str = "track_mixnode_unbond";
|
||||
pub const TRACK_GATEWAY_UNBOND_EVENT_TYPE: &str = "track_gateway_unbond";
|
||||
@@ -108,6 +109,10 @@ pub fn new_vesting_mixnode_bonding_event() -> Event {
|
||||
Event::new(VESTING_MIXNODE_BONDING_EVENT_TYPE)
|
||||
}
|
||||
|
||||
pub fn new_vesting_update_mixnode_config_event() -> Event {
|
||||
Event::new(VESTING_UPDATE_MIXNODE_CONFIG_EVENT_TYPE)
|
||||
}
|
||||
|
||||
pub fn new_vesting_mixnode_unbonding_event() -> Event {
|
||||
Event::new(VESTING_MIXNODE_UNBONDING_EVENT_TYPE)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,70 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::Coin;
|
||||
use cosmwasm_std::{Coin, Timestamp};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub mod events;
|
||||
pub mod messages;
|
||||
|
||||
pub fn one_unym() -> Coin {
|
||||
pub fn one_ucoin() -> Coin {
|
||||
Coin::new(1, DENOM)
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, JsonSchema)]
|
||||
pub enum Period {
|
||||
Before,
|
||||
In(usize),
|
||||
After,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
pub struct PledgeData {
|
||||
amount: Coin,
|
||||
block_time: Timestamp,
|
||||
}
|
||||
|
||||
impl PledgeData {
|
||||
pub fn amount(&self) -> Coin {
|
||||
self.amount.clone()
|
||||
}
|
||||
|
||||
pub fn block_time(&self) -> Timestamp {
|
||||
self.block_time
|
||||
}
|
||||
|
||||
pub fn new(amount: Coin, block_time: Timestamp) -> Self {
|
||||
Self { amount, block_time }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
pub struct OriginalVestingResponse {
|
||||
amount: Coin,
|
||||
number_of_periods: usize,
|
||||
period_duration: u64,
|
||||
}
|
||||
|
||||
impl OriginalVestingResponse {
|
||||
pub fn amount(&self) -> Coin {
|
||||
self.amount.clone()
|
||||
}
|
||||
|
||||
pub fn number_of_periods(&self) -> usize {
|
||||
self.number_of_periods
|
||||
}
|
||||
|
||||
pub fn period_duration(&self) -> u64 {
|
||||
self.period_duration
|
||||
}
|
||||
|
||||
pub fn new(amount: Coin, number_of_periods: usize, period_duration: u64) -> Self {
|
||||
Self {
|
||||
amount,
|
||||
number_of_periods,
|
||||
period_duration,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,9 @@ impl VestingSpecification {
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ExecuteMsg {
|
||||
UpdateMixnodeConfig {
|
||||
profit_margin_percent: u8,
|
||||
},
|
||||
UpdateMixnetAddress {
|
||||
address: String,
|
||||
},
|
||||
@@ -145,4 +148,7 @@ pub enum QueryMsg {
|
||||
GetGateway {
|
||||
address: String,
|
||||
},
|
||||
GetCurrentVestingPeriod {
|
||||
address: String,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -11,6 +11,6 @@ url = "2.2"
|
||||
|
||||
# I guess temporarily until we get serde support in coconut up and running
|
||||
coconut-interface = { path = "../coconut-interface" }
|
||||
crypto = { path = "../crypto" }
|
||||
crypto = { path = "../crypto", features = ["asymmetric"] }
|
||||
network-defaults = { path = "../network-defaults" }
|
||||
validator-client = { path = "../client-libs/validator-client" }
|
||||
|
||||
@@ -147,7 +147,7 @@ pub async fn obtain_aggregate_signature(
|
||||
attributes.extend_from_slice(public_attributes);
|
||||
|
||||
let mut indices: Vec<u64> = Vec::with_capacity(validators_partial_vks.len());
|
||||
for i in 1..validators_partial_vks.len() {
|
||||
for i in 0..validators_partial_vks.len() {
|
||||
indices.push(i as u64);
|
||||
}
|
||||
let verification_key =
|
||||
|
||||
+19
-11
@@ -7,21 +7,29 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
aes = { version = "0.7.4", features = ["ctr"] }
|
||||
aes = { version = "0.8.1", optional = true }
|
||||
bs58 = "0.4.0"
|
||||
blake3 = { version = "~1.2.0", features = ["traits-preview"] }
|
||||
digest = "0.9.0"
|
||||
generic-array = "0.14"
|
||||
hkdf = "0.11.0"
|
||||
hmac = "0.11.0"
|
||||
cipher = "0.3.0"
|
||||
x25519-dalek = "1.1"
|
||||
ed25519-dalek = "1.0"
|
||||
log = "0.4"
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
blake3 = { version = "1.3.1", features = ["traits-preview"], optional = true }
|
||||
ctr = { version = "0.9.1", optional = true }
|
||||
digest = { version = "0.10.3", optional = true }
|
||||
generic-array = { version = "0.14", optional = true }
|
||||
hkdf = { version = "0.12.3", optional = true }
|
||||
hmac = { version = "0.12.1", optional = true }
|
||||
cipher = { version = "0.4.3", optional = true }
|
||||
x25519-dalek = { version = "1.1", optional = true }
|
||||
ed25519-dalek = { version = "1.0", optional = true }
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"], optional = true }
|
||||
subtle-encoding = { version = "0.5", features = ["bech32-preview"]}
|
||||
|
||||
# internal
|
||||
nymsphinx-types = { path = "../nymsphinx/types" }
|
||||
pemstore = { path = "../../common/pemstore" }
|
||||
config = { path="../../common/config" }
|
||||
|
||||
[dev-dependencies]
|
||||
rand_chacha = "0.2"
|
||||
|
||||
[features]
|
||||
asymmetric = ["x25519-dalek", "ed25519-dalek"]
|
||||
hashing = ["blake3", "digest", "hkdf", "hmac", "generic-array"]
|
||||
symmetric = ["aes", "ctr", "cipher", "generic-array"]
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use pemstore::traits::{PemStorableKey, PemStorableKeyPair};
|
||||
#[cfg(feature = "rand")]
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
@@ -46,6 +47,7 @@ pub struct KeyPair {
|
||||
}
|
||||
|
||||
impl KeyPair {
|
||||
#[cfg(feature = "rand")]
|
||||
pub fn new<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
|
||||
let private_key = x25519_dalek::StaticSecret::new(rng);
|
||||
let public_key = (&private_key).into();
|
||||
|
||||
@@ -6,6 +6,7 @@ pub use ed25519_dalek::SignatureError;
|
||||
pub use ed25519_dalek::{Verifier, PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, SIGNATURE_LENGTH};
|
||||
use nymsphinx_types::{DestinationAddressBytes, DESTINATION_ADDRESS_LENGTH};
|
||||
use pemstore::traits::{PemStorableKey, PemStorableKeyPair};
|
||||
#[cfg(feature = "rand")]
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
@@ -45,6 +46,7 @@ pub struct KeyPair {
|
||||
}
|
||||
|
||||
impl KeyPair {
|
||||
#[cfg(feature = "rand")]
|
||||
pub fn new<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
|
||||
let ed25519_keypair = ed25519_dalek::Keypair::generate(rng);
|
||||
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use digest::{BlockInput, Digest, FixedOutput, Reset, Update};
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use digest::{Digest, Output};
|
||||
|
||||
pub fn compute_digest<D>(data: &[u8]) -> GenericArray<u8, <D as Digest>::OutputSize>
|
||||
pub fn compute_digest<D>(data: &[u8]) -> Output<D>
|
||||
where
|
||||
D: Update + BlockInput + FixedOutput + Reset + Default + Clone,
|
||||
D::BlockSize: ArrayLength<u8>,
|
||||
D::OutputSize: ArrayLength<u8>,
|
||||
D: Digest,
|
||||
{
|
||||
D::digest(data)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use digest::{BlockInput, FixedOutput, Reset, Update};
|
||||
use generic_array::ArrayLength;
|
||||
use hkdf::Hkdf;
|
||||
use hkdf::{
|
||||
hmac::{
|
||||
digest::{crypto_common::BlockSizeUser, Digest},
|
||||
SimpleHmac,
|
||||
},
|
||||
Hkdf,
|
||||
};
|
||||
|
||||
/// Perform HKDF `extract` then `expand` as a single step.
|
||||
pub fn extract_then_expand<D>(
|
||||
@@ -13,14 +17,12 @@ pub fn extract_then_expand<D>(
|
||||
okm_length: usize,
|
||||
) -> Result<Vec<u8>, hkdf::InvalidLength>
|
||||
where
|
||||
D: Update + BlockInput + FixedOutput + Reset + Default + Clone,
|
||||
D::BlockSize: ArrayLength<u8>,
|
||||
D::OutputSize: ArrayLength<u8>,
|
||||
D: Digest + BlockSizeUser + Clone,
|
||||
{
|
||||
// TODO: this would need to change if we ever needed the generated pseudorandom key, but
|
||||
// realistically I don't see any reasons why we might need it
|
||||
|
||||
let hkdf = Hkdf::<D>::new(salt, ikm);
|
||||
let hkdf = Hkdf::<D, SimpleHmac<D>>::new(salt, ikm);
|
||||
let mut okm = vec![0u8; okm_length];
|
||||
hkdf.expand(info.unwrap_or(&[]), &mut okm)?;
|
||||
|
||||
|
||||
+19
-24
@@ -1,24 +1,23 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use digest::{BlockInput, FixedOutput, Reset, Update};
|
||||
use generic_array::{typenum::Unsigned, ArrayLength, GenericArray};
|
||||
use hmac::{crypto_mac, Hmac, Mac, NewMac};
|
||||
use hmac::{
|
||||
digest::{crypto_common::BlockSizeUser, CtOutput, Digest, Output},
|
||||
Mac, SimpleHmac,
|
||||
};
|
||||
|
||||
pub use hmac;
|
||||
|
||||
// Type alias for ease of use so that it would not require explicit import of crypto_mac or Hmac
|
||||
pub type HmacOutput<D> = crypto_mac::Output<Hmac<D>>;
|
||||
// TODO: We should probably change it to use some sealed trait to allow for both `Hmac` and `SimpleHmac`
|
||||
pub type HmacOutput<D> = CtOutput<SimpleHmac<D>>;
|
||||
|
||||
/// Compute keyed hmac
|
||||
pub fn compute_keyed_hmac<D>(key: &[u8], data: &[u8]) -> HmacOutput<D>
|
||||
where
|
||||
D: Update + BlockInput + FixedOutput + Reset + Default + Clone,
|
||||
D::BlockSize: ArrayLength<u8>,
|
||||
D::OutputSize: ArrayLength<u8>,
|
||||
D: Digest + BlockSizeUser,
|
||||
{
|
||||
let mut hmac =
|
||||
Hmac::<D>::new_from_slice(key).expect("HMAC should be able to take key of any size!");
|
||||
let mut hmac = SimpleHmac::<D>::new_from_slice(key)
|
||||
.expect("HMAC was instantiated with a key of an invalid size!");
|
||||
hmac.update(data);
|
||||
hmac.finalize()
|
||||
}
|
||||
@@ -26,32 +25,28 @@ where
|
||||
/// Compute keyed hmac and performs constant time equality check with the provided tag value.
|
||||
pub fn recompute_keyed_hmac_and_verify_tag<D>(key: &[u8], data: &[u8], tag: &[u8]) -> bool
|
||||
where
|
||||
D: Update + BlockInput + FixedOutput + Reset + Default + Clone,
|
||||
D::BlockSize: ArrayLength<u8>,
|
||||
D::OutputSize: ArrayLength<u8>,
|
||||
D: Digest + BlockSizeUser,
|
||||
{
|
||||
let mut hmac =
|
||||
Hmac::<D>::new_from_slice(key).expect("HMAC should be able to take key of any size!");
|
||||
let mut hmac = SimpleHmac::<D>::new_from_slice(key)
|
||||
.expect("HMAC was instantiated with a key of an invalid size!");
|
||||
hmac.update(data);
|
||||
|
||||
let tag_arr = Output::<D>::from_slice(tag);
|
||||
// note, under the hood ct_eq is called
|
||||
hmac.verify(tag).is_ok()
|
||||
hmac.verify(tag_arr).is_ok()
|
||||
}
|
||||
|
||||
/// Verifies tag of an hmac output.
|
||||
pub fn verify_tag<D>(tag: &[u8], out: HmacOutput<D>) -> bool
|
||||
where
|
||||
D: Update + BlockInput + FixedOutput + Reset + Default + Clone,
|
||||
D::BlockSize: ArrayLength<u8>,
|
||||
D::OutputSize: ArrayLength<u8>,
|
||||
D: Digest + BlockSizeUser,
|
||||
{
|
||||
if tag.len() != D::OutputSize::to_usize() {
|
||||
if tag.len() != <D as Digest>::output_size() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let tag_bytes = GenericArray::clone_from_slice(tag);
|
||||
let tag_out = HmacOutput::new(tag_bytes);
|
||||
// note, under the hood ct_eq is called
|
||||
out == tag_out
|
||||
let tag_arr = Output::<D>::from_slice(tag);
|
||||
out == tag_arr.into()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1,21 +1,33 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#[cfg(feature = "asymmetric")]
|
||||
pub mod asymmetric;
|
||||
pub mod bech32_address_validation;
|
||||
#[cfg(feature = "hashing")]
|
||||
pub mod crypto_hash;
|
||||
#[cfg(feature = "hashing")]
|
||||
pub mod hkdf;
|
||||
#[cfg(feature = "hashing")]
|
||||
pub mod hmac;
|
||||
#[cfg(all(feature = "asymmetric", feature = "hashing", feature = "symmetric"))]
|
||||
pub mod shared_key;
|
||||
#[cfg(feature = "symmetric")]
|
||||
pub mod symmetric;
|
||||
|
||||
pub use digest::Digest;
|
||||
#[cfg(feature = "hashing")]
|
||||
pub use digest::{Digest, OutputSizeUser};
|
||||
#[cfg(any(feature = "hashing", feature = "symmetric"))]
|
||||
pub use generic_array;
|
||||
|
||||
// with the below my idea was to try to introduce having a single place of importing all hashing, encryption,
|
||||
// etc. algorithms and import them elsewhere as needed via common/crypto
|
||||
#[cfg(feature = "symmetric")]
|
||||
pub use aes;
|
||||
#[cfg(feature = "hashing")]
|
||||
pub use blake3;
|
||||
#[cfg(feature = "symmetric")]
|
||||
pub use ctr;
|
||||
|
||||
// TODO: this function uses all three modules: asymmetric crypto, symmetric crypto and derives key...,
|
||||
// so I don't know where to put it...
|
||||
|
||||
@@ -3,22 +3,22 @@
|
||||
|
||||
use crate::asymmetric::encryption;
|
||||
use crate::hkdf;
|
||||
use cipher::{CipherKey, NewCipher, StreamCipher};
|
||||
use digest::{BlockInput, FixedOutput, Reset, Update};
|
||||
use generic_array::{typenum::Unsigned, ArrayLength};
|
||||
use cipher::{Key, KeyIvInit, StreamCipher};
|
||||
use digest::crypto_common::BlockSizeUser;
|
||||
use digest::Digest;
|
||||
#[cfg(feature = "rand")]
|
||||
use rand::{CryptoRng, RngCore};
|
||||
|
||||
/// Generate an ephemeral encryption keypair and perform diffie-hellman to establish
|
||||
/// shared key with the remote.
|
||||
#[cfg(feature = "rand")]
|
||||
pub fn new_ephemeral_shared_key<C, D, R>(
|
||||
rng: &mut R,
|
||||
remote_key: &encryption::PublicKey,
|
||||
) -> (encryption::KeyPair, CipherKey<C>)
|
||||
) -> (encryption::KeyPair, Key<C>)
|
||||
where
|
||||
C: StreamCipher + NewCipher,
|
||||
D: Update + BlockInput + FixedOutput + Reset + Default + Clone,
|
||||
D::BlockSize: ArrayLength<u8>,
|
||||
D::OutputSize: ArrayLength<u8>,
|
||||
C: StreamCipher + KeyIvInit,
|
||||
D: Digest + BlockSizeUser + Clone,
|
||||
R: RngCore + CryptoRng,
|
||||
{
|
||||
let ephemeral_keypair = encryption::KeyPair::new(rng);
|
||||
@@ -27,11 +27,11 @@ where
|
||||
let dh_result = ephemeral_keypair.private_key().diffie_hellman(remote_key);
|
||||
|
||||
// there is no reason for this to fail as our okm is expected to be only C::KeySize bytes
|
||||
let okm = hkdf::extract_then_expand::<D>(None, &dh_result, None, C::KeySize::to_usize())
|
||||
let okm = hkdf::extract_then_expand::<D>(None, &dh_result, None, C::key_size())
|
||||
.expect("somehow too long okm was provided");
|
||||
|
||||
let derived_shared_key =
|
||||
CipherKey::<C>::from_exact_iter(okm).expect("okm was expanded to incorrect length!");
|
||||
Key::<C>::from_exact_iter(okm).expect("okm was expanded to incorrect length!");
|
||||
|
||||
(ephemeral_keypair, derived_shared_key)
|
||||
}
|
||||
@@ -40,18 +40,16 @@ where
|
||||
pub fn recompute_shared_key<C, D>(
|
||||
remote_key: &encryption::PublicKey,
|
||||
local_key: &encryption::PrivateKey,
|
||||
) -> CipherKey<C>
|
||||
) -> Key<C>
|
||||
where
|
||||
C: StreamCipher + NewCipher,
|
||||
D: Update + BlockInput + FixedOutput + Reset + Default + Clone,
|
||||
D::BlockSize: ArrayLength<u8>,
|
||||
D::OutputSize: ArrayLength<u8>,
|
||||
C: StreamCipher + KeyIvInit,
|
||||
D: Digest + BlockSizeUser + Clone,
|
||||
{
|
||||
let dh_result = local_key.diffie_hellman(remote_key);
|
||||
|
||||
// there is no reason for this to fail as our okm is expected to be only C::KeySize bytes
|
||||
let okm = hkdf::extract_then_expand::<D>(None, &dh_result, None, C::KeySize::to_usize())
|
||||
let okm = hkdf::extract_then_expand::<D>(None, &dh_result, None, C::key_size())
|
||||
.expect("somehow too long okm was provided");
|
||||
|
||||
CipherKey::<C>::from_exact_iter(okm).expect("okm was expanded to incorrect length!")
|
||||
Key::<C>::from_exact_iter(okm).expect("okm was expanded to incorrect length!")
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use cipher::{Nonce, StreamCipher};
|
||||
use generic_array::{typenum::Unsigned, GenericArray};
|
||||
use cipher::{Iv, StreamCipher};
|
||||
pub use cipher::{IvSizeUser, KeyIvInit, KeySizeUser};
|
||||
#[cfg(feature = "rand")]
|
||||
use rand::{CryptoRng, RngCore};
|
||||
|
||||
// re-export this for ease of use
|
||||
pub use cipher::{CipherKey, NewCipher};
|
||||
pub use cipher::Key as CipherKey;
|
||||
|
||||
// SECURITY:
|
||||
// TODO: note that this is not the most secure approach here
|
||||
@@ -19,49 +20,51 @@ pub use cipher::{CipherKey, NewCipher};
|
||||
|
||||
// I think 'IV' looks better than 'Iv', feel free to change that.
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub type IV<C> = Nonce<C>;
|
||||
pub type IV<C> = Iv<C>;
|
||||
|
||||
#[cfg(feature = "rand")]
|
||||
pub fn generate_key<C, R>(rng: &mut R) -> CipherKey<C>
|
||||
where
|
||||
C: NewCipher,
|
||||
C: KeyIvInit,
|
||||
R: RngCore + CryptoRng,
|
||||
{
|
||||
let mut key = GenericArray::default();
|
||||
let mut key = CipherKey::<C>::default();
|
||||
rng.fill_bytes(&mut key);
|
||||
key
|
||||
}
|
||||
|
||||
#[cfg(feature = "rand")]
|
||||
pub fn random_iv<C, R>(rng: &mut R) -> IV<C>
|
||||
where
|
||||
C: NewCipher,
|
||||
C: KeyIvInit,
|
||||
R: RngCore + CryptoRng,
|
||||
{
|
||||
let mut iv = GenericArray::default();
|
||||
let mut iv = IV::<C>::default();
|
||||
rng.fill_bytes(&mut iv);
|
||||
iv
|
||||
}
|
||||
|
||||
pub fn zero_iv<C>() -> IV<C>
|
||||
where
|
||||
C: NewCipher,
|
||||
C: KeyIvInit,
|
||||
{
|
||||
GenericArray::default()
|
||||
Iv::<C>::default()
|
||||
}
|
||||
|
||||
pub fn iv_from_slice<C>(b: &[u8]) -> &IV<C>
|
||||
where
|
||||
C: NewCipher,
|
||||
C: KeyIvInit,
|
||||
{
|
||||
if b.len() != C::NonceSize::to_usize() {
|
||||
if b.len() != C::iv_size() {
|
||||
// `from_slice` would have caused a panic about this issue anyway.
|
||||
// Now we at least have slightly more information
|
||||
panic!(
|
||||
"Tried to convert {} bytes to IV. Expected {}",
|
||||
b.len(),
|
||||
C::NonceSize::to_usize()
|
||||
C::iv_size()
|
||||
)
|
||||
}
|
||||
GenericArray::from_slice(b)
|
||||
IV::<C>::from_slice(b)
|
||||
}
|
||||
|
||||
// TODO: there's really no way to use more parts of the keystream if it was required at some point.
|
||||
@@ -70,7 +73,7 @@ where
|
||||
#[inline]
|
||||
pub fn encrypt<C>(key: &CipherKey<C>, iv: &IV<C>, data: &[u8]) -> Vec<u8>
|
||||
where
|
||||
C: StreamCipher + NewCipher,
|
||||
C: StreamCipher + KeyIvInit,
|
||||
{
|
||||
let mut ciphertext = data.to_vec();
|
||||
encrypt_in_place::<C>(key, iv, &mut ciphertext);
|
||||
@@ -80,7 +83,7 @@ where
|
||||
#[inline]
|
||||
pub fn encrypt_in_place<C>(key: &CipherKey<C>, iv: &IV<C>, data: &mut [u8])
|
||||
where
|
||||
C: StreamCipher + NewCipher,
|
||||
C: StreamCipher + KeyIvInit,
|
||||
{
|
||||
let mut cipher = C::new(key, iv);
|
||||
cipher.apply_keystream(data)
|
||||
@@ -89,7 +92,7 @@ where
|
||||
#[inline]
|
||||
pub fn decrypt<C>(key: &CipherKey<C>, iv: &IV<C>, ciphertext: &[u8]) -> Vec<u8>
|
||||
where
|
||||
C: StreamCipher + NewCipher,
|
||||
C: StreamCipher + KeyIvInit,
|
||||
{
|
||||
let mut data = ciphertext.to_vec();
|
||||
decrypt_in_place::<C>(key, iv, &mut data);
|
||||
@@ -99,7 +102,7 @@ where
|
||||
#[inline]
|
||||
pub fn decrypt_in_place<C>(key: &CipherKey<C>, iv: &IV<C>, data: &mut [u8])
|
||||
where
|
||||
C: StreamCipher + NewCipher,
|
||||
C: StreamCipher + KeyIvInit,
|
||||
{
|
||||
let mut cipher = C::new(key, iv);
|
||||
cipher.apply_keystream(data)
|
||||
@@ -108,12 +111,12 @@ where
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rand::rngs::OsRng;
|
||||
use rand_chacha::rand_core::SeedableRng;
|
||||
|
||||
#[cfg(test)]
|
||||
mod aes_ctr128 {
|
||||
use super::*;
|
||||
use aes::Aes128Ctr;
|
||||
type Aes128Ctr = ctr::Ctr64LE<aes::Aes128>;
|
||||
|
||||
#[test]
|
||||
fn zero_iv_is_actually_zero() {
|
||||
@@ -125,7 +128,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn decryption_is_reciprocal_to_encryption() {
|
||||
let mut rng = OsRng;
|
||||
let dummy_seed = [1u8; 32];
|
||||
let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed);
|
||||
|
||||
let arr_input = [42; 200];
|
||||
let vec_input = vec![123, 200];
|
||||
@@ -148,7 +152,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn in_place_variants_work_same_way() {
|
||||
let mut rng = OsRng;
|
||||
let dummy_seed = [1u8; 32];
|
||||
let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed);
|
||||
|
||||
let mut data = [42; 200];
|
||||
let original_data = data;
|
||||
|
||||
@@ -4,129 +4,546 @@
|
||||
// This should be modified whenever an updated Ethereum contract is uploaded
|
||||
pub const ETH_JSON_ABI: &str = r#"
|
||||
[
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "contract ERC20Burnable",
|
||||
"name": "_erc20",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "constructor"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "Bandwidth",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "uint256",
|
||||
"name": "VerificationKey",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "bytes",
|
||||
"name": "SignedVerificationKey",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"name": "Burned",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "previousOwner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "newOwner",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "OwnershipTransferred",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "verificationKey",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "signedVerificationKey",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"name": "burnTokenForAccessCode",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "erc20",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "contract ERC20Burnable",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "owner",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "renounceOwnership",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "newOwner",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "transferOwnership",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
}
|
||||
]
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "contract CosmosERC20",
|
||||
"name": "_erc20",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "contract Gravity",
|
||||
"name": "_gravityBridge",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "constructor"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "Bandwidth",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "uint256",
|
||||
"name": "VerificationKey",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "bytes",
|
||||
"name": "SignedVerificationKey",
|
||||
"type": "bytes"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "string",
|
||||
"name": "CosmosRecipient",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"name": "BBCredentialPurchased",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "bool",
|
||||
"name": "Enabled",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"name": "CredentialGenerationSwitch",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "previousOwner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "newOwner",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "OwnershipTransferred",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "uint256",
|
||||
"name": "NewBytesPerToken",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "RatioChanged",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "BytesPerToken",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_amount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "bandwidthFromToken",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_newBytesPerTokenAmount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "changeRatio",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "credentialGenerationEnabled",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "_generation",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"name": "credentialGenerationSwitch",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "erc20",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "contract CosmosERC20",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_amount",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_verificationKey",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "_signedVerificationKey",
|
||||
"type": "bytes"
|
||||
},
|
||||
{
|
||||
"internalType": "string",
|
||||
"name": "_cosmosRecipient",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"name": "generateBasicBandwidthCredential",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "gravityBridge",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "contract Gravity",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "owner",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "renounceOwnership",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "newOwner",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "transferOwnership",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
}
|
||||
]
|
||||
"#;
|
||||
|
||||
pub const ETH_ERC20_JSON_ABI: &str = r#"
|
||||
[
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "string",
|
||||
"name": "name_",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"internalType": "string",
|
||||
"name": "symbol_",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "constructor"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "owner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "spender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "Approval",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "from",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "Transfer",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "owner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "spender",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "allowance",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "spender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "approve",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "account",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "balanceOf",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "decimals",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint8",
|
||||
"name": "",
|
||||
"type": "uint8"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "spender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "subtractedValue",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "decreaseAllowance",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "spender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "addedValue",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "increaseAllowance",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "name",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "string",
|
||||
"name": "",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "symbol",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "string",
|
||||
"name": "",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "totalSupply",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "transfer",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "sender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "transferFrom",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
}
|
||||
]
|
||||
"#;
|
||||
|
||||
@@ -17,6 +17,8 @@ cfg_if::cfg_if! {
|
||||
pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = mainnet::MIXNET_CONTRACT_ADDRESS;
|
||||
pub const DEFAULT_VESTING_CONTRACT_ADDRESS: &str = mainnet::VESTING_CONTRACT_ADDRESS;
|
||||
pub const DEFAULT_BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = mainnet::BANDWIDTH_CLAIM_CONTRACT_ADDRESS;
|
||||
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = mainnet::_ETH_CONTRACT_ADDRESS;
|
||||
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = mainnet::_ETH_ERC20_CONTRACT_ADDRESS;
|
||||
pub const DEFAULT_REWARDING_VALIDATOR_ADDRESS: &str = mainnet::REWARDING_VALIDATOR_ADDRESS;
|
||||
|
||||
pub fn default_validators() -> Vec<ValidatorDetails> {
|
||||
@@ -33,6 +35,8 @@ cfg_if::cfg_if! {
|
||||
pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = qa::MIXNET_CONTRACT_ADDRESS;
|
||||
pub const DEFAULT_VESTING_CONTRACT_ADDRESS: &str = qa::VESTING_CONTRACT_ADDRESS;
|
||||
pub const DEFAULT_BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = qa::BANDWIDTH_CLAIM_CONTRACT_ADDRESS;
|
||||
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = qa::_ETH_CONTRACT_ADDRESS;
|
||||
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = qa::_ETH_ERC20_CONTRACT_ADDRESS;
|
||||
pub const DEFAULT_REWARDING_VALIDATOR: &str = qa::REWARDING_VALIDATOR_ADDRESS;
|
||||
|
||||
pub fn default_validators() -> Vec<ValidatorDetails> {
|
||||
@@ -49,6 +53,8 @@ cfg_if::cfg_if! {
|
||||
pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = sandbox::MIXNET_CONTRACT_ADDRESS;
|
||||
pub const DEFAULT_VESTING_CONTRACT_ADDRESS: &str = sandbox::VESTING_CONTRACT_ADDRESS;
|
||||
pub const DEFAULT_BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = sandbox::BANDWIDTH_CLAIM_CONTRACT_ADDRESS;
|
||||
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = sandbox::_ETH_CONTRACT_ADDRESS;
|
||||
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = sandbox::_ETH_ERC20_CONTRACT_ADDRESS;
|
||||
pub const DEFAULT_REWARDING_VALIDATOR: &str = sandbox::REWARDING_VALIDATOR_ADDRESS;
|
||||
|
||||
pub fn default_validators() -> Vec<ValidatorDetails> {
|
||||
@@ -106,18 +112,22 @@ pub fn default_api_endpoints() -> Vec<Url> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub const ETH_CONTRACT_ADDRESS: [u8; 20] =
|
||||
hex_literal::hex!("9fEE3e28c17dbB87310A51F13C4fbf4331A6f102");
|
||||
// Name of the event triggered by the eth contract. If the event name is changed,
|
||||
// this would also need to be changed; It is currently tested against the json abi
|
||||
pub const ETH_EVENT_NAME: &str = "Burned";
|
||||
pub const ETH_BURN_FUNCTION_NAME: &str = "burnTokenForAccessCode";
|
||||
pub const ETH_EVENT_NAME: &str = "BBCredentialPurchased";
|
||||
pub const ETH_BURN_FUNCTION_NAME: &str = "generateBasicBandwidthCredential";
|
||||
pub const ETH_ERC20_APPROVE_FUNCTION_NAME: &str = "approve";
|
||||
|
||||
// Ethereum constants used for token bridge
|
||||
/// How much bandwidth (in bytes) one token can buy
|
||||
const BYTES_PER_TOKEN: u64 = 1024 * 1024 * 1024;
|
||||
|
||||
/// Threshold for claiming more bandwidth: 1 MB
|
||||
pub const REMAINING_BANDWIDTH_THRESHOLD: i64 = 1024 * 1024;
|
||||
/// How many ERC20 tokens should be burned to buy bandwidth
|
||||
pub const TOKENS_TO_BURN: u64 = 10;
|
||||
pub const TOKENS_TO_BURN: u64 = 1;
|
||||
/// How many ERC20 utokens should be burned to buy bandwidth
|
||||
pub const UTOKENS_TO_BURN: u64 = TOKENS_TO_BURN * 1000000;
|
||||
/// Default bandwidth (in bytes) that we try to buy
|
||||
pub const BANDWIDTH_VALUE: u64 = TOKENS_TO_BURN * BYTES_PER_TOKEN;
|
||||
|
||||
|
||||
@@ -10,6 +10,10 @@ pub(crate) const MIXNET_CONTRACT_ADDRESS: &str = "n19lc9u84cz0yz3fww5283nucc9yvr
|
||||
pub(crate) const VESTING_CONTRACT_ADDRESS: &str = "n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0";
|
||||
pub(crate) const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str =
|
||||
"n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0";
|
||||
pub(crate) const _ETH_CONTRACT_ADDRESS: [u8; 20] =
|
||||
hex_literal::hex!("0000000000000000000000000000000000000000");
|
||||
pub(crate) const _ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] =
|
||||
hex_literal::hex!("0000000000000000000000000000000000000000");
|
||||
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "n17zujduc46wvkwvp6f062mm5xhr7jc3fewvqu9e";
|
||||
|
||||
pub(crate) fn validators() -> Vec<ValidatorDetails> {
|
||||
|
||||
@@ -6,10 +6,14 @@ use crate::ValidatorDetails;
|
||||
pub(crate) const BECH32_PREFIX: &str = "nymt";
|
||||
pub const DENOM: &str = "unymt";
|
||||
|
||||
pub(crate) const MIXNET_CONTRACT_ADDRESS: &str = "nymt14hj2tavq8fpesdwxxcu44rty3hh90vhuysqrsr";
|
||||
pub(crate) const VESTING_CONTRACT_ADDRESS: &str = "nymt17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9f8xzkv";
|
||||
pub(crate) const MIXNET_CONTRACT_ADDRESS: &str = "nymt17x6pt4msccvawgxjeg5nmnygttu56tftg5l6j3";
|
||||
pub(crate) const VESTING_CONTRACT_ADDRESS: &str = "nymt1t4dmskxea0avvrj8xtmu66hv7dkyg9s8059t3c";
|
||||
pub(crate) const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str =
|
||||
"nymt17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9f8xzkv";
|
||||
pub(crate) const _ETH_CONTRACT_ADDRESS: [u8; 20] =
|
||||
hex_literal::hex!("0000000000000000000000000000000000000000");
|
||||
pub(crate) const _ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] =
|
||||
hex_literal::hex!("0000000000000000000000000000000000000000");
|
||||
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "nymt1dn52nx8wv9wkqmrvj6tcmdzh4es6jt8tr7f6j9";
|
||||
|
||||
pub(crate) fn validators() -> Vec<ValidatorDetails> {
|
||||
|
||||
@@ -7,10 +7,14 @@ pub(crate) const BECH32_PREFIX: &str = "nymt";
|
||||
pub const DENOM: &str = "unymt";
|
||||
|
||||
pub(crate) const MIXNET_CONTRACT_ADDRESS: &str = "nymt1ghd753shjuwexxywmgs4xz7x2q732vcnstz02j";
|
||||
pub(crate) const VESTING_CONTRACT_ADDRESS: &str = "nymt1nc5tatafv6eyq7llkr2gv50ff9e22mnfp9pc5s";
|
||||
pub(crate) const VESTING_CONTRACT_ADDRESS: &str = "nymt14ejqjyq8um4p3xfqj74yld5waqljf88fn549lh";
|
||||
pub(crate) const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str =
|
||||
"nymt17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9f8xzkv";
|
||||
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "nymt17zujduc46wvkwvp6f062mm5xhr7jc3fewvqu9e";
|
||||
pub(crate) const _ETH_CONTRACT_ADDRESS: [u8; 20] =
|
||||
hex_literal::hex!("8e0DcFF7F3085235C32E845f3667aEB3f1e83133");
|
||||
pub(crate) const _ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] =
|
||||
hex_literal::hex!("E8883BAeF3869e14E4823F46662e81D4F7d2A81F");
|
||||
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "nymt1jh0s6qu6tuw9ut438836mmn7f3f2wencrnmdj4";
|
||||
|
||||
pub(crate) fn validators() -> Vec<ValidatorDetails> {
|
||||
vec![ValidatorDetails::new(
|
||||
|
||||
@@ -7,9 +7,9 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
rand = {version = "0.7.3", features = ["wasm-bindgen"]}
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
|
||||
crypto = { path = "../../crypto" }
|
||||
crypto = { path = "../../crypto", features = ["symmetric", "rand"] }
|
||||
nymsphinx-addressing = { path = "../addressing" }
|
||||
nymsphinx-params = { path = "../params" }
|
||||
nymsphinx-types = { path = "../types" }
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::AckKey;
|
||||
use crypto::generic_array::typenum::Unsigned;
|
||||
use crypto::symmetric::stream_cipher::{self, encrypt, iv_from_slice, random_iv, NewCipher};
|
||||
use crypto::symmetric::stream_cipher::{self, encrypt, iv_from_slice, random_iv, IvSizeUser};
|
||||
use nymsphinx_params::{
|
||||
packet_sizes::PacketSize, AckEncryptionAlgorithm, SerializedFragmentIdentifier, FRAG_ID_LEN,
|
||||
};
|
||||
@@ -33,7 +32,7 @@ pub fn recover_identifier(
|
||||
return None;
|
||||
}
|
||||
|
||||
let iv_size = <AckEncryptionAlgorithm as NewCipher>::NonceSize::to_usize();
|
||||
let iv_size = AckEncryptionAlgorithm::iv_size();
|
||||
let iv = iv_from_slice::<AckEncryptionAlgorithm>(&iv_id_ciphertext[..iv_size]);
|
||||
|
||||
let id = stream_cipher::decrypt::<AckEncryptionAlgorithm>(
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crypto::generic_array::{typenum::Unsigned, GenericArray};
|
||||
use crypto::symmetric::stream_cipher::{generate_key, CipherKey, NewCipher};
|
||||
use crypto::symmetric::stream_cipher::{generate_key, CipherKey, KeySizeUser};
|
||||
use nymsphinx_params::AckEncryptionAlgorithm;
|
||||
use pemstore::traits::PemStorableKey;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
@@ -33,11 +32,14 @@ impl AckKey {
|
||||
}
|
||||
|
||||
pub fn try_from_bytes(bytes: &[u8]) -> Result<Self, AckKeyConversionError> {
|
||||
if bytes.len() != <AckEncryptionAlgorithm as NewCipher>::KeySize::to_usize() {
|
||||
if bytes.len() != AckEncryptionAlgorithm::key_size() {
|
||||
return Err(AckKeyConversionError::BytesOfInvalidLengthError);
|
||||
}
|
||||
|
||||
Ok(AckKey(GenericArray::clone_from_slice(bytes)))
|
||||
// Ok(AckKey(GenericArray::clone_from_slice(bytes)))
|
||||
Ok(AckKey(
|
||||
CipherKey::<AckEncryptionAlgorithm>::clone_from_slice(bytes),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
|
||||
@@ -7,7 +7,7 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
crypto = { path = "../../crypto" } # all addresses are expressed in terms on their crypto keys
|
||||
crypto = { path = "../../crypto", features = ["asymmetric"] } # all addresses are expressed in terms on their crypto keys
|
||||
nymsphinx-types = { path = "../types" } # we need to be able to refer to some types defined inside sphinx crate
|
||||
serde = "1.0" # implementing serialization/deserialization for some types, like `Recipient`
|
||||
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub use crypto::generic_array::typenum::Unsigned;
|
||||
use crypto::{
|
||||
crypto_hash,
|
||||
generic_array::GenericArray,
|
||||
symmetric::stream_cipher::{generate_key, CipherKey, NewCipher},
|
||||
Digest,
|
||||
generic_array::{typenum::Unsigned, GenericArray},
|
||||
symmetric::stream_cipher::{generate_key, CipherKey, KeySizeUser},
|
||||
OutputSizeUser,
|
||||
};
|
||||
use nymsphinx_params::{ReplySurbEncryptionAlgorithm, ReplySurbKeyDigestAlgorithm};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
pub type EncryptionKeyDigest =
|
||||
GenericArray<u8, <ReplySurbKeyDigestAlgorithm as Digest>::OutputSize>;
|
||||
GenericArray<u8, <ReplySurbKeyDigestAlgorithm as OutputSizeUser>::OutputSize>;
|
||||
|
||||
pub type SurbEncryptionKeySize = <ReplySurbEncryptionAlgorithm as NewCipher>::KeySize;
|
||||
pub type SurbEncryptionKeySize = <ReplySurbEncryptionAlgorithm as KeySizeUser>::KeySize;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SurbEncryptionKey(CipherKey<ReplySurbEncryptionAlgorithm>);
|
||||
@@ -45,7 +44,7 @@ impl SurbEncryptionKey {
|
||||
}
|
||||
|
||||
pub fn try_from_bytes(bytes: &[u8]) -> Result<Self, SurbEncryptionKeyError> {
|
||||
if bytes.len() != SurbEncryptionKeySize::to_usize() {
|
||||
if bytes.len() != SurbEncryptionKeySize::USIZE {
|
||||
return Err(SurbEncryptionKeyError::BytesOfInvalidLengthError);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod encryption_key;
|
||||
pub mod reply_surb;
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::encryption_key::{
|
||||
SurbEncryptionKey, SurbEncryptionKeyError, SurbEncryptionKeySize, Unsigned,
|
||||
};
|
||||
use crypto::Digest;
|
||||
use crate::encryption_key::{SurbEncryptionKey, SurbEncryptionKeyError, SurbEncryptionKeySize};
|
||||
use crypto::{generic_array::typenum::Unsigned, Digest};
|
||||
use nymsphinx_addressing::clients::Recipient;
|
||||
use nymsphinx_addressing::nodes::{NymNodeRoutingAddress, MAX_NODE_ADDRESS_UNPADDED_LEN};
|
||||
use nymsphinx_params::packet_sizes::PacketSize;
|
||||
@@ -65,7 +63,7 @@ pub struct ReplySurb {
|
||||
// Serialize + Deserialize is not really used anymore (it was for a CBOR experiment)
|
||||
// however, if we decided we needed it again, it's already here
|
||||
impl Serialize for ReplySurb {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
@@ -139,7 +137,7 @@ impl ReplySurb {
|
||||
|
||||
// the SURB itself consists of SURB_header, first hop address and set of payload keys
|
||||
// (note extra 1 for the gateway)
|
||||
SurbEncryptionKeySize::to_usize()
|
||||
SurbEncryptionKeySize::USIZE
|
||||
+ HEADER_SIZE
|
||||
+ NODE_ADDRESS_LENGTH
|
||||
+ (1 + mix_hops as usize) * PAYLOAD_KEY_SIZE
|
||||
@@ -160,9 +158,9 @@ impl ReplySurb {
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<Self, ReplySurbError> {
|
||||
let encryption_key =
|
||||
SurbEncryptionKey::try_from_bytes(&bytes[..SurbEncryptionKeySize::to_usize()])?;
|
||||
SurbEncryptionKey::try_from_bytes(&bytes[..SurbEncryptionKeySize::USIZE])?;
|
||||
|
||||
let surb = match SURB::from_bytes(&bytes[SurbEncryptionKeySize::to_usize()..]) {
|
||||
let surb = match SURB::from_bytes(&bytes[SurbEncryptionKeySize::USIZE..]) {
|
||||
Err(err) => return Err(ReplySurbError::RecoveryError(err)),
|
||||
Ok(surb) => surb,
|
||||
};
|
||||
|
||||
@@ -7,5 +7,5 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
crypto = { path = "../../crypto" }
|
||||
crypto = { path = "../../crypto", features = ["hashing", "symmetric"] }
|
||||
nymsphinx-types = { path = "../types" }
|
||||
@@ -1,8 +1,11 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crypto::aes::Aes128Ctr;
|
||||
use crypto::aes::Aes128;
|
||||
use crypto::blake3;
|
||||
use crypto::ctr;
|
||||
|
||||
type Aes128Ctr = ctr::Ctr64LE<Aes128>;
|
||||
|
||||
// Re-export for ease of use
|
||||
pub use packet_modes::PacketMode;
|
||||
|
||||
Generated
-99
@@ -27,12 +27,6 @@ version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
@@ -90,21 +84,6 @@ dependencies = [
|
||||
"opaque-debug 0.2.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blake3"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "526c210b4520e416420759af363083471656e819a75e831b8d2c9d5a584f2413"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"constant_time_eq",
|
||||
"crypto-mac 0.11.1",
|
||||
"digest 0.9.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.7.3"
|
||||
@@ -230,12 +209,6 @@ version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b"
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||
|
||||
[[package]]
|
||||
name = "contracts-common"
|
||||
version = "0.1.0"
|
||||
@@ -320,22 +293,11 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||
name = "crypto"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"blake3",
|
||||
"bs58",
|
||||
"cipher",
|
||||
"config",
|
||||
"digest 0.9.0",
|
||||
"ed25519-dalek",
|
||||
"generic-array 0.14.5",
|
||||
"hkdf",
|
||||
"hmac",
|
||||
"log",
|
||||
"nymsphinx-types",
|
||||
"pemstore",
|
||||
"rand",
|
||||
"subtle-encoding",
|
||||
"x25519-dalek",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -448,29 +410,6 @@ dependencies = [
|
||||
"signature",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ed25519"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74e1069e39f1454367eb2de793ed062fac4c35c2934b76a81d90dd9abcd28816"
|
||||
dependencies = [
|
||||
"signature",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ed25519-dalek"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d"
|
||||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"ed25519",
|
||||
"rand",
|
||||
"serde",
|
||||
"sha2",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ed25519-zebra"
|
||||
version = "2.2.0"
|
||||
@@ -1369,18 +1308,6 @@ dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.12.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.30"
|
||||
@@ -1653,34 +1580,8 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "x25519-dalek"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2392b6b94a576b4e2bf3c5b2757d63f10ada8020a2e4d08ac849ebcf6ea8e077"
|
||||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"rand_core 0.5.1",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd"
|
||||
dependencies = [
|
||||
"zeroize_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize_derive"
|
||||
version = "1.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65f1a51723ec88c66d5d1fe80c841f17f63587d6691901d66be9bec6c3b51f73"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"GRAVITY":"0xe58c12f8bA4a28e87841b10BdEdf80A47F86BA9B"
|
||||
},
|
||||
"mainnet":{
|
||||
"NYM_ERC20":"0xCf6DeE9947fdDc958985E5283e63d41CBC83Ff61",
|
||||
"NYM_ERC20":"0x525A8F6F3Ba4752868cde25164382BfbaE3990e1",
|
||||
"NYMT": "0xE8883BAeF3869e14E4823F46662e81D4F7d2A81F",
|
||||
"BANDWIDTH_GENERATOR":"",
|
||||
"BANDWIDTH_GENERATOR_NYMT":"0xB3BF30DD53044c9050B7309031Bbf26b2cecF3be",
|
||||
|
||||
+7
-21
@@ -6524,9 +6524,9 @@
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.14.7",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz",
|
||||
"integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==",
|
||||
"version": "1.14.8",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
|
||||
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==",
|
||||
"dev": true
|
||||
},
|
||||
"for-each": {
|
||||
@@ -14257,21 +14257,7 @@
|
||||
"simple-concat": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
|
||||
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"simple-get": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.1.tgz",
|
||||
"integrity": "sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"decompress-response": "^3.3.0",
|
||||
"once": "^1.3.1",
|
||||
"simple-concat": "^1.0.0"
|
||||
}
|
||||
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="
|
||||
},
|
||||
"snapdragon": {
|
||||
"version": "0.8.2",
|
||||
@@ -19376,9 +19362,9 @@
|
||||
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="
|
||||
},
|
||||
"simple-get": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.1.tgz",
|
||||
"integrity": "sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==",
|
||||
"version": "2.8.2",
|
||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.2.tgz",
|
||||
"integrity": "sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw==",
|
||||
"requires": {
|
||||
"decompress-response": "^3.3.0",
|
||||
"once": "^1.3.1",
|
||||
|
||||
@@ -122,6 +122,16 @@ pub fn execute(
|
||||
info,
|
||||
profit_margin_percent,
|
||||
),
|
||||
ExecuteMsg::UpdateMixnodeConfigOnBehalf {
|
||||
profit_margin_percent,
|
||||
owner,
|
||||
} => crate::mixnodes::transactions::try_update_mixnode_config_on_behalf(
|
||||
deps,
|
||||
env,
|
||||
info,
|
||||
profit_margin_percent,
|
||||
owner,
|
||||
),
|
||||
ExecuteMsg::BondGateway {
|
||||
gateway,
|
||||
owner_signature,
|
||||
@@ -315,64 +325,9 @@ 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> {
|
||||
use cw_storage_plus::Item;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// needed migration:
|
||||
/*
|
||||
1. removal of rewarding_interval_starting_block field from ContractState
|
||||
2. removal of latest_rewarding_interval_nonce field from ContractState
|
||||
3. removal of rewarding_in_progress field from ContractState
|
||||
4. interval_storage::CURRENT_INTERVAL.save(deps.storage, &Interval::default())?;
|
||||
5. interval_storage::CURRENT_REWARDED_SET_HEIGHT.save(deps.storage, &env.block.height)?;
|
||||
6. removal of active_set_work_factor fields from ContractStateParams
|
||||
*/
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct OldContractStateParams {
|
||||
pub minimum_mixnode_pledge: Uint128,
|
||||
pub minimum_gateway_pledge: Uint128,
|
||||
pub mixnode_rewarded_set_size: u32,
|
||||
pub mixnode_active_set_size: u32,
|
||||
pub active_set_work_factor: u8,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct OldContractState {
|
||||
pub owner: Addr, // only the owner account can update state
|
||||
pub rewarding_validator_address: Addr,
|
||||
pub params: OldContractStateParams,
|
||||
pub rewarding_interval_starting_block: u64,
|
||||
pub latest_rewarding_interval_nonce: u32,
|
||||
pub rewarding_in_progress: bool,
|
||||
}
|
||||
|
||||
let old_contract_state: Item<'_, OldContractState> = Item::new("config");
|
||||
|
||||
let old_state = old_contract_state.load(deps.storage)?;
|
||||
|
||||
let new_params = mixnet_contract_common::ContractStateParams {
|
||||
minimum_mixnode_pledge: old_state.params.minimum_mixnode_pledge,
|
||||
minimum_gateway_pledge: old_state.params.minimum_mixnode_pledge,
|
||||
mixnode_rewarded_set_size: old_state.params.mixnode_rewarded_set_size,
|
||||
mixnode_active_set_size: old_state.params.mixnode_active_set_size,
|
||||
};
|
||||
|
||||
let new_state = crate::mixnet_contract_settings::models::ContractState {
|
||||
owner: old_state.owner,
|
||||
rewarding_validator_address: old_state.rewarding_validator_address,
|
||||
params: new_params,
|
||||
};
|
||||
let rewarding_interval =
|
||||
Interval::new(0, DEFAULT_FIRST_INTERVAL_START, REWARDING_INTERVAL_LENGTH);
|
||||
|
||||
mixnet_params_storage::CONTRACT_STATE.save(deps.storage, &new_state)?;
|
||||
|
||||
interval_storage::CURRENT_INTERVAL.save(deps.storage, &rewarding_interval)?;
|
||||
interval_storage::CURRENT_REWARDED_SET_HEIGHT.save(deps.storage, &env.block.height)?;
|
||||
|
||||
pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
|
||||
Ok(Default::default())
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ use cw_storage_plus::PrimaryKey;
|
||||
use mixnet_contract_common::events::{new_delegation_event, new_undelegation_event};
|
||||
use mixnet_contract_common::{Delegation, IdentityKey};
|
||||
use vesting_contract_common::messages::ExecuteMsg as VestingContractExecuteMsg;
|
||||
use vesting_contract_common::one_unym;
|
||||
use vesting_contract_common::one_ucoin;
|
||||
|
||||
fn validate_delegation_stake(mut delegation: Vec<Coin>) -> Result<Coin, ContractError> {
|
||||
// check if anything was put as delegation
|
||||
@@ -213,7 +213,7 @@ pub(crate) fn _try_remove_delegation_from_mixnode(
|
||||
amount: old_delegation.amount.clone(),
|
||||
});
|
||||
|
||||
let track_undelegation_msg = wasm_execute(proxy, &msg, vec![one_unym()])?;
|
||||
let track_undelegation_msg = wasm_execute(proxy, &msg, vec![one_ucoin()])?;
|
||||
|
||||
response = response.add_message(track_undelegation_msg);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ use cosmwasm_std::{
|
||||
use mixnet_contract_common::events::{new_gateway_bonding_event, new_gateway_unbonding_event};
|
||||
use mixnet_contract_common::{Gateway, GatewayBond, Layer};
|
||||
use vesting_contract_common::messages::ExecuteMsg as VestingContractExecuteMsg;
|
||||
use vesting_contract_common::one_unym;
|
||||
use vesting_contract_common::one_ucoin;
|
||||
|
||||
pub fn try_add_gateway(
|
||||
deps: DepsMut<'_>,
|
||||
@@ -177,7 +177,7 @@ pub(crate) fn _try_remove_gateway(
|
||||
amount: gateway_bond.pledge_amount(),
|
||||
};
|
||||
|
||||
let track_unbond_message = wasm_execute(proxy, &msg, vec![one_unym()])?;
|
||||
let track_unbond_message = wasm_execute(proxy, &msg, vec![one_ucoin()])?;
|
||||
response = response.add_message(track_unbond_message);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ use cosmwasm_std::{
|
||||
use mixnet_contract_common::events::{new_mixnode_bonding_event, new_mixnode_unbonding_event};
|
||||
use mixnet_contract_common::MixNode;
|
||||
use vesting_contract_common::messages::ExecuteMsg as VestingContractExecuteMsg;
|
||||
use vesting_contract_common::one_unym;
|
||||
use vesting_contract_common::one_ucoin;
|
||||
|
||||
pub fn try_add_mixnode(
|
||||
deps: DepsMut<'_>,
|
||||
@@ -201,7 +201,7 @@ pub(crate) fn _try_remove_mixnode(
|
||||
amount: mixnode_bond.pledge_amount(),
|
||||
};
|
||||
|
||||
let track_unbond_message = wasm_execute(proxy, &msg, vec![one_unym()])?;
|
||||
let track_unbond_message = wasm_execute(proxy, &msg, vec![one_ucoin()])?;
|
||||
response = response.add_message(track_unbond_message);
|
||||
}
|
||||
|
||||
@@ -222,14 +222,43 @@ pub(crate) fn try_update_mixnode_config(
|
||||
profit_margin_percent: u8,
|
||||
) -> Result<Response, ContractError> {
|
||||
let owner = deps.api.addr_validate(info.sender.as_ref())?;
|
||||
let mix_identity = storage::mixnodes()
|
||||
_try_update_mixnode_config(deps, env, profit_margin_percent, owner, None)
|
||||
}
|
||||
|
||||
pub(crate) fn try_update_mixnode_config_on_behalf(
|
||||
deps: DepsMut,
|
||||
env: Env,
|
||||
info: MessageInfo,
|
||||
profit_margin_percent: u8,
|
||||
owner: String,
|
||||
) -> Result<Response, ContractError> {
|
||||
let owner = deps.api.addr_validate(&owner)?;
|
||||
let proxy = deps.api.addr_validate(info.sender.as_ref())?;
|
||||
_try_update_mixnode_config(deps, env, profit_margin_percent, owner, Some(proxy))
|
||||
}
|
||||
|
||||
pub(crate) fn _try_update_mixnode_config(
|
||||
deps: DepsMut,
|
||||
env: Env,
|
||||
profit_margin_percent: u8,
|
||||
owner: Addr,
|
||||
proxy: Option<Addr>,
|
||||
) -> Result<Response, ContractError> {
|
||||
let mixnode_bond = storage::mixnodes()
|
||||
.idx
|
||||
.owner
|
||||
.item(deps.storage, owner.clone())?
|
||||
.ok_or(ContractError::NoAssociatedMixNodeBond { owner })?
|
||||
.1
|
||||
.identity()
|
||||
.clone();
|
||||
.1;
|
||||
|
||||
if proxy != mixnode_bond.proxy {
|
||||
return Err(ContractError::ProxyMismatch {
|
||||
existing: mixnode_bond
|
||||
.proxy
|
||||
.map_or_else(|| "None".to_string(), |a| a.as_str().to_string()),
|
||||
incoming: proxy.map_or_else(|| "None".to_string(), |a| a.as_str().to_string()),
|
||||
});
|
||||
}
|
||||
|
||||
// We don't have to check lower bound as its an u8
|
||||
if profit_margin_percent > 100 {
|
||||
@@ -238,7 +267,7 @@ pub(crate) fn try_update_mixnode_config(
|
||||
));
|
||||
}
|
||||
|
||||
storage::mixnodes().update(deps.storage, &mix_identity, |mixnode_bond_opt| {
|
||||
storage::mixnodes().update(deps.storage, mixnode_bond.identity(), |mixnode_bond_opt| {
|
||||
mixnode_bond_opt
|
||||
.map(|mut mixnode_bond| {
|
||||
mixnode_bond.mix_node.profit_margin_percent = profit_margin_percent;
|
||||
@@ -248,7 +277,19 @@ pub(crate) fn try_update_mixnode_config(
|
||||
.ok_or(ContractError::NoBondFound)
|
||||
})?;
|
||||
|
||||
Ok(Response::new())
|
||||
let mut response = Response::new();
|
||||
|
||||
if let Some(proxy) = proxy {
|
||||
// Returns one_ucoin proxy had to send in order to execute the contract to contract transaction, this is potentially leaky as anyone can say that they're a proxy,
|
||||
// and they could potentially leak 1 unym per transaction, altough I'm pretty sure transaction fees make that silly.
|
||||
let return_one_ucoint = BankMsg::Send {
|
||||
to_address: proxy.as_str().to_string(),
|
||||
amount: vec![one_ucoin()],
|
||||
};
|
||||
response = response.add_message(return_one_ucoint);
|
||||
}
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
fn validate_mixnode_pledge(
|
||||
|
||||
@@ -260,6 +260,9 @@ pub(crate) fn try_reward_mixnode(
|
||||
);
|
||||
}
|
||||
|
||||
let node_pledge = current_bond.pledge_amount.amount;
|
||||
let node_delegation = current_bond.total_delegation.amount;
|
||||
|
||||
// check if it has non-zero uptime
|
||||
if params.uptime() == 0 {
|
||||
storage::REWARDING_STATUS.save(
|
||||
@@ -315,6 +318,8 @@ pub(crate) fn try_reward_mixnode(
|
||||
interval_id,
|
||||
&mix_identity,
|
||||
node_reward_result,
|
||||
node_pledge,
|
||||
node_delegation,
|
||||
operator_reward,
|
||||
total_delegator_reward,
|
||||
further_delegations,
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::storage::{account_from_address, ADMIN, MIXNET_CONTRACT_ADDRESS};
|
||||
use crate::traits::{
|
||||
DelegatingAccount, GatewayBondingAccount, MixnodeBondingAccount, VestingAccount,
|
||||
};
|
||||
use crate::vesting::{populate_vesting_periods, Account, PledgeData};
|
||||
use crate::vesting::{populate_vesting_periods, Account};
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::{
|
||||
coin, entry_point, to_binary, BankMsg, Coin, Deps, DepsMut, Env, MessageInfo, QueryResponse,
|
||||
@@ -18,6 +18,7 @@ use vesting_contract_common::events::{
|
||||
use vesting_contract_common::messages::{
|
||||
ExecuteMsg, InitMsg, MigrateMsg, QueryMsg, VestingSpecification,
|
||||
};
|
||||
use vesting_contract_common::{OriginalVestingResponse, Period, PledgeData};
|
||||
|
||||
#[entry_point]
|
||||
pub fn instantiate(
|
||||
@@ -45,6 +46,9 @@ pub fn execute(
|
||||
msg: ExecuteMsg,
|
||||
) -> Result<Response, ContractError> {
|
||||
match msg {
|
||||
ExecuteMsg::UpdateMixnodeConfig {
|
||||
profit_margin_percent,
|
||||
} => try_update_mixnode_config(profit_margin_percent, info, deps),
|
||||
ExecuteMsg::UpdateMixnetAddress { address } => {
|
||||
try_update_mixnet_address(address, info, deps)
|
||||
}
|
||||
@@ -102,6 +106,15 @@ pub fn execute(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_update_mixnode_config(
|
||||
profit_margin_percent: u8,
|
||||
info: MessageInfo,
|
||||
deps: DepsMut,
|
||||
) -> Result<Response, ContractError> {
|
||||
let account = account_from_address(info.sender.as_str(), deps.storage, deps.api)?;
|
||||
account.try_update_mixnode_config(profit_margin_percent, deps.storage)
|
||||
}
|
||||
|
||||
// Only contract admin, set at init
|
||||
pub fn try_update_mixnet_address(
|
||||
address: String,
|
||||
@@ -431,11 +444,23 @@ pub fn query(deps: Deps<'_>, env: Env, msg: QueryMsg) -> Result<QueryResponse, C
|
||||
QueryMsg::GetAccount { address } => to_binary(&try_get_account(&address, deps)?),
|
||||
QueryMsg::GetMixnode { address } => to_binary(&try_get_mixnode(&address, deps)?),
|
||||
QueryMsg::GetGateway { address } => to_binary(&try_get_gateway(&address, deps)?),
|
||||
QueryMsg::GetCurrentVestingPeriod { address } => {
|
||||
to_binary(&try_get_current_vesting_period(&address, deps, env)?)
|
||||
}
|
||||
};
|
||||
|
||||
Ok(query_res?)
|
||||
}
|
||||
|
||||
pub fn try_get_current_vesting_period(
|
||||
address: &str,
|
||||
deps: Deps<'_>,
|
||||
env: Env,
|
||||
) -> Result<Period, ContractError> {
|
||||
let account = account_from_address(address, deps.storage, deps.api)?;
|
||||
Ok(account.get_current_vesting_period(env.block.time))
|
||||
}
|
||||
|
||||
pub fn try_get_mixnode(address: &str, deps: Deps<'_>) -> Result<Option<PledgeData>, ContractError> {
|
||||
let account = account_from_address(address, deps.storage, deps.api)?;
|
||||
account.load_mixnode_pledge(deps.storage)
|
||||
@@ -509,7 +534,7 @@ pub fn try_get_end_time(
|
||||
pub fn try_get_original_vesting(
|
||||
vesting_account_address: &str,
|
||||
deps: Deps<'_>,
|
||||
) -> Result<Coin, ContractError> {
|
||||
) -> Result<OriginalVestingResponse, ContractError> {
|
||||
let account = account_from_address(vesting_account_address, deps.storage, deps.api)?;
|
||||
Ok(account.get_original_vesting())
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use crate::errors::ContractError;
|
||||
use crate::vesting::Account;
|
||||
use crate::vesting::PledgeData;
|
||||
use cosmwasm_std::{Addr, Api, Storage, Uint128};
|
||||
use cw_storage_plus::{Item, Map};
|
||||
use mixnet_contract_common::IdentityKey;
|
||||
use vesting_contract_common::PledgeData;
|
||||
|
||||
type BlockHeight = u64;
|
||||
|
||||
|
||||
@@ -19,6 +19,12 @@ pub trait MixnodeBondingAccount {
|
||||
amount: Coin,
|
||||
storage: &mut dyn Storage,
|
||||
) -> Result<(), ContractError>;
|
||||
|
||||
fn try_update_mixnode_config(
|
||||
&self,
|
||||
profit_margin_percent: u8,
|
||||
storage: &mut dyn Storage,
|
||||
) -> Result<Response, ContractError>;
|
||||
}
|
||||
|
||||
pub trait GatewayBondingAccount {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::errors::ContractError;
|
||||
use cosmwasm_std::{Addr, Coin, Env, Storage, Timestamp};
|
||||
use vesting_contract_common::OriginalVestingResponse;
|
||||
|
||||
pub trait VestingAccount {
|
||||
// locked_coins returns the set of coins that are not spendable (can still be delegated tough) (i.e. locked),
|
||||
@@ -37,7 +38,7 @@ pub trait VestingAccount {
|
||||
fn get_start_time(&self) -> Timestamp;
|
||||
fn get_end_time(&self) -> Timestamp;
|
||||
|
||||
fn get_original_vesting(&self) -> Coin;
|
||||
fn get_original_vesting(&self) -> OriginalVestingResponse;
|
||||
fn get_delegated_free(
|
||||
&self,
|
||||
block_time: Option<Timestamp>,
|
||||
|
||||
@@ -8,7 +8,7 @@ use mixnet_contract_common::IdentityKey;
|
||||
use vesting_contract_common::events::{
|
||||
new_vesting_delegation_event, new_vesting_undelegation_event,
|
||||
};
|
||||
use vesting_contract_common::one_unym;
|
||||
use vesting_contract_common::one_ucoin;
|
||||
|
||||
use super::Account;
|
||||
|
||||
@@ -70,7 +70,7 @@ impl DelegatingAccount for Account {
|
||||
let undelegate_from_mixnode = wasm_execute(
|
||||
MIXNET_CONTRACT_ADDRESS.load(storage)?,
|
||||
&msg,
|
||||
vec![one_unym()],
|
||||
vec![one_ucoin()],
|
||||
)?;
|
||||
|
||||
Ok(Response::new()
|
||||
|
||||
@@ -7,7 +7,7 @@ use mixnet_contract_common::{ExecuteMsg as MixnetExecuteMsg, Gateway};
|
||||
use vesting_contract_common::events::{
|
||||
new_vesting_gateway_bonding_event, new_vesting_gateway_unbonding_event,
|
||||
};
|
||||
use vesting_contract_common::one_unym;
|
||||
use vesting_contract_common::one_ucoin;
|
||||
|
||||
use super::Account;
|
||||
|
||||
@@ -34,10 +34,7 @@ impl GatewayBondingAccount for Account {
|
||||
self.owner_address().as_str().to_string(),
|
||||
));
|
||||
} else {
|
||||
PledgeData {
|
||||
block_time: env.block.time,
|
||||
amount: pledge.amount,
|
||||
}
|
||||
PledgeData::new(pledge.clone(), env.block.time)
|
||||
};
|
||||
|
||||
let msg = MixnetExecuteMsg::BondGatewayOnBehalf {
|
||||
@@ -68,7 +65,7 @@ impl GatewayBondingAccount for Account {
|
||||
let unbond_msg = wasm_execute(
|
||||
MIXNET_CONTRACT_ADDRESS.load(storage)?,
|
||||
&msg,
|
||||
vec![one_unym()],
|
||||
vec![one_ucoin()],
|
||||
)?;
|
||||
|
||||
Ok(Response::new()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use super::PledgeData;
|
||||
use crate::errors::ContractError;
|
||||
use crate::storage::MIXNET_CONTRACT_ADDRESS;
|
||||
use crate::traits::MixnodeBondingAccount;
|
||||
@@ -6,12 +5,36 @@ use cosmwasm_std::{wasm_execute, Coin, Env, Response, Storage, Uint128};
|
||||
use mixnet_contract_common::{ExecuteMsg as MixnetExecuteMsg, MixNode};
|
||||
use vesting_contract_common::events::{
|
||||
new_vesting_mixnode_bonding_event, new_vesting_mixnode_unbonding_event,
|
||||
new_vesting_update_mixnode_config_event,
|
||||
};
|
||||
use vesting_contract_common::one_unym;
|
||||
|
||||
use vesting_contract_common::one_ucoin;
|
||||
use vesting_contract_common::PledgeData;
|
||||
|
||||
use super::Account;
|
||||
|
||||
impl MixnodeBondingAccount for Account {
|
||||
fn try_update_mixnode_config(
|
||||
&self,
|
||||
profit_margin_percent: u8,
|
||||
storage: &mut dyn Storage,
|
||||
) -> Result<Response, ContractError> {
|
||||
let msg = MixnetExecuteMsg::UpdateMixnodeConfigOnBehalf {
|
||||
profit_margin_percent,
|
||||
owner: self.owner_address().into_string(),
|
||||
};
|
||||
|
||||
let update_mixnode_config_msg = wasm_execute(
|
||||
MIXNET_CONTRACT_ADDRESS.load(storage)?,
|
||||
&msg,
|
||||
vec![one_ucoin()],
|
||||
)?;
|
||||
|
||||
Ok(Response::new()
|
||||
.add_message(update_mixnode_config_msg)
|
||||
.add_event(new_vesting_update_mixnode_config_event()))
|
||||
}
|
||||
|
||||
fn try_bond_mixnode(
|
||||
&self,
|
||||
mix_node: MixNode,
|
||||
@@ -34,10 +57,7 @@ impl MixnodeBondingAccount for Account {
|
||||
self.owner_address().as_str().to_string(),
|
||||
));
|
||||
} else {
|
||||
PledgeData {
|
||||
block_time: env.block.time,
|
||||
amount: pledge.amount,
|
||||
}
|
||||
PledgeData::new(pledge.clone(), env.block.time)
|
||||
};
|
||||
|
||||
let msg = MixnetExecuteMsg::BondMixnodeOnBehalf {
|
||||
@@ -68,7 +88,7 @@ impl MixnodeBondingAccount for Account {
|
||||
let unbond_msg = wasm_execute(
|
||||
MIXNET_CONTRACT_ADDRESS.load(storage)?,
|
||||
&msg,
|
||||
vec![one_unym()],
|
||||
vec![one_ucoin()],
|
||||
)?;
|
||||
|
||||
Ok(Response::new()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user