Compare commits

...

135 Commits

Author SHA1 Message Date
Jędrzej Stuczyński 3c82d58343 Running tests with all features in CI 2022-03-02 10:32:14 +00:00
Jędrzej Stuczyński 1f05e956fb Feature-locking parts of common/crypto 2022-03-02 10:32:02 +00:00
Jędrzej Stuczyński dbfe9a0b92 Merge with origin 2022-03-01 14:40:22 +00:00
Jędrzej Stuczyński eb3ed98f94 Performed the rest of the upgrade 2022-03-01 14:38:22 +00:00
Jędrzej Stuczyński 9d6a4ea99d Traits should be fixed now 2022-03-01 12:20:39 +00:00
Jędrzej Stuczyński 5701ea5c02 First level of trait updates 2022-03-01 11:55:12 +00:00
Mark Sinclair e3cd1f7eb7 Upgrade blake3 2022-03-01 10:46:15 +00:00
Mark Sinclair 080616a461 Revert 2022-03-01 10:41:42 +00:00
Mark Sinclair 2a0ccf30f9 Upgrade tauri to 1.0.0 RC3, to fix tray area issues 2022-03-01 10:25:09 +00:00
Mark Sinclair cef9e17796 Removing common/tauri-client from build because of a dependency conflict between tauri build tools and common/crypto for blake3 crate 2022-03-01 10:23:22 +00:00
durch 4d0b5b34ec Export additional wallet types 2022-02-28 18:28:53 +01:00
durch 6af0dbd1da Add AccountInfo to wallet 2022-02-28 18:24:40 +01:00
Mark Sinclair 2004148710 Network Explorer world map shows muted fill for countries with zero mixnodes 2022-02-28 12:58:18 +00:00
Bogdan-Ștefan Neacșu 1e805be5ad Start from 0 instead of 1, to have the correct length 2022-02-28 12:56:32 +02:00
fmtabbara 7a25e600b3 merge auto-screen size for the wallet 2022-02-28 10:34:09 +00:00
Raphaël Walther 1fd7d54715 Set nightly builds notification only on failure 2022-02-28 10:10:25 +01:00
Fouad 43a6e62050 Merge pull request #1132 from nymtech/feature/vesting-ui
Feature/vesting UI
2022-02-25 15:23:27 +00:00
fmtabbara 39fb131d95 minor updates 2022-02-25 13:06:11 +00:00
fmtabbara 9533c2440a clear all balanced on logout 2022-02-25 11:54:23 +00:00
fmtabbara aab2be1fbd only allow QA network selection in development mode 2022-02-25 10:56:28 +00:00
Raphaël Walther 448dcbeaa8 Added missing token for notification 2022-02-25 10:55:28 +01:00
fmtabbara 29b07b4904 sort out car alignment! 2022-02-24 17:55:18 +00:00
fmtabbara cceb7a40bd update contract addressess 2022-02-24 16:50:58 +00:00
fmtabbara fb4b32359d log error 2022-02-24 16:41:49 +00:00
fmtabbara 7ca92cc487 hide vesting card if no vesting period created 2022-02-24 15:59:34 +00:00
fmtabbara 15d612eff6 add fee 2022-02-24 15:00:13 +00:00
Jon Häggblad 021c2d14f2 gateway: extract out PersistantStorage 2022-02-24 15:37:34 +01:00
fmtabbara 3b85927a90 merge develop 2022-02-24 12:17:00 +00:00
fmtabbara b386388b82 reorganise vesting ui 2022-02-24 12:15:40 +00:00
fmtabbara 7941b7099f use window maximize 2022-02-24 09:51:38 +00:00
dependabot[bot] 6604d927c5 Bump ws from 6.2.1 to 6.2.2 in /clients/webassembly/js-example (#1126)
Bumps [ws](https://github.com/websockets/ws) from 6.2.1 to 6.2.2.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/6.2.1...6.2.2)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-23 13:56:04 +00:00
Jon Häggblad 4fedf05b64 Fix clippy warnings on beta channel 2022-02-23 14:45:41 +01:00
Raphaël Walther fa00f85a31 Removed condition in notification 2022-02-23 14:05:55 +01:00
Raphaël Walther abf5a2d307 Triggerd workflow 2022-02-23 12:30:26 +01:00
Raphaël Walther 8e0000cb0b Removed test workflow 2022-02-23 12:02:30 +01:00
Raphaël Walther cc27911671 Moved workflow to different runners 2022-02-23 11:29:53 +01:00
Bogdan-Ștefan Neacșu b598f1d1db Make sure run uses the args passed at init, in eth mode 2022-02-23 12:45:31 +03:00
Raphaël Walther d4f10c1d68 Triggered workflow 2022-02-23 09:24:22 +01:00
Raphaël Walther 1d7ff40d02 Added test workflow 2022-02-23 09:14:21 +01:00
Raphaël Walther 72703b36e1 Tested build workflow 2022-02-22 17:35:50 +01:00
Raphaël Walther ecf7a40010 Enabled sccache 2022-02-22 17:23:47 +01:00
Raphaël Walther 272e9187d2 Removed test workflow 2022-02-22 16:18:28 +01:00
Raphaël Walther 69a1f3773c Amended test workflow 2022-02-22 15:41:20 +01:00
Raphaël Walther 15c97b1cae Amended test workflow 2022-02-22 15:31:02 +01:00
Raphaël Walther 2660ef59f7 Amended test workflow 2022-02-22 13:29:21 +01:00
dependabot[bot] 12a06d9dfe Bump url-parse from 1.4.7 to 1.5.7 in /clients/webassembly/react-example (#1125)
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.4.7 to 1.5.7.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.4.7...1.5.7)

---
updated-dependencies:
- dependency-name: url-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-22 09:56:29 +00:00
dependabot[bot] 6399cd24c8 Bump url-parse in /clients/native/examples/js-examples/websocket (#1124)
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.4 to 1.5.7.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.4...1.5.7)

---
updated-dependencies:
- dependency-name: url-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-22 09:56:20 +00:00
dependabot[bot] f30b5162e8 Bump url-parse from 1.5.1 to 1.5.7 in /clients/webassembly/js-example (#1122)
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.1 to 1.5.7.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.1...1.5.7)

---
updated-dependencies:
- dependency-name: url-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-22 09:56:15 +00:00
dependabot[bot] 229329ae4c Bump follow-redirects in /contracts/basic-bandwidth-generation (#1117)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.7 to 1.14.8.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.7...v1.14.8)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-22 09:56:10 +00:00
dependabot[bot] a3bb5e466d Bump follow-redirects from 1.14.3 to 1.14.8 in /explorer (#1116)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.3 to 1.14.8.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.3...v1.14.8)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-22 09:56:03 +00:00
dependabot[bot] 65d893a70b Bump follow-redirects from 1.14.5 to 1.14.8 in /nym-wallet (#1115)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.5 to 1.14.8.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.5...v1.14.8)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-22 09:55:55 +00:00
dependabot[bot] e0944e5238 Bump follow-redirects in /clients/native/examples/js-examples/websocket (#1114)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.7 to 1.14.8.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.7...v1.14.8)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-22 09:55:49 +00:00
dependabot[bot] b451d4b709 Bump follow-redirects from 1.14.7 to 1.14.8 in /testnet-faucet (#1113)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.7 to 1.14.8.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.7...v1.14.8)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-22 09:55:42 +00:00
dependabot[bot] 1507e48158 Bump follow-redirects in /clients/webassembly/js-example (#1112)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.1 to 1.14.8.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.1...v1.14.8)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-22 09:55:36 +00:00
dependabot[bot] 6e7a7ed4a6 Bump simple-get from 3.1.0 to 3.1.1 in /explorer (#1109)
Bumps [simple-get](https://github.com/feross/simple-get) from 3.1.0 to 3.1.1.
- [Release notes](https://github.com/feross/simple-get/releases)
- [Commits](https://github.com/feross/simple-get/compare/v3.1.0...v3.1.1)

---
updated-dependencies:
- dependency-name: simple-get
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-22 09:55:29 +00:00
Jędrzej Stuczyński af4801ac47 Removes migration code (#1071) 2022-02-22 09:54:57 +00:00
Raphaël Walther b748c55d4e Amended test workflow 2022-02-22 09:37:31 +01:00
Raphaël Walther 84e5bfc286 Amended test workflow 2022-02-21 17:37:12 +01:00
Raphaël Walther 96bd9ecf49 Amended test workflow 2022-02-21 15:48:10 +01:00
Raphaël Walther 092851976f Added test workflow 2022-02-21 13:23:04 +01:00
durch 9da1f82cca Restore cargo.lock 2022-02-20 21:58:01 +01:00
durch 8c60927fe2 Update tauri 2022-02-18 18:20:18 +01:00
fmtabbara ec5ef1db56 dynamic window sizing 2022-02-18 16:22:24 +00:00
fmtabbara 5dee6dd44f layout updates 2022-02-18 15:54:32 +00:00
durch aa6f5ad664 Update minor/patch versions 2022-02-18 12:18:28 +01:00
fmtabbara 201b5cc56f ui updates 2022-02-17 17:09:02 +00:00
fmtabbara 510553a697 update content 2022-02-17 14:56:38 +00:00
Raphaël Walther b81967c9f5 Set nightly notification on failure 2022-02-17 14:19:28 +01:00
Bogdan-Ștefan Neacşu fadff7888b Feature/reuse init owner (#970)
* Save gateway owner for later use in erc20 bandwidth request

* Pass owner in network monitor

* Switch to variable length owner address

* Add erc20 bridge contract in validator client

* Check bandwidth credential refers to gateway

* Check the owner of the gateway from the eth event

* Fix wasm client

* Hack to avoid unused warning on coconut path

* Hacked, one-time payment

* Remove print

* Update arg format

* Fix token check

* Fix native template

* Use utokens instead of full token

... when talking to eth

* Fix parse event for new field

* Fix socks5 template

* Add estimation of gas call

* Make fs backup more reliable

* Fix clippy

* Fix unused import

* Update waiting time

* Remove defaults from run, as it they should be set on init

* Remove debugging prints

* Replaced unwrap with error

* Fix build

* Make eth contract address dependent of network

* Use tokio for sleep

* Add approve before spending token on bandwidth

* Put bandwidth claim only at the beginning of the process
2022-02-17 11:56:11 +01:00
fmtabbara 24854f9254 Merge branch 'feature/faucet-release' into develop 2022-02-17 10:49:02 +00:00
Tommy Verrall 8ea7726e81 Merge pull request #1121 from nymtech/feature/update-sandbox
update contract address
2022-02-16 18:26:07 +00:00
Tommy Verrall ea32a897b2 update contract address 2022-02-16 17:38:27 +00:00
Raphaël Walther 5d7a14c5ab Added a custom runner for ubuntu only builds 2022-02-16 17:14:19 +01:00
Raphaël Walther cad68b8d6c Set test schedule 2022-02-16 16:42:09 +01:00
Raphaël Walther 1d125ed97f Set test schedule 2022-02-16 14:36:36 +01:00
Raphaël Walther 36d4ec5a72 Set test schedule 2022-02-16 13:49:38 +01:00
Raphaël Walther 44981b8621 Set test schedule 2022-02-16 13:27:40 +01:00
fmtabbara bd68797432 replace local storage with cookie 2022-02-16 12:23:44 +00:00
Mark Sinclair 636759789c Merge pull request #1119 from nymtech/feature/gh-actions-notifications
Refactor GitHub Actions notifications
2022-02-16 14:21:16 +02:00
Mark Sinclair c03a859223 Refactor GitHub Actions notifications 2022-02-16 14:09:12 +02:00
fmtabbara b269cdae31 refactor 2022-02-16 11:10:15 +00:00
Raphaël Walther 2177a396b9 Added assume yes option on apt-get install 2022-02-16 11:48:11 +01:00
Raphaël Walther 4c50dd64f4 Added test build 2022-02-16 11:19:41 +01:00
fmtabbara be9d3a48bb update error message 2022-02-16 10:19:09 +00:00
fmtabbara 37d890c634 refactor 💪 2022-02-15 22:15:10 +00:00
fmtabbara 6287583f4b component refactor 2022-02-15 21:35:34 +00:00
fmtabbara c7760c6c10 eslint check + additional validation 2022-02-15 18:46:03 +00:00
fmtabbara 2c0058c477 update env sample£ 2022-02-15 16:38:07 +00:00
fmtabbara 02fb2e56ca add validation 2022-02-15 16:34:41 +00:00
Jon Häggblad 8b2c72eb91 gateway: upgrade clap and use declarative cli argument parsing 2022-02-15 17:11:51 +01:00
durch 805eb31728 Fix typo 2022-02-15 16:21:13 +01:00
fmtabbara 22d4c89e48 display total vesting 2022-02-15 15:04:14 +00:00
fmtabbara 28d5ac92b3 fix alignment 2022-02-15 14:19:37 +00:00
fmtabbara a2e678587c Merge branch 'feature/vesting-ui' of https://github.com/nymtech/nym into feature/vesting-ui 2022-02-15 13:59:46 +00:00
fmtabbara 0ac7bb5f03 terminology updates 2022-02-15 13:59:35 +00:00
durch 7f45cbd5df Rename all -> test 2022-02-15 14:41:00 +01:00
fmtabbara 8ce709bbb4 update currency 2022-02-15 10:20:07 +00:00
Raphaël Walther 46db139f79 Set cron schedule 2022-02-14 18:09:31 +01:00
Raphaël Walther 069c5bf332 Added repo checkout on new job 2022-02-14 18:08:06 +01:00
Jess 54a4653e7d Merge pull request #1118 from nymtech/bugfix/gateway-bond
Change `pledge` to `bond` in gateway list
2022-02-14 15:07:49 +00:00
Raphaël Walther ea1f689c71 Added a job for notification 2022-02-14 15:59:35 +01:00
Mark Sinclair 3d60299b22 Change pledge to bond in gateway list 2022-02-14 16:42:04 +02:00
fmtabbara 4d9dfac812 [ci skip] Generate TS types 2022-02-14 14:07:39 +00:00
fmtabbara 0012294dc0 add current vesting period 2022-02-14 13:58:45 +00:00
Raphaël Walther 5b5063676f Corrected wrong indentation 2022-02-14 14:20:54 +01:00
Raphaël Walther 833556020d Set runner OS to ubuntu-latest for notification 2022-02-14 14:16:27 +01:00
Fouad Tabbara 0cdb68bcf3 fix breaking changes + add vesting total period 2022-02-14 11:47:42 +00:00
Raphaël Walther aa00eb70d5 Adedd env variables for notification 2022-02-14 12:19:13 +01:00
Fouad Tabbara a882d10848 Merge branch 'develop' into feature/vesting-ui 2022-02-14 11:18:07 +00:00
Fouad Tabbara c03a58ae9a change file ext 2022-02-14 11:15:31 +00:00
Drazen Urch 2caf79fba0 Feature/vesting get current period (#1111)
* Add GetCurrentPeriod Msg

* Add a few more query endpoints

* Enrich original vesting response
2022-02-14 12:13:55 +01:00
Raphaël Walther eda1822653 Removed beta and nightly rust builds 2022-02-14 10:28:12 +01:00
Raphaël Walther 0f1ff5ffd2 Added notifications to nightly builds 2022-02-14 09:04:02 +01:00
Raphaël Walther 9512fc34f0 Added workflow for daily builds 2022-02-11 14:21:06 +01:00
fmtabbara 75348922fc close snackbars on component unmount 2022-02-11 13:13:45 +00:00
Drazen Urch 938eb2d0f0 Add UpdateMixnodeConfigOnBehalf to vestng contract (#1091)
* Add UpdateMixnodeConfigOnBehalf

* Rename one_u* function
2022-02-11 12:15:00 +01:00
dependabot[bot] ede51fa589 Bump simple-get in /contracts/basic-bandwidth-generation (#1110)
Bumps [simple-get](https://github.com/feross/simple-get) from 2.8.1 to 2.8.2.
- [Release notes](https://github.com/feross/simple-get/releases)
- [Commits](https://github.com/feross/simple-get/compare/v2.8.1...v2.8.2)

---
updated-dependencies:
- dependency-name: simple-get
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-11 11:03:26 +00:00
dependabot[bot] 7e0711ce12 Bump simple-get from 3.1.0 to 3.1.1 in /clients/tauri-client (#1108)
Bumps [simple-get](https://github.com/feross/simple-get) from 3.1.0 to 3.1.1.
- [Release notes](https://github.com/feross/simple-get/releases)
- [Commits](https://github.com/feross/simple-get/compare/v3.1.0...v3.1.1)

---
updated-dependencies:
- dependency-name: simple-get
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-11 11:02:32 +00:00
dependabot[bot] 822f40239f Bump simple-get from 3.1.0 to 3.1.1 in /nym-wallet (#1107)
Bumps [simple-get](https://github.com/feross/simple-get) from 3.1.0 to 3.1.1.
- [Release notes](https://github.com/feross/simple-get/releases)
- [Commits](https://github.com/feross/simple-get/compare/v3.1.0...v3.1.1)

---
updated-dependencies:
- dependency-name: simple-get
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-11 11:02:27 +00:00
Tommy Verrall 31149e6ba1 Merge pull request #1105 from nymtech/dependabot/npm_and_yarn/clients/webassembly/react-example/node-sass-7.0.0
Bump node-sass from 4.14.1 to 7.0.0 in /clients/webassembly/react-example
2022-02-11 10:36:16 +00:00
Drazen Urch ba233b6016 Fix hardcoded period logic (#1104) 2022-02-11 09:44:15 +01:00
dependabot[bot] 3d17ab6a4b Bump node-sass in /clients/webassembly/react-example
Bumps [node-sass](https://github.com/sass/node-sass) from 4.14.1 to 7.0.0.
- [Release notes](https://github.com/sass/node-sass/releases)
- [Changelog](https://github.com/sass/node-sass/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sass/node-sass/compare/v4.14.1...v7.0.0)

---
updated-dependencies:
- dependency-name: node-sass
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-10 23:34:48 +00:00
fmtabbara 492f1dd199 add notifications 2022-02-10 10:16:23 +00:00
fmtabbara 172399f792 unlock spendable tokens 2022-02-09 17:06:31 +00:00
fmtabbara 22407c2911 create address component 2022-02-09 13:49:56 +00:00
fmtabbara bdace0f9cb truncate address 2022-02-09 12:31:30 +00:00
fmtabbara 15bbba590b minor refactors 2022-02-09 11:27:26 +00:00
fmtabbara a72264c685 get and display token allocation values 2022-02-09 11:27:09 +00:00
fmtabbara 2612cca708 refactoring 2022-02-09 11:25:26 +00:00
fmtabbara fc16d1c839 add QA to network selector (temporary) 2022-02-09 10:36:29 +00:00
Jędrzej Stuczyński f22bb282ab Fixed underflow in rewarding all delegators (#1099)
* Fixed underflow in rewarding all delegators

* Slightly simplifying the loop
2022-02-07 11:30:17 +00:00
Jędrzej Stuczyński d907b6b81a Fixes infinite loops in requests involving pagination (#1085)
* Fixes infinite loops in requests involving pagination

* Removed duplicate code and added extra explanation for the decision
2022-02-07 11:29:00 +00:00
Tommy Verrall 1903938035 Merge pull request #1094 from nymtech/feature/minor-rewarding-adjustments
Emit original bond as part of rewarding event
2022-02-03 14:58:13 +00:00
mfahampshire bb646c4f6a updated token contract address 2022-02-03 14:43:37 +01:00
Jędrzej Stuczyński 4c65ef3a2f Emit original bond as part of rewarding event 2022-02-03 09:52:44 +00:00
211 changed files with 6946 additions and 3672 deletions
+8 -32
View File
@@ -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
+2 -33
View File
@@ -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"
}
]
]
+3 -2
View File
@@ -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
+124
View File
@@ -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"
}
]
+4 -1
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
16
+58
View File
@@ -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
```
+1
View File
@@ -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,
};
@@ -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();
@@ -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
View File
File diff suppressed because it is too large Load Diff
+13 -3
View File
@@ -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");
}
+30 -14
View File
@@ -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"))]
@@ -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",
+11 -6
View File
@@ -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 #####
+5
View File
@@ -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,
+6 -6
View File
@@ -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());
+2 -2
View File
@@ -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);
+11 -7
View File
@@ -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 #####
+5
View File
@@ -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,
+6 -6
View File
@@ -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());
+2 -2
View File
@@ -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);
+17 -7
View File
@@ -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",
+7 -7
View File
@@ -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
View File
@@ -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",
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",
+1
View File
@@ -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(&eth_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(&eth_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 =
+23 -19
View File
@@ -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,
},
}
+1 -1
View File
@@ -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" }
+1 -1
View File
@@ -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
View File
@@ -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);
+3 -6
View File
@@ -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)
}
+9 -7
View File
@@ -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
View File
@@ -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)]
+13 -1
View File
@@ -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...
+15 -17
View File
@@ -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!")
}
+27 -22
View File
@@ -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;
+542 -125
View File
@@ -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"
}
]
"#;
+15 -5
View File
@@ -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;
+4
View File
@@ -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 -2
View File
@@ -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> {
+6 -2
View File
@@ -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(
+2 -2
View File
@@ -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>(
+6 -4
View File
@@ -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> {
+1 -1
View File
@@ -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,
};
+1 -1
View File
@@ -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" }
+4 -1
View File
@@ -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;
-99
View File
@@ -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
View File
@@ -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",
+12 -57
View File
@@ -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);
}
+49 -8
View File
@@ -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,
+27 -2
View File
@@ -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 -1
View File
@@ -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;
+6
View File
@@ -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