Compare commits

..

173 Commits

Author SHA1 Message Date
serinko 0cc8cf0846 update plugins 2023-10-16 14:04:22 +02:00
serinko 87b3b76854 update mdbook admonish 2023-10-16 13:46:16 +02:00
serinko b3739c02c7 re-update mdbook-admonish 2023-10-11 11:12:10 +02:00
serinko 5b7b3c0bdc upate admonish 2023-10-10 23:21:42 +02:00
serinko f2c2f273d7 fix syntax and formatting 2023-10-10 23:17:08 +02:00
serinko 3913e3e56b [DOC]: edit minor syntax - smoosh-faq.md 2023-10-10 13:08:44 +00:00
Tommy Verrall 5f3f97f3be Merge pull request #3975 from nymtech/bugfix/3973
Add packet type to NE mixnet response listener
2023-10-10 12:27:33 +02:00
Jon Häggblad fb2b7d3480 Fix rust-analyzer warnings (#3974)
* Fix rust-analyzer warnings

Fix some warnings that rust-analyzer emits due to enabling all features.
These are annoying when you try to list all warnings in the entire
workspace.

* Revert change to signing client

* Instead add nested feature
2023-10-10 12:02:00 +02:00
Jon Häggblad 7577ec9cb2 [NC-43] Route packets back to WG peer (#3965)
* Initial work on reverse nat

* wip

* Refine key gen

* Rename to wg_tunnel

* Forward packet to peer

* Remove source_addr

* Check if allowed to write to tunnel

* Extract out network_table

* Move map struc definitions to udp_listener

* Delegate ip network table calls

* Fix mac compilation

* Add TunTaskTx type
2023-10-10 11:01:03 +02:00
Drazen Urch 1e900c32df Gateway client registry and api routes (#3955)
* Add HTTP API and Client registry to Gateway

* Update CHANGELOG

* Smooshify structure

* Reify x25519 public key

* Hmac message verification

* Add lightweight handshake with replay protection

* Tidy up, move registartion to its own file

* Test for the registration flow

* Fix nonce loop hole
2023-10-10 10:55:26 +02:00
Drazen cb4eaddc9f Add packet type to NE mixnet response listener 2023-10-10 10:36:28 +02:00
Tommy Verrall 52151c5fb4 Merge pull request #3971 from nymtech/move_builds_to_ubuntu_lts
Github Actions: Fix release process
2023-10-09 11:27:26 +02:00
Raphaël Walther 24fe628e15 Github Actions: Fix release process 2023-10-09 07:24:18 +02:00
Jon Häggblad 369330f517 Fix clippy for latest stable toolchain (#3935)
* clippy::redundant-guards

* clippy::incorrect_partial_ord_impl_on_ord_type

* clippy::redundant-guards

* clippy::unwrap-or-default

* rustfmt

* noop_method_call

* nym-wallet Cargo.lock

* Unpin rust toolchain for nym-wallet

* cargo clippy --fix --workspace

* clippy::redundant_locals

* Reorder Makefile targets for more logical ordering
2023-10-06 11:04:26 +02:00
Jon Häggblad ada30f5483 ci: skip tests in ci-build for mac due to lack of runners 2023-10-06 10:53:29 +02:00
Tommy Verrall c906770370 Merge pull request #3895 from nymtech/feature/issue-3894/wallet-rename-accounts
Wallet: Introduce edit account name
2023-10-05 16:05:58 +02:00
Raphaël Walther 6f94124256 Merge pull request #3967 from nymtech/add_workflow_trigger
Add workflow trigger
2023-10-05 15:31:47 +02:00
Raphaël Walther e15c243202 Add workflow trigger 2023-10-05 15:25:13 +02:00
Tommy Verrall c5599bf07d Merge pull request #3942 from nymtech/jon/fix-contract-schema
Update cw3-flex-multisig schema
2023-10-05 15:03:08 +02:00
Tommy Verrall 70de88d53a Merge pull request #3948 from nymtech/jon/upgrade-webpki
Upgrade webpki 0.22.0 to 0.22.2
2023-10-05 14:20:59 +02:00
Tommy Verrall ef30a6706b Merge pull request #3956 from nymtech/jon/update-chrono
Update chrono
2023-10-05 13:11:49 +02:00
Tommy Verrall c784d95088 Merge pull request #3951 from nymtech/feature/localnet
Feature/localnet
2023-10-05 13:10:30 +02:00
Jon Häggblad d57a4bc242 Merge pull request #3961 from nymtech/jon/wireguard-platform-specific
Compartmentalize the platform specific modules in the wg crate
2023-10-05 12:41:21 +02:00
Jon Häggblad 750a59461c ci: enable mac on ci-build 2023-10-05 11:09:35 +02:00
Jon Häggblad f244cff810 Comment out unused rocksdb in ephemera (#3957) 2023-10-05 11:08:15 +02:00
Jon Häggblad 63bbdfa523 Move platform specific code to platform directory 2023-10-05 09:56:01 +02:00
Jon Häggblad 1774606ec6 Merge pull request #3960 from nymtech/feature/wg-target-locking
don't build tokio-tun on non-linux targets
2023-10-04 21:26:21 +02:00
Jon Häggblad e6c0b48819 Create dummy start_wireguard for non-linux 2023-10-04 21:01:16 +02:00
Jon Häggblad cabadcb5cc rustfmt 2023-10-04 20:11:28 +02:00
Jędrzej Stuczyński 0cec9f636f don't build tokio-tun on non-linux targets 2023-10-04 16:41:12 +01:00
Jędrzej Stuczyński 56ddadc4c4 removed dead code 2023-10-04 09:03:51 +01:00
Jędrzej Stuczyński 2ab5b63086 script to startup localnet 2023-10-04 09:03:51 +01:00
Jędrzej Stuczyński ffcb7348ff fixed conflicting flags 2023-10-04 09:03:51 +01:00
Jędrzej Stuczyński 05739b4d84 added 'custom_mixnet' arg to nr 2023-10-04 09:03:50 +01:00
Jon Häggblad 3a6f1bec79 ci: enable wireguard on linux only in CI 2023-10-04 08:46:03 +02:00
Jon Häggblad 538fd7c5ee Remove old unused lock file (#3958) 2023-10-04 08:39:25 +02:00
Drazen 12c931be36 Feature gate nym-wireguard 2023-10-04 08:24:18 +02:00
Jon Häggblad ca0525d949 Fix clippy 2023-10-03 23:01:25 +02:00
Jon Häggblad 053fee7fdc Update quinn-proto (#3954) 2023-10-03 22:43:58 +02:00
Jon Häggblad 97981e536d Update chrono 2023-10-03 22:42:58 +02:00
Jon Häggblad a7595ff176 nym-connect: update Cargo.lock after the tungstenite upgrade (#3953) 2023-10-03 22:24:44 +02:00
Jon Häggblad 14fbf8e064 Upgrade webpki 0.22.0 to 0.22.2 in nym-connect 2023-10-03 22:21:52 +02:00
Jon Häggblad bb1fc9bb6a ci: try enable color (#3952)
* ci: add CARGO_TERM_COLOR=always

* ci: revert dedup check since it doesn't always work
2023-10-03 22:02:19 +02:00
Jon Häggblad 581edbf0b3 Use TUN device for forwarding wireguard traffic (#3902)
* Initial experiments with using tun device

* Remove some unused stuff and start tidying

* Match stored peer addr

* Refine comments and names

* Fix deadlock

* Annotate with some more logging

* Tweak log statements in handle_routine

* wip: temp logging

* log to info

* Refine logging

* clippy
2023-10-03 18:18:38 +02:00
Jon Häggblad 03c33b1ee5 Upgrade tungstenite to latest (#3947) 2023-10-03 17:06:32 +02:00
Jon Häggblad e13eeeb561 Update Cargo.lock 2023-10-03 14:38:41 +02:00
Jon Häggblad e51881dbdf Merge pull request #3950 from nymtech/master
Master into develop
2023-10-03 13:47:42 +02:00
benedetta davico 2a8ccace26 Merge branch 'master' into release/2023.1-milka 2023-10-03 12:38:02 +02:00
Jon Häggblad 1fd02ede95 ci: avoid duplicate builds for another two CI builds 2023-10-03 11:58:51 +02:00
Jon Häggblad c324804aa9 ci: avoid duplicate builds for two CI builds 2023-10-03 11:56:11 +02:00
serinko d5b961be5b syntax correction 2023-10-03 09:18:49 +00:00
mx 1e26d4c88e Merge pull request #3944 from nymtech/feature/documentation/events-page
DOCS: Create page for web3 privacy talk (Rome)
2023-10-03 09:09:03 +00:00
mfahampshire f91fa95888 typo fixes 2023-10-03 11:08:00 +02:00
Jon Häggblad b67d1e7a99 Upgrade webpki 0.22.0 to 0.22.2 2023-10-03 10:48:58 +02:00
Jędrzej Stuczyński 56a384ea09 [wasm-client] keeping ownership over 'ReceivedBufferRequestSender' channel when spawning 'ResponsePusher' (#3945)
* [wasm-client] keeping ownership over 'ReceivedBufferRequestSender' channel when spawning 'ResponsePusher'

* Bump version of Typescript SDK to RC.10

* GitHub Actions workflow to publish SDK to NPM

* Bump package version manually

---------

Co-authored-by: Mark Sinclair <mmsinclair@users.noreply.github.com>
2023-10-03 09:36:25 +01:00
Jon Häggblad c7da8a7594 ci: reorder nightly build matrix to group on toolchain 2023-10-03 09:09:51 +02:00
Jon Häggblad da404b636d Add sdk example for geo-aware topology provider (#3941)
* Add sdk example for geo-aware topology provider

* Re-export geo topology types
2023-10-02 14:21:53 +02:00
Jon Häggblad d8821c26bc ci: move nightly-nym-wallet to custom-linux 2023-10-02 14:07:13 +02:00
serinko cc9b444394 add aztec partnership link 2023-10-02 14:04:52 +02:00
serinko 22c1d80712 initialise web3privacy page 2023-10-02 13:58:08 +02:00
Jon Häggblad a06c2fb70c ci: fail-fast set to false 2023-10-02 12:59:04 +02:00
Jon Häggblad 908191914f ci: use continue-on-error so we get notifications 2023-10-02 08:29:22 +02:00
Jon Häggblad b05ce4c733 ci: don't fail-fast on nightly build 2023-10-02 08:17:19 +02:00
Jon Häggblad 382464a143 ci: nightly nym-wallet reorder steps to fix cwd 2023-10-01 23:35:49 +02:00
Jon Häggblad 05f3af765b ci: nightly nym-wallet install deps 2023-10-01 23:32:44 +02:00
Jon Häggblad a9d3e5047d ci: add workflow_dispatch to ci-contracts-schema 2023-10-01 23:09:56 +02:00
Jon Häggblad c424f7d3f7 ci: fix bug in trigger 2023-10-01 23:09:37 +02:00
Jon Häggblad 093bb18119 ci: move work in progress files to subdirectory 2023-10-01 23:04:58 +02:00
Jon Häggblad 4d5bd0ddf4 ci: remove old unused nightly build files 2023-10-01 23:02:09 +02:00
Jon Häggblad 48d7e934b7 ci: remove commented out code in nightly 2023-10-01 23:00:47 +02:00
Jon Häggblad ff7c359d0e ci: try using normal matrix build 2023-10-01 22:54:05 +02:00
Jon Häggblad d0b91444a0 ci: revert back to debug mode for nightly 2023-10-01 22:43:07 +02:00
Jon Häggblad 8c39cdf434 ci: nightly build in release mode 2023-10-01 21:42:17 +02:00
Jon Häggblad fef164bf93 ci: nightly-build tidy 2023-10-01 21:17:15 +02:00
Jon Häggblad 759cb4b9b4 ci: fix workflow_dispatch for nightly build 2023-10-01 19:54:31 +02:00
Jon Häggblad a800cbae02 Merge pull request #3943 from nymtech/jon/ci-work
Optimize some CI builds
2023-09-30 17:11:38 +02:00
Jon Häggblad e4a2c639fc Add names to contract job steps 2023-09-30 17:05:46 +02:00
Jon Häggblad a67a9c4b32 Try adding conditional to avoid duplicate builds 2023-09-30 16:58:19 +02:00
Jon Häggblad a450e2910f Add workflow_dispatch to nightly build 2023-09-30 16:58:19 +02:00
Jon Häggblad bd75c9c78d ci: disable sccache
sccache keeps randomly failing, try disabling to see the impact on CI
build times
2023-09-30 16:58:19 +02:00
Jon Häggblad fbfec25228 Remove nightly toolchain from contracts and nightly build
Building with the beta toolchain should be enough to alert us to
impending compiler and clippy changes.
2023-09-30 16:58:19 +02:00
Jon Häggblad 0b38e20298 Fix CI contract schema check 2023-09-30 11:47:01 +02:00
Jon Häggblad 38f78c9983 Generate multisig schema 2023-09-30 11:46:41 +02:00
Tommy Verrall 81db915401 Merge pull request #3933 from nymtech/feature/nym-api-tests
Adding missing tests and cleaning up Types files
2023-09-30 11:30:56 +02:00
Jon Häggblad b27c7d0b14 ci: fix contracts-wasm target rename 2023-09-29 23:51:20 +02:00
Jon Häggblad ed3a58b6a2 Tidy up Makefile (#3934)
* Attempt at simplifying top-level Makefile

* Another sweep at tidying up Makefile

* Further refinements

* Remove deprecated clippy-happy and no-clippy targets
2023-09-29 22:40:01 +02:00
mx 93733e73a2 Merge pull request #3911 from nymtech/feature/documentation/events-page
DOC/dev-portal: Initialize events page & prep HCPP23 pages
2023-09-28 17:03:57 +00:00
serinko d7f69433d6 finished - ready for final review 2023-09-28 17:22:07 +02:00
serinko ee282cfe9d finished - ready for final review 2023-09-28 17:15:10 +02:00
serinko 1c13d466b1 spell checks 2023-09-28 16:14:53 +02:00
serinko 238dd533a8 finish ircd configuration guide 2023-09-28 16:11:42 +02:00
serinko 2d925c24c7 edit ircd_config.toml configuration 2023-09-28 10:28:23 +02:00
serinko e6d5c5ec8c add ircd_config.toml configuration 2023-09-28 10:21:14 +02:00
serinko b4a7b9ed75 Merge branch 'feature/documentation/events-page' of github_serinko:nymtech/nym into feature/documentation/events-page 2023-09-26 23:16:10 +02:00
serinko 7bed01902e add allow.list setup 2023-09-26 23:15:47 +02:00
mfahampshire a77980a0da added event links page 2023-09-26 22:53:25 +02:00
mfahampshire d328bc15f8 add max hcpp event page to summary 2023-09-26 22:53:13 +02:00
serinko 871d88e3ed add ircd intro 2023-09-26 22:15:53 +02:00
serinko 3904afa747 change comments above commands 2023-09-26 15:25:25 +02:00
serinko 2f8442760f add wget command to download binary 2023-09-26 13:56:47 +02:00
serinko ecdd3648ae small edits 2023-09-26 12:50:12 +02:00
serinko 0218f436b2 edits in build nym section 2023-09-25 12:52:55 +02:00
serinko 3c26a4d4f6 added mac setup to matrix user guide 2023-09-25 12:43:18 +02:00
serinko bedbe34f17 added matrix NC guide 2023-09-25 12:40:50 +02:00
serinko 26c822d637 added monero wallet NC guide 2023-09-25 12:31:46 +02:00
serinko 359be442bc add monero setup giff 2023-09-25 11:52:51 +02:00
serinko 6f14c3b0fd intro edits & flow change 2023-09-25 11:31:28 +02:00
benedettadavico 6e3bb2ec18 update changelog and bump version 2023-09-24 15:25:44 +02:00
benedettadavico 8bb0e8c510 Adding missing tests and cleaning up Types files 2023-09-22 17:38:03 +02:00
Jon Häggblad 412776e336 Add missing toolchain in ci-build-upload-binaries.yml 2023-09-22 17:17:04 +02:00
Jon Häggblad 68d363af3c Rename the files for release workflows (#3932) 2023-09-22 16:51:57 +02:00
Jon Häggblad 7415cf1934 Another round of tidy gh workflows (#3931)
* Remove unused Makefile target

* Split out ci-contracts-upload-binaries

* Remove the contracts from the main workflow

* Rename build-and-upload-binaries-ci

* Rename network-explorer name

* Rename network-explorer filename and check-merge-conflicts

* Rename three more workflows

* Rename sdk-publish

* Remove deprecated clippy-all

* Rename matrix includes json and delete one that is unused

* Typo in filename

* Delete nym-wallet-release.yml
2023-09-22 16:50:43 +02:00
Jon Häggblad 8c6421f240 Reverse naming for a whole bunch of workflows (#3928) 2023-09-22 16:50:34 +02:00
Jon Häggblad c3f03a657f Update some CI workflow names (#3926)
* Rename two workflows to fit naming scheme

* ci-build name change

* Rename 3 more workflows to ci- names

* Rename wallet.yml and nym-wallet-nightly-build to reverse naming scheme

* Rename to ci-contracts.yml

* Delete nym-wallet webdriverio workflow

* Update some workflow names
2023-09-22 16:50:24 +02:00
Jon Häggblad 95646e5770 nym-wallet-nightly-build: enable notification 2023-09-22 16:50:16 +02:00
Jon Häggblad 34ec1149d7 nm-wallet-nightly-build: reenable steps 2023-09-22 16:50:03 +02:00
Jon Häggblad 13f095a587 Fix nym-wallet-nightly-build toolchain 2023-09-22 16:49:50 +02:00
Jon Häggblad 696a27ec76 Initial work on splitting out nym-wallet nightliy build (#3924) 2023-09-22 16:49:35 +02:00
fmtabbara c0b8ddd48e fix linting 2023-09-22 14:41:03 +01:00
fmtabbara f35396481f take user password when editing account name 2023-09-22 12:21:19 +01:00
fmtabbara be8b9e5a83 pass button title and modal title as prop 2023-09-22 12:21:19 +01:00
Jon Häggblad 7429487f30 fix clippy 2023-09-22 12:21:19 +01:00
Jon Häggblad 23d11ce523 rustfmt 2023-09-22 12:21:19 +01:00
Jon Häggblad 4f4cb83456 Add tauri functions 2023-09-22 12:21:19 +01:00
Jon Häggblad 9fe1ee6436 Check against renaming to existing name 2023-09-22 12:21:19 +01:00
Jon Häggblad 9ae5ee38f6 Add rename account to backend structs 2023-09-22 12:21:19 +01:00
Jon Häggblad 0f8d1f6439 Add unit test for adding duplicate account id 2023-09-22 12:21:19 +01:00
fmtabbara b92527437a introduce edit account name 2023-09-22 12:21:17 +01:00
serinko 5eb935a079 guide to electrum setup 2023-09-20 17:18:44 +02:00
serinko c7be467685 DOC: dev-portal: initializ events page 2023-09-20 14:46:25 +02:00
serinko d936c66e1f added integrations-faq page 2023-09-18 16:17:10 +02:00
serinko e63de3f52b corrected faq dir path 2023-09-18 16:01:03 +02:00
serinko bded08dce9 Merge pull request #3892 from nymtech/feature/operators/smoosh-faq
Create smoosh FAQ section & re-organize operators/faq accordingly
2023-09-18 15:51:22 +02:00
Tommy Verrall 9fcffb1d94 Merge branch 'release/v1.1.31-kitkat' 2023-09-14 14:52:11 +02:00
Jędrzej Stuczyński ed24afa207 fixed ChangeMixCostParams event deserialization (#3873) 2023-09-12 09:12:22 +01:00
Tommy Verrall d966eab085 Merge pull request #3837 from nymtech/release/v1.1.30-twix
Release/v1.1.30 twix
2023-09-07 10:59:39 +02:00
Mark Sinclair e67c6613c0 Docs: add prod deploy settings 2023-09-06 18:07:22 +01:00
Tommy Verrall 2111251d35 Merge pull request #3858 from nymtech/patch/docs-postprocess
Docs: new post-processing for books so that assets stay relative
2023-09-06 18:57:05 +02:00
Mark Sinclair c60b52e9c4 Docs: new post-processing for books so that assets stay relative
This commit has the same content as https://github.com/nymtech/nym/pull/3842
2023-09-06 17:01:25 +01:00
benedettadavico 8b14e2b1b6 updating changelog and bumping versions 2023-09-05 09:46:11 +02:00
mx a59295f036 Merge pull request #3828 from nymtech/documentation/patch-variables
Documentation/patch-variables
2023-09-04 14:12:26 +00:00
mfahampshire d988fe02b5 changed comment 2023-09-04 13:42:14 +02:00
mfahampshire 9bdc3b260f changed version bumper script: removed platform_release_version references 2023-09-04 13:39:48 +02:00
mfahampshire 2381e52d3b removed all instances of platform_release_version var 2023-09-04 13:28:19 +02:00
mfahampshire aa2e0b662e removed all instances of platform_release_version var 2023-09-04 13:27:48 +02:00
serinko 6c7c9e46f4 PR finished - ready for review and merge 2023-09-04 12:17:28 +02:00
serinko ee27dfe06c dev-portal: matrix.md - added banner 2023-09-04 12:16:09 +02:00
serinko 600b89b5c7 dev-portal: telegram.md - added banner & minor fix 2023-09-04 12:11:24 +02:00
serinko 092268def9 dev-portal: moredo.md up to date w NC default 2023-09-04 12:04:03 +02:00
Tommy Verrall 80f7175abe Merge pull request #3833 from nymtech/feature/gh-actions-hash-release
GitHub Action to hash releases
2023-09-04 09:27:07 +02:00
serinko a90378f987 dev-portal: faq.md - variable changed 2023-09-01 17:09:27 +02:00
serinko a6278e9ae7 dev-portal: mixnet-integration.md - variable changed 2023-09-01 17:08:01 +02:00
serinko 825c30a547 operators: all variables finished 2023-09-01 17:01:37 +02:00
serinko fd54f8a32f docs: all variables changed 2023-09-01 16:42:19 +02:00
serinko 9488b8ba6a docs: mixnet-contract.md - changing variables 2023-09-01 16:36:41 +02:00
serinko c1f167bbd4 docs: vesting-contract.md - changing variables 2023-09-01 16:34:50 +02:00
serinko dbeeeb9796 docs: rust.md - changing variables 2023-09-01 16:31:59 +02:00
serinko 81fbcdfdb2 docs: typescript.md - changing variables 2023-09-01 16:27:39 +02:00
serinko 13313d705f make binaries executable 2023-09-01 16:13:00 +02:00
serinko e7c9c2b319 corrected path of config 2023-09-01 12:27:54 +02:00
serinko 236a441036 changed last vers. checkout to master 2023-09-01 12:27:27 +02:00
Tommy Verrall d8bef263b5 Merge pull request #3822 from nymtech/release/v1.1.29-snickers
Release/v1.1.29 snickers
2023-08-29 16:32:15 +02:00
benedettadavico e04c759c14 changelog update and version bump 2023-08-23 17:12:46 +02:00
Jędrzej Stuczyński 9d22387b18 [hotfix]: don't assign invalid fields when crossing the JS boundary (#3805)
* [hotfix]: don't assign invalid fields when crossing the JS boundary

* eslint
2023-08-23 16:11:27 +01:00
Tommy Verrall 6254656ab6 Merge pull request #3797 from nymtech/release/v1.1.28
Release/v1.1.28
2023-08-22 13:56:36 +02:00
Tommy Verrall afda62a5cf Merge branch 'master' into release/v1.1.28 2023-08-22 11:26:27 +02:00
Mark Sinclair a322becfec Update cd-docs.yml 2023-08-18 15:43:02 +01:00
Mark Sinclair 9b4e25221f Update cd-docs.yml 2023-08-18 14:52:41 +01:00
Tommy Verrall f46cc9d1bb Merge pull request #3782 from nymtech/release/v1.1.27
Release/v1.1.27
2023-08-17 11:49:06 +02:00
Tommy Verrall bf53a107af Merge pull request #3778 from nymtech/release/v1.1.27
Release/v1.1.27
2023-08-16 15:58:59 +02:00
Tommy Verrall 25ebdbb6eb Merge branch 'develop' 2023-08-08 18:26:42 +01:00
Lorexia 47d045b1c7 Add updates to community list projects 2023-08-01 10:35:01 +02:00
mfahampshire 0b0bb8175f removed old wallet address flag again 2023-08-01 10:33:34 +02:00
181 changed files with 4187 additions and 7043 deletions
@@ -20,6 +20,8 @@ jobs:
platform: [ubuntu-20.04]
runs-on: ${{ matrix.platform }}
env:
CARGO_TERM_COLOR: always
steps:
- uses: actions/checkout@v3
@@ -42,6 +42,10 @@ jobs:
platform: [ubuntu-20.04]
runs-on: ${{ matrix.platform }}
env:
CARGO_TERM_COLOR: always
# a push event from the origin repo, or a PR from external repo
if: ${{ github.event_name == 'push' || github.event.pull_request.head.repo.full_name != 'nymtech/nym' }}
steps:
- uses: actions/checkout@v3
+22 -10
View File
@@ -37,17 +37,25 @@ on:
- 'tools/nym-nr-query/**'
- 'tools/ts-rs-cli/**'
- 'Cargo.toml'
workflow_dispatch:
jobs:
build:
runs-on: [ self-hosted, custom-linux ]
# Enable sccache via environment variable
strategy:
fail-fast: false
matrix:
os: [custom-linux, custom-runner-mac-m1]
runs-on: ${{ matrix.os }}
env:
RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
CARGO_TERM_COLOR: always
# 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 -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools protobuf-compiler
continue-on-error: true
if: matrix.os == 'custom-linux'
- name: Check out repository code
uses: actions/checkout@v2
@@ -70,36 +78,40 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace
# Enable wireguard by default on linux only
args: --workspace --features wireguard
- name: Build all examples
if: matrix.os == 'custom-linux'
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace --examples
args: --workspace --examples --features wireguard
- name: Run all tests
if: matrix.os == 'custom-linux'
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace
args: --workspace --features wireguard
- name: Run expensive tests
if: github.ref == 'refs/heads/develop' || github.event.pull_request.base.ref == 'develop' || github.event.pull_request.base.ref == 'master'
if: (github.ref == 'refs/heads/develop' || github.event.pull_request.base.ref == 'develop' || github.event.pull_request.base.ref == 'master') && matrix.os == 'custom-linux'
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace -- --ignored
args: --workspace --features wireguard -- --ignored
- name: Annotate with clippy checks
if: matrix.os == 'custom-linux'
uses: actions-rs/clippy-check@v1
continue-on-error: true
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --workspace
args: --workspace --features wireguard
- name: Clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --workspace --all-targets -- -D warnings
args: --workspace --all-targets --features wireguard -- -D warnings
@@ -6,9 +6,5 @@
{
"rust":"beta",
"runOnEvent":"pull_request"
},
{
"rust":"nightly",
"runOnEvent":"pull_request"
}
]
]
+4 -2
View File
@@ -1,6 +1,7 @@
name: ci-contracts-schema
on:
workflow_dispatch:
push:
paths:
- 'contracts/**'
@@ -14,6 +15,8 @@ jobs:
check-schema:
name: Generate and check schema
runs-on: custom-runner-linux
env:
CARGO_TERM_COLOR: always
steps:
- name: Check out repository code
uses: actions/checkout@v2
@@ -23,9 +26,8 @@ jobs:
with:
toolchain: stable
- name: Generate the schema
run: make contract-schema
- name: Check for diff
run: git diff --exit-code -- contracts/*/schema
run: git diff --exit-code -- contracts/**/schema
@@ -22,6 +22,10 @@ jobs:
platform: [ubuntu-20.04]
runs-on: ${{ matrix.platform }}
env:
CARGO_TERM_COLOR: always
# a push event from the origin repo, or a PR from external repo
if: ${{ github.event_name == 'push' || github.event.pull_request.head.repo.full_name != 'nymtech/nym' }}
steps:
- uses: actions/checkout@v3
@@ -49,7 +53,7 @@ jobs:
run: cargo install --version 0.112.0 wasm-opt
- name: Build release contracts
run: make contracts-wasm
run: make contracts
- name: Prepare build output
shell: bash
+13 -8
View File
@@ -6,7 +6,7 @@ on:
- 'contracts/**'
- 'common/**'
pull_request:
paths-ignore:
paths:
- 'contracts/**'
- 'common/**'
@@ -27,7 +27,8 @@ jobs:
# since it's going to be compiled into wasm, there's absolutely
# no point in running CI on different OS-es
runs-on: ubuntu-20.04
continue-on-error: ${{ matrix.rust == 'nightly' }}
env:
CARGO_TERM_COLOR: always
needs: matrix_prep
strategy:
fail-fast: false
@@ -35,7 +36,8 @@ jobs:
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
- name: Setup rust
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
@@ -43,25 +45,28 @@ jobs:
override: true
components: rustfmt, clippy
- uses: actions-rs/cargo@v1
- name: Build contracts
uses: actions-rs/cargo@v1
env:
RUSTFLAGS: '-C link-arg=-s'
with:
command: build
args: --manifest-path contracts/Cargo.toml --workspace --lib --target wasm32-unknown-unknown
- uses: actions-rs/cargo@v1
- name: Run unit tests
uses: actions-rs/cargo@v1
with:
command: test
args: --lib --manifest-path contracts/Cargo.toml
- uses: actions-rs/cargo@v1
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --manifest-path contracts/Cargo.toml --all -- --check
- uses: actions-rs/cargo@v1
if: ${{ matrix.rust != 'nightly' }}
- name: Run clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --lib --manifest-path contracts/Cargo.toml --workspace --all-targets -- -D warnings
@@ -26,7 +26,9 @@ jobs:
build:
runs-on: [self-hosted, custom-linux]
env:
RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
CARGO_TERM_COLOR: always
# env:
# RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
steps:
- name: Install Dependencies (Linux)
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 libayatana-appindicator3-dev
+4 -2
View File
@@ -18,7 +18,9 @@ jobs:
build:
runs-on: [ self-hosted, custom-linux ]
env:
RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
CARGO_TERM_COLOR: always
# env:
# RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
steps:
- name: Install Dependencies (Linux)
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
@@ -31,7 +33,7 @@ jobs:
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: 1.71.0
toolchain: stable
override: true
components: rustfmt, clippy
+4 -2
View File
@@ -10,13 +10,15 @@ on:
jobs:
wasm:
runs-on: [custom-runner-linux]
env:
CARGO_TERM_COLOR: always
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v3
with:
node-version: 18
- uses: actions-rs/toolchain@v1
with:
profile: minimal
@@ -35,7 +37,7 @@ jobs:
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Install wasm-opt
run: cargo install wasm-opt
run: cargo install wasm-opt
- name: Install wasm-bindgen-cli
run: cargo install wasm-bindgen-cli
@@ -1,37 +1,30 @@
name: Nightly builds
name: nightly-build
on:
workflow_dispatch:
schedule:
- cron: '14 1 * * *'
jobs:
matrix_prep:
runs-on: ubuntu-20.04
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
# creates the matrix strategy from nightly_build_matrix_includes.json
- uses: actions/checkout@v3
- 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)}}
fail-fast: false
matrix:
rust: [stable, beta]
os: [custom-linux, windows10, custom-runner-mac-m1]
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.rust == 'nightly' || matrix.rust == 'beta' || matrix.rust == 'stable' }}
env:
CARGO_TERM_COLOR: always
continue-on-error: true
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 libudev-dev squashfs-tools protobuf-compiler
run: sudo apt-get update && sudo apt-get install -y build-essential curl wget libssl-dev libudev-dev squashfs-tools protobuf-compiler
continue-on-error: true
if: matrix.os == 'custom-linux'
- name: Check out repository code
uses: actions/checkout@v3
- name: Install rust toolchain
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
@@ -45,75 +38,36 @@ jobs:
command: fmt
args: --all -- --check
- name: Build all binaries
- name: Build binaries
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace
- name: Reclaim some disk space
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'custom-linux' }}
with:
command: clean
- name: Build all examples
- name: Build examples
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace --examples
- name: Reclaim some disk space
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'custom-linux' }}
with:
command: clean
- name: Run all tests
- name: Run unit tests
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace
- name: Reclaim some disk space
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'custom-linux' }}
with:
command: clean
- name: Run expensive tests
if: github.ref == 'refs/heads/develop' || github.event.pull_request.base.ref == 'develop' || github.event.pull_request.base.ref == 'master'
- name: Run slow unit tests
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace -- --ignored
- name: Reclaim some disk space
- name: Clippy
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'custom-linux' }}
with:
command: clean
- uses: actions-rs/clippy-check@v1
name: Clippy checks
continue-on-error: true
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --workspace
- name: Run clippy
uses: actions-rs/cargo@v1
if: ${{ matrix.rust != 'nightly' }}
with:
command: clippy
args: --workspace --all-targets -- -D warnings
- name: Reclaim some disk space
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'custom-linux' }}
with:
command: clean
notification:
needs: build
runs-on: custom-runner-linux
+10 -9
View File
@@ -12,25 +12,26 @@ defaults:
jobs:
build:
strategy:
matrix:
os: [ubuntu-20.04, macos-latest, windows10]
fail-fast: false
matrix:
os: [custom-ubuntu-20.04, macos-latest, windows10]
runs-on: ${{ matrix.os }}
env:
CARGO_TERM_COLOR: always
continue-on-error: true
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 libudev-dev squashfs-tools protobuf-compiler
continue-on-error: true
if: matrix.os == 'ubuntu-20.04'
- name: Check out repository code
uses: actions/checkout@v3
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get install -y libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools protobuf-compiler
if: matrix.os == 'custom-linux'
- name: Install rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
# There is an issue with 1.72.0 where clippy crashes on nym-wallet-types. Pin to 1.71.0 for now
toolchain: 1.71.0
toolchain: stable
override: true
components: rustfmt, clippy
@@ -1,50 +0,0 @@
[
{
"os":"custom-linux",
"rust":"stable",
"runOnEvent":"schedule"
},
{
"os":"windows10",
"rust":"stable",
"runOnEvent":"schedule"
},
{
"os":"custom-runner-mac-m1",
"rust":"stable",
"runOnEvent":"schedule"
},
{
"os":"custom-linux",
"rust":"beta",
"runOnEvent":"schedule"
},
{
"os":"windows10",
"rust":"beta",
"runOnEvent":"schedule"
},
{
"os":"custom-runner-mac-m1",
"rust":"beta",
"runOnEvent":"schedule"
},
{
"os":"custom-linux",
"rust":"nightly",
"runOnEvent":"schedule"
},
{
"os":"windows10",
"rust":"nightly",
"runOnEvent":"schedule"
},
{
"os":"custom-runner-mac-m1",
"rust":"nightly",
"runOnEvent":"schedule"
}
]
@@ -1,50 +0,0 @@
[
{
"os":"ubuntu-20.04",
"rust":"stable",
"runOnEvent":"workflow_dispatch"
},
{
"os":"windows10",
"rust":"stable",
"runOnEvent":"workflow_dispatch"
},
{
"os":"custom-runner-mac-m1",
"rust":"stable",
"runOnEvent":"workflow_dispatch"
},
{
"os":"ubuntu-20.04",
"rust":"beta",
"runOnEvent":"workflow_dispatch"
},
{
"os":"windows10",
"rust":"beta",
"runOnEvent":"workflow_dispatch"
},
{
"os":"custom-runner-mac-m1",
"rust":"beta",
"runOnEvent":"workflow_dispatch"
},
{
"os":"ubuntu-20.04",
"rust":"nightly",
"runOnEvent":"workflow_dispatch"
},
{
"os":"windows10",
"rust":"nightly",
"runOnEvent":"workflow_dispatch"
},
{
"os":"custom-runner-mac-m1",
"rust":"nightly",
"runOnEvent":"workflow_dispatch"
}
]
@@ -1,174 +0,0 @@
name: Nightly builds on dispatch
on: workflow_dispatch
jobs:
matrix_prep:
runs-on: ubuntu-20.04
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
# creates the matrix strategy from nightly_build_matrix_includes.json
- uses: actions/checkout@v3
- id: set-matrix
uses: JoshuaTheMiller/conditional-build-matrix@main
with:
inputFile: '.github/workflows/nightly_build_matrix_on_dispatch.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 libudev-dev squashfs-tools protobuf-compiler
continue-on-error: true
if: matrix.os == 'ubuntu-20.04'
- name: Check out repository code
uses: actions/checkout@v3
- name: Install rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
override: true
components: rustfmt, clippy
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
- name: Build all binaries
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace
- name: Reclaim some disk space
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
with:
command: clean
- name: Build all examples
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace --examples
- name: Reclaim some disk space
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
with:
command: clean
- name: Run all tests
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace
- name: Reclaim some disk space
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
with:
command: clean
- name: Run expensive tests
if: github.ref == 'refs/heads/develop' || github.event.pull_request.base.ref == 'develop' || github.event.pull_request.base.ref == 'master'
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace -- --ignored
- name: Reclaim some disk space
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
with:
command: clean
- uses: actions-rs/clippy-check@v1
name: Clippy checks
continue-on-error: true
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --workspace
- name: Run clippy
uses: actions-rs/cargo@v1
if: ${{ matrix.rust != 'nightly' }}
with:
command: clippy
args: --workspace --all-targets -- -D warnings
- name: Reclaim some disk space
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
with:
command: clean
# nym-wallet (the rust part)
- name: Build nym-wallet rust code
uses: actions-rs/cargo@v1
with:
command: build
args: --manifest-path nym-wallet/Cargo.toml --workspace
- name: Run nym-wallet tests
uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path nym-wallet/Cargo.toml --workspace
- name: Check nym-wallet formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --manifest-path nym-wallet/Cargo.toml --all -- --check
- name: Run clippy for nym-wallet
uses: actions-rs/cargo@v1
if: ${{ matrix.rust != 'nightly' }}
with:
command: clippy
args: --manifest-path nym-wallet/Cargo.toml --workspace --all-targets -- -D warnings
notification:
needs: build
runs-on: custom-runner-linux
steps:
- name: Collect jobs status
uses: technote-space/workflow-conclusion-action@v2
- name: Check out repository code
uses: actions/checkout@v3
- name: install npm
uses: actions/setup-node@v3
if: env.WORKFLOW_CONCLUSION == 'failure'
with:
node-version: 18
- name: Matrix - Node Install
if: env.WORKFLOW_CONCLUSION == 'failure'
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - 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##*/}"
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_NIGHTLY }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
strategy:
fail-fast: false
matrix:
platform: [custom-runner-linux]
platform: [custom-ubuntu-20.04]
runs-on: ${{ matrix.platform }}
outputs:
@@ -14,7 +14,7 @@ jobs:
strategy:
fail-fast: false
matrix:
platform: [custom-runner-linux]
platform: [custom-ubuntu-20.04]
runs-on: ${{ matrix.platform }}
outputs:
+3 -3
View File
@@ -7,10 +7,10 @@ on:
jobs:
build:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-contracts-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
runs-on: [self-hosted, custom-runner-linux]
runs-on: [self-hosted, custom-ubuntu-20.04]
steps:
- uses: actions/checkout@v2
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
@@ -23,7 +23,7 @@ jobs:
run: cargo install --version 0.112.0 wasm-opt
- name: Build release contracts
run: make contracts-wasm
run: make contracts
- name: Upload Mixnet Contract Artifact
uses: actions/upload-artifact@v3
@@ -14,7 +14,7 @@ jobs:
strategy:
fail-fast: false
matrix:
platform: [custom-runner-linux]
platform: [custom-ubuntu-20.04]
runs-on: ${{ matrix.platform }}
outputs:
@@ -12,7 +12,7 @@ on:
jobs:
build:
name: Build APK
runs-on: custom-runner-linux
runs-on: custom-ubuntu-20.04
env:
ANDROID_HOME: ${{ github.workspace }}/android-sdk
NDK_VERSION: 25.2.9519653
+7 -5
View File
@@ -1,10 +1,10 @@
name: publish-sdk-npm
name: Publish Typescript SDK
on:
workflow_dispatch:
jobs:
publish:
runs-on: [custom-runner-linux]
runs-on: [custom-ubuntu-20.04]
steps:
- uses: actions/checkout@v2
@@ -28,8 +28,10 @@ jobs:
- name: Install dependencies
run: yarn
- name: Build and publish
- name: Build WASM and Typescript SDK
run: yarn sdk:build
- name: Publish to NPM
env:
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
working-directory: ./sdk/typescript/packages/sdk
run: scripts/publish.sh
run: ./sdk/typescript/scripts/publish.sh
+25
View File
@@ -3,6 +3,31 @@
Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
- add client registry to Gateway ([#3955])
- add HTTP API to Gateway ([#3955])
- add `/client/<pub-key>`, `clients` and `register` routes to the gateway ([#3955])
## [2023.1-milka] (2023-09-24)
- custom Debug impl for mix::Node and gateway::Node ([#3930])
- added forceTls argument to 'MixFetchOptsSimple' ([#3907])
- Enable loop cover traffic by default in NR ([#3904])
- Fix all the cargo warnings ([#3899])
- [Issue] nym-socks5-client crash on UDP request ([#3898])
- Feature/gateway inbuilt nr ([#3877])
- removed queued mixnet migration that was already run ([#3872])
- [feat] Socks5 and Native client: run with hardcoded topology ([#3866])
- Introduce a local network requester directly inside a gateway ([#3838])
[#3930]: https://github.com/nymtech/nym/pull/3930
[#3907]: https://github.com/nymtech/nym/pull/3907
[#3904]: https://github.com/nymtech/nym/pull/3904
[#3899]: https://github.com/nymtech/nym/pull/3899
[#3898]: https://github.com/nymtech/nym/issues/3898
[#3877]: https://github.com/nymtech/nym/pull/3877
[#3872]: https://github.com/nymtech/nym/pull/3872
[#3866]: https://github.com/nymtech/nym/pull/3866
[#3838]: https://github.com/nymtech/nym/issues/3838
## [v1.1.31-kitkat] (2023-09-12)
Generated
+824 -955
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -164,6 +164,8 @@ tap = "1.0.1"
tendermint-rpc = "0.32" # same version as used by cosmrs
thiserror = "1.0.38"
tokio = "1.24.1"
tokio-tungstenite = "0.20.1"
tungstenite = { version = "0.20.1", default-features = false }
ts-rs = "7.0.0"
url = "2.4"
zeroize = "1.6.0"
+109 -130
View File
@@ -1,72 +1,85 @@
# Default target
# Top-level Makefile for the nym monorepo
# Default target. Probably what you want to run in normal day-to-day usage when
# you want to check all backend code in one step.
all: test
test: clippy cargo-test contracts-wasm sdk-wasm-test fmt
help:
@echo "The main targets are"
@echo " all: the default target. Alias for test"
@echo " build: build all binaries"
@echo " build-release: build platform binaries and contracts in release mode"
@echo " clippy: run clippy for all workspaces"
@echo " test: run clippy, unit tests, and formatting."
@echo " test-all: like test, but also includes the expensive tests"
# -----------------------------------------------------------------------------
# Meta targets
# -----------------------------------------------------------------------------
# Run clippy for all workspaces, run all tests, format all Rust code
test: clippy cargo-test fmt
# Same as test, but also runs slow tests
test-all: test cargo-test-expensive
no-clippy: build cargo-test contracts-wasm fmt fmt-browser-extension-storage
# Build release binaries for the main workspace (platform binaries) and the
# contracts, including running wasm-opt.
# Producing release versions of other components is deferred to their
# respective toolchains.
build-release: build-release-main contracts
happy: fmt clippy-happy test
# Not a meta target, more of a top-level target for building all binaries (in
# debug mode). Listed here for visibility. The deps are appended successively
build:
build: sdk-wasm-build build-browser-extension-storage
# Building release binaries is a little manual as we can't just build --release
# on all workspaces.
build-release: build-release-main contracts-wasm
clippy: sdk-wasm-lint clippy-browser-extension-storage
# Not a meta target, more of a top-level target for clippy. Listed here for
# visibility. The deps are appended successively.
clippy:
# -----------------------------------------------------------------------------
# Define targets for a given workspace
# $(1): name
# $(2): path to workspace
# $(3): extra arguments to cargo
# $(4): RUSTFLAGS prefix env
# -----------------------------------------------------------------------------
define add_cargo_workspace
clippy-happy-$(1):
cargo clippy --manifest-path $(2)/Cargo.toml $(3)
clippy-$(1):
cargo clippy --manifest-path $(2)/Cargo.toml --workspace $(3) -- -D warnings
clippy-examples-$(1):
cargo clippy --manifest-path $(2)/Cargo.toml --workspace --examples -- -D warnings
check-$(1):
cargo check --manifest-path $(2)/Cargo.toml --workspace $(3)
build-$(1):
cargo build --manifest-path $(2)/Cargo.toml --workspace $(3)
build-extra-$(1):
cargo build --manifest-path $(2)/Cargo.toml --workspace --examples --tests
build-release-$(1):
$(4) cargo $$($(1)_BUILD_RELEASE_TOOLCHAIN) build --manifest-path $(2)/Cargo.toml --workspace --release $(3)
test-$(1):
cargo test --manifest-path $(2)/Cargo.toml --workspace
test-expensive-$(1):
cargo test --manifest-path $(2)/Cargo.toml --workspace -- --ignored
build-standalone-$(1):
cargo build --manifest-path $(2)/Cargo.toml $(3)
clippy-$(1):
cargo $$($(1)_CLIPPY_TOOLCHAIN) clippy --manifest-path $(2)/Cargo.toml --workspace $(3) -- -D warnings
build-$(1):
cargo build --manifest-path $(2)/Cargo.toml --workspace $(3)
build-examples-$(1):
cargo build --manifest-path $(2)/Cargo.toml --workspace --examples
build-release-$(1):
cargo build --manifest-path $(2)/Cargo.toml --workspace --release $(3)
clippy-extra-$(1):
cargo $$($(1)_CLIPPY_TOOLCHAIN) clippy --manifest-path $(2)/Cargo.toml --workspace --examples --tests -- -D warnings
fmt-$(1):
cargo fmt --manifest-path $(2)/Cargo.toml --all
clippy-happy: clippy-happy-$(1)
clippy: clippy-$(1) clippy-examples-$(1)
check: check-$(1)
build: build-$(1) build-extra-$(1)
build-release-all: build-release-$(1)
cargo-test: test-$(1)
cargo-test-expensive: test-expensive-$(1)
build: build-$(1) build-examples-$(1)
build-release-all: build-release-$(1)
clippy: clippy-$(1) clippy-extra-$(1)
fmt: fmt-$(1)
endef
# -----------------------------------------------------------------------------
@@ -76,11 +89,68 @@ endef
# Generate targets for the various cargo workspaces
$(eval $(call add_cargo_workspace,main,.))
$(eval $(call add_cargo_workspace,contracts,contracts,--lib --target wasm32-unknown-unknown))
#$(eval $(call add_cargo_workspace,wasm-client,clients/webassembly,--target wasm32-unknown-unknown))
$(eval $(call add_cargo_workspace,wallet,nym-wallet,))
$(eval $(call add_cargo_workspace,contracts,contracts,--lib --target wasm32-unknown-unknown,RUSTFLAGS='-C link-arg=-s'))
$(eval $(call add_cargo_workspace,wallet,nym-wallet))
$(eval $(call add_cargo_workspace,connect,nym-connect/desktop))
# OVERRIDE: wasm-opt fails if the binary has been built with the latest rustc.
# Pin to the last working version.
contracts_BUILD_RELEASE_TOOLCHAIN := +1.69.0
# -----------------------------------------------------------------------------
# SDK
# -----------------------------------------------------------------------------
sdk-wasm: sdk-wasm-build sdk-wasm-test sdk-wasm-lint
sdk-wasm-build:
$(MAKE) -C nym-browser-extension/storage wasm-pack
$(MAKE) -C wasm/client
$(MAKE) -C wasm/node-tester
$(MAKE) -C wasm/mix-fetch
$(MAKE) -C wasm/full-nym-wasm
# run this from npm/yarn to ensure tools are in the path, e.g. yarn build:sdk from root of repo
sdk-typescript-build:
npx lerna run --scope @nymproject/sdk build --stream
npx lerna run --scope @nymproject/mix-fetch build --stream
npx lerna run --scope @nymproject/node-tester build --stream
yarn --cwd sdk/typescript/codegen/contract-clients build
# NOTE: These targets are part of the main workspace (but not as wasm32-unknown-unknown)
WASM_CRATES = extension-storage nym-client-wasm nym-node-tester-wasm nym-wasm-sdk
sdk-wasm-test:
#cargo test $(addprefix -p , $(WASM_CRATES)) --target wasm32-unknown-unknown -- -Dwarnings
sdk-wasm-lint:
cargo clippy $(addprefix -p , $(WASM_CRATES)) --target wasm32-unknown-unknown -- -Dwarnings
$(MAKE) -C wasm/mix-fetch check-fmt
# Add to top-level targets
build: sdk-wasm-build
cargo-test: sdk-wasm-test
clippy: sdk-wasm-lint
# -----------------------------------------------------------------------------
# Build contracts ready for deploy
# -----------------------------------------------------------------------------
CONTRACTS=vesting_contract mixnet_contract nym_service_provider_directory nym_name_service
CONTRACTS_WASM=$(addsuffix .wasm, $(CONTRACTS))
CONTRACTS_OUT_DIR=contracts/target/wasm32-unknown-unknown/release
contracts: build-release-contracts wasm-opt-contracts
wasm-opt-contracts:
for contract in $(CONTRACTS_WASM); do \
wasm-opt --disable-sign-ext -Os $(CONTRACTS_OUT_DIR)/$$contract -o $(CONTRACTS_OUT_DIR)/$$contract; \
done
# Consider adding 's' to make plural consistent (beware: used in github workflow)
contract-schema:
$(MAKE) -C contracts schema
# -----------------------------------------------------------------------------
# Convenience targets for crates that are already part of the main workspace
# -----------------------------------------------------------------------------
@@ -91,98 +161,6 @@ build-explorer-api:
build-nym-cli:
cargo build -p nym-cli --release
build-browser-extension-storage:
cargo build -p extension-storage --target wasm32-unknown-unknown
fmt-browser-extension-storage:
cargo fmt -p extension-storage -- --check
clippy-browser-extension-storage:
cargo clippy -p extension-storage --target wasm32-unknown-unknown -- -Dwarnings
sdk-wasm: sdk-wasm-build sdk-wasm-test sdk-wasm-lint
sdk-wasm-build:
# browser storage
$(MAKE) -C nym-browser-extension/storage wasm-pack
# client
$(MAKE) -C wasm/client build
# client (node)
$(MAKE) -C wasm/client build-node
# node-tester
$(MAKE) -C wasm/node-tester build
# mix-fetch
$(MAKE) -C wasm/mix-fetch build
# mix-fetch (node)
$(MAKE) -C wasm/mix-fetch build-node
# full
$(MAKE) -C wasm/full-nym-wasm build-full
# run this from npm/yarn to ensure tools are in the path, e.g. yarn build:sdk from root of repo
sdk-typescript-build:
npx lerna run --scope @nymproject/sdk build --stream
npx lerna run --scope @nymproject/mix-fetch build --stream
npx lerna run --scope @nymproject/node-tester build --stream
yarn --cwd sdk/typescript/codegen/contract-clients build
sdk-wasm-test:
# # client
# cargo test -p nym-client-wasm --target wasm32-unknown-unknown
#
# # node-tester
# cargo test -p nym-node-tester-wasm --target wasm32-unknown-unknown
#
# # mix-fetch
# #cargo test -p nym-wasm-sdk --target wasm32-unknown-unknown
#
# # full
# cargo test -p nym-wasm-sdk --target wasm32-unknown-unknown
sdk-wasm-lint:
# client
cargo clippy -p nym-client-wasm --target wasm32-unknown-unknown -- -Dwarnings
# node-tester
cargo clippy -p nym-node-tester-wasm --target wasm32-unknown-unknown -- -Dwarnings
# mix-fetch
$(MAKE) -C wasm/mix-fetch check-fmt
# full
cargo clippy -p nym-wasm-sdk --target wasm32-unknown-unknown -- -Dwarnings
# -----------------------------------------------------------------------------
# Build contracts ready for deploy
# -----------------------------------------------------------------------------
CONTRACTS_OUT_DIR=contracts/target/wasm32-unknown-unknown/release
VESTING_CONTRACT=$(CONTRACTS_OUT_DIR)/vesting_contract.wasm
MIXNET_CONTRACT=$(CONTRACTS_OUT_DIR)/mixnet_contract.wasm
SERVICE_PROVIDER_DIRECTORY_CONTRACT=$(CONTRACTS_OUT_DIR)/nym_service_provider_directory.wasm
NAME_SERVICE_CONTRACT=$(CONTRACTS_OUT_DIR)/nym_name_service.wasm
contracts-wasm: contracts-wasm-build contracts-wasm-opt
contracts-wasm-build:
RUSTFLAGS='-C link-arg=-s' cargo build --lib --manifest-path contracts/Cargo.toml --release --target wasm32-unknown-unknown
contracts-wasm-opt:
wasm-opt --disable-sign-ext -Os $(VESTING_CONTRACT) -o $(VESTING_CONTRACT)
wasm-opt --disable-sign-ext -Os $(MIXNET_CONTRACT) -o $(MIXNET_CONTRACT)
wasm-opt --disable-sign-ext -Os $(SERVICE_PROVIDER_DIRECTORY_CONTRACT) -o $(SERVICE_PROVIDER_DIRECTORY_CONTRACT)
wasm-opt --disable-sign-ext -Os $(NAME_SERVICE_CONTRACT) -o $(NAME_SERVICE_CONTRACT)
contract-schema:
$(MAKE) -C contracts schema
# -----------------------------------------------------------------------------
# Misc
# -----------------------------------------------------------------------------
@@ -193,3 +171,4 @@ generate-typescript:
run-api-tests:
cd nym-api/tests/functional_test && yarn test:qa
+3 -3
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.29"
version = "1.1.30"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client"
edition = "2021"
@@ -30,8 +30,8 @@ serde = { workspace = true, features = ["derive"] } # for config serialization/d
serde_json = { workspace = true }
thiserror = { workspace = true }
tap = "1.0.1"
tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal"] } # async runtime
tokio-tungstenite = "0.14" # websocket
tokio = { workspace = true, features = ["rt-multi-thread", "net", "signal"] } # async runtime
tokio-tungstenite = { workspace = true }
## internal
nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "1.1.29"
version = "1.1.30"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
edition = "2021"
+6 -1
View File
@@ -64,7 +64,12 @@ pub(crate) struct Init {
nyxd_urls: Option<Vec<url::Url>>,
/// Comma separated list of rest endpoints of the API validators
#[clap(long, alias = "api_validators", value_delimiter = ',')]
#[clap(
long,
alias = "api_validators",
value_delimiter = ',',
group = "network"
)]
// the alias here is included for backwards compatibility (1.1.4 and before)
nym_apis: Option<Vec<url::Url>>,
+2 -2
View File
@@ -24,7 +24,7 @@ sha2 = "0.10.6"
tap = "1.0.1"
thiserror = { workspace = true }
url = { workspace = true, features = ["serde"] }
tungstenite = { version = "0.13.0", default-features = false }
tungstenite = { workspace = true, default-features = false }
tokio = { workspace = true, features = ["macros"]}
time = "0.3.17"
zeroize = { workspace = true }
@@ -54,7 +54,7 @@ workspace = true
features = ["time"]
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-tungstenite]
version = "0.14"
version = "0.20.1"
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.sqlx]
version = "0.6.2"
@@ -47,11 +47,7 @@ impl<T> PersistedGatewayDetails<T> {
pub fn validate(&self, shared_key: Option<&SharedKeys>) -> Result<(), ClientCoreError> {
match self {
PersistedGatewayDetails::Default(details) => {
if !details.verify(
shared_key
.ok_or(ClientCoreError::UnavailableSharedKey)?
.deref(),
) {
if !details.verify(shared_key.ok_or(ClientCoreError::UnavailableSharedKey)?) {
Err(ClientCoreError::MismatchedGatewayDetails {
gateway_id: details.details.gateway_id.clone(),
})
@@ -199,7 +199,7 @@ fn group_mixnodes_by_country_code(
if let Some(ref location) = m.location {
let country_code = location.two_letter_iso_country_code.clone();
let group_code = CountryGroup::new(country_code.as_str());
let mixnodes = acc.entry(group_code).or_insert_with(Vec::new);
let mixnodes = acc.entry(group_code).or_default();
mixnodes.push(m.mix_id);
}
acc
+2 -2
View File
@@ -31,7 +31,7 @@ serde = { workspace = true, features = ["derive"] }
[dependencies.tungstenite]
version = "0.13"
workspace = true
default-features = false
# non-wasm-only dependencies
@@ -44,7 +44,7 @@ version = "0.1.11"
features = ["net", "sync", "time"]
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-tungstenite]
version = "0.14"
workspace = true
# wasm-only dependencies
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-bindgen]
@@ -86,4 +86,5 @@ required-features = ["http-client"]
default = ["http-client"]
http-client = ["cosmrs/rpc", "openssl"]
generate-ts = []
contract-testing = ["nym-mixnet-contract-common/contract-testing"]
@@ -683,13 +683,14 @@ pub trait MixnetSigningClient {
.await
}
#[cfg(feature = "nym_mixnet_contract_common/contract-testing")]
#[cfg(feature = "contract-testing")]
async fn testing_resolve_all_pending_events(
&self,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::TestingResolveAllPendingEvents {},
MixnetExecuteMsg::TestingResolveAllPendingEvents { limit: None },
vec![],
)
.await
@@ -928,8 +929,8 @@ mod tests {
.withdraw_delegator_reward_on_behalf(owner.parse().unwrap(), mix_id, None)
.ignore(),
#[cfg(feature = "nym_mixnet_contract_common/contract-testing")]
MixnetExecuteMsg::TestingResolveAllPendingEvents {} => {
#[cfg(feature = "contract-testing")]
MixnetExecuteMsg::TestingResolveAllPendingEvents { .. } => {
client.testing_resolve_all_pending_events(None).ignore()
}
};
@@ -572,7 +572,7 @@ mod tests {
let env = mock_env();
// epoch just begun
let interval = Interval {
let mut interval = Interval {
id: 0,
epochs_in_interval: 100,
current_epoch_start: OffsetDateTime::from_unix_timestamp(
@@ -586,19 +586,16 @@ mod tests {
assert!(!interval.is_current_epoch_over(&env));
// current time == current epoch start
let mut interval = interval;
interval.current_epoch_start =
OffsetDateTime::from_unix_timestamp(env.block.time.seconds() as i64).unwrap();
assert!(!interval.is_current_epoch_over(&env));
// epoch HASN'T yet begun (weird edge case, but can happen if we decide to manually adjust things)
let mut interval = interval;
interval.current_epoch_start =
OffsetDateTime::from_unix_timestamp(env.block.time.seconds() as i64 + 100).unwrap();
assert!(!interval.is_current_epoch_over(&env));
// current_time = EXACTLY end of the epoch
let mut interval = interval;
interval.current_epoch_start =
OffsetDateTime::from_unix_timestamp(env.block.time.seconds() as i64).unwrap()
- interval.epoch_length;
+1 -1
View File
@@ -80,7 +80,7 @@ pub fn number_of_required_fragments(
let max_linked = linked_fragment_payload_max_len(plaintext_per_fragment);
match set::total_number_of_sets(message_len, plaintext_per_fragment) {
n if n == 1 => {
1 => {
// is if it's a single fragment message
if message_len < max_unlinked {
return (1, max_unlinked - message_len);
+1 -1
View File
@@ -89,7 +89,7 @@ pub enum PacketSize {
impl PartialOrd for PacketSize {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
// order them by actual packet size
self.size().partial_cmp(&other.size())
Some(self.cmp(other))
}
}
@@ -193,10 +193,7 @@ impl Controller {
}
} else if !self.recently_closed.contains(&hdr.connection_id) {
debug!("Received a 'Send' before 'Connect' - going to buffer the data");
let pending = self
.pending_messages
.entry(hdr.connection_id)
.or_insert_with(Vec::new);
let pending = self.pending_messages.entry(hdr.connection_id).or_default();
pending.push(message);
} else if !hdr.local_socket_closed {
error!(
+1 -1
View File
@@ -434,7 +434,7 @@ impl TaskClient {
.await
{
self.log(Level::Error, "Task stopped without shutdown called");
panic!("{timeout}")
panic!("{:?}: {timeout}", self.name)
}
}
+2 -2
View File
@@ -175,8 +175,8 @@ impl WasmStorage {
K: wasm_bindgen::JsCast,
{
match self.key_count(store, key).await? {
n if n == 0 => Ok(false),
n if n == 1 => Ok(true),
0 => Ok(false),
1 => Ok(true),
n => Err(StorageError::DuplicateKey { count: n }),
}
}
+1 -1
View File
@@ -18,7 +18,7 @@ gloo-net = { version = "0.3.1", features = ["websocket"], optional = true }
# we don't want entire tokio-tungstenite, tungstenite itself is just fine - we just want message and error enums
[dependencies.tungstenite]
version = "0.13"
workspace = true
default-features = false
optional = true
+8 -1
View File
@@ -19,9 +19,16 @@ base64 = "0.21.3"
#boringtun = "0.6.0"
boringtun = { git = "https://github.com/cloudflare/boringtun", rev = "e1d6360d6ab4529fc942a078e4c54df107abe2ba" }
bytes = "1.5.0"
dashmap = "5.5.3"
etherparse = "0.13.0"
futures = "0.3.28"
ip_network = "0.4.1"
ip_network_table = "0.2.0"
log.workspace = true
nym-task = { path = "../task" }
tap.workspace = true
thiserror.workspace = true
tokio = { workspace = true, features = ["rt-multi-thread", "net"]}
tokio = { workspace = true, features = ["rt-multi-thread", "net", "io-util"] }
[target.'cfg(target_os = "linux")'.dependencies]
tokio-tun = "0.9.0"
-5
View File
@@ -5,8 +5,6 @@ use bytes::Bytes;
#[allow(unused)]
#[derive(Debug, Clone)]
pub enum Event {
/// Dumb event with no data.
Dumb,
/// IP packet received from the WireGuard tunnel that should be passed through to the corresponding virtual device/internet.
/// Original implementation also has protocol here since it understands it, but we'll have to infer it downstream
WgPacket(Bytes),
@@ -17,9 +15,6 @@ pub enum Event {
impl Display for Event {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Event::Dumb => {
write!(f, "Dumb{{}}")
}
Event::WgPacket(data) => {
let size = data.len();
write!(f, "WgPacket{{ size={size} }}")
+33 -125
View File
@@ -1,140 +1,48 @@
use std::{collections::HashMap, net::SocketAddr, sync::Arc};
use base64::{engine::general_purpose, Engine as _};
use boringtun::x25519;
use futures::StreamExt;
use log::{error, info};
use nym_task::TaskClient;
use tap::TapFallible;
use tokio::{net::UdpSocket, sync::mpsc, task::JoinHandle};
use tun::WireGuardTunnel;
use crate::event::Event;
pub use error::WgError;
#![cfg_attr(not(target_os = "linux"), allow(dead_code))]
mod error;
mod event;
mod tun;
mod network_table;
mod platform;
mod setup;
mod udp_listener;
mod wg_tunnel;
//const WG_ADDRESS = "0.0.0.0:51820";
const WG_ADDRESS: &str = "0.0.0.0:51822";
// Currently the module related to setting up the virtual network device is platform specific.
#[cfg(target_os = "linux")]
use platform::linux::tun_device;
// The private key of the listener
// Corresponding public key: "WM8s8bYegwMa0TJ+xIwhk+dImk2IpDUKslDBCZPizlE="
const PRIVATE_KEY: &str = "AEqXrLFT4qjYq3wmX0456iv94uM6nDj5ugp6Jedcflg=";
#[derive(Clone)]
struct TunTaskTx(tokio::sync::mpsc::UnboundedSender<Vec<u8>>);
// The public keys of the registered peers (clients)
const PEERS: &[&str; 1] = &[
// Corresponding private key: "ILeN6gEh6vJ3Ju8RJ3HVswz+sPgkcKtAYTqzQRhTtlo="
"NCIhkgiqxFx1ckKl3Zuh595DzIFl8mxju1Vg995EZhI=", // "mxV/mw7WZTe+0Msa0kvJHMHERDA/cSskiZWQce+TdEs=",
];
const MAX_PACKET: usize = 65535;
fn init_static_dev_keys() -> (x25519::StaticSecret, x25519::PublicKey) {
// TODO: this is a temporary solution for development
let static_private_bytes: [u8; 32] = general_purpose::STANDARD
.decode(PRIVATE_KEY)
.unwrap()
.try_into()
.unwrap();
let static_private = x25519::StaticSecret::try_from(static_private_bytes).unwrap();
let static_public = x25519::PublicKey::from(&static_private);
info!(
"wg public key: {}",
general_purpose::STANDARD.encode(static_public)
);
// TODO: A single static public key is used for all peers during development
let peer_static_public_bytes: [u8; 32] = general_purpose::STANDARD
.decode(PEERS[0])
.unwrap()
.try_into()
.unwrap();
let peer_static_public = x25519::PublicKey::try_from(peer_static_public_bytes).unwrap();
(static_private, peer_static_public)
impl TunTaskTx {
fn send(&self, packet: Vec<u8>) -> Result<(), tokio::sync::mpsc::error::SendError<Vec<u8>>> {
self.0.send(packet)
}
}
fn start_wg_tunnel(
addr: SocketAddr,
udp: Arc<UdpSocket>,
static_private: x25519::StaticSecret,
peer_static_public: x25519::PublicKey,
) -> (JoinHandle<SocketAddr>, mpsc::UnboundedSender<Event>) {
let (mut tunnel, peer_tx) = WireGuardTunnel::new(udp, addr, static_private, peer_static_public);
let join_handle = tokio::spawn(async move {
tunnel.spin_off().await;
addr
});
(join_handle, peer_tx)
}
pub async fn start_wg_listener(
mut task_client: TaskClient,
#[cfg(target_os = "linux")]
pub async fn start_wireguard(
task_client: nym_task::TaskClient,
) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
log::info!("Starting wireguard listener on {}", WG_ADDRESS);
let udp_socket = Arc::new(UdpSocket::bind(WG_ADDRESS).await?);
use std::sync::Arc;
// Setup some static keys for development
let (static_private, peer_static_public) = init_static_dev_keys();
// The set of active tunnels indexed by the peer's address
let active_peers = Arc::new(udp_listener::ActivePeers::new());
let peers_by_ip = Arc::new(std::sync::Mutex::new(network_table::NetworkTable::new()));
tokio::spawn(async move {
// The set of active tunnels indexed by the peer's address
let mut active_peers: HashMap<SocketAddr, mpsc::UnboundedSender<Event>> = HashMap::new();
// Each tunnel is run in its own task, and the task handle is stored here so we can remove
// it from `active_peers` when the tunnel is closed
let mut active_peers_task_handles = futures::stream::FuturesUnordered::new();
let mut buf = [0u8; MAX_PACKET];
// Start the tun device that is used to relay traffic outbound
let tun_task_tx = tun_device::start_tun_device(peers_by_ip.clone());
while !task_client.is_shutdown() {
tokio::select! {
_ = task_client.recv() => {
log::trace!("WireGuard listener: received shutdown");
break;
}
// Handle tunnel closing
Some(addr) = active_peers_task_handles.next() => {
match addr {
Ok(addr) => {
info!("WireGuard listener: closed {addr:?}");
active_peers.remove(&addr);
}
Err(err) => {
error!("WireGuard listener: error receiving shutdown from peer: {err}");
}
}
}
// Handle incoming packets
Ok((len, addr)) = udp_socket.recv_from(&mut buf) => {
log::info!("Received {} bytes from {}", len, addr);
if let Some(peer_tx) = active_peers.get_mut(&addr) {
log::info!("WireGuard listener: received packet from known peer");
peer_tx.send(Event::WgPacket(buf[..len].to_vec().into()))
.tap_err(|err| log::error!("{err}"))
.unwrap();
} else {
log::info!("WireGuard listener: received packet from unknown peer, starting tunnel");
let (join_handle, peer_tx) = start_wg_tunnel(
addr,
udp_socket.clone(),
static_private.clone(),
peer_static_public
);
peer_tx.send(Event::WgPacket(buf[..len].to_vec().into()))
.tap_err(|err| log::error!("{err}"))
.unwrap();
active_peers.insert(addr, peer_tx);
active_peers_task_handles.push(join_handle);
}
}
}
}
log::info!("WireGuard listener: shutting down");
});
// Start the UDP listener that clients connect to
udp_listener::start_udp_listener(tun_task_tx, active_peers, peers_by_ip, task_client).await?;
Ok(())
}
#[cfg(not(target_os = "linux"))]
pub async fn start_wireguard(
_task_client: nym_task::TaskClient,
) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
todo!("WireGuard is currently only supported on Linux")
}
+25
View File
@@ -0,0 +1,25 @@
use std::net::IpAddr;
use ip_network::IpNetwork;
use ip_network_table::IpNetworkTable;
#[derive(Default)]
pub(crate) struct NetworkTable<T> {
ips: IpNetworkTable<T>,
}
impl<T> NetworkTable<T> {
pub(crate) fn new() -> Self {
Self {
ips: IpNetworkTable::new(),
}
}
pub fn insert<N: Into<IpNetwork>>(&mut self, network: N, data: T) -> Option<T> {
self.ips.insert(network, data)
}
pub fn longest_match<I: Into<IpAddr>>(&self, ip: I) -> Option<(IpNetwork, &T)> {
self.ips.longest_match(ip)
}
}
@@ -0,0 +1 @@
pub(crate) mod tun_device;
@@ -0,0 +1,99 @@
use std::{net::Ipv4Addr, sync::Arc};
use etherparse::{InternetSlice, SlicedPacket};
use tap::TapFallible;
use tokio::{
io::{AsyncReadExt, AsyncWriteExt},
sync::mpsc::{self},
};
use crate::{
event::Event,
setup::{TUN_BASE_NAME, TUN_DEVICE_ADDRESS, TUN_DEVICE_NETMASK},
udp_listener::PeersByIp,
TunTaskTx,
};
fn setup_tokio_tun_device(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> tokio_tun::Tun {
log::info!("Creating TUN device with: address={address}, netmask={netmask}");
tokio_tun::Tun::builder()
.name(name)
.tap(false)
.packet_info(false)
.mtu(1350)
.up()
.address(address)
.netmask(netmask)
.try_build()
.expect("Failed to setup tun device, do you have permission?")
}
pub(crate) fn start_tun_device(peers_by_ip: Arc<std::sync::Mutex<PeersByIp>>) -> TunTaskTx {
let tun = setup_tokio_tun_device(
format!("{}%d", TUN_BASE_NAME).as_str(),
TUN_DEVICE_ADDRESS.parse().unwrap(),
TUN_DEVICE_NETMASK.parse().unwrap(),
);
log::info!("Created TUN device: {}", tun.name());
let (mut tun_device_rx, mut tun_device_tx) = tokio::io::split(tun);
// Channels to communicate with the other tasks
let (tun_task_tx, mut tun_task_rx) = mpsc::unbounded_channel::<Vec<u8>>();
let tun_task_tx = TunTaskTx(tun_task_tx);
tokio::spawn(async move {
let mut buf = [0u8; 1024];
loop {
tokio::select! {
// Reading from the TUN device
len = tun_device_rx.read(&mut buf) => match len {
Ok(len) => {
let packet = &buf[..len];
let dst_addr = boringtun::noise::Tunn::dst_address(packet).unwrap();
let headers = SlicedPacket::from_ip(packet).unwrap();
let src_addr = match headers.ip.unwrap() {
InternetSlice::Ipv4(ip, _) => ip.source_addr().to_string(),
InternetSlice::Ipv6(ip, _) => ip.source_addr().to_string(),
};
log::info!("iface: read Packet({src_addr} -> {dst_addr}, {len} bytes)");
// Route packet to the correct peer.
if let Some(peer_tx) = peers_by_ip.lock().unwrap().longest_match(dst_addr).map(|(_, tx)| tx) {
log::info!("Forward packet to wg tunnel");
peer_tx
.send(Event::IpPacket(packet.to_vec().into()))
.tap_err(|err| log::error!("{err}"))
.unwrap();
} else {
log::info!("No peer found, packet dropped");
}
},
Err(err) => {
log::info!("iface: read error: {err}");
break;
}
},
// Writing to the TUN device
Some(data) = tun_task_rx.recv() => {
let headers = SlicedPacket::from_ip(&data).unwrap();
let (source_addr, destination_addr) = match headers.ip.unwrap() {
InternetSlice::Ipv4(ip, _) => (ip.source_addr(), ip.destination_addr()),
InternetSlice::Ipv6(_, _) => unimplemented!(),
};
log::info!(
"iface: write Packet({source_addr} -> {destination_addr}, {} bytes)",
data.len()
);
// log::info!("iface: writing {} bytes", data.len());
tun_device_tx.write_all(&data).await.unwrap();
}
}
}
log::info!("TUN device shutting down");
});
tun_task_tx
}
+2
View File
@@ -0,0 +1,2 @@
#[cfg(target_os = "linux")]
pub(crate) mod linux;
+63
View File
@@ -0,0 +1,63 @@
use std::net::IpAddr;
use base64::{engine::general_purpose, Engine as _};
use boringtun::x25519;
use log::info;
// The wireguard UDP listener
pub const WG_ADDRESS: &str = "0.0.0.0";
pub const WG_PORT: u16 = 51822;
// The interface used to route traffic
pub const TUN_BASE_NAME: &str = "nymtun";
pub const TUN_DEVICE_ADDRESS: &str = "10.0.0.1";
pub const TUN_DEVICE_NETMASK: &str = "255.255.255.0";
// The private key of the listener
// Corresponding public key: "WM8s8bYegwMa0TJ+xIwhk+dImk2IpDUKslDBCZPizlE="
const PRIVATE_KEY: &str = "AEqXrLFT4qjYq3wmX0456iv94uM6nDj5ugp6Jedcflg=";
// The public keys of the registered peer (clients)
// Corresponding private key: "ILeN6gEh6vJ3Ju8RJ3HVswz+sPgkcKtAYTqzQRhTtlo="
const PEER: &str = "NCIhkgiqxFx1ckKl3Zuh595DzIFl8mxju1Vg995EZhI=";
// The AllowedIPs for the connected peer, which is one a single IP and the same as the IP that the
// peer has configured on their side.
const ALLOWED_IPS: &str = "10.0.0.2";
fn decode_base64_key(base64_key: &str) -> [u8; 32] {
general_purpose::STANDARD
.decode(base64_key)
.unwrap()
.try_into()
.unwrap()
}
pub fn server_static_private_key() -> x25519::StaticSecret {
// TODO: this is a temporary solution for development
let static_private_bytes: [u8; 32] = decode_base64_key(PRIVATE_KEY);
let static_private = x25519::StaticSecret::try_from(static_private_bytes).unwrap();
let static_public = x25519::PublicKey::from(&static_private);
info!(
"wg public key: {}",
general_purpose::STANDARD.encode(static_public)
);
static_private
}
pub fn peer_static_public_key() -> x25519::PublicKey {
// A single static public key is used during development
let peer_static_public_bytes: [u8; 32] = decode_base64_key(PEER);
let peer_static_public = x25519::PublicKey::try_from(peer_static_public_bytes).unwrap();
info!(
"peer public key: {}",
general_purpose::STANDARD.encode(peer_static_public)
);
peer_static_public
}
pub fn peer_allowed_ips() -> ip_network::IpNetwork {
let key: IpAddr = ALLOWED_IPS.parse().unwrap();
let cidr = 0u8;
ip_network::IpNetwork::new_truncate(key, cidr).unwrap()
}
+109
View File
@@ -0,0 +1,109 @@
use std::{net::SocketAddr, sync::Arc};
use dashmap::DashMap;
use futures::StreamExt;
use log::error;
use nym_task::TaskClient;
use tap::TapFallible;
use tokio::{
net::UdpSocket,
sync::mpsc::{self},
};
use crate::{
event::Event,
network_table::NetworkTable,
setup::{self, WG_ADDRESS, WG_PORT},
TunTaskTx,
};
const MAX_PACKET: usize = 65535;
pub(crate) type ActivePeers = DashMap<SocketAddr, mpsc::UnboundedSender<Event>>;
pub(crate) type PeersByIp = NetworkTable<mpsc::UnboundedSender<Event>>;
pub(crate) async fn start_udp_listener(
tun_task_tx: TunTaskTx,
active_peers: Arc<ActivePeers>,
peers_by_ip: Arc<std::sync::Mutex<PeersByIp>>,
mut task_client: TaskClient,
) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
let wg_address = SocketAddr::new(WG_ADDRESS.parse().unwrap(), WG_PORT);
log::info!("Starting wireguard UDP listener on {wg_address}");
let udp_socket = Arc::new(UdpSocket::bind(wg_address).await?);
// Setup some static keys for development
let static_private = setup::server_static_private_key();
let peer_static_public = setup::peer_static_public_key();
let peer_allowed_ips = setup::peer_allowed_ips();
tokio::spawn(async move {
// Each tunnel is run in its own task, and the task handle is stored here so we can remove
// it from `active_peers` when the tunnel is closed
let mut active_peers_task_handles = futures::stream::FuturesUnordered::new();
let mut buf = [0u8; MAX_PACKET];
while !task_client.is_shutdown() {
tokio::select! {
_ = task_client.recv() => {
log::trace!("WireGuard UDP listener: received shutdown");
break;
}
// Handle tunnel closing
Some(addr) = active_peers_task_handles.next() => {
match addr {
Ok(addr) => {
log::info!("Removing peer: {addr:?}");
active_peers.remove(&addr);
// TODO: remove from peers_by_ip
}
Err(err) => {
error!("WireGuard UDP listener: error receiving shutdown from peer: {err}");
}
}
},
// Handle incoming packets
Ok((len, addr)) = udp_socket.recv_from(&mut buf) => {
log::trace!("udp: received {} bytes from {}", len, addr);
if let Some(peer_tx) = active_peers.get_mut(&addr) {
log::info!("udp: received {len} bytes from {addr} from known peer");
peer_tx.send(Event::WgPacket(buf[..len].to_vec().into()))
.tap_err(|err| log::error!("{err}"))
.unwrap();
} else {
log::info!("udp: received {len} bytes from {addr} from unknown peer, starting tunnel");
// TODO: this is a temporary solution for development since this
// assumes we know the peer_static_public this corresponds to.
// TODO: rework this before production! This is likely not secure!
log::warn!("Assuming peer_static_public is known");
log::warn!("SECURITY: Rework me to do proper handshake before creating the tunnel!");
let (join_handle, peer_tx) = crate::wg_tunnel::start_wg_tunnel(
addr,
udp_socket.clone(),
static_private.clone(),
peer_static_public,
peer_allowed_ips,
tun_task_tx.clone(),
);
peers_by_ip.lock().unwrap().insert(peer_allowed_ips, peer_tx.clone());
peer_tx.send(Event::WgPacket(buf[..len].to_vec().into()))
.tap_err(|err| log::error!("{err}"))
.unwrap();
// WIP(JON): active peers should probably be keyed by peer_static_public
// instead. Does this current setup lead to any issues?
log::info!("Adding peer: {addr}");
active_peers.insert(addr, peer_tx);
active_peers_task_handles.push(join_handle);
}
},
}
}
log::info!("WireGuard listener: shutting down");
});
Ok(())
}
@@ -14,19 +14,22 @@ use tokio::{
time::timeout,
};
use crate::{event::Event, WgError};
use crate::{error::WgError, event::Event, network_table::NetworkTable, TunTaskTx};
const MAX_PACKET: usize = 65535;
pub struct WireGuardTunnel {
// Incoming data from the UDP socket received in the main event loop
udp_rx: mpsc::UnboundedReceiver<Event>,
peer_rx: mpsc::UnboundedReceiver<Event>,
// UDP socket used for sending data
udp: Arc<UdpSocket>,
// Peer endpoint
addr: SocketAddr,
endpoint: Arc<tokio::sync::RwLock<SocketAddr>>,
// AllowedIPs for this peer
allowed_ips: NetworkTable<()>,
// `boringtun` tunnel, used for crypto & WG protocol
wg_tunnel: Arc<tokio::sync::Mutex<Tunn>>,
@@ -34,6 +37,9 @@ pub struct WireGuardTunnel {
// Signal close
close_tx: broadcast::Sender<()>,
close_rx: broadcast::Receiver<()>,
// Send data to the task that handles sending data through the tun device
tun_task_tx: TunTaskTx,
}
impl Drop for WireGuardTunnel {
@@ -44,16 +50,18 @@ impl Drop for WireGuardTunnel {
}
impl WireGuardTunnel {
fn close(&self) {
let _ = self.close_tx.send(());
}
pub fn new(
pub(crate) fn new(
udp: Arc<UdpSocket>,
addr: SocketAddr,
endpoint: SocketAddr,
static_private: x25519::StaticSecret,
peer_static_public: x25519::PublicKey,
peer_allowed_ips: ip_network::IpNetwork,
tunnel_tx: TunTaskTx,
) -> (Self, mpsc::UnboundedSender<Event>) {
let local_addr = udp.local_addr().unwrap();
let peer_addr = udp.peer_addr();
log::info!("New wg tunnel: endpoint: {endpoint}, local_addr: {local_addr}, peer_addr: {peer_addr:?}");
let preshared_key = None;
let persistent_keepalive = None;
let index = 0;
@@ -72,21 +80,30 @@ impl WireGuardTunnel {
));
// Channels with incoming data that is received by the main event loop
let (udp_tx, udp_rx) = mpsc::unbounded_channel();
let (peer_tx, peer_rx) = mpsc::unbounded_channel();
// Signal close tunnel
let (close_tx, close_rx) = broadcast::channel(1);
let mut allowed_ips = NetworkTable::new();
allowed_ips.insert(peer_allowed_ips, ());
let tunnel = WireGuardTunnel {
udp_rx,
peer_rx,
udp,
addr,
endpoint: Arc::new(tokio::sync::RwLock::new(endpoint)),
allowed_ips,
wg_tunnel,
close_tx,
close_rx,
tun_task_tx: tunnel_tx,
};
(tunnel, udp_tx)
(tunnel, peer_tx)
}
fn close(&self) {
let _ = self.close_tx.send(());
}
pub async fn spin_off(&mut self) {
@@ -96,9 +113,9 @@ impl WireGuardTunnel {
info!("WireGuard tunnel: received msg to close");
break;
},
packet = self.udp_rx.recv() => match packet {
packet = self.peer_rx.recv() => match packet {
Some(packet) => {
info!("WireGuard tunnel received: {packet}");
info!("event loop: {packet}");
match packet {
Event::WgPacket(data) => {
let _ = self.consume_wg(&data)
@@ -106,7 +123,6 @@ impl WireGuardTunnel {
.tap_err(|err| error!("WireGuard tunnel: consume_wg error: {err}"));
},
Event::IpPacket(data) => self.consume_eth(&data).await,
_ => {},
}
},
None => {
@@ -121,7 +137,7 @@ impl WireGuardTunnel {
},
}
}
info!("WireGuard tunnel ({}): closed", self.addr);
info!("WireGuard tunnel ({}): closed", self.endpoint.read().await);
}
async fn wg_tunnel_lock(&self) -> Result<tokio::sync::MutexGuard<'_, Tunn>, WgError> {
@@ -130,21 +146,31 @@ impl WireGuardTunnel {
.map_err(|_| WgError::UnableToGetTunnel)
}
async fn consume_wg(&self, data: &[u8]) -> Result<(), WgError> {
#[allow(unused)]
async fn set_endpoint(&self, addr: SocketAddr) {
if *self.endpoint.read().await != addr {
log::info!("wg tunnel update endpoint: {addr}");
*self.endpoint.write().await = addr;
}
}
async fn consume_wg(&mut self, data: &[u8]) -> Result<(), WgError> {
let mut send_buf = [0u8; MAX_PACKET];
let mut peer = self.wg_tunnel_lock().await?;
match peer.decapsulate(None, data, &mut send_buf) {
let mut tunnel = self.wg_tunnel_lock().await?;
match tunnel.decapsulate(None, data, &mut send_buf) {
TunnResult::WriteToNetwork(packet) => {
debug!("WireGuard: writing to network");
if let Err(err) = self.udp.send_to(packet, self.addr).await {
let endpoint = self.endpoint.read().await;
log::info!("udp: send {} bytes to {}", packet.len(), *endpoint);
if let Err(err) = self.udp.send_to(packet, *endpoint).await {
error!("Failed to send decapsulation-instructed packet to WireGuard endpoint: {err:?}");
};
// Flush pending queue
loop {
let mut send_buf = [0u8; MAX_PACKET];
match peer.decapsulate(None, &[], &mut send_buf) {
match tunnel.decapsulate(None, &[], &mut send_buf) {
TunnResult::WriteToNetwork(packet) => {
if let Err(err) = self.udp.send_to(packet, self.addr).await {
log::info!("udp: send {} bytes to {}", packet.len(), *endpoint);
if let Err(err) = self.udp.send_to(packet, *endpoint).await {
error!("Failed to send decapsulation-instructed packet to WireGuard endpoint: {err:?}");
break;
};
@@ -155,13 +181,23 @@ impl WireGuardTunnel {
}
}
}
TunnResult::WriteToTunnelV4(packet, _) | TunnResult::WriteToTunnelV6(packet, _) => {
debug!("WireGuard: writing to tunnel");
info!(
"WireGuard endpoint sent IP packet of {} bytes (not yet implemented)",
packet.len()
);
// TODO
TunnResult::WriteToTunnelV4(packet, addr) => {
// TODO: once the flow is redone, we should add updating the endpoint dynamically
// self.set_endpoint(addr);
if self.allowed_ips.longest_match(addr).is_some() {
self.tun_task_tx.send(packet.to_vec()).unwrap();
} else {
warn!("Packet from {addr} not in allowed_ips");
}
}
TunnResult::WriteToTunnelV6(packet, addr) => {
// TODO: once the flow is redone, we should add updating the endpoint dynamically
// self.set_endpoint(addr);
if self.allowed_ips.longest_match(addr).is_some() {
self.tun_task_tx.send(packet.to_vec()).unwrap();
} else {
warn!("Packet (v6) from {addr} not in allowed_ips");
}
}
TunnResult::Done => {
debug!("WireGuard: decapsulate done");
@@ -173,9 +209,36 @@ impl WireGuardTunnel {
Ok(())
}
async fn consume_eth(&self, _data: &Bytes) {
info!("WireGuard tunnel: consume_eth");
todo!();
async fn consume_eth(&self, data: &Bytes) {
info!("consume_eth: raw packet size: {}", data.len());
let encapsulated_packet = self.encapsulate_packet(data).await;
info!(
"consume_eth: after encapsulate: {}",
encapsulated_packet.len()
);
let endpoint = self.endpoint.read().await;
info!("consume_eth: send to {}: {}", *endpoint, data.len());
self.udp
.send_to(&encapsulated_packet, *endpoint)
.await
.unwrap();
}
async fn encapsulate_packet(&self, payload: &[u8]) -> Vec<u8> {
// TODO: use fixed dst and src buffers that we can reuse
let len = 148.max(payload.len() + 32);
let mut dst = vec![0; len];
let mut wg_tunnel = self.wg_tunnel_lock().await.unwrap();
match wg_tunnel.encapsulate(payload, &mut dst) {
TunnResult::WriteToNetwork(packet) => packet.to_vec(),
unexpected => {
error!("{:?}", unexpected);
vec![]
}
}
}
async fn update_wg_timers(&mut self) -> Result<(), WgError> {
@@ -190,16 +253,15 @@ impl WireGuardTunnel {
async fn handle_routine_tun_result<'a: 'async_recursion>(&self, result: TunnResult<'a>) {
match result {
TunnResult::WriteToNetwork(packet) => {
info!(
"Sending routine packet of {} bytes to WireGuard endpoint",
packet.len()
);
if let Err(err) = self.udp.send_to(packet, self.addr).await {
error!("Failed to send routine packet to WireGuard endpoint: {err:?}",);
let endpoint = self.endpoint.read().await;
log::info!("routine: write to network: {}: {}", endpoint, packet.len());
if let Err(err) = self.udp.send_to(packet, *endpoint).await {
error!("routine: failed to send packet: {err:?}");
};
}
TunnResult::Err(WireGuardError::ConnectionExpired) => {
warn!("Wireguard handshake has expired!");
// WIP(JON): consider just closing the tunnel here
let mut buf = vec![0u8; MAX_PACKET];
let Ok(mut peer) = self.wg_tunnel_lock().await else {
warn!("Failed to lock WireGuard peer, closing tunnel");
@@ -219,3 +281,29 @@ impl WireGuardTunnel {
};
}
}
pub(crate) fn start_wg_tunnel(
endpoint: SocketAddr,
udp: Arc<UdpSocket>,
static_private: x25519::StaticSecret,
peer_static_public: x25519::PublicKey,
peer_allowed_ips: ip_network::IpNetwork,
tunnel_tx: TunTaskTx,
) -> (
tokio::task::JoinHandle<SocketAddr>,
mpsc::UnboundedSender<Event>,
) {
let (mut tunnel, peer_tx) = WireGuardTunnel::new(
udp,
endpoint,
static_private,
peer_static_public,
peer_allowed_ips,
tunnel_tx,
);
let join_handle = tokio::spawn(async move {
tunnel.spin_off().await;
endpoint
});
(join_handle, peer_tx)
}
File diff suppressed because it is too large Load Diff
@@ -234,67 +234,6 @@
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"staking"
],
"properties": {
"staking": {
"$ref": "#/definitions/StakingMsg"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"distribution"
],
"properties": {
"distribution": {
"$ref": "#/definitions/DistributionMsg"
}
},
"additionalProperties": false
},
{
"description": "A Stargate message encoded the same way as a protobuf [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). This is the same structure as messages in `TxBody` from [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md)",
"type": "object",
"required": [
"stargate"
],
"properties": {
"stargate": {
"type": "object",
"required": [
"type_url",
"value"
],
"properties": {
"type_url": {
"type": "string"
},
"value": {
"$ref": "#/definitions/Binary"
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"ibc"
],
"properties": {
"ibc": {
"$ref": "#/definitions/IbcMsg"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
@@ -306,67 +245,6 @@
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"gov"
],
"properties": {
"gov": {
"$ref": "#/definitions/GovMsg"
}
},
"additionalProperties": false
}
]
},
"DistributionMsg": {
"description": "The message types of the distribution module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto",
"oneOf": [
{
"description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37). `delegator_address` is automatically filled with the current contract's address.",
"type": "object",
"required": [
"set_withdraw_address"
],
"properties": {
"set_withdraw_address": {
"type": "object",
"required": [
"address"
],
"properties": {
"address": {
"description": "The `withdraw_address`",
"type": "string"
}
}
}
},
"additionalProperties": false
},
{
"description": "This is translated to a [[MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.",
"type": "object",
"required": [
"withdraw_delegator_reward"
],
"properties": {
"withdraw_delegator_reward": {
"type": "object",
"required": [
"validator"
],
"properties": {
"validator": {
"description": "The `validator_address`",
"type": "string"
}
}
}
},
"additionalProperties": false
}
]
},
@@ -421,196 +299,6 @@
}
]
},
"GovMsg": {
"description": "This message type allows the contract interact with the [x/gov] module in order to cast votes.\n\n[x/gov]: https://github.com/cosmos/cosmos-sdk/tree/v0.45.12/x/gov\n\n## Examples\n\nCast a simple vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); use cosmwasm_std::{GovMsg, VoteOption};\n\n#[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result<Response, StdError> { // ... Ok(Response::new().add_message(GovMsg::Vote { proposal_id: 4, vote: VoteOption::Yes, })) } ```\n\nCast a weighted vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); # #[cfg(feature = \"cosmwasm_1_2\")] use cosmwasm_std::{Decimal, GovMsg, VoteOption, WeightedVoteOption};\n\n# #[cfg(feature = \"cosmwasm_1_2\")] #[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result<Response, StdError> { // ... Ok(Response::new().add_message(GovMsg::VoteWeighted { proposal_id: 4, options: vec![ WeightedVoteOption { option: VoteOption::Yes, weight: Decimal::percent(65), }, WeightedVoteOption { option: VoteOption::Abstain, weight: Decimal::percent(35), }, ], })) } ```",
"oneOf": [
{
"description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.",
"type": "object",
"required": [
"vote"
],
"properties": {
"vote": {
"type": "object",
"required": [
"proposal_id",
"vote"
],
"properties": {
"proposal_id": {
"type": "integer",
"format": "uint64",
"minimum": 0.0
},
"vote": {
"description": "The vote option.\n\nThis should be called \"option\" for consistency with Cosmos SDK. Sorry for that. See <https://github.com/CosmWasm/cosmwasm/issues/1571>.",
"allOf": [
{
"$ref": "#/definitions/VoteOption"
}
]
}
}
}
},
"additionalProperties": false
}
]
},
"IbcMsg": {
"description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)",
"oneOf": [
{
"description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.",
"type": "object",
"required": [
"transfer"
],
"properties": {
"transfer": {
"type": "object",
"required": [
"amount",
"channel_id",
"timeout",
"to_address"
],
"properties": {
"amount": {
"description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20",
"allOf": [
{
"$ref": "#/definitions/Coin"
}
]
},
"channel_id": {
"description": "exisiting channel to send the tokens over",
"type": "string"
},
"timeout": {
"description": "when packet times out, measured on remote chain",
"allOf": [
{
"$ref": "#/definitions/IbcTimeout"
}
]
},
"to_address": {
"description": "address on the remote chain to receive these tokens",
"type": "string"
}
}
}
},
"additionalProperties": false
},
{
"description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.",
"type": "object",
"required": [
"send_packet"
],
"properties": {
"send_packet": {
"type": "object",
"required": [
"channel_id",
"data",
"timeout"
],
"properties": {
"channel_id": {
"type": "string"
},
"data": {
"$ref": "#/definitions/Binary"
},
"timeout": {
"description": "when packet times out, measured on remote chain",
"allOf": [
{
"$ref": "#/definitions/IbcTimeout"
}
]
}
}
}
},
"additionalProperties": false
},
{
"description": "This will close an existing channel that is owned by this contract. Port is auto-assigned to the contract's IBC port",
"type": "object",
"required": [
"close_channel"
],
"properties": {
"close_channel": {
"type": "object",
"required": [
"channel_id"
],
"properties": {
"channel_id": {
"type": "string"
}
}
}
},
"additionalProperties": false
}
]
},
"IbcTimeout": {
"description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.",
"type": "object",
"properties": {
"block": {
"anyOf": [
{
"$ref": "#/definitions/IbcTimeoutBlock"
},
{
"type": "null"
}
]
},
"timestamp": {
"anyOf": [
{
"$ref": "#/definitions/Timestamp"
},
{
"type": "null"
}
]
}
}
},
"IbcTimeoutBlock": {
"description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)",
"type": "object",
"required": [
"height",
"revision"
],
"properties": {
"height": {
"description": "block height after which the packet times out. the height within the given revision",
"type": "integer",
"format": "uint64",
"minimum": 0.0
},
"revision": {
"description": "the version that the client is currently on (eg. after reseting the chain this could increment 1 as height drops to 0)",
"type": "integer",
"format": "uint64",
"minimum": 0.0
}
}
},
"MemberChangedHookMsg": {
"description": "MemberChangedHookMsg should be de/serialized under `MemberChangedHook()` variant in a ExecuteMsg. This contains a list of all diffs on the given transaction.",
"type": "object",
@@ -656,90 +344,6 @@
},
"additionalProperties": false
},
"StakingMsg": {
"description": "The message types of the staking module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto",
"oneOf": [
{
"description": "This is translated to a [MsgDelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L81-L90). `delegator_address` is automatically filled with the current contract's address.",
"type": "object",
"required": [
"delegate"
],
"properties": {
"delegate": {
"type": "object",
"required": [
"amount",
"validator"
],
"properties": {
"amount": {
"$ref": "#/definitions/Coin"
},
"validator": {
"type": "string"
}
}
}
},
"additionalProperties": false
},
{
"description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.",
"type": "object",
"required": [
"undelegate"
],
"properties": {
"undelegate": {
"type": "object",
"required": [
"amount",
"validator"
],
"properties": {
"amount": {
"$ref": "#/definitions/Coin"
},
"validator": {
"type": "string"
}
}
}
},
"additionalProperties": false
},
{
"description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.",
"type": "object",
"required": [
"redelegate"
],
"properties": {
"redelegate": {
"type": "object",
"required": [
"amount",
"dst_validator",
"src_validator"
],
"properties": {
"amount": {
"$ref": "#/definitions/Coin"
},
"dst_validator": {
"type": "string"
},
"src_validator": {
"type": "string"
}
}
}
},
"additionalProperties": false
}
]
},
"Timestamp": {
"description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```",
"allOf": [
@@ -788,15 +392,6 @@
}
]
},
"VoteOption": {
"type": "string",
"enum": [
"yes",
"no",
"abstain",
"no_with_veto"
]
},
"WasmMsg": {
"description": "The message types of the wasm module.\n\nSee https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto",
"oneOf": [
@@ -121,67 +121,6 @@
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"staking"
],
"properties": {
"staking": {
"$ref": "#/definitions/StakingMsg"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"distribution"
],
"properties": {
"distribution": {
"$ref": "#/definitions/DistributionMsg"
}
},
"additionalProperties": false
},
{
"description": "A Stargate message encoded the same way as a protobuf [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). This is the same structure as messages in `TxBody` from [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md)",
"type": "object",
"required": [
"stargate"
],
"properties": {
"stargate": {
"type": "object",
"required": [
"type_url",
"value"
],
"properties": {
"type_url": {
"type": "string"
},
"value": {
"$ref": "#/definitions/Binary"
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"ibc"
],
"properties": {
"ibc": {
"$ref": "#/definitions/IbcMsg"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
@@ -193,18 +132,6 @@
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"gov"
],
"properties": {
"gov": {
"$ref": "#/definitions/GovMsg"
}
},
"additionalProperties": false
}
]
},
@@ -272,55 +199,6 @@
},
"additionalProperties": false
},
"DistributionMsg": {
"description": "The message types of the distribution module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto",
"oneOf": [
{
"description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37). `delegator_address` is automatically filled with the current contract's address.",
"type": "object",
"required": [
"set_withdraw_address"
],
"properties": {
"set_withdraw_address": {
"type": "object",
"required": [
"address"
],
"properties": {
"address": {
"description": "The `withdraw_address`",
"type": "string"
}
}
}
},
"additionalProperties": false
},
{
"description": "This is translated to a [[MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.",
"type": "object",
"required": [
"withdraw_delegator_reward"
],
"properties": {
"withdraw_delegator_reward": {
"type": "object",
"required": [
"validator"
],
"properties": {
"validator": {
"description": "The `validator_address`",
"type": "string"
}
}
}
},
"additionalProperties": false
}
]
},
"Empty": {
"description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)",
"type": "object"
@@ -372,196 +250,6 @@
}
]
},
"GovMsg": {
"description": "This message type allows the contract interact with the [x/gov] module in order to cast votes.\n\n[x/gov]: https://github.com/cosmos/cosmos-sdk/tree/v0.45.12/x/gov\n\n## Examples\n\nCast a simple vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); use cosmwasm_std::{GovMsg, VoteOption};\n\n#[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result<Response, StdError> { // ... Ok(Response::new().add_message(GovMsg::Vote { proposal_id: 4, vote: VoteOption::Yes, })) } ```\n\nCast a weighted vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); # #[cfg(feature = \"cosmwasm_1_2\")] use cosmwasm_std::{Decimal, GovMsg, VoteOption, WeightedVoteOption};\n\n# #[cfg(feature = \"cosmwasm_1_2\")] #[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result<Response, StdError> { // ... Ok(Response::new().add_message(GovMsg::VoteWeighted { proposal_id: 4, options: vec![ WeightedVoteOption { option: VoteOption::Yes, weight: Decimal::percent(65), }, WeightedVoteOption { option: VoteOption::Abstain, weight: Decimal::percent(35), }, ], })) } ```",
"oneOf": [
{
"description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.",
"type": "object",
"required": [
"vote"
],
"properties": {
"vote": {
"type": "object",
"required": [
"proposal_id",
"vote"
],
"properties": {
"proposal_id": {
"type": "integer",
"format": "uint64",
"minimum": 0.0
},
"vote": {
"description": "The vote option.\n\nThis should be called \"option\" for consistency with Cosmos SDK. Sorry for that. See <https://github.com/CosmWasm/cosmwasm/issues/1571>.",
"allOf": [
{
"$ref": "#/definitions/VoteOption"
}
]
}
}
}
},
"additionalProperties": false
}
]
},
"IbcMsg": {
"description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)",
"oneOf": [
{
"description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.",
"type": "object",
"required": [
"transfer"
],
"properties": {
"transfer": {
"type": "object",
"required": [
"amount",
"channel_id",
"timeout",
"to_address"
],
"properties": {
"amount": {
"description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20",
"allOf": [
{
"$ref": "#/definitions/Coin"
}
]
},
"channel_id": {
"description": "exisiting channel to send the tokens over",
"type": "string"
},
"timeout": {
"description": "when packet times out, measured on remote chain",
"allOf": [
{
"$ref": "#/definitions/IbcTimeout"
}
]
},
"to_address": {
"description": "address on the remote chain to receive these tokens",
"type": "string"
}
}
}
},
"additionalProperties": false
},
{
"description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.",
"type": "object",
"required": [
"send_packet"
],
"properties": {
"send_packet": {
"type": "object",
"required": [
"channel_id",
"data",
"timeout"
],
"properties": {
"channel_id": {
"type": "string"
},
"data": {
"$ref": "#/definitions/Binary"
},
"timeout": {
"description": "when packet times out, measured on remote chain",
"allOf": [
{
"$ref": "#/definitions/IbcTimeout"
}
]
}
}
}
},
"additionalProperties": false
},
{
"description": "This will close an existing channel that is owned by this contract. Port is auto-assigned to the contract's IBC port",
"type": "object",
"required": [
"close_channel"
],
"properties": {
"close_channel": {
"type": "object",
"required": [
"channel_id"
],
"properties": {
"channel_id": {
"type": "string"
}
}
}
},
"additionalProperties": false
}
]
},
"IbcTimeout": {
"description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.",
"type": "object",
"properties": {
"block": {
"anyOf": [
{
"$ref": "#/definitions/IbcTimeoutBlock"
},
{
"type": "null"
}
]
},
"timestamp": {
"anyOf": [
{
"$ref": "#/definitions/Timestamp"
},
{
"type": "null"
}
]
}
}
},
"IbcTimeoutBlock": {
"description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)",
"type": "object",
"required": [
"height",
"revision"
],
"properties": {
"height": {
"description": "block height after which the packet times out. the height within the given revision",
"type": "integer",
"format": "uint64",
"minimum": 0.0
},
"revision": {
"description": "the version that the client is currently on (eg. after reseting the chain this could increment 1 as height drops to 0)",
"type": "integer",
"format": "uint64",
"minimum": 0.0
}
}
},
"ProposalResponse_for_Empty": {
"description": "Note, if you are storing custom messages in the proposal, the querier needs to know what possible custom message types those are in order to parse the response",
"type": "object",
@@ -623,90 +311,6 @@
},
"additionalProperties": false
},
"StakingMsg": {
"description": "The message types of the staking module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto",
"oneOf": [
{
"description": "This is translated to a [MsgDelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L81-L90). `delegator_address` is automatically filled with the current contract's address.",
"type": "object",
"required": [
"delegate"
],
"properties": {
"delegate": {
"type": "object",
"required": [
"amount",
"validator"
],
"properties": {
"amount": {
"$ref": "#/definitions/Coin"
},
"validator": {
"type": "string"
}
}
}
},
"additionalProperties": false
},
{
"description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.",
"type": "object",
"required": [
"undelegate"
],
"properties": {
"undelegate": {
"type": "object",
"required": [
"amount",
"validator"
],
"properties": {
"amount": {
"$ref": "#/definitions/Coin"
},
"validator": {
"type": "string"
}
}
}
},
"additionalProperties": false
},
{
"description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.",
"type": "object",
"required": [
"redelegate"
],
"properties": {
"redelegate": {
"type": "object",
"required": [
"amount",
"dst_validator",
"src_validator"
],
"properties": {
"amount": {
"$ref": "#/definitions/Coin"
},
"dst_validator": {
"type": "string"
},
"src_validator": {
"type": "string"
}
}
}
},
"additionalProperties": false
}
]
},
"Status": {
"oneOf": [
{
@@ -857,15 +461,6 @@
"description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```",
"type": "string"
},
"VoteOption": {
"type": "string",
"enum": [
"yes",
"no",
"abstain",
"no_with_veto"
]
},
"WasmMsg": {
"description": "The message types of the wasm module.\n\nSee https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto",
"oneOf": [
@@ -167,67 +167,6 @@
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"staking"
],
"properties": {
"staking": {
"$ref": "#/definitions/StakingMsg"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"distribution"
],
"properties": {
"distribution": {
"$ref": "#/definitions/DistributionMsg"
}
},
"additionalProperties": false
},
{
"description": "A Stargate message encoded the same way as a protobuf [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). This is the same structure as messages in `TxBody` from [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md)",
"type": "object",
"required": [
"stargate"
],
"properties": {
"stargate": {
"type": "object",
"required": [
"type_url",
"value"
],
"properties": {
"type_url": {
"type": "string"
},
"value": {
"$ref": "#/definitions/Binary"
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"ibc"
],
"properties": {
"ibc": {
"$ref": "#/definitions/IbcMsg"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
@@ -239,18 +178,6 @@
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"gov"
],
"properties": {
"gov": {
"$ref": "#/definitions/GovMsg"
}
},
"additionalProperties": false
}
]
},
@@ -318,55 +245,6 @@
},
"additionalProperties": false
},
"DistributionMsg": {
"description": "The message types of the distribution module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto",
"oneOf": [
{
"description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37). `delegator_address` is automatically filled with the current contract's address.",
"type": "object",
"required": [
"set_withdraw_address"
],
"properties": {
"set_withdraw_address": {
"type": "object",
"required": [
"address"
],
"properties": {
"address": {
"description": "The `withdraw_address`",
"type": "string"
}
}
}
},
"additionalProperties": false
},
{
"description": "This is translated to a [[MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.",
"type": "object",
"required": [
"withdraw_delegator_reward"
],
"properties": {
"withdraw_delegator_reward": {
"type": "object",
"required": [
"validator"
],
"properties": {
"validator": {
"description": "The `validator_address`",
"type": "string"
}
}
}
},
"additionalProperties": false
}
]
},
"Empty": {
"description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)",
"type": "object"
@@ -418,280 +296,6 @@
}
]
},
"GovMsg": {
"description": "This message type allows the contract interact with the [x/gov] module in order to cast votes.\n\n[x/gov]: https://github.com/cosmos/cosmos-sdk/tree/v0.45.12/x/gov\n\n## Examples\n\nCast a simple vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); use cosmwasm_std::{GovMsg, VoteOption};\n\n#[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result<Response, StdError> { // ... Ok(Response::new().add_message(GovMsg::Vote { proposal_id: 4, vote: VoteOption::Yes, })) } ```\n\nCast a weighted vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); # #[cfg(feature = \"cosmwasm_1_2\")] use cosmwasm_std::{Decimal, GovMsg, VoteOption, WeightedVoteOption};\n\n# #[cfg(feature = \"cosmwasm_1_2\")] #[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result<Response, StdError> { // ... Ok(Response::new().add_message(GovMsg::VoteWeighted { proposal_id: 4, options: vec![ WeightedVoteOption { option: VoteOption::Yes, weight: Decimal::percent(65), }, WeightedVoteOption { option: VoteOption::Abstain, weight: Decimal::percent(35), }, ], })) } ```",
"oneOf": [
{
"description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.",
"type": "object",
"required": [
"vote"
],
"properties": {
"vote": {
"type": "object",
"required": [
"proposal_id",
"vote"
],
"properties": {
"proposal_id": {
"type": "integer",
"format": "uint64",
"minimum": 0.0
},
"vote": {
"description": "The vote option.\n\nThis should be called \"option\" for consistency with Cosmos SDK. Sorry for that. See <https://github.com/CosmWasm/cosmwasm/issues/1571>.",
"allOf": [
{
"$ref": "#/definitions/VoteOption"
}
]
}
}
}
},
"additionalProperties": false
}
]
},
"IbcMsg": {
"description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)",
"oneOf": [
{
"description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.",
"type": "object",
"required": [
"transfer"
],
"properties": {
"transfer": {
"type": "object",
"required": [
"amount",
"channel_id",
"timeout",
"to_address"
],
"properties": {
"amount": {
"description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20",
"allOf": [
{
"$ref": "#/definitions/Coin"
}
]
},
"channel_id": {
"description": "exisiting channel to send the tokens over",
"type": "string"
},
"timeout": {
"description": "when packet times out, measured on remote chain",
"allOf": [
{
"$ref": "#/definitions/IbcTimeout"
}
]
},
"to_address": {
"description": "address on the remote chain to receive these tokens",
"type": "string"
}
}
}
},
"additionalProperties": false
},
{
"description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.",
"type": "object",
"required": [
"send_packet"
],
"properties": {
"send_packet": {
"type": "object",
"required": [
"channel_id",
"data",
"timeout"
],
"properties": {
"channel_id": {
"type": "string"
},
"data": {
"$ref": "#/definitions/Binary"
},
"timeout": {
"description": "when packet times out, measured on remote chain",
"allOf": [
{
"$ref": "#/definitions/IbcTimeout"
}
]
}
}
}
},
"additionalProperties": false
},
{
"description": "This will close an existing channel that is owned by this contract. Port is auto-assigned to the contract's IBC port",
"type": "object",
"required": [
"close_channel"
],
"properties": {
"close_channel": {
"type": "object",
"required": [
"channel_id"
],
"properties": {
"channel_id": {
"type": "string"
}
}
}
},
"additionalProperties": false
}
]
},
"IbcTimeout": {
"description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.",
"type": "object",
"properties": {
"block": {
"anyOf": [
{
"$ref": "#/definitions/IbcTimeoutBlock"
},
{
"type": "null"
}
]
},
"timestamp": {
"anyOf": [
{
"$ref": "#/definitions/Timestamp"
},
{
"type": "null"
}
]
}
}
},
"IbcTimeoutBlock": {
"description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)",
"type": "object",
"required": [
"height",
"revision"
],
"properties": {
"height": {
"description": "block height after which the packet times out. the height within the given revision",
"type": "integer",
"format": "uint64",
"minimum": 0.0
},
"revision": {
"description": "the version that the client is currently on (eg. after reseting the chain this could increment 1 as height drops to 0)",
"type": "integer",
"format": "uint64",
"minimum": 0.0
}
}
},
"StakingMsg": {
"description": "The message types of the staking module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto",
"oneOf": [
{
"description": "This is translated to a [MsgDelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L81-L90). `delegator_address` is automatically filled with the current contract's address.",
"type": "object",
"required": [
"delegate"
],
"properties": {
"delegate": {
"type": "object",
"required": [
"amount",
"validator"
],
"properties": {
"amount": {
"$ref": "#/definitions/Coin"
},
"validator": {
"type": "string"
}
}
}
},
"additionalProperties": false
},
{
"description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.",
"type": "object",
"required": [
"undelegate"
],
"properties": {
"undelegate": {
"type": "object",
"required": [
"amount",
"validator"
],
"properties": {
"amount": {
"$ref": "#/definitions/Coin"
},
"validator": {
"type": "string"
}
}
}
},
"additionalProperties": false
},
{
"description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.",
"type": "object",
"required": [
"redelegate"
],
"properties": {
"redelegate": {
"type": "object",
"required": [
"amount",
"dst_validator",
"src_validator"
],
"properties": {
"amount": {
"$ref": "#/definitions/Coin"
},
"dst_validator": {
"type": "string"
},
"src_validator": {
"type": "string"
}
}
}
},
"additionalProperties": false
}
]
},
"Status": {
"oneOf": [
{
@@ -842,15 +446,6 @@
"description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```",
"type": "string"
},
"VoteOption": {
"type": "string",
"enum": [
"yes",
"no",
"abstain",
"no_with_veto"
]
},
"WasmMsg": {
"description": "The message types of the wasm module.\n\nSee https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto",
"oneOf": [
@@ -121,67 +121,6 @@
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"staking"
],
"properties": {
"staking": {
"$ref": "#/definitions/StakingMsg"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"distribution"
],
"properties": {
"distribution": {
"$ref": "#/definitions/DistributionMsg"
}
},
"additionalProperties": false
},
{
"description": "A Stargate message encoded the same way as a protobuf [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). This is the same structure as messages in `TxBody` from [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md)",
"type": "object",
"required": [
"stargate"
],
"properties": {
"stargate": {
"type": "object",
"required": [
"type_url",
"value"
],
"properties": {
"type_url": {
"type": "string"
},
"value": {
"$ref": "#/definitions/Binary"
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"ibc"
],
"properties": {
"ibc": {
"$ref": "#/definitions/IbcMsg"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
@@ -193,18 +132,6 @@
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"gov"
],
"properties": {
"gov": {
"$ref": "#/definitions/GovMsg"
}
},
"additionalProperties": false
}
]
},
@@ -272,55 +199,6 @@
},
"additionalProperties": false
},
"DistributionMsg": {
"description": "The message types of the distribution module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto",
"oneOf": [
{
"description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37). `delegator_address` is automatically filled with the current contract's address.",
"type": "object",
"required": [
"set_withdraw_address"
],
"properties": {
"set_withdraw_address": {
"type": "object",
"required": [
"address"
],
"properties": {
"address": {
"description": "The `withdraw_address`",
"type": "string"
}
}
}
},
"additionalProperties": false
},
{
"description": "This is translated to a [[MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.",
"type": "object",
"required": [
"withdraw_delegator_reward"
],
"properties": {
"withdraw_delegator_reward": {
"type": "object",
"required": [
"validator"
],
"properties": {
"validator": {
"description": "The `validator_address`",
"type": "string"
}
}
}
},
"additionalProperties": false
}
]
},
"Empty": {
"description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)",
"type": "object"
@@ -372,196 +250,6 @@
}
]
},
"GovMsg": {
"description": "This message type allows the contract interact with the [x/gov] module in order to cast votes.\n\n[x/gov]: https://github.com/cosmos/cosmos-sdk/tree/v0.45.12/x/gov\n\n## Examples\n\nCast a simple vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); use cosmwasm_std::{GovMsg, VoteOption};\n\n#[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result<Response, StdError> { // ... Ok(Response::new().add_message(GovMsg::Vote { proposal_id: 4, vote: VoteOption::Yes, })) } ```\n\nCast a weighted vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); # #[cfg(feature = \"cosmwasm_1_2\")] use cosmwasm_std::{Decimal, GovMsg, VoteOption, WeightedVoteOption};\n\n# #[cfg(feature = \"cosmwasm_1_2\")] #[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result<Response, StdError> { // ... Ok(Response::new().add_message(GovMsg::VoteWeighted { proposal_id: 4, options: vec![ WeightedVoteOption { option: VoteOption::Yes, weight: Decimal::percent(65), }, WeightedVoteOption { option: VoteOption::Abstain, weight: Decimal::percent(35), }, ], })) } ```",
"oneOf": [
{
"description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.",
"type": "object",
"required": [
"vote"
],
"properties": {
"vote": {
"type": "object",
"required": [
"proposal_id",
"vote"
],
"properties": {
"proposal_id": {
"type": "integer",
"format": "uint64",
"minimum": 0.0
},
"vote": {
"description": "The vote option.\n\nThis should be called \"option\" for consistency with Cosmos SDK. Sorry for that. See <https://github.com/CosmWasm/cosmwasm/issues/1571>.",
"allOf": [
{
"$ref": "#/definitions/VoteOption"
}
]
}
}
}
},
"additionalProperties": false
}
]
},
"IbcMsg": {
"description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)",
"oneOf": [
{
"description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.",
"type": "object",
"required": [
"transfer"
],
"properties": {
"transfer": {
"type": "object",
"required": [
"amount",
"channel_id",
"timeout",
"to_address"
],
"properties": {
"amount": {
"description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20",
"allOf": [
{
"$ref": "#/definitions/Coin"
}
]
},
"channel_id": {
"description": "exisiting channel to send the tokens over",
"type": "string"
},
"timeout": {
"description": "when packet times out, measured on remote chain",
"allOf": [
{
"$ref": "#/definitions/IbcTimeout"
}
]
},
"to_address": {
"description": "address on the remote chain to receive these tokens",
"type": "string"
}
}
}
},
"additionalProperties": false
},
{
"description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.",
"type": "object",
"required": [
"send_packet"
],
"properties": {
"send_packet": {
"type": "object",
"required": [
"channel_id",
"data",
"timeout"
],
"properties": {
"channel_id": {
"type": "string"
},
"data": {
"$ref": "#/definitions/Binary"
},
"timeout": {
"description": "when packet times out, measured on remote chain",
"allOf": [
{
"$ref": "#/definitions/IbcTimeout"
}
]
}
}
}
},
"additionalProperties": false
},
{
"description": "This will close an existing channel that is owned by this contract. Port is auto-assigned to the contract's IBC port",
"type": "object",
"required": [
"close_channel"
],
"properties": {
"close_channel": {
"type": "object",
"required": [
"channel_id"
],
"properties": {
"channel_id": {
"type": "string"
}
}
}
},
"additionalProperties": false
}
]
},
"IbcTimeout": {
"description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.",
"type": "object",
"properties": {
"block": {
"anyOf": [
{
"$ref": "#/definitions/IbcTimeoutBlock"
},
{
"type": "null"
}
]
},
"timestamp": {
"anyOf": [
{
"$ref": "#/definitions/Timestamp"
},
{
"type": "null"
}
]
}
}
},
"IbcTimeoutBlock": {
"description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)",
"type": "object",
"required": [
"height",
"revision"
],
"properties": {
"height": {
"description": "block height after which the packet times out. the height within the given revision",
"type": "integer",
"format": "uint64",
"minimum": 0.0
},
"revision": {
"description": "the version that the client is currently on (eg. after reseting the chain this could increment 1 as height drops to 0)",
"type": "integer",
"format": "uint64",
"minimum": 0.0
}
}
},
"ProposalResponse_for_Empty": {
"description": "Note, if you are storing custom messages in the proposal, the querier needs to know what possible custom message types those are in order to parse the response",
"type": "object",
@@ -623,90 +311,6 @@
},
"additionalProperties": false
},
"StakingMsg": {
"description": "The message types of the staking module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto",
"oneOf": [
{
"description": "This is translated to a [MsgDelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L81-L90). `delegator_address` is automatically filled with the current contract's address.",
"type": "object",
"required": [
"delegate"
],
"properties": {
"delegate": {
"type": "object",
"required": [
"amount",
"validator"
],
"properties": {
"amount": {
"$ref": "#/definitions/Coin"
},
"validator": {
"type": "string"
}
}
}
},
"additionalProperties": false
},
{
"description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.",
"type": "object",
"required": [
"undelegate"
],
"properties": {
"undelegate": {
"type": "object",
"required": [
"amount",
"validator"
],
"properties": {
"amount": {
"$ref": "#/definitions/Coin"
},
"validator": {
"type": "string"
}
}
}
},
"additionalProperties": false
},
{
"description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.",
"type": "object",
"required": [
"redelegate"
],
"properties": {
"redelegate": {
"type": "object",
"required": [
"amount",
"dst_validator",
"src_validator"
],
"properties": {
"amount": {
"$ref": "#/definitions/Coin"
},
"dst_validator": {
"type": "string"
},
"src_validator": {
"type": "string"
}
}
}
},
"additionalProperties": false
}
]
},
"Status": {
"oneOf": [
{
@@ -857,15 +461,6 @@
"description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```",
"type": "string"
},
"VoteOption": {
"type": "string",
"enum": [
"yes",
"no",
"abstain",
"no_with_veto"
]
},
"WasmMsg": {
"description": "The message types of the wasm module.\n\nSee https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto",
"oneOf": [
+2 -2
View File
@@ -43,7 +43,7 @@ turn-off = true
[preprocessor.admonish]
command = "mdbook-admonish"
assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install`
assets_version = "3.0.0" # do not edit: managed by `mdbook-admonish install`
# variables preprocessor: import variables into files
# https://gitlab.com/tglman/mdbook-variables/
@@ -76,7 +76,7 @@ curly-quotes = true
# mathjax-support = false # useful if we want to pull equations in ?
copy-fonts = true
no-section-label = false
additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "custom.css"]
additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "custom.css", "./mdbook-admonish.css"]
additional-js = ["theme/pagetoc.js"]
git-repository-url = "https://github.com/nymtech/nym"
git-repository-icon = "fa-github"
+81 -92
View File
@@ -1,31 +1,18 @@
@charset "UTF-8";
:root {
--md-admonition-icon--note:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z'/></svg>");
--md-admonition-icon--abstract:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17 9H7V7h10m0 6H7v-2h10m-3 6H7v-2h7M12 3a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1m7 0h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2z'/></svg>");
--md-admonition-icon--info:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 9h-2V7h2m0 10h-2v-6h2m-1-9A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2z'/></svg>");
--md-admonition-icon--tip:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17.66 11.2c-.23-.3-.51-.56-.77-.82-.67-.6-1.43-1.03-2.07-1.66C13.33 7.26 13 4.85 13.95 3c-.95.23-1.78.75-2.49 1.32-2.59 2.08-3.61 5.75-2.39 8.9.04.1.08.2.08.33 0 .22-.15.42-.35.5-.23.1-.47.04-.66-.12a.58.58 0 0 1-.14-.17c-1.13-1.43-1.31-3.48-.55-5.12C5.78 10 4.87 12.3 5 14.47c.06.5.12 1 .29 1.5.14.6.41 1.2.71 1.73 1.08 1.73 2.95 2.97 4.96 3.22 2.14.27 4.43-.12 6.07-1.6 1.83-1.66 2.47-4.32 1.53-6.6l-.13-.26c-.21-.46-.77-1.26-.77-1.26m-3.16 6.3c-.28.24-.74.5-1.1.6-1.12.4-2.24-.16-2.9-.82 1.19-.28 1.9-1.16 2.11-2.05.17-.8-.15-1.46-.28-2.23-.12-.74-.1-1.37.17-2.06.19.38.39.76.63 1.06.77 1 1.98 1.44 2.24 2.8.04.14.06.28.06.43.03.82-.33 1.72-.93 2.27z'/></svg>");
--md-admonition-icon--success:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m9 20.42-6.21-6.21 2.83-2.83L9 14.77l9.88-9.89 2.83 2.83L9 20.42z'/></svg>");
--md-admonition-icon--question:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m15.07 11.25-.9.92C13.45 12.89 13 13.5 13 15h-2v-.5c0-1.11.45-2.11 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41a2 2 0 0 0-2-2 2 2 0 0 0-2 2H8a4 4 0 0 1 4-4 4 4 0 0 1 4 4 3.2 3.2 0 0 1-.93 2.25M13 19h-2v-2h2M12 2A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10c0-5.53-4.5-10-10-10z'/></svg>");
--md-admonition-icon--warning:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 14h-2V9h2m0 9h-2v-2h2M1 21h22L12 2 1 21z'/></svg>");
--md-admonition-icon--failure:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20 6.91 17.09 4 12 9.09 6.91 4 4 6.91 9.09 12 4 17.09 6.91 20 12 14.91 17.09 20 20 17.09 14.91 12 20 6.91z'/></svg>");
--md-admonition-icon--danger:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 15H6l7-14v8h5l-7 14v-8z'/></svg>");
--md-admonition-icon--bug:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 12h-4v-2h4m0 6h-4v-2h4m6-6h-2.81a5.985 5.985 0 0 0-1.82-1.96L17 4.41 15.59 3l-2.17 2.17a6.002 6.002 0 0 0-2.83 0L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8z'/></svg>");
--md-admonition-icon--example:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M7 13v-2h14v2H7m0 6v-2h14v2H7M7 7V5h14v2H7M3 8V5H2V4h2v4H3m-1 9v-1h3v4H2v-1h2v-.5H3v-1h1V17H2m2.25-7a.75.75 0 0 1 .75.75c0 .2-.08.39-.21.52L3.12 13H5v1H2v-.92L4 11H2v-1h2.25z'/></svg>");
--md-admonition-icon--quote:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 17h3l2-4V7h-6v6h3M6 17h3l2-4V7H5v6h3l-2 4z'/></svg>");
--md-details-icon:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M8.59 16.58 13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42Z'/></svg>");
--md-admonition-icon--admonish-note: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z'/></svg>");
--md-admonition-icon--admonish-abstract: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17 9H7V7h10m0 6H7v-2h10m-3 6H7v-2h7M12 3a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1m7 0h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2z'/></svg>");
--md-admonition-icon--admonish-info: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 9h-2V7h2m0 10h-2v-6h2m-1-9A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2z'/></svg>");
--md-admonition-icon--admonish-tip: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17.66 11.2c-.23-.3-.51-.56-.77-.82-.67-.6-1.43-1.03-2.07-1.66C13.33 7.26 13 4.85 13.95 3c-.95.23-1.78.75-2.49 1.32-2.59 2.08-3.61 5.75-2.39 8.9.04.1.08.2.08.33 0 .22-.15.42-.35.5-.23.1-.47.04-.66-.12a.58.58 0 0 1-.14-.17c-1.13-1.43-1.31-3.48-.55-5.12C5.78 10 4.87 12.3 5 14.47c.06.5.12 1 .29 1.5.14.6.41 1.2.71 1.73 1.08 1.73 2.95 2.97 4.96 3.22 2.14.27 4.43-.12 6.07-1.6 1.83-1.66 2.47-4.32 1.53-6.6l-.13-.26c-.21-.46-.77-1.26-.77-1.26m-3.16 6.3c-.28.24-.74.5-1.1.6-1.12.4-2.24-.16-2.9-.82 1.19-.28 1.9-1.16 2.11-2.05.17-.8-.15-1.46-.28-2.23-.12-.74-.1-1.37.17-2.06.19.38.39.76.63 1.06.77 1 1.98 1.44 2.24 2.8.04.14.06.28.06.43.03.82-.33 1.72-.93 2.27z'/></svg>");
--md-admonition-icon--admonish-success: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m9 20.42-6.21-6.21 2.83-2.83L9 14.77l9.88-9.89 2.83 2.83L9 20.42z'/></svg>");
--md-admonition-icon--admonish-question: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m15.07 11.25-.9.92C13.45 12.89 13 13.5 13 15h-2v-.5c0-1.11.45-2.11 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41a2 2 0 0 0-2-2 2 2 0 0 0-2 2H8a4 4 0 0 1 4-4 4 4 0 0 1 4 4 3.2 3.2 0 0 1-.93 2.25M13 19h-2v-2h2M12 2A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10c0-5.53-4.5-10-10-10z'/></svg>");
--md-admonition-icon--admonish-warning: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 14h-2V9h2m0 9h-2v-2h2M1 21h22L12 2 1 21z'/></svg>");
--md-admonition-icon--admonish-failure: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20 6.91 17.09 4 12 9.09 6.91 4 4 6.91 9.09 12 4 17.09 6.91 20 12 14.91 17.09 20 20 17.09 14.91 12 20 6.91z'/></svg>");
--md-admonition-icon--admonish-danger: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 15H6l7-14v8h5l-7 14v-8z'/></svg>");
--md-admonition-icon--admonish-bug: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 12h-4v-2h4m0 6h-4v-2h4m6-6h-2.81a5.985 5.985 0 0 0-1.82-1.96L17 4.41 15.59 3l-2.17 2.17a6.002 6.002 0 0 0-2.83 0L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8z'/></svg>");
--md-admonition-icon--admonish-example: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M7 13v-2h14v2H7m0 6v-2h14v2H7M7 7V5h14v2H7M3 8V5H2V4h2v4H3m-1 9v-1h3v4H2v-1h2v-.5H3v-1h1V17H2m2.25-7a.75.75 0 0 1 .75.75c0 .2-.08.39-.21.52L3.12 13H5v1H2v-.92L4 11H2v-1h2.25z'/></svg>");
--md-admonition-icon--admonish-quote: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 17h3l2-4V7h-6v6h3M6 17h3l2-4V7H5v6h3l-2 4z'/></svg>");
--md-details-icon: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M8.59 16.58 13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42Z'/></svg>");
}
:is(.admonition) {
@@ -75,8 +62,9 @@ a.admonition-anchor-link::before {
content: "§";
}
:is(.admonition-title, summary) {
:is(.admonition-title, summary.admonition-title) {
position: relative;
min-height: 4rem;
margin-block: 0;
margin-inline: -1.6rem -1.2rem;
padding-block: 0.8rem;
@@ -85,13 +73,13 @@ a.admonition-anchor-link::before {
background-color: rgba(68, 138, 255, 0.1);
display: flex;
}
:is(.admonition-title, summary) p {
:is(.admonition-title, summary.admonition-title) p {
margin: 0;
}
html :is(.admonition-title, summary):last-child {
html :is(.admonition-title, summary.admonition-title):last-child {
margin-bottom: 0;
}
:is(.admonition-title, summary)::before {
:is(.admonition-title, summary.admonition-title)::before {
position: absolute;
top: 0.625em;
inset-inline-start: 1.6rem;
@@ -106,7 +94,7 @@ html :is(.admonition-title, summary):last-child {
-webkit-mask-size: contain;
content: "";
}
:is(.admonition-title, summary):hover a.admonition-anchor-link {
:is(.admonition-title, summary.admonition-title):hover a.admonition-anchor-link {
display: initial;
}
@@ -131,204 +119,204 @@ details[open].admonition > summary.admonition-title::after {
transform: rotate(90deg);
}
:is(.admonition):is(.note) {
:is(.admonition):is(.admonish-note) {
border-color: #448aff;
}
:is(.note) > :is(.admonition-title, summary) {
:is(.admonish-note) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(68, 138, 255, 0.1);
}
:is(.note) > :is(.admonition-title, summary)::before {
:is(.admonish-note) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #448aff;
mask-image: var(--md-admonition-icon--note);
-webkit-mask-image: var(--md-admonition-icon--note);
mask-image: var(--md-admonition-icon--admonish-note);
-webkit-mask-image: var(--md-admonition-icon--admonish-note);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.abstract, .summary, .tldr) {
:is(.admonition):is(.admonish-abstract, .admonish-summary, .admonish-tldr) {
border-color: #00b0ff;
}
:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary) {
:is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(0, 176, 255, 0.1);
}
:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary)::before {
:is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #00b0ff;
mask-image: var(--md-admonition-icon--abstract);
-webkit-mask-image: var(--md-admonition-icon--abstract);
mask-image: var(--md-admonition-icon--admonish-abstract);
-webkit-mask-image: var(--md-admonition-icon--admonish-abstract);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.info, .todo) {
:is(.admonition):is(.admonish-info, .admonish-todo) {
border-color: #00b8d4;
}
:is(.info, .todo) > :is(.admonition-title, summary) {
:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(0, 184, 212, 0.1);
}
:is(.info, .todo) > :is(.admonition-title, summary)::before {
:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #00b8d4;
mask-image: var(--md-admonition-icon--info);
-webkit-mask-image: var(--md-admonition-icon--info);
mask-image: var(--md-admonition-icon--admonish-info);
-webkit-mask-image: var(--md-admonition-icon--admonish-info);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.tip, .hint, .important) {
:is(.admonition):is(.admonish-tip, .admonish-hint, .admonish-important) {
border-color: #00bfa5;
}
:is(.tip, .hint, .important) > :is(.admonition-title, summary) {
:is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(0, 191, 165, 0.1);
}
:is(.tip, .hint, .important) > :is(.admonition-title, summary)::before {
:is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #00bfa5;
mask-image: var(--md-admonition-icon--tip);
-webkit-mask-image: var(--md-admonition-icon--tip);
mask-image: var(--md-admonition-icon--admonish-tip);
-webkit-mask-image: var(--md-admonition-icon--admonish-tip);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.success, .check, .done) {
:is(.admonition):is(.admonish-success, .admonish-check, .admonish-done) {
border-color: #00c853;
}
:is(.success, .check, .done) > :is(.admonition-title, summary) {
:is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(0, 200, 83, 0.1);
}
:is(.success, .check, .done) > :is(.admonition-title, summary)::before {
:is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #00c853;
mask-image: var(--md-admonition-icon--success);
-webkit-mask-image: var(--md-admonition-icon--success);
mask-image: var(--md-admonition-icon--admonish-success);
-webkit-mask-image: var(--md-admonition-icon--admonish-success);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.question, .help, .faq) {
:is(.admonition):is(.admonish-question, .admonish-help, .admonish-faq) {
border-color: #64dd17;
}
:is(.question, .help, .faq) > :is(.admonition-title, summary) {
:is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(100, 221, 23, 0.1);
}
:is(.question, .help, .faq) > :is(.admonition-title, summary)::before {
:is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #64dd17;
mask-image: var(--md-admonition-icon--question);
-webkit-mask-image: var(--md-admonition-icon--question);
mask-image: var(--md-admonition-icon--admonish-question);
-webkit-mask-image: var(--md-admonition-icon--admonish-question);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.warning, .caution, .attention) {
:is(.admonition):is(.admonish-warning, .admonish-caution, .admonish-attention) {
border-color: #ff9100;
}
:is(.warning, .caution, .attention) > :is(.admonition-title, summary) {
:is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(255, 145, 0, 0.1);
}
:is(.warning, .caution, .attention) > :is(.admonition-title, summary)::before {
:is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #ff9100;
mask-image: var(--md-admonition-icon--warning);
-webkit-mask-image: var(--md-admonition-icon--warning);
mask-image: var(--md-admonition-icon--admonish-warning);
-webkit-mask-image: var(--md-admonition-icon--admonish-warning);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.failure, .fail, .missing) {
:is(.admonition):is(.admonish-failure, .admonish-fail, .admonish-missing) {
border-color: #ff5252;
}
:is(.failure, .fail, .missing) > :is(.admonition-title, summary) {
:is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(255, 82, 82, 0.1);
}
:is(.failure, .fail, .missing) > :is(.admonition-title, summary)::before {
:is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #ff5252;
mask-image: var(--md-admonition-icon--failure);
-webkit-mask-image: var(--md-admonition-icon--failure);
mask-image: var(--md-admonition-icon--admonish-failure);
-webkit-mask-image: var(--md-admonition-icon--admonish-failure);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.danger, .error) {
:is(.admonition):is(.admonish-danger, .admonish-error) {
border-color: #ff1744;
}
:is(.danger, .error) > :is(.admonition-title, summary) {
:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(255, 23, 68, 0.1);
}
:is(.danger, .error) > :is(.admonition-title, summary)::before {
:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #ff1744;
mask-image: var(--md-admonition-icon--danger);
-webkit-mask-image: var(--md-admonition-icon--danger);
mask-image: var(--md-admonition-icon--admonish-danger);
-webkit-mask-image: var(--md-admonition-icon--admonish-danger);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.bug) {
:is(.admonition):is(.admonish-bug) {
border-color: #f50057;
}
:is(.bug) > :is(.admonition-title, summary) {
:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(245, 0, 87, 0.1);
}
:is(.bug) > :is(.admonition-title, summary)::before {
:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #f50057;
mask-image: var(--md-admonition-icon--bug);
-webkit-mask-image: var(--md-admonition-icon--bug);
mask-image: var(--md-admonition-icon--admonish-bug);
-webkit-mask-image: var(--md-admonition-icon--admonish-bug);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.example) {
:is(.admonition):is(.admonish-example) {
border-color: #7c4dff;
}
:is(.example) > :is(.admonition-title, summary) {
:is(.admonish-example) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(124, 77, 255, 0.1);
}
:is(.example) > :is(.admonition-title, summary)::before {
:is(.admonish-example) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #7c4dff;
mask-image: var(--md-admonition-icon--example);
-webkit-mask-image: var(--md-admonition-icon--example);
mask-image: var(--md-admonition-icon--admonish-example);
-webkit-mask-image: var(--md-admonition-icon--admonish-example);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.quote, .cite) {
:is(.admonition):is(.admonish-quote, .admonish-cite) {
border-color: #9e9e9e;
}
:is(.quote, .cite) > :is(.admonition-title, summary) {
:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(158, 158, 158, 0.1);
}
:is(.quote, .cite) > :is(.admonition-title, summary)::before {
:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #9e9e9e;
mask-image: var(--md-admonition-icon--quote);
-webkit-mask-image: var(--md-admonition-icon--quote);
mask-image: var(--md-admonition-icon--admonish-quote);
-webkit-mask-image: var(--md-admonition-icon--admonish-quote);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
@@ -339,7 +327,8 @@ details[open].admonition > summary.admonition-title::after {
background-color: var(--sidebar-bg);
}
.ayu :is(.admonition), .coal :is(.admonition) {
.ayu :is(.admonition),
.coal :is(.admonition) {
background-color: var(--theme-hover);
}
+6 -1
View File
@@ -50,8 +50,13 @@
- [Sending a Message Through the Mixnet](tutorials/simple-service-provider/sending-message.md)
# FAQ
# Events
- [Web3Privacy Now](./events/web3-privacy.md)
- [HCPP23-serinko](./events/hcpp23-serinko.md)
- [HCPP23-max](./events/hcpp23-max.md)
# FAQ
- [General](faq/general-faq.md)
- [Integrations](faq/integrations-faq.md)
- [Rewards & Token](faq/rewards-faq.md)
@@ -0,0 +1,34 @@
# HCPP23 - Building with Nym workshop
This is a *reference page*, to see the entire presentation join Max's talk at [HCPP 2023](https://resistance.hcpp.cz/) on [Satuday](https://cfp.paralelnipolis.cz/hcpp23/talk/LLPWXW/).
## Mixnet architecture
* [Mixnet motivations](https://nymtech.net/developers/infrastructure/nym.html)
* [Mixnet architecture overview](https://nymtech.net/docs/architecture/network-overview.html)
* [Mixnet traffic flow](https://nymtech.net/docs/architecture/traffic-flow.html)
* [Tor + VPN comparison](https://nymtech.net/developers/infrastructure/nym-vs-others.html)
* [Addressing system](https://nymtech.net/docs/clients/addressing-system.html)
## Clients
* [Clients overview](https://nymtech.net/docs/clients/overview.html)
## SDKs
* [Rust SDK](https://nymtech.net/docs/sdk/rust.html)
* [Typescript SDK](https://nymtech.net/docs/sdk/typescript.html)
* [Interactive Typescript SDK docs](https://sdk.nymtech.net)
### Rust examples
* [Libp2p examples](https://github.com/nymtech/nym/tree/develop/sdk/rust/nym-sdk/examples)
* [Lighthouse PoC](https://github.com/ChainSafe/lighthouse/blob/nym/USE_NYM.md)
* [Dev tutoral: chain service](https://nymtech.net/developers/tutorials/cosmos-service/intro.html)
* [Community: Darkfi over Nym](https://darkrenaissance.github.io/darkfi/clients/nym_outbound.html?highlight=nym#3--run)
### Typescript
* [Mixfetch NPM](https://www.npmjs.com/package/@nymproject/mix-fetch)
* [Interactive Typescript SDK docs](https://sdk.nymtech.net)
@@ -0,0 +1,323 @@
# HCPP 2023 - Securing the Lunarpunks Workshop
[Serinko's](https://resistance.hcpp.cz/) [workshop](ttps://cfp.paralelnipolis.cz/hcpp23/talk/LLPWXW/) will introduce ***why*** and ***how to use [Nym](https://nymtech.net) platform as a network protection*** layer when using some of our favorite privacy applications. This page serves as an accessible guide alongside the talk and it includes all the steps, pre-requisities and dependencies needed. Preferably the users interested in this setup start downloading and building the tools before the workshop or in the beginning of it. We can use the limited time for questions and addressing problems. This guide will stay online after the event just in case people were not finished and want to catch up later.
This page is a *how to guide* so it contains the setup only, to see the entire presentation join in at [HCPP 2023](https://resistance.hcpp.cz/) on [Sunday](https://cfp.paralelnipolis.cz/hcpp23/talk/LLPWXW/).
## Preparation
During this workshop we will introduce [NymConnect](https://nymtech.net/developers/quickstart/nymconnect-gui.html) and [Socks5 client](https://nymtech.net/docs/clients/socks5-client.html). The difference between them is that the Socks5 client does everything Nymconnect does, but it has more optionality and it's run from a commandline. NymConnect is a one-button GUI application that wraps around the `nym-socks5-client` for proxying application traffic through the Mixnet.
We will learn how to run through [Nym Mixnet](https://nymtech.net/docs/architecture/network-overview.html) the following applications: Electrum Bitcoin wallet, Monero wallet (desktop and CLI), Matrix (Element app) and ircd chat. For those who want to run ircd through the Mixnet, `nym-socks5-client` client is a must. For all other applications you can choose if you settle with our slick app NymConnect which does all the job in the background or you prefer Socks5 client.
> Any syntax in `<>` brackets is a user's/version unique variable. Exchange with a corresponding name without the `<>` brackets.
## NymConnect Installation
NymConnect application is for everyone who does not want to install and run `nym-socks5-client`. NymConnect is plug-and-play, fast and easy use. Electrum Bitcoin wallet, Monero wallet (desktop and CLI) and Matrix (Element app) connects through NymConnect automatically to the Mixnet.
1. [Download](https://nymtech.net/download/nymconnect) NymConnect
2. On Linux and Mac, make executable by opening terminal in the same directory and run:
```sh
chmod +x ./nym-connect_<VERSION>.AppImage
```
3. Start the application
4. Click on `Connect` button to initialise the connection with the Mixnet
5. Anytime you'll need to setup Host and Port in your applications, click on `IP` and `Port` to copy the values to clipboard
6. In case you have problems such as `Gateway Issues`, try to reconnect or restart the application
## Connect Privacy Enhanced Applications (PEApps)
For simplification in this guide we connect Electrum, Monero wallet and Matrix (Element) using NymConnect and ircd over `nym-socks5-client`. Of course if your choice is to run `nym-socks5-client` all these apps will connect through that and you don't need to install NymConnect.
```admonish info
This guide aims to connect your favourite applications to Nym Mixnet, therefore we do not include detailed guides on how to install them, only reference to the source pages.
```
### Electrum Bitcoin wallet via NymConnect
To download Electrum visit the [official webpage](https://electrum.org/#download). To connect to the Mixnet follow these steps:
1. Start and connect [NymConnect](./hcpp23-serinko.html#nymconnect-installation) (or [`nym-socks5-client`](./hcpp23-serinko.html#building-nym-platform))
2. Start your Electrum Bitcoin wallet
3. Go to: *Tools* -> *Network* -> *Proxy*
4. Set *Use proxy* to ✅, choose `SOCKS5` from the drop-down and add the values from your NymConnect application
5. Now your Electrum Bitcoin wallet runs through the Mixnet and it will be connected only if your NymConnect or `nym-socks5-client` are connected.
![Electrum Bitcoin wallet setup](../images/electrum_tutorial/electrum.gif)
### Monero wallet via NymConnect
To download Monero wallet visit [getmonero.org](https://www.getmonero.org/downloads/). To connect to the Mixnet follow these steps:
1. Start and connect [NymConnect](./hcpp23-serinko.html#nymconnect-installation) (or [`nym-socks5-client`](./hcpp23-serinko.html#building-nym-platform))
2. Start your Monero wallet
3. Go to: *Settings* -> *Interface* -> *Socks5 proxy* -> Add values: IP address `127.0.0.1`, Port `1080` (the values copied from NymConnect)
5. Now your Monero wallet runs through the Mixnet and it will be connected only if your NymConnect or `nym-socks5-client` are connected.
![Monero wallet setup](../images/monero_tutorial/monero-gui-NC.gif)
If you prefer to run Monero-CLI wallet with Monerod, please check out [this guide](https://nymtech.net/developers/tutorials/monero.html#how-can-i-use-monero-over-the-nym-mixnet).
### Matrix (Element) via NymConnect
To download Element (chat client for Matrix) visit [element.io](https://element.io/download). To connect to the Mixnet follow these steps:
1. Start and connect [NymConnect](./hcpp23-serinko.html#nymconnect-installation) (or [`nym-socks5-client`](./hcpp23-serinko.html#building-nym-platform))
2. Start `element-desktop` with `--proxy-server` argument:
**Linux**
```sh
element-desktop --proxy-server=socks5://127.0.0.1:1080
```
**Mac**
```sh
open -a Element --args --proxy-server=socks5://127.0.0.1:1080
```
To setup your own alias or key-binding see our [*Matrix NymConnect Integration* guide](https://nymtech.net/developers/tutorials/matrix.html#optimise-setup-with-a-keybinding--alias).
## Building Nym Platform
If you prefer to run to run `nym-socks5-client` the possibility is to download the pre-build binary or build the entire platform. To run ircd through the Mixnet `nym-socks5-client` and `nym-network-requester` are mandatory. Before you start with download and installation, make sure you are on the same machine from which you will connect to ircd.
We recommend to clone and build the entire platform instead of individual binaries as it offers an easier update and more options down the road, however it takes a basic command-line knowledge and more time. The [Nym platform](https://github.com/nymtech/nym) is written in Rust. For that to work we will need a few pre-requisities. If you prefer to download individual pre-build binaries, skip this part and go directly [that chapter](./hcpp23-serinko.html#pre-built-binaries).
### Prerequisites
- Debian/Ubuntu: `pkg-config`, `build-essential`, `libssl-dev`, `curl`, `jq`, `git`
```sh
apt install pkg-config build-essential libssl-dev curl jq git
```
- Arch/Manjaro: `base-devel`
```sh
pacman -S base-devel
```
- Mac OS X: `pkg-config` , `brew`, `openss1`, `protobuf`, `curl`, `git`
Running the following the script installs Homebrew and the above dependencies:
```sh
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```
- `Rust & cargo >= {{minimum_rust_version}}`
We recommend using the [Rust shell script installer](https://www.rust-lang.org/tools/install). Installing cargo from your package manager (e.g. `apt`) is not recommended as the packaged versions are usually too old.
If you really don't want to use the shell script installer, the [Rust installation docs](https://forge.rust-lang.org/infra/other-installation-methods.html) contain instructions for many platforms.
### Download and Compile Nym
The following commands will compile binaries into the `nym/target/release` directory:
```sh
rustup update
git clone https://github.com/nymtech/nym.git
cd nym
git checkout master # master branch has the latest release version: `develop` will most likely be incompatible with deployed public networks
cargo build --release # build your binaries with **mainnet** configuration
```
Quite a bit of stuff gets built. The key working parts for the workshop are:
* [socks5 client](https://nymtech.net/docs/clients/socks5-client.html): `nym-socks5-client`
* [network requester](https://nymtech.net/operators/nodes/network-requester-setup.html): `nym-network-requester`
## Pre-built Binaries
The [Github releases page](https://github.com/nymtech/nym/releases) has pre-built binaries which should work on Ubuntu 20.04 and other Debian-based systems, but at this stage cannot be guaranteed to work everywhere.
**Download:** Find the binary of your choice, right click on the binary, select *Copy Link*. This will save the binary `<URL>` to clipboard. Run the following commands on your machine:
```
wget <URL> # to download the binary
```
If the pre-built binaries don't work or are unavailable for your system, you will need to [build the platform](./hcpp23-serinko.html#building-nym-platform) yourself.
All Nym binaries must first be made executable.
To make a binary executable, open terminal in the same directory and run:
```sh
chmod +x ./<BINARY_NAME>
# for example: chmod +x ./nym-network-requester
```
## Initialize Socks5 Client and Network Requester
Whether you build the entire platform or downloaded binaries, `nym-socks5-client` and `nym-network-requester` need to be initialised with `init` before being `run`.
In your terminal navigate to the directory where you have your `nym-socks5-client` and `nym-network-requester`. In case you built the entire platform it's in `nym/target/release`.
```sh
# change directory from nym repo
cd target/release
```
**Network Requester**
The `init` command is usually where you pass flags specifying configuration arguments such as the gateway you wish to communicate with, the ports you wish your binary to listen on, etc.
The `init` command will also create the necessary keypairs and configuration files at `~/.nym/<BINARY_TYPE>/<BINARY_ID>/` if these files do not already exist. **It will NOT overwrite existing keypairs if they are present.**
To run [ircd](https://darkrenaissance.github.io/darkfi/clients/nym_outbound.html) through the Mixnet you need to run your own [Network Requester](https://nymtech.net/operators/nodes/network-requester-setup.html) and add known peer's domains/addresses to `~/.nym/service-providers/network-requester/<NETWORK-REQUESTER-ID>/data/allowed.list`. For all other applications `nym-socks5-client` (or NymCOnnect) is enough, no need to initialize and run `nym-network-requester`.
Here are the steps to initialize `nym-network-requester`:
```sh
# open the directory with your binaries
./nym-network-requester init --id <CHOOSE_ANY_NAME_AS_ID>
```
This will print you information about your client `<ADDRESS>`, it will look like:
```sh
The address of this client is: 8hUvtEyZK8umsdxxPS2BizQhEDmbNeXEPBZLgscE57Zh.5P2bWn6WybVL8QgoPEUHf6h2zXktmwrWaqaucEBZy7Vb@5vC8spDvw5VDQ8Zvd9fVvBhbUDv9jABR4cXzd4Kh5vz
```
**Socks5 Client**
If you run `nym-socks5-client` instead of NymConnect, you can choose your `--provider` [here](https://explorer.nymtech.net/network-components/service-providers) or leave that flag empty and your client will chose one randomly. To run ircd, you will need to connect it to your `nym-network-requester` by using your `<ADDRESS>` for your `nym-socks5-client` initialisation and add a flag `--use-reply-surbs true`. Run the command in the next terminal window:
```sh
# to connect to your nym-network-requester as a provider for ircd
./nym-socks5-client init --use-reply-surbs true --id <CHOSE_ANY_NAME_AS_ID> --provider <ADDRESS>
# simple socks5 client init (random provider) for other apps
./nym-socks5-client init --id <CHOSE_ANY_NAME_AS_ID>
```
```admonish info
You can reconfigure your binaries at any time by editing the config file located at `~/.nym/service-providers/<BINARY_TYPE>/<BINARY_ID>/config/config.toml` and restarting the binary process.
```
**Run Clients**
Once you have run `init`, you can start your binary with the `run` command, accompanied by the `id` of the binary that you specified.
This `id` is **never** transmitted over the network, and is used to select which local config and key files to use for startup.
```sh
# network requester
./nym-network-requester run --id <ID>
# socks5 client (in other terminal window)
./nym-socks5-client run --id <ID>
```
**Troubleshooting**
In case your `nym-socks5-client` has a problem to connect to your `nym-network-requester` try to setup a firewall by running these commands:
```sh
# check if you have ufw installed
ufw version
# if it is not installed, install with
sudo apt install ufw -y
# enable ufw
sudo ufw enable
# check the status of the firewall
sudo ufw status
# open firewall ports for network requester
sudo ufw allow 22,9000/tcp
# re-check the ufw status
sudo ufw status
```
Restart your network requester.
## ircd
[Dark.fi](htps://dark.fi) built a fully anonymous and p2p instance of IRC chat called [ircd](https://darkrenaissance.github.io/darkfi/misc/ircd/ircd.html). The team is just finishing their new instance of the program darkirc which we hope to see in production soon.
```admonish info
It is highly recomended to install [dark.fi architecture](https://github.com/darkrenaissance/darkfi) prior to the workshop following the [documentation](https://darkrenaissance.github.io/darkfi/misc/ircd/ircd.html) so we have enough time for the network configuration.
```
### Configuration
Make sure to have [ircd installed](https://darkrenaissance.github.io/darkfi/misc/ircd/ircd.html) on the same machine like your `nym-socks5-client` (`nym-network-requester` can run anywhere).
Currently `nym-network-requester` automatically connnects only to the [whitelisted URLs](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt). This will [change soon](https://nymtech.net/operators/faq/smoosh-faq.html) into a more opened setup. This list can be changed by an operator running a node.
**Edit allowed.list**
1. Open a text editor and add:
```yaml
dasman.xyz
```
2. Save it as `allowed.list` in `~/.nym/service-providers/network-requester/<NETWORK-REQUESTER-ID>/data/`
3. Restart your `nym-network-requester`
```sh
./nym-network-requester run --id <ID>
```
4. Make sure both `nym-socks5-client` and `nym-network-requester` are running and connected
**ircd setup**
In case your ircd has problems to start or connect, run the following:
```sh
# cd to darkfi repo
git pull
git checkout c4b78ead5111b0423fca3bd53cb7185acd6f0faa
# compile ircd
make ircd
# in case of dependency error: "failed to load source for dependency `halo2_gadgets`"
rm Cargo.lock
make ircd
# remove the config file (rename it if you want to safe any values first)
rm ~/.config/darkfi/ircd_config.toml
# rerun ircd to generate new config file
./ircd
# add your custom values from the old config file
```
5. Open `~/.config/darkfi/ircd_config.toml`
6. Coment the line with `seeds`
7. Add line:
```yaml
peers = ["nym://dasman.xyz:25552"]
```
8. Change `outbond_transports` to:
```yaml
outbond_transports = ["nym"]
```
9. Make sure that
```yaml
outbound_connections = 0
```
10. Save and restart `ircd`
Observe the ircd deamon to see that the communication is running through the mixnet.
## Bonus: Join hcpp23 channel
Now, when your Darkfi's ircd runs through Nym Mixnet, you can join public and fully anonymous channel `#hcpp23`. To do so, follow one of the two possibilities:
1. Run a command in your weechat:
```sh
/join #hcpp23
```
2. Open `~/.config/darkfi/ircd_config.toml` and add `"#hcpp23"` to the `autojoin = []` brackets, save and restart ircd.
@@ -0,0 +1,38 @@
# Web3 Privacy Now - Nym for Ethereum validator privacy
Serinko's presentation on [Web3Privacy Now: Community 1st](https://lu.ma/web3privacynow_rome) introduces ***why network privacy matters*** for ETH 2.0 validators' security and decentralisation.
This page serves as an accessible list of references mentioned during the talk.
## References
### Mixnet architecture
* [Mixnet motivations](https://nymtech.net/developers/infrastructure/nym.html)
* [Mixnet architecture overview](https://nymtech.net/docs/architecture/network-overview.html)
* [Mixnet traffic flow](https://nymtech.net/docs/architecture/traffic-flow.html)
* [Tor + VPN comparison](https://nymtech.net/developers/infrastructure/nym-vs-others.html)
* [Addressing system](https://nymtech.net/docs/clients/addressing-system.html)
### Nym \<\> ETH 2.0
* [Chainsafe Rust libp2p Nym intergration repo](https://github.com/ChainSafe/rust-libp2p-nym)
* [rust-libp2p-nym Transport Specification](https://hackmd.io/@nZ-twauPRISEa6G9zg3XRw/HkE8sHuns)
* [Lighthouse PoC](https://github.com/ChainSafe/lighthouse/blob/nym/USE_NYM.md)
* [Nym \<\> Aztec partnership](https://blog.nymtech.net/nym-partners-with-aztec-to-provide-integral-infrastructure-privacy-in-ethereum-chains-694963c55192)
### Rust Examples
* [Dev tutorial: chain service](https://nymtech.net/developers/tutorials/cosmos-service/intro.html)
### Clients
* [Clients overview](https://nymtech.net/docs/clients/overview.html)
### Nym Docs
* [Nym Developer Portal](https://nymtech.net/developers)
* [Nym Operators Guide](https://nymtech.net/operators)
* [Nym technical Documentation](https://nymtech.net/docs)
Binary file not shown.

After

Width:  |  Height:  |  Size: 532 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

@@ -13,10 +13,18 @@ Make sure you have installed and started **[NymConnect](https://nymtech.net/deve
To then start Matrix's Element client via a Socks5 proxy connected to NymConnect, open terminal and run:
**Linux**
```sh
element-desktop --proxy-server=socks5://127.0.0.1:1080
```
**Mac**
```sh
open -a Element --args --proxy-server=socks5://127.0.0.1:1080
```
## Optimise setup with a keybinding / alias
### Keybinding
+2 -2
View File
@@ -42,7 +42,7 @@ turn-off = true
[preprocessor.admonish]
command = "mdbook-admonish"
assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install`
assets_version = "3.0.0" # do not edit: managed by `mdbook-admonish install`
# variables preprocessor: import variables into files
# https://gitlab.com/tglman/mdbook-variables/
@@ -83,7 +83,7 @@ curly-quotes = true
# mathjax-support = false # useful if we want to pull equations in
copy-fonts = true
no-section-label = false
additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "./custom.css"]
additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "./custom.css", "./mdbook-admonish.css"]
additional-js = ["theme/pagetoc.js"]
git-repository-url = "https://github.com/nymtech/nym"
git-repository-icon = "fa-github"
+81 -92
View File
@@ -1,31 +1,18 @@
@charset "UTF-8";
:root {
--md-admonition-icon--note:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z'/></svg>");
--md-admonition-icon--abstract:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17 9H7V7h10m0 6H7v-2h10m-3 6H7v-2h7M12 3a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1m7 0h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2z'/></svg>");
--md-admonition-icon--info:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 9h-2V7h2m0 10h-2v-6h2m-1-9A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2z'/></svg>");
--md-admonition-icon--tip:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17.66 11.2c-.23-.3-.51-.56-.77-.82-.67-.6-1.43-1.03-2.07-1.66C13.33 7.26 13 4.85 13.95 3c-.95.23-1.78.75-2.49 1.32-2.59 2.08-3.61 5.75-2.39 8.9.04.1.08.2.08.33 0 .22-.15.42-.35.5-.23.1-.47.04-.66-.12a.58.58 0 0 1-.14-.17c-1.13-1.43-1.31-3.48-.55-5.12C5.78 10 4.87 12.3 5 14.47c.06.5.12 1 .29 1.5.14.6.41 1.2.71 1.73 1.08 1.73 2.95 2.97 4.96 3.22 2.14.27 4.43-.12 6.07-1.6 1.83-1.66 2.47-4.32 1.53-6.6l-.13-.26c-.21-.46-.77-1.26-.77-1.26m-3.16 6.3c-.28.24-.74.5-1.1.6-1.12.4-2.24-.16-2.9-.82 1.19-.28 1.9-1.16 2.11-2.05.17-.8-.15-1.46-.28-2.23-.12-.74-.1-1.37.17-2.06.19.38.39.76.63 1.06.77 1 1.98 1.44 2.24 2.8.04.14.06.28.06.43.03.82-.33 1.72-.93 2.27z'/></svg>");
--md-admonition-icon--success:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m9 20.42-6.21-6.21 2.83-2.83L9 14.77l9.88-9.89 2.83 2.83L9 20.42z'/></svg>");
--md-admonition-icon--question:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m15.07 11.25-.9.92C13.45 12.89 13 13.5 13 15h-2v-.5c0-1.11.45-2.11 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41a2 2 0 0 0-2-2 2 2 0 0 0-2 2H8a4 4 0 0 1 4-4 4 4 0 0 1 4 4 3.2 3.2 0 0 1-.93 2.25M13 19h-2v-2h2M12 2A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10c0-5.53-4.5-10-10-10z'/></svg>");
--md-admonition-icon--warning:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 14h-2V9h2m0 9h-2v-2h2M1 21h22L12 2 1 21z'/></svg>");
--md-admonition-icon--failure:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20 6.91 17.09 4 12 9.09 6.91 4 4 6.91 9.09 12 4 17.09 6.91 20 12 14.91 17.09 20 20 17.09 14.91 12 20 6.91z'/></svg>");
--md-admonition-icon--danger:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 15H6l7-14v8h5l-7 14v-8z'/></svg>");
--md-admonition-icon--bug:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 12h-4v-2h4m0 6h-4v-2h4m6-6h-2.81a5.985 5.985 0 0 0-1.82-1.96L17 4.41 15.59 3l-2.17 2.17a6.002 6.002 0 0 0-2.83 0L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8z'/></svg>");
--md-admonition-icon--example:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M7 13v-2h14v2H7m0 6v-2h14v2H7M7 7V5h14v2H7M3 8V5H2V4h2v4H3m-1 9v-1h3v4H2v-1h2v-.5H3v-1h1V17H2m2.25-7a.75.75 0 0 1 .75.75c0 .2-.08.39-.21.52L3.12 13H5v1H2v-.92L4 11H2v-1h2.25z'/></svg>");
--md-admonition-icon--quote:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 17h3l2-4V7h-6v6h3M6 17h3l2-4V7H5v6h3l-2 4z'/></svg>");
--md-details-icon:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M8.59 16.58 13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42Z'/></svg>");
--md-admonition-icon--admonish-note: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z'/></svg>");
--md-admonition-icon--admonish-abstract: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17 9H7V7h10m0 6H7v-2h10m-3 6H7v-2h7M12 3a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1m7 0h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2z'/></svg>");
--md-admonition-icon--admonish-info: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 9h-2V7h2m0 10h-2v-6h2m-1-9A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2z'/></svg>");
--md-admonition-icon--admonish-tip: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17.66 11.2c-.23-.3-.51-.56-.77-.82-.67-.6-1.43-1.03-2.07-1.66C13.33 7.26 13 4.85 13.95 3c-.95.23-1.78.75-2.49 1.32-2.59 2.08-3.61 5.75-2.39 8.9.04.1.08.2.08.33 0 .22-.15.42-.35.5-.23.1-.47.04-.66-.12a.58.58 0 0 1-.14-.17c-1.13-1.43-1.31-3.48-.55-5.12C5.78 10 4.87 12.3 5 14.47c.06.5.12 1 .29 1.5.14.6.41 1.2.71 1.73 1.08 1.73 2.95 2.97 4.96 3.22 2.14.27 4.43-.12 6.07-1.6 1.83-1.66 2.47-4.32 1.53-6.6l-.13-.26c-.21-.46-.77-1.26-.77-1.26m-3.16 6.3c-.28.24-.74.5-1.1.6-1.12.4-2.24-.16-2.9-.82 1.19-.28 1.9-1.16 2.11-2.05.17-.8-.15-1.46-.28-2.23-.12-.74-.1-1.37.17-2.06.19.38.39.76.63 1.06.77 1 1.98 1.44 2.24 2.8.04.14.06.28.06.43.03.82-.33 1.72-.93 2.27z'/></svg>");
--md-admonition-icon--admonish-success: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m9 20.42-6.21-6.21 2.83-2.83L9 14.77l9.88-9.89 2.83 2.83L9 20.42z'/></svg>");
--md-admonition-icon--admonish-question: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m15.07 11.25-.9.92C13.45 12.89 13 13.5 13 15h-2v-.5c0-1.11.45-2.11 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41a2 2 0 0 0-2-2 2 2 0 0 0-2 2H8a4 4 0 0 1 4-4 4 4 0 0 1 4 4 3.2 3.2 0 0 1-.93 2.25M13 19h-2v-2h2M12 2A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10c0-5.53-4.5-10-10-10z'/></svg>");
--md-admonition-icon--admonish-warning: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 14h-2V9h2m0 9h-2v-2h2M1 21h22L12 2 1 21z'/></svg>");
--md-admonition-icon--admonish-failure: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20 6.91 17.09 4 12 9.09 6.91 4 4 6.91 9.09 12 4 17.09 6.91 20 12 14.91 17.09 20 20 17.09 14.91 12 20 6.91z'/></svg>");
--md-admonition-icon--admonish-danger: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 15H6l7-14v8h5l-7 14v-8z'/></svg>");
--md-admonition-icon--admonish-bug: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 12h-4v-2h4m0 6h-4v-2h4m6-6h-2.81a5.985 5.985 0 0 0-1.82-1.96L17 4.41 15.59 3l-2.17 2.17a6.002 6.002 0 0 0-2.83 0L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8z'/></svg>");
--md-admonition-icon--admonish-example: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M7 13v-2h14v2H7m0 6v-2h14v2H7M7 7V5h14v2H7M3 8V5H2V4h2v4H3m-1 9v-1h3v4H2v-1h2v-.5H3v-1h1V17H2m2.25-7a.75.75 0 0 1 .75.75c0 .2-.08.39-.21.52L3.12 13H5v1H2v-.92L4 11H2v-1h2.25z'/></svg>");
--md-admonition-icon--admonish-quote: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 17h3l2-4V7h-6v6h3M6 17h3l2-4V7H5v6h3l-2 4z'/></svg>");
--md-details-icon: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M8.59 16.58 13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42Z'/></svg>");
}
:is(.admonition) {
@@ -75,8 +62,9 @@ a.admonition-anchor-link::before {
content: "§";
}
:is(.admonition-title, summary) {
:is(.admonition-title, summary.admonition-title) {
position: relative;
min-height: 4rem;
margin-block: 0;
margin-inline: -1.6rem -1.2rem;
padding-block: 0.8rem;
@@ -85,13 +73,13 @@ a.admonition-anchor-link::before {
background-color: rgba(68, 138, 255, 0.1);
display: flex;
}
:is(.admonition-title, summary) p {
:is(.admonition-title, summary.admonition-title) p {
margin: 0;
}
html :is(.admonition-title, summary):last-child {
html :is(.admonition-title, summary.admonition-title):last-child {
margin-bottom: 0;
}
:is(.admonition-title, summary)::before {
:is(.admonition-title, summary.admonition-title)::before {
position: absolute;
top: 0.625em;
inset-inline-start: 1.6rem;
@@ -106,7 +94,7 @@ html :is(.admonition-title, summary):last-child {
-webkit-mask-size: contain;
content: "";
}
:is(.admonition-title, summary):hover a.admonition-anchor-link {
:is(.admonition-title, summary.admonition-title):hover a.admonition-anchor-link {
display: initial;
}
@@ -131,204 +119,204 @@ details[open].admonition > summary.admonition-title::after {
transform: rotate(90deg);
}
:is(.admonition):is(.note) {
:is(.admonition):is(.admonish-note) {
border-color: #448aff;
}
:is(.note) > :is(.admonition-title, summary) {
:is(.admonish-note) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(68, 138, 255, 0.1);
}
:is(.note) > :is(.admonition-title, summary)::before {
:is(.admonish-note) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #448aff;
mask-image: var(--md-admonition-icon--note);
-webkit-mask-image: var(--md-admonition-icon--note);
mask-image: var(--md-admonition-icon--admonish-note);
-webkit-mask-image: var(--md-admonition-icon--admonish-note);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.abstract, .summary, .tldr) {
:is(.admonition):is(.admonish-abstract, .admonish-summary, .admonish-tldr) {
border-color: #00b0ff;
}
:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary) {
:is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(0, 176, 255, 0.1);
}
:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary)::before {
:is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #00b0ff;
mask-image: var(--md-admonition-icon--abstract);
-webkit-mask-image: var(--md-admonition-icon--abstract);
mask-image: var(--md-admonition-icon--admonish-abstract);
-webkit-mask-image: var(--md-admonition-icon--admonish-abstract);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.info, .todo) {
:is(.admonition):is(.admonish-info, .admonish-todo) {
border-color: #00b8d4;
}
:is(.info, .todo) > :is(.admonition-title, summary) {
:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(0, 184, 212, 0.1);
}
:is(.info, .todo) > :is(.admonition-title, summary)::before {
:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #00b8d4;
mask-image: var(--md-admonition-icon--info);
-webkit-mask-image: var(--md-admonition-icon--info);
mask-image: var(--md-admonition-icon--admonish-info);
-webkit-mask-image: var(--md-admonition-icon--admonish-info);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.tip, .hint, .important) {
:is(.admonition):is(.admonish-tip, .admonish-hint, .admonish-important) {
border-color: #00bfa5;
}
:is(.tip, .hint, .important) > :is(.admonition-title, summary) {
:is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(0, 191, 165, 0.1);
}
:is(.tip, .hint, .important) > :is(.admonition-title, summary)::before {
:is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #00bfa5;
mask-image: var(--md-admonition-icon--tip);
-webkit-mask-image: var(--md-admonition-icon--tip);
mask-image: var(--md-admonition-icon--admonish-tip);
-webkit-mask-image: var(--md-admonition-icon--admonish-tip);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.success, .check, .done) {
:is(.admonition):is(.admonish-success, .admonish-check, .admonish-done) {
border-color: #00c853;
}
:is(.success, .check, .done) > :is(.admonition-title, summary) {
:is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(0, 200, 83, 0.1);
}
:is(.success, .check, .done) > :is(.admonition-title, summary)::before {
:is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #00c853;
mask-image: var(--md-admonition-icon--success);
-webkit-mask-image: var(--md-admonition-icon--success);
mask-image: var(--md-admonition-icon--admonish-success);
-webkit-mask-image: var(--md-admonition-icon--admonish-success);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.question, .help, .faq) {
:is(.admonition):is(.admonish-question, .admonish-help, .admonish-faq) {
border-color: #64dd17;
}
:is(.question, .help, .faq) > :is(.admonition-title, summary) {
:is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(100, 221, 23, 0.1);
}
:is(.question, .help, .faq) > :is(.admonition-title, summary)::before {
:is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #64dd17;
mask-image: var(--md-admonition-icon--question);
-webkit-mask-image: var(--md-admonition-icon--question);
mask-image: var(--md-admonition-icon--admonish-question);
-webkit-mask-image: var(--md-admonition-icon--admonish-question);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.warning, .caution, .attention) {
:is(.admonition):is(.admonish-warning, .admonish-caution, .admonish-attention) {
border-color: #ff9100;
}
:is(.warning, .caution, .attention) > :is(.admonition-title, summary) {
:is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(255, 145, 0, 0.1);
}
:is(.warning, .caution, .attention) > :is(.admonition-title, summary)::before {
:is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #ff9100;
mask-image: var(--md-admonition-icon--warning);
-webkit-mask-image: var(--md-admonition-icon--warning);
mask-image: var(--md-admonition-icon--admonish-warning);
-webkit-mask-image: var(--md-admonition-icon--admonish-warning);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.failure, .fail, .missing) {
:is(.admonition):is(.admonish-failure, .admonish-fail, .admonish-missing) {
border-color: #ff5252;
}
:is(.failure, .fail, .missing) > :is(.admonition-title, summary) {
:is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(255, 82, 82, 0.1);
}
:is(.failure, .fail, .missing) > :is(.admonition-title, summary)::before {
:is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #ff5252;
mask-image: var(--md-admonition-icon--failure);
-webkit-mask-image: var(--md-admonition-icon--failure);
mask-image: var(--md-admonition-icon--admonish-failure);
-webkit-mask-image: var(--md-admonition-icon--admonish-failure);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.danger, .error) {
:is(.admonition):is(.admonish-danger, .admonish-error) {
border-color: #ff1744;
}
:is(.danger, .error) > :is(.admonition-title, summary) {
:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(255, 23, 68, 0.1);
}
:is(.danger, .error) > :is(.admonition-title, summary)::before {
:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #ff1744;
mask-image: var(--md-admonition-icon--danger);
-webkit-mask-image: var(--md-admonition-icon--danger);
mask-image: var(--md-admonition-icon--admonish-danger);
-webkit-mask-image: var(--md-admonition-icon--admonish-danger);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.bug) {
:is(.admonition):is(.admonish-bug) {
border-color: #f50057;
}
:is(.bug) > :is(.admonition-title, summary) {
:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(245, 0, 87, 0.1);
}
:is(.bug) > :is(.admonition-title, summary)::before {
:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #f50057;
mask-image: var(--md-admonition-icon--bug);
-webkit-mask-image: var(--md-admonition-icon--bug);
mask-image: var(--md-admonition-icon--admonish-bug);
-webkit-mask-image: var(--md-admonition-icon--admonish-bug);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.example) {
:is(.admonition):is(.admonish-example) {
border-color: #7c4dff;
}
:is(.example) > :is(.admonition-title, summary) {
:is(.admonish-example) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(124, 77, 255, 0.1);
}
:is(.example) > :is(.admonition-title, summary)::before {
:is(.admonish-example) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #7c4dff;
mask-image: var(--md-admonition-icon--example);
-webkit-mask-image: var(--md-admonition-icon--example);
mask-image: var(--md-admonition-icon--admonish-example);
-webkit-mask-image: var(--md-admonition-icon--admonish-example);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.quote, .cite) {
:is(.admonition):is(.admonish-quote, .admonish-cite) {
border-color: #9e9e9e;
}
:is(.quote, .cite) > :is(.admonition-title, summary) {
:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(158, 158, 158, 0.1);
}
:is(.quote, .cite) > :is(.admonition-title, summary)::before {
:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #9e9e9e;
mask-image: var(--md-admonition-icon--quote);
-webkit-mask-image: var(--md-admonition-icon--quote);
mask-image: var(--md-admonition-icon--admonish-quote);
-webkit-mask-image: var(--md-admonition-icon--admonish-quote);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
@@ -339,7 +327,8 @@ details[open].admonition > summary.admonition-title::after {
background-color: var(--sidebar-bg);
}
.ayu :is(.admonition), .coal :is(.admonition) {
.ayu :is(.admonition),
.coal :is(.admonition) {
background-color: var(--theme-hover);
}
+2 -2
View File
@@ -42,7 +42,7 @@ turn-off = true
[preprocessor.admonish]
command = "mdbook-admonish"
assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install`
assets_version = "3.0.0" # do not edit: managed by `mdbook-admonish install`
# variables preprocessor: import variables into files
# https://gitlab.com/tglman/mdbook-variables/
@@ -83,7 +83,7 @@ curly-quotes = true
# mathjax-support = false # useful if we want to pull equations in
copy-fonts = true
no-section-label = false
additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css","./custom.css"]
additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css","./custom.css", "./mdbook-admonish.css"]
additional-js = ["theme/pagetoc.js"]
git-repository-url = "https://github.com/nymtech/nym"
git-repository-icon = "fa-github"
+81 -92
View File
@@ -1,31 +1,18 @@
@charset "UTF-8";
:root {
--md-admonition-icon--note:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z'/></svg>");
--md-admonition-icon--abstract:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17 9H7V7h10m0 6H7v-2h10m-3 6H7v-2h7M12 3a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1m7 0h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2z'/></svg>");
--md-admonition-icon--info:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 9h-2V7h2m0 10h-2v-6h2m-1-9A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2z'/></svg>");
--md-admonition-icon--tip:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17.66 11.2c-.23-.3-.51-.56-.77-.82-.67-.6-1.43-1.03-2.07-1.66C13.33 7.26 13 4.85 13.95 3c-.95.23-1.78.75-2.49 1.32-2.59 2.08-3.61 5.75-2.39 8.9.04.1.08.2.08.33 0 .22-.15.42-.35.5-.23.1-.47.04-.66-.12a.58.58 0 0 1-.14-.17c-1.13-1.43-1.31-3.48-.55-5.12C5.78 10 4.87 12.3 5 14.47c.06.5.12 1 .29 1.5.14.6.41 1.2.71 1.73 1.08 1.73 2.95 2.97 4.96 3.22 2.14.27 4.43-.12 6.07-1.6 1.83-1.66 2.47-4.32 1.53-6.6l-.13-.26c-.21-.46-.77-1.26-.77-1.26m-3.16 6.3c-.28.24-.74.5-1.1.6-1.12.4-2.24-.16-2.9-.82 1.19-.28 1.9-1.16 2.11-2.05.17-.8-.15-1.46-.28-2.23-.12-.74-.1-1.37.17-2.06.19.38.39.76.63 1.06.77 1 1.98 1.44 2.24 2.8.04.14.06.28.06.43.03.82-.33 1.72-.93 2.27z'/></svg>");
--md-admonition-icon--success:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m9 20.42-6.21-6.21 2.83-2.83L9 14.77l9.88-9.89 2.83 2.83L9 20.42z'/></svg>");
--md-admonition-icon--question:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m15.07 11.25-.9.92C13.45 12.89 13 13.5 13 15h-2v-.5c0-1.11.45-2.11 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41a2 2 0 0 0-2-2 2 2 0 0 0-2 2H8a4 4 0 0 1 4-4 4 4 0 0 1 4 4 3.2 3.2 0 0 1-.93 2.25M13 19h-2v-2h2M12 2A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10c0-5.53-4.5-10-10-10z'/></svg>");
--md-admonition-icon--warning:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 14h-2V9h2m0 9h-2v-2h2M1 21h22L12 2 1 21z'/></svg>");
--md-admonition-icon--failure:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20 6.91 17.09 4 12 9.09 6.91 4 4 6.91 9.09 12 4 17.09 6.91 20 12 14.91 17.09 20 20 17.09 14.91 12 20 6.91z'/></svg>");
--md-admonition-icon--danger:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 15H6l7-14v8h5l-7 14v-8z'/></svg>");
--md-admonition-icon--bug:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 12h-4v-2h4m0 6h-4v-2h4m6-6h-2.81a5.985 5.985 0 0 0-1.82-1.96L17 4.41 15.59 3l-2.17 2.17a6.002 6.002 0 0 0-2.83 0L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8z'/></svg>");
--md-admonition-icon--example:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M7 13v-2h14v2H7m0 6v-2h14v2H7M7 7V5h14v2H7M3 8V5H2V4h2v4H3m-1 9v-1h3v4H2v-1h2v-.5H3v-1h1V17H2m2.25-7a.75.75 0 0 1 .75.75c0 .2-.08.39-.21.52L3.12 13H5v1H2v-.92L4 11H2v-1h2.25z'/></svg>");
--md-admonition-icon--quote:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 17h3l2-4V7h-6v6h3M6 17h3l2-4V7H5v6h3l-2 4z'/></svg>");
--md-details-icon:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M8.59 16.58 13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42Z'/></svg>");
--md-admonition-icon--admonish-note: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z'/></svg>");
--md-admonition-icon--admonish-abstract: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17 9H7V7h10m0 6H7v-2h10m-3 6H7v-2h7M12 3a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1m7 0h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2z'/></svg>");
--md-admonition-icon--admonish-info: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 9h-2V7h2m0 10h-2v-6h2m-1-9A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2z'/></svg>");
--md-admonition-icon--admonish-tip: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17.66 11.2c-.23-.3-.51-.56-.77-.82-.67-.6-1.43-1.03-2.07-1.66C13.33 7.26 13 4.85 13.95 3c-.95.23-1.78.75-2.49 1.32-2.59 2.08-3.61 5.75-2.39 8.9.04.1.08.2.08.33 0 .22-.15.42-.35.5-.23.1-.47.04-.66-.12a.58.58 0 0 1-.14-.17c-1.13-1.43-1.31-3.48-.55-5.12C5.78 10 4.87 12.3 5 14.47c.06.5.12 1 .29 1.5.14.6.41 1.2.71 1.73 1.08 1.73 2.95 2.97 4.96 3.22 2.14.27 4.43-.12 6.07-1.6 1.83-1.66 2.47-4.32 1.53-6.6l-.13-.26c-.21-.46-.77-1.26-.77-1.26m-3.16 6.3c-.28.24-.74.5-1.1.6-1.12.4-2.24-.16-2.9-.82 1.19-.28 1.9-1.16 2.11-2.05.17-.8-.15-1.46-.28-2.23-.12-.74-.1-1.37.17-2.06.19.38.39.76.63 1.06.77 1 1.98 1.44 2.24 2.8.04.14.06.28.06.43.03.82-.33 1.72-.93 2.27z'/></svg>");
--md-admonition-icon--admonish-success: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m9 20.42-6.21-6.21 2.83-2.83L9 14.77l9.88-9.89 2.83 2.83L9 20.42z'/></svg>");
--md-admonition-icon--admonish-question: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m15.07 11.25-.9.92C13.45 12.89 13 13.5 13 15h-2v-.5c0-1.11.45-2.11 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41a2 2 0 0 0-2-2 2 2 0 0 0-2 2H8a4 4 0 0 1 4-4 4 4 0 0 1 4 4 3.2 3.2 0 0 1-.93 2.25M13 19h-2v-2h2M12 2A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10c0-5.53-4.5-10-10-10z'/></svg>");
--md-admonition-icon--admonish-warning: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 14h-2V9h2m0 9h-2v-2h2M1 21h22L12 2 1 21z'/></svg>");
--md-admonition-icon--admonish-failure: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20 6.91 17.09 4 12 9.09 6.91 4 4 6.91 9.09 12 4 17.09 6.91 20 12 14.91 17.09 20 20 17.09 14.91 12 20 6.91z'/></svg>");
--md-admonition-icon--admonish-danger: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 15H6l7-14v8h5l-7 14v-8z'/></svg>");
--md-admonition-icon--admonish-bug: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 12h-4v-2h4m0 6h-4v-2h4m6-6h-2.81a5.985 5.985 0 0 0-1.82-1.96L17 4.41 15.59 3l-2.17 2.17a6.002 6.002 0 0 0-2.83 0L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8z'/></svg>");
--md-admonition-icon--admonish-example: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M7 13v-2h14v2H7m0 6v-2h14v2H7M7 7V5h14v2H7M3 8V5H2V4h2v4H3m-1 9v-1h3v4H2v-1h2v-.5H3v-1h1V17H2m2.25-7a.75.75 0 0 1 .75.75c0 .2-.08.39-.21.52L3.12 13H5v1H2v-.92L4 11H2v-1h2.25z'/></svg>");
--md-admonition-icon--admonish-quote: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 17h3l2-4V7h-6v6h3M6 17h3l2-4V7H5v6h3l-2 4z'/></svg>");
--md-details-icon: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M8.59 16.58 13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42Z'/></svg>");
}
:is(.admonition) {
@@ -75,8 +62,9 @@ a.admonition-anchor-link::before {
content: "§";
}
:is(.admonition-title, summary) {
:is(.admonition-title, summary.admonition-title) {
position: relative;
min-height: 4rem;
margin-block: 0;
margin-inline: -1.6rem -1.2rem;
padding-block: 0.8rem;
@@ -85,13 +73,13 @@ a.admonition-anchor-link::before {
background-color: rgba(68, 138, 255, 0.1);
display: flex;
}
:is(.admonition-title, summary) p {
:is(.admonition-title, summary.admonition-title) p {
margin: 0;
}
html :is(.admonition-title, summary):last-child {
html :is(.admonition-title, summary.admonition-title):last-child {
margin-bottom: 0;
}
:is(.admonition-title, summary)::before {
:is(.admonition-title, summary.admonition-title)::before {
position: absolute;
top: 0.625em;
inset-inline-start: 1.6rem;
@@ -106,7 +94,7 @@ html :is(.admonition-title, summary):last-child {
-webkit-mask-size: contain;
content: "";
}
:is(.admonition-title, summary):hover a.admonition-anchor-link {
:is(.admonition-title, summary.admonition-title):hover a.admonition-anchor-link {
display: initial;
}
@@ -131,204 +119,204 @@ details[open].admonition > summary.admonition-title::after {
transform: rotate(90deg);
}
:is(.admonition):is(.note) {
:is(.admonition):is(.admonish-note) {
border-color: #448aff;
}
:is(.note) > :is(.admonition-title, summary) {
:is(.admonish-note) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(68, 138, 255, 0.1);
}
:is(.note) > :is(.admonition-title, summary)::before {
:is(.admonish-note) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #448aff;
mask-image: var(--md-admonition-icon--note);
-webkit-mask-image: var(--md-admonition-icon--note);
mask-image: var(--md-admonition-icon--admonish-note);
-webkit-mask-image: var(--md-admonition-icon--admonish-note);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.abstract, .summary, .tldr) {
:is(.admonition):is(.admonish-abstract, .admonish-summary, .admonish-tldr) {
border-color: #00b0ff;
}
:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary) {
:is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(0, 176, 255, 0.1);
}
:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary)::before {
:is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #00b0ff;
mask-image: var(--md-admonition-icon--abstract);
-webkit-mask-image: var(--md-admonition-icon--abstract);
mask-image: var(--md-admonition-icon--admonish-abstract);
-webkit-mask-image: var(--md-admonition-icon--admonish-abstract);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.info, .todo) {
:is(.admonition):is(.admonish-info, .admonish-todo) {
border-color: #00b8d4;
}
:is(.info, .todo) > :is(.admonition-title, summary) {
:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(0, 184, 212, 0.1);
}
:is(.info, .todo) > :is(.admonition-title, summary)::before {
:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #00b8d4;
mask-image: var(--md-admonition-icon--info);
-webkit-mask-image: var(--md-admonition-icon--info);
mask-image: var(--md-admonition-icon--admonish-info);
-webkit-mask-image: var(--md-admonition-icon--admonish-info);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.tip, .hint, .important) {
:is(.admonition):is(.admonish-tip, .admonish-hint, .admonish-important) {
border-color: #00bfa5;
}
:is(.tip, .hint, .important) > :is(.admonition-title, summary) {
:is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(0, 191, 165, 0.1);
}
:is(.tip, .hint, .important) > :is(.admonition-title, summary)::before {
:is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #00bfa5;
mask-image: var(--md-admonition-icon--tip);
-webkit-mask-image: var(--md-admonition-icon--tip);
mask-image: var(--md-admonition-icon--admonish-tip);
-webkit-mask-image: var(--md-admonition-icon--admonish-tip);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.success, .check, .done) {
:is(.admonition):is(.admonish-success, .admonish-check, .admonish-done) {
border-color: #00c853;
}
:is(.success, .check, .done) > :is(.admonition-title, summary) {
:is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(0, 200, 83, 0.1);
}
:is(.success, .check, .done) > :is(.admonition-title, summary)::before {
:is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #00c853;
mask-image: var(--md-admonition-icon--success);
-webkit-mask-image: var(--md-admonition-icon--success);
mask-image: var(--md-admonition-icon--admonish-success);
-webkit-mask-image: var(--md-admonition-icon--admonish-success);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.question, .help, .faq) {
:is(.admonition):is(.admonish-question, .admonish-help, .admonish-faq) {
border-color: #64dd17;
}
:is(.question, .help, .faq) > :is(.admonition-title, summary) {
:is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(100, 221, 23, 0.1);
}
:is(.question, .help, .faq) > :is(.admonition-title, summary)::before {
:is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #64dd17;
mask-image: var(--md-admonition-icon--question);
-webkit-mask-image: var(--md-admonition-icon--question);
mask-image: var(--md-admonition-icon--admonish-question);
-webkit-mask-image: var(--md-admonition-icon--admonish-question);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.warning, .caution, .attention) {
:is(.admonition):is(.admonish-warning, .admonish-caution, .admonish-attention) {
border-color: #ff9100;
}
:is(.warning, .caution, .attention) > :is(.admonition-title, summary) {
:is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(255, 145, 0, 0.1);
}
:is(.warning, .caution, .attention) > :is(.admonition-title, summary)::before {
:is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #ff9100;
mask-image: var(--md-admonition-icon--warning);
-webkit-mask-image: var(--md-admonition-icon--warning);
mask-image: var(--md-admonition-icon--admonish-warning);
-webkit-mask-image: var(--md-admonition-icon--admonish-warning);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.failure, .fail, .missing) {
:is(.admonition):is(.admonish-failure, .admonish-fail, .admonish-missing) {
border-color: #ff5252;
}
:is(.failure, .fail, .missing) > :is(.admonition-title, summary) {
:is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(255, 82, 82, 0.1);
}
:is(.failure, .fail, .missing) > :is(.admonition-title, summary)::before {
:is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #ff5252;
mask-image: var(--md-admonition-icon--failure);
-webkit-mask-image: var(--md-admonition-icon--failure);
mask-image: var(--md-admonition-icon--admonish-failure);
-webkit-mask-image: var(--md-admonition-icon--admonish-failure);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.danger, .error) {
:is(.admonition):is(.admonish-danger, .admonish-error) {
border-color: #ff1744;
}
:is(.danger, .error) > :is(.admonition-title, summary) {
:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(255, 23, 68, 0.1);
}
:is(.danger, .error) > :is(.admonition-title, summary)::before {
:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #ff1744;
mask-image: var(--md-admonition-icon--danger);
-webkit-mask-image: var(--md-admonition-icon--danger);
mask-image: var(--md-admonition-icon--admonish-danger);
-webkit-mask-image: var(--md-admonition-icon--admonish-danger);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.bug) {
:is(.admonition):is(.admonish-bug) {
border-color: #f50057;
}
:is(.bug) > :is(.admonition-title, summary) {
:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(245, 0, 87, 0.1);
}
:is(.bug) > :is(.admonition-title, summary)::before {
:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #f50057;
mask-image: var(--md-admonition-icon--bug);
-webkit-mask-image: var(--md-admonition-icon--bug);
mask-image: var(--md-admonition-icon--admonish-bug);
-webkit-mask-image: var(--md-admonition-icon--admonish-bug);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.example) {
:is(.admonition):is(.admonish-example) {
border-color: #7c4dff;
}
:is(.example) > :is(.admonition-title, summary) {
:is(.admonish-example) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(124, 77, 255, 0.1);
}
:is(.example) > :is(.admonition-title, summary)::before {
:is(.admonish-example) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #7c4dff;
mask-image: var(--md-admonition-icon--example);
-webkit-mask-image: var(--md-admonition-icon--example);
mask-image: var(--md-admonition-icon--admonish-example);
-webkit-mask-image: var(--md-admonition-icon--admonish-example);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.quote, .cite) {
:is(.admonition):is(.admonish-quote, .admonish-cite) {
border-color: #9e9e9e;
}
:is(.quote, .cite) > :is(.admonition-title, summary) {
:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(158, 158, 158, 0.1);
}
:is(.quote, .cite) > :is(.admonition-title, summary)::before {
:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #9e9e9e;
mask-image: var(--md-admonition-icon--quote);
-webkit-mask-image: var(--md-admonition-icon--quote);
mask-image: var(--md-admonition-icon--admonish-quote);
-webkit-mask-image: var(--md-admonition-icon--admonish-quote);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
@@ -339,7 +327,8 @@ details[open].admonition > summary.admonition-title::after {
background-color: var(--sidebar-bg);
}
.ayu :is(.admonition), .coal :is(.admonition) {
.ayu :is(.admonition),
.coal :is(.admonition) {
background-color: var(--theme-hover);
}
@@ -2,9 +2,10 @@
> We aim on purpose to make minimal changes to reward scheme and software. We're just 'smooshing' together stuff we already debugged and know works.
> -- Harry Halpin, Nym CEO
<p>
<p></p>
This page refer to the changes which are planned to take place over Q3 and Q4 2023. As this is a transition period in the beginning (Q3 2023) the [Mix Nodes FAQ page](./mixnodes-faq.md) holds more answers to the current setup as project Smoosh refers to the eventual setup. As project Smoosh gets progressively implemented the answers on this page will become to be more relevant to the current state and eventually this FAQ page will be merged with the still relevant parts of the main Mix Nodes FAQ page.
</p>
If any questions are not answered or it's not clear for you in which stage project Smoosh is right now, please reach out in Node Operators [Matrix room](https://matrix.to/#/#operators:nymtech.chat).
## Overview
@@ -40,7 +41,7 @@ Yes, to run a mix node only is an option. However it will be less rewarded as no
### What are the incentives for the node operator?
In the original setup there were no incentives to run a `network-requester`. After the transition all the users will buy multiple tickets of zkNyms credentials and use those as [anonymous e-cash](https://arxiv.org/abs/2303.08221) to pay for their data traffic (`[Nym API](https://github.com/nymtech/nym/tree/master/nym-api)` will do the do cryptographical checks to prevent double-spending). All collected fees get distributed to all active nodes proportionally to their work by the end of each epoch.
In the original setup there were no incentives to run a `network-requester`. After the transition all the users will buy multiple tickets of zkNyms credentials and use those as [anonymous e-cash](https://arxiv.org/abs/2303.08221) to pay for their data traffic ([`Nym API`](https://github.com/nymtech/nym/tree/master/nym-api) will do the do cryptographical checks to prevent double-spending). All collected fees get distributed to all active nodes proportionally to their work by the end of each epoch.
### How does this change the token economics?
+7 -3
View File
@@ -37,14 +37,16 @@ nym-ephemera-common = { path = "../common/cosmwasm-smart-contracts/ephemera" }
pretty_env_logger = "0.4"
refinery = { version = "0.8.7", features = ["rusqlite"], optional = true }
reqwest = { version = "0.11.6", features = ["json"] }
rocksdb = { version = "0.21.0", optional = true }
# Rocksdb kills compilation times and we're not currently using it. The reason
# we comment it out is that rust-analyzer runs with --all-features
#rocksdb = { version = "0.21.0", optional = true }
rusqlite = { version = "0.27.0", features = ["bundled"], optional = true }
serde = { version = "1.0", features = ["derive"] }
serde_derive = "1.0.149"
serde_json = "1.0.91"
thiserror = "1.0.37"
tokio = { version = "1", features = ["macros", "net","rt-multi-thread"] }
tokio-tungstenite = "0.18.0"
tokio-tungstenite = { workspace = true }
tokio-util = { version = "0.7.4", features = ["full"] }
toml = "0.7.0"
unsigned-varint = "0.7.1"
@@ -61,5 +63,7 @@ rand = "0.8.5"
[features]
default = ["sqlite_storage"]
rocksdb_storage = ["rocksdb"]
# Rocksdb kills compilation times and we're not currently using it. The reason
# we comment it out is that rust-analyzer runs with --all-features
#rocksdb_storage = ["rocksdb"]
sqlite_storage = ["rusqlite", "refinery"]
+2 -2
View File
@@ -20,7 +20,7 @@ pub(crate) async fn submit_message(
api: web::Data<CommandExecutor>,
) -> HttpResponse {
match api.send_ephemera_message(message.into_inner()).await {
Ok(_) => HttpResponse::Ok().json("Message submitted"),
Ok(()) => HttpResponse::Ok().json("Message submitted"),
Err(err) => {
if let ApiError::DuplicateMessage = err {
debug!("Message already submitted {err:?}");
@@ -53,7 +53,7 @@ pub(crate) async fn store_in_dht(
let value = request.value();
match api.store_in_dht(key, value).await {
Ok(_) => HttpResponse::Ok().json("Store request submitted"),
Ok(()) => HttpResponse::Ok().json("Store request submitted"),
Err(err) => {
error!("Error storing in dht: {}", err);
HttpResponse::InternalServerError().json("Server failed to process request")
+1 -1
View File
@@ -278,7 +278,7 @@ impl BlockManager {
}
match self.message_pool.remove_messages(&block.messages) {
Ok(_) => {
Ok(()) => {
self.block_chain_state
.mark_last_produced_block_as_committed();
}
+4 -4
View File
@@ -132,7 +132,7 @@ impl ApiCmdProcessor {
.send_ephemera_event(EphemeraEvent::StoreInDht { key, value })
.await
{
Ok(_) => Ok(()),
Ok(()) => Ok(()),
Err(err) => {
error!("Error sending StoreInDht to network: {:?}", err);
Err(ApiError::Internal("Failed to store in DHT".to_string()))
@@ -153,7 +153,7 @@ impl ApiCmdProcessor {
.send_ephemera_event(EphemeraEvent::QueryDht { key: key.clone() })
.await
{
Ok(_) => {
Ok(()) => {
//Save the reply channel in a map and send the reply when we get the response from the network
ephemera
.api_cmd_processor
@@ -278,7 +278,7 @@ impl ApiCmdProcessor {
// Send to BlockManager to verify it and put into memory pool
let ephemera_msg: message::EphemeraMessage = (*api_msg).into();
match ephemera.block_manager.on_new_message(ephemera_msg.clone()) {
Ok(_) => {
Ok(()) => {
//Gossip to network for other nodes to receive
match ephemera
.to_network
@@ -287,7 +287,7 @@ impl ApiCmdProcessor {
))
.await
{
Ok(_) => Ok(()),
Ok(()) => Ok(()),
Err(err) => {
error!("Error sending EphemeraMessage to network: {:?}", err);
Err(ApiError::Internal("Failed to submit message".to_string()))
+3 -3
View File
@@ -267,7 +267,7 @@ impl<A: Application> EphemeraStarterWithApplication<A> {
}
ws_stopped = websocket.run() => {
match ws_stopped {
Ok(_) => info!("Websocket stopped unexpectedly"),
Ok(()) => info!("Websocket stopped unexpectedly"),
Err(e) => error!("Websocket stopped with error: {}", e),
}
}
@@ -293,7 +293,7 @@ impl<A: Application> EphemeraStarterWithApplication<A> {
}
http_stopped = http => {
match http_stopped {
Ok(_) => info!("Http server stopped unexpectedly"),
Ok(()) => info!("Http server stopped unexpectedly"),
Err(e) => error!("Http server stopped with error: {}", e),
}
}
@@ -330,7 +330,7 @@ impl<A: Application> EphemeraStarterWithApplication<A> {
}
nw_stopped = network.start() => {
match nw_stopped {
Ok(_) => info!("Network stopped unexpectedly"),
Ok(()) => info!("Network stopped unexpectedly"),
Err(e) => error!("Network stopped with error: {e}",),
}
}
+1 -1
View File
@@ -120,7 +120,7 @@ impl<A: Application> Ephemera<A> {
while !shutdown.is_shutdown() {
tokio::select! {
biased;
_ = shutdown.recv() => {
() = shutdown.recv() => {
trace!("UpdateHandler: Received shutdown");
self.shutdown_manager.stop().await;
break;
+1 -1
View File
@@ -57,7 +57,7 @@ impl ShutdownManager {
.map(|(i, h)| (i + 1, h))
{
match handle.await.unwrap() {
Ok(_) => info!("Task {i} finished successfully"),
Ok(()) => info!("Task {i} finished successfully"),
Err(e) => info!("Task {i} finished with error: {e}",),
}
}
@@ -309,7 +309,7 @@ impl ConnectionHandler for Handler {
match event {
ConnectionEvent::FullyNegotiatedInbound(FullyNegotiatedInbound {
protocol: stream,
info: _,
info: (),
}) => {
if self.inbound_substream_attempts > MAX_SUBSTREAM_ATTEMPTS {
log::warn!("Too many inbound substream attempts, refusing stream");
@@ -320,7 +320,7 @@ impl ConnectionHandler for Handler {
}
ConnectionEvent::FullyNegotiatedOutbound(FullyNegotiatedOutbound {
protocol,
info: _,
info: (),
}) => {
if self.outbound_substream_attempts > MAX_SUBSTREAM_ATTEMPTS {
log::warn!("Too many outbound substream attempts, refusing stream");
+2 -2
View File
@@ -1,12 +1,12 @@
[package]
name = "explorer-api"
version = "1.1.29"
version = "1.1.30"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
chrono = { version = "0.4.19", features = ["serde"] }
chrono = { version = "0.4.31", features = ["serde"] }
clap = { version = "4.0", features = ["cargo", "derive"] }
dotenvy = "0.15.6"
humantime-serde = "1.0"
+29 -6
View File
@@ -3,7 +3,7 @@
[package]
name = "nym-gateway"
version = "1.1.29"
version = "1.1.30"
authors = [
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
"Jędrzej Stuczyński <andrew@nymtech.net>",
@@ -15,6 +15,13 @@ rust-version = "1.56"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
axum = "0.6.20"
sha2 = "0.10.8"
hmac = "0.12.1"
axum-macros = "0.3.8" # Useful for debugging axum Handler trait errors
fastrand = "2"
x25519-dalek = { version = "2.0.0", features = ["static_secrets"] }
base64 = "0.21.4"
anyhow = { workspace = true }
async-trait = { workspace = true }
atty = "0.2"
@@ -34,12 +41,23 @@ pretty_env_logger = "0.4"
rand = "0.7"
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
sqlx = { version = "0.5", features = [ "runtime-tokio-rustls", "sqlite", "macros", "migrate", ] }
sqlx = { version = "0.5", features = [
"runtime-tokio-rustls",
"sqlite",
"macros",
"migrate",
] }
subtle-encoding = { version = "0.5", features = ["bech32-preview"] }
thiserror = "1"
tokio = { workspace = true, features = [ "rt-multi-thread", "net", "signal", "fs", "time" ] }
tokio = { workspace = true, features = [
"rt-multi-thread",
"net",
"signal",
"fs",
"time",
] }
tokio-stream = { version = "0.1.11", features = ["fs"] }
tokio-tungstenite = "0.14"
tokio-tungstenite = { version = "0.20.1" }
tokio-util = { version = "0.7.4", features = ["codec"] }
url = { version = "2.2", features = ["serde"] }
zeroize = { workspace = true }
@@ -62,7 +80,12 @@ nym-statistics-common = { path = "../common/statistics" }
nym-task = { path = "../common/task" }
nym-types = { path = "../common/types" }
nym-validator-client = { path = "../common/client-libs/validator-client" }
nym-wireguard = { path = "../common/wireguard" }
nym-wireguard = { path = "../common/wireguard", optional = true }
[dev-dependencies]
tower = "0.4.13"
rand = "0.8.5"
hyper = "0.14.27"
[build-dependencies]
tokio = { version = "1.24.1", features = ["rt-multi-thread", "macros"] }
@@ -74,4 +97,4 @@ sqlx = { version = "0.5", features = [
] }
[features]
wireguard = []
wireguard = ["nym-wireguard"]
+1 -1
View File
@@ -28,6 +28,6 @@ nym-coconut-interface = { path = "../../common/coconut-interface" }
nym-credentials = { path = "../../common/credentials" }
[dependencies.tungstenite]
version = "0.13.0"
workspace = true
default-features = false
+10
View File
@@ -106,6 +106,16 @@ pub(crate) enum GatewayError {
#[from]
source: NyxdError,
},
#[error("Error verifying hmac digest")]
HmacDigestError {
#[from]
source: hmac::digest::MacError,
},
#[error("Invalid hmac length")]
HmacInvalidLength {
#[from]
source: hmac::digest::InvalidLength,
},
}
impl From<ClientCoreError> for GatewayError {
@@ -0,0 +1,181 @@
use std::{
collections::HashMap,
fmt,
hash::{Hash, Hasher},
net::SocketAddr,
ops::Deref,
str::FromStr,
};
use base64::{engine::general_purpose, Engine};
use hmac::{Hmac, Mac};
use nym_crypto::asymmetric::encryption::PrivateKey;
use serde::{Deserialize, Serialize};
use sha2::Sha256;
use x25519_dalek::StaticSecret;
use crate::error::GatewayError;
#[derive(Debug, Clone, Deserialize, Serialize)]
pub(crate) enum ClientMessage {
Init(InitMessage),
Final(Client),
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub(crate) struct InitMessage {
pub_key: ClientPublicKey,
}
impl InitMessage {
pub fn pub_key(&self) -> &ClientPublicKey {
&self.pub_key
}
#[allow(dead_code)]
pub fn new(pub_key: ClientPublicKey) -> Self {
InitMessage { pub_key }
}
}
// Client that wants to register sends its PublicKey and SocketAddr bytes mac digest encrypted with a DH shared secret.
// Gateway can then verify pub_key payload using the sme process
#[derive(Debug, Clone, Deserialize, Serialize)]
pub(crate) struct Client {
// base64 encoded public key, using x25519-dalek for impl
pub(crate) pub_key: ClientPublicKey,
pub(crate) socket: SocketAddr,
pub(crate) mac: ClientMac,
}
pub type HmacSha256 = Hmac<Sha256>;
impl Client {
// Reusable secret should be gateways Wireguard PK
// Client should perform this step when generating its payload, using its own WG PK
pub fn verify(&self, gateway_key: &PrivateKey, nonce: u64) -> Result<(), GatewayError> {
#[allow(clippy::expect_used)]
let static_secret =
StaticSecret::try_from(gateway_key.to_bytes()).expect("This is infalliable");
let dh = static_secret.diffie_hellman(&self.pub_key);
let mut mac = HmacSha256::new_from_slice(dh.as_bytes())?;
mac.update(self.pub_key.as_bytes());
mac.update(self.socket.ip().to_string().as_bytes());
mac.update(self.socket.port().to_string().as_bytes());
mac.update(&nonce.to_le_bytes());
Ok(mac.verify_slice(&self.mac)?)
}
pub fn pub_key(&self) -> &ClientPublicKey {
&self.pub_key
}
pub fn socket(&self) -> SocketAddr {
self.socket
}
}
// This should go into nym-wireguard crate
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ClientPublicKey(x25519_dalek::PublicKey);
#[derive(Debug, Clone)]
pub(crate) struct ClientMac(Vec<u8>);
impl ClientMac {
#[allow(dead_code)]
pub fn new(mac: Vec<u8>) -> Self {
ClientMac(mac)
}
}
impl Deref for ClientMac {
type Target = Vec<u8>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl fmt::Display for ClientPublicKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", general_purpose::STANDARD.encode(self.0.as_bytes()))
}
}
impl Hash for ClientPublicKey {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.as_bytes().hash(state)
}
}
impl FromStr for ClientMac {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mac_bytes: Vec<u8> = general_purpose::STANDARD
.decode(s)
.map_err(|_| "Could not base64 decode public key mac representation".to_string())?;
Ok(ClientMac(mac_bytes))
}
}
impl Serialize for ClientMac {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let encoded_key = general_purpose::STANDARD.encode(self.0.clone());
serializer.serialize_str(&encoded_key)
}
}
impl<'de> Deserialize<'de> for ClientMac {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let encoded_key = String::deserialize(deserializer)?;
ClientMac::from_str(&encoded_key).map_err(serde::de::Error::custom)
}
}
impl ClientPublicKey {
#[allow(dead_code)]
pub fn new(key: x25519_dalek::PublicKey) -> Self {
ClientPublicKey(key)
}
pub fn as_bytes(&self) -> &[u8] {
self.0.as_bytes()
}
}
impl Deref for ClientPublicKey {
type Target = x25519_dalek::PublicKey;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl FromStr for ClientPublicKey {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let key_bytes: [u8; 32] = general_purpose::STANDARD
.decode(s)
.map_err(|_| "Could not base64 decode public key representation".to_string())?
.try_into()
.map_err(|_| "Invalid key length".to_string())?;
Ok(ClientPublicKey(x25519_dalek::PublicKey::from(key_bytes)))
}
}
impl Serialize for ClientPublicKey {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let encoded_key = general_purpose::STANDARD.encode(self.0.as_bytes());
serializer.serialize_str(&encoded_key)
}
}
impl<'de> Deserialize<'de> for ClientPublicKey {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let encoded_key = String::deserialize(deserializer)?;
Ok(ClientPublicKey::from_str(&encoded_key).map_err(serde::de::Error::custom))?
}
}
pub(crate) type ClientRegistry = HashMap<SocketAddr, Client>;
+1
View File
@@ -3,6 +3,7 @@
pub(crate) mod active_clients;
mod bandwidth;
pub(crate) mod client_registration;
pub(crate) mod embedded_network_requester;
pub(crate) mod websocket;
@@ -91,7 +91,7 @@ impl CoconutVerifier {
let req = nym_api_requests::coconut::VerifyCredentialBody::new(
credential.clone(),
proposal_id,
self.nyxd_client.address().clone(),
self.nyxd_client.address(),
);
for client in api_clients {
self.nyxd_client
@@ -19,11 +19,11 @@ mod authenticated;
pub(crate) mod coconut;
mod fresh;
//// TODO: note for my future self to consider the following idea:
//// split the socket connection into sink and stream
//// stream will be for reading explicit requests
//// and sink for pumping responses AND mix traffic
//// but as byproduct this might (or might not) break the clean "SocketStream" enum here
// TODO: note for my future self to consider the following idea:
// split the socket connection into sink and stream
// stream will be for reading explicit requests
// and sink for pumping responses AND mix traffic
// but as byproduct this might (or might not) break the clean "SocketStream" enum here
pub(crate) enum SocketStream<S> {
RawTcp(S),
+1
View File
@@ -0,0 +1 @@
pub(crate) mod v1;
@@ -0,0 +1,105 @@
use axum::extract::Path;
use std::sync::Arc;
use axum::http::StatusCode;
use axum::{extract::State, Json};
use std::str::FromStr;
// use axum_macros::debug_handler;
use crate::node::client_handling::client_registration::{
Client, ClientMessage, ClientPublicKey, InitMessage,
};
use crate::node::http::ApiState;
async fn process_final_message(client: Client, state: Arc<ApiState>) -> StatusCode {
let preshared_nonce = {
let in_progress_ro = state.registration_in_progress.read().await;
if let Some(nonce) = in_progress_ro.get(client.pub_key()) {
*nonce
} else {
return StatusCode::BAD_REQUEST;
}
};
if client
.verify(state.sphinx_key_pair.private_key(), preshared_nonce)
.is_ok()
{
{
let mut in_progress_rw = state.registration_in_progress.write().await;
in_progress_rw.remove(client.pub_key());
}
{
let mut registry_rw = state.client_registry.write().await;
registry_rw.insert(client.socket(), client);
}
return StatusCode::OK;
}
StatusCode::BAD_REQUEST
}
async fn process_init_message(init_message: InitMessage, state: Arc<ApiState>) -> u64 {
let nonce: u64 = fastrand::u64(..);
let mut registry_rw = state.registration_in_progress.write().await;
registry_rw.insert(init_message.pub_key().clone(), nonce);
nonce
}
// #[debug_handler]
pub(crate) async fn register_client(
State(state): State<Arc<ApiState>>,
Json(payload): Json<ClientMessage>,
) -> (StatusCode, Json<Option<u64>>) {
match payload {
ClientMessage::Init(i) => (
StatusCode::OK,
Json(Some(process_init_message(i, Arc::clone(&state)).await)),
),
ClientMessage::Final(client) => (
process_final_message(client, Arc::clone(&state)).await,
Json(None),
),
}
}
pub(crate) async fn get_all_clients(
State(state): State<Arc<ApiState>>,
) -> (StatusCode, Json<Vec<ClientPublicKey>>) {
let registry_ro = state.client_registry.read().await;
(
StatusCode::OK,
Json(
registry_ro
.values()
.map(|c| c.pub_key().clone())
.collect::<Vec<ClientPublicKey>>(),
),
)
}
pub(crate) async fn get_client(
Path(pub_key): Path<String>,
State(state): State<Arc<ApiState>>,
) -> (StatusCode, Json<Vec<Client>>) {
let pub_key = match ClientPublicKey::from_str(&pub_key) {
Ok(pub_key) => pub_key,
Err(_) => return (StatusCode::BAD_REQUEST, Json(vec![])),
};
let registry_ro = state.client_registry.read().await;
let clients = registry_ro
.iter()
.filter_map(|(_, c)| {
if c.pub_key() == &pub_key {
Some(c.clone())
} else {
None
}
})
.collect::<Vec<Client>>();
if clients.is_empty() {
return (StatusCode::NOT_FOUND, Json(clients));
}
(StatusCode::OK, Json(clients))
}
+1
View File
@@ -0,0 +1 @@
pub(crate) mod client_registry;
+206
View File
@@ -0,0 +1,206 @@
use std::{collections::HashMap, sync::Arc};
use axum::{
routing::{get, post},
Router,
};
use log::info;
use nym_crypto::asymmetric::encryption;
use tokio::sync::RwLock;
mod api;
use api::v1::client_registry::*;
use super::client_handling::client_registration::{ClientPublicKey, ClientRegistry};
const ROUTE_PREFIX: &str = "/api/v1/gateway/client-interfaces/wireguard";
pub struct ApiState {
client_registry: Arc<RwLock<ClientRegistry>>,
sphinx_key_pair: Arc<encryption::KeyPair>,
registration_in_progress: Arc<RwLock<HashMap<ClientPublicKey, u64>>>,
}
fn router_with_state(state: Arc<ApiState>) -> Router {
Router::new()
.route(&format!("{}/clients", ROUTE_PREFIX), get(get_all_clients))
.route(&format!("{}/client", ROUTE_PREFIX), post(register_client))
.route(
&format!("{}/client/:pub_key", ROUTE_PREFIX),
get(get_client),
)
.with_state(state)
}
pub(crate) async fn start_http_api(
client_registry: Arc<RwLock<ClientRegistry>>,
sphinx_key_pair: Arc<encryption::KeyPair>,
) {
// Port should be 80 post smoosh
let port = 8000;
info!("Started HTTP API on port {}", port);
let client_registry = Arc::clone(&client_registry);
let state = Arc::new(ApiState {
client_registry,
sphinx_key_pair,
registration_in_progress: Arc::new(RwLock::new(HashMap::new())),
});
let routes = router_with_state(state);
#[allow(clippy::unwrap_used)]
axum::Server::bind(&format!("0.0.0.0:{}", port).parse().unwrap())
.serve(routes.into_make_service())
.await
.unwrap();
}
#[cfg(test)]
mod test {
use std::net::SocketAddr;
use std::str::FromStr;
use std::{collections::HashMap, sync::Arc};
use axum::body::Body;
use axum::http::Request;
use axum::http::StatusCode;
use hmac::Mac;
use tower::Service;
use tower::ServiceExt;
use nym_crypto::asymmetric::encryption;
use tokio::sync::RwLock;
use x25519_dalek::{PublicKey, StaticSecret};
use crate::node::client_handling::client_registration::{
Client, ClientMac, ClientMessage, InitMessage,
};
use crate::node::client_handling::client_registration::{ClientPublicKey, HmacSha256};
use crate::node::http::{router_with_state, ApiState, ROUTE_PREFIX};
#[tokio::test]
async fn registration() {
// 1. Provision random keys for gateway and client
// 2. Generate DH shared secret
// 3. Client submits its public key to the gateway to start the handshake process, gateway responds with nonce
// 4. Client generates mac digest using DH shared secret, its own public key, socket address and port, and nonce
// 5. Client sends its public key, socket address and port, nonce and mac digest to the gateway
// 6. Gateway verifies mac digest and nonce, and stores client's public key and socket address and port
let mut rng = rand::thread_rng();
let gateway_key_pair = encryption::KeyPair::new(&mut rng);
let client_key_pair = encryption::KeyPair::new(&mut rng);
let gateway_static_public =
PublicKey::try_from(gateway_key_pair.public_key().to_bytes()).unwrap();
let client_static_private =
StaticSecret::try_from(client_key_pair.private_key().to_bytes()).unwrap();
let client_static_public =
PublicKey::try_from(client_key_pair.public_key().to_bytes()).unwrap();
let client_dh = client_static_private.diffie_hellman(&gateway_static_public);
let registration_in_progress = Arc::new(RwLock::new(HashMap::new()));
let client_registry = Arc::new(RwLock::new(HashMap::new()));
let state = Arc::new(ApiState {
client_registry: Arc::clone(&client_registry),
sphinx_key_pair: Arc::new(gateway_key_pair),
registration_in_progress: Arc::clone(&registration_in_progress),
});
// `Router` implements `tower::Service<Request<Body>>` so we can
// call it like any tower service, no need to run an HTTP server.
let mut app = router_with_state(state);
let init_message =
ClientMessage::Init(InitMessage::new(ClientPublicKey::new(client_static_public)));
let init_request = Request::builder()
.method("POST")
.uri(format!("{}/client", ROUTE_PREFIX))
.header("Content-type", "application/json")
.body(Body::from(serde_json::to_vec(&init_message).unwrap()))
.unwrap();
let response = ServiceExt::<Request<Body>>::ready(&mut app)
.await
.unwrap()
.call(init_request)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
assert!(!registration_in_progress.read().await.is_empty());
let nonce: Option<u64> =
serde_json::from_slice(&hyper::body::to_bytes(response.into_body()).await.unwrap())
.unwrap();
assert!(nonce.is_some());
let mut mac = HmacSha256::new_from_slice(client_dh.as_bytes()).unwrap();
mac.update(client_static_public.as_bytes());
mac.update("127.0.0.1".as_bytes());
mac.update("8080".as_bytes());
mac.update(&nonce.unwrap().to_le_bytes());
let mac = mac.finalize().into_bytes();
let finalized_message = ClientMessage::Final(Client {
pub_key: ClientPublicKey::new(client_static_public),
socket: SocketAddr::from_str("127.0.0.1:8080").unwrap(),
mac: ClientMac::new(mac.as_slice().to_vec()),
});
let final_request = Request::builder()
.method("POST")
.uri(format!("{}/client", ROUTE_PREFIX))
.header("Content-type", "application/json")
.body(Body::from(serde_json::to_vec(&finalized_message).unwrap()))
.unwrap();
let response = ServiceExt::<Request<Body>>::ready(&mut app)
.await
.unwrap()
.call(final_request)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
assert!(!client_registry.read().await.is_empty());
let clients_request = Request::builder()
.method("GET")
.uri(format!("{}/clients", ROUTE_PREFIX))
.body(Body::empty())
.unwrap();
let response = ServiceExt::<Request<Body>>::ready(&mut app)
.await
.unwrap()
.call(clients_request)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
let clients: Vec<ClientPublicKey> =
serde_json::from_slice(&hyper::body::to_bytes(response.into_body()).await.unwrap())
.unwrap();
assert!(!clients.is_empty());
let ro_clients = client_registry.read().await.clone();
assert_eq!(
ro_clients
.values()
.map(|c| c.pub_key().clone())
.collect::<Vec<ClientPublicKey>>(),
clients
)
}
}
+16 -1
View File
@@ -1,6 +1,7 @@
// Copyright 2020-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use self::client_handling::client_registration::ClientRegistry;
use self::storage::PersistentStorage;
use crate::commands::helpers::{override_network_requester_config, OverrideNetworkRequesterConfig};
use crate::config::Config;
@@ -12,6 +13,7 @@ use crate::node::client_handling::embedded_network_requester::{
use crate::node::client_handling::websocket;
use crate::node::client_handling::websocket::connection_handler::coconut::CoconutVerifier;
use crate::node::helpers::{initialise_main_storage, load_network_requester_config};
use crate::node::http::start_http_api;
use crate::node::mixnet_handling::receiver::connection_handler::ConnectionHandler;
use crate::node::statistics::collector::GatewayStatisticsCollector;
use crate::node::storage::Storage;
@@ -27,13 +29,16 @@ use nym_task::{TaskClient, TaskManager};
use nym_validator_client::{nyxd, DirectSigningHttpRpcNyxdClient};
use rand::seq::SliceRandom;
use rand::thread_rng;
use std::collections::HashMap;
use std::error::Error;
use std::net::SocketAddr;
use std::path::PathBuf;
use std::sync::Arc;
use tokio::sync::RwLock;
pub(crate) mod client_handling;
pub(crate) mod helpers;
pub(crate) mod http;
pub(crate) mod mixnet_handling;
pub(crate) mod statistics;
pub(crate) mod storage;
@@ -85,6 +90,8 @@ pub(crate) struct Gateway<St = PersistentStorage> {
/// x25519 keypair used for Diffie-Hellman. Currently only used for sphinx key derivation.
sphinx_keypair: Arc<encryption::KeyPair>,
storage: St,
client_registry: Arc<RwLock<ClientRegistry>>,
}
impl<St> Gateway<St> {
@@ -100,6 +107,7 @@ impl<St> Gateway<St> {
sphinx_keypair: Arc::new(helpers::load_sphinx_keys(&config)?),
config,
network_requester_opts,
client_registry: Arc::new(RwLock::new(HashMap::new())),
})
}
@@ -117,6 +125,7 @@ impl<St> Gateway<St> {
identity_keypair: Arc::new(identity_keypair),
sphinx_keypair: Arc::new(sphinx_keypair),
storage,
client_registry: Arc::new(RwLock::new(HashMap::new())),
}
}
@@ -370,11 +379,17 @@ impl<St> Gateway<St> {
// Once this is a bit more mature, make this a commandline flag instead of a compile time
// flag
#[cfg(feature = "wireguard")]
if let Err(err) = nym_wireguard::start_wg_listener(shutdown.subscribe()).await {
if let Err(err) = nym_wireguard::start_wireguard(shutdown.subscribe()).await {
// that's a nasty workaround, but anyhow errors are generally nicer, especially on exit
bail!("{err}")
}
// This should likely be wireguard feature gated, but its easier to test if it hangs in here
tokio::spawn(start_http_api(
Arc::clone(&self.client_registry),
Arc::clone(&self.sphinx_keypair),
));
info!("Finished nym gateway startup procedure - it should now be able to receive mix and client traffic!");
if let Err(err) = Self::wait_for_interrupt(shutdown).await {
+1 -1
View File
@@ -3,7 +3,7 @@
[package]
name = "nym-mixnode"
version = "1.1.30"
version = "1.1.31"
authors = [
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
"Jędrzej Stuczyński <andrew@nymtech.net>",
+1 -1
View File
@@ -3,7 +3,7 @@
[package]
name = "nym-api"
version = "1.1.30"
version = "1.1.31"
authors = [
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
"Jędrzej Stuczyński <andrew@nymtech.net>",
+1 -1
View File
@@ -48,7 +48,7 @@ impl Epoch {
let start_time = NaiveDateTime::from_timestamp_opt(info.start_time, 0)
.ok_or("Invalid start time")
.unwrap();
let start_time: DateTime<Utc> = DateTime::from_utc(start_time, Utc);
let start_time: DateTime<Utc> = DateTime::from_naive_utc_and_offset(start_time, Utc);
let interval = tokio::time::interval(std::time::Duration::from_secs(info.duration));
Self {
start_time,
@@ -21,4 +21,18 @@ describe("Get service provider info", (): void => {
return;
}
});
it("Get Nym address names", async (): Promise<void> => {
const response = await contract.getNymAddressNames();
if ("[id]" in response) {
response.names.forEach((x) => {
expect(typeof x.name.name).toBe("string");
expect(typeof x.name.address.gateway_id).toBe("string");
expect(typeof x.id).toBe("number");
});
} else if ("[ ]" in response) {
return;
}
});
});
@@ -0,0 +1,47 @@
import NetworkTypes from "../../src/endpoints/Network";
let contract: NetworkTypes;
describe("Get network and contract details", (): void => {
beforeAll(async (): Promise<void> => {
contract = new NetworkTypes();
});
it("Get network details", async (): Promise<void> => {
const response = await contract.getNetworkDetails();
expect(typeof response.network.network_name).toBe("string");
});
it("Get nym contract info", async (): Promise<void> => {
const response = await contract.getNymContractInfo();
for (const key in response) {
if (response.hasOwnProperty(key)) {
const additionalProp = response[key];
expect(typeof additionalProp.address).toBe("string");
if ("build_timestamp" in response) {
expect(typeof additionalProp.details.contract).toBe("string");
expect(typeof additionalProp.details.version).toBe("string");
}
else if (additionalProp.details === null) {
expect(additionalProp.details).toBeNull();
}
}
}
});
it("Get nym contract info detailed", async (): Promise<void> => {
const response = await contract.getNymContractDetailedInfo();
for (const key in response) {
if (response.hasOwnProperty(key)) {
const additionalProp = response[key];
expect(typeof additionalProp.address).toBe("string");
if ("build_timestamp" in response) {
expect(typeof additionalProp.details.build_timestamp).toBe("string");
expect(typeof additionalProp.details.rustc_version).toBe("string");
}
else if (additionalProp.details === null) {
expect(additionalProp.details).toBeNull();
}
}
}
});
});
@@ -5,6 +5,7 @@ import {
EpochRewardParams,
CurrentEpoch,
ServiceProviders,
NymAddressNames,
} from "../types/ContractCacheTypes";
import { APIClient } from "./abstracts/APIClient";
@@ -97,4 +98,11 @@ export default class ContractCache extends APIClient {
});
return response.data;
}
public async getNymAddressNames(): Promise<NymAddressNames> {
const response = await this.restClient.sendGet({
route: `names`,
});
return response.data;
}
}
+29
View File
@@ -0,0 +1,29 @@
import { NetworkDetails, NymContracts, NymContractsDetailed } from "../types/NetworkTypes";
import { APIClient } from "./abstracts/APIClient";
export default class NetworkTypes extends APIClient {
constructor() {
super("/");
}
public async getNetworkDetails(): Promise<NetworkDetails> {
const response = await this.restClient.sendGet({
route: `network/details`,
});
return response.data;
}
public async getNymContractInfo(): Promise<NymContracts> {
const response = await this.restClient.sendGet({
route: `network/nym-contracts`,
});
return response.data;
}
public async getNymContractDetailedInfo(): Promise<NymContractsDetailed> {
const response = await this.restClient.sendGet({
route: `network/nym-contracts-detailed`,
});
return response.data;
}
}

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