Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 48-error-base-58-requirement-is-violated
  • elois-ci-refactor
  • gtest
  • hugo/dev
  • hugo/gtest
  • hugo/tx-comments
  • json-output
  • master
  • no-rename
  • nostr
  • poka/dev
  • tuxmain/mail
  • 0.1.0
  • 0.2.0
  • 0.2.1
  • 0.2.10
  • 0.2.12
  • 0.2.13
  • 0.2.14
  • 0.2.15
  • 0.2.16
  • 0.2.17
  • 0.2.3
  • 0.2.4
  • 0.2.5
  • 0.2.6
  • 0.2.7
  • 0.2.8
  • 0.2.9
  • 0.3.0
  • 0.4.0
  • 0.4.1
  • 0.4.2
  • 0.4.3-RC1
  • 0.4.3-RC2
  • 0.4.3-gtest-RC1
  • test-gtest
37 results

Target

Select target project
  • clients/rust/gcli-v2s
  • d0p1/gcli-v2s
  • flebon/gcli-v2s
  • zicmama/gcli-v2s
  • Nicolas80/gcli-v2s
5 results
Select Git revision
  • master
1 result
Show changes
Commits on Source (51)
  • Millicent Billette's avatar
    1000i100 (clients/rust/gcli-v2s!35) · 3bb993f7
    Millicent Billette authored and Hugo Trentesaux's avatar Hugo Trentesaux committed
    * Update README.md
    
    * Add Install instruction
    3bb993f7
  • Hugo Trentesaux's avatar
    update squid API and add endpoints · e999ecf4
    Hugo Trentesaux authored
    e999ecf4
  • Moul's avatar
    config save: Print update confirmation · 671f1496
    Moul authored
    671f1496
  • Hugo Trentesaux's avatar
    update subxt dependency · bdffe9f8
    Hugo Trentesaux authored
    bdffe9f8
  • Hugo Trentesaux's avatar
    also upgrade in cargo.toml · 51ba001a
    Hugo Trentesaux authored
    51ba001a
  • Hugo Trentesaux's avatar
  • Hugo Trentesaux's avatar
    more precise error type · 260a225a
    Hugo Trentesaux authored
    260a225a
  • Hugo Trentesaux's avatar
    manage error when no indexer · 4ae6d5de
    Hugo Trentesaux authored
    closes #35
    4ae6d5de
  • Hugo Trentesaux's avatar
    update version number · a6480ee9
    Hugo Trentesaux authored
    a6480ee9
  • Hugo Trentesaux's avatar
    update metadata · aa8494dd
    Hugo Trentesaux authored
    on runtime 802
    changed crypto types
    aa8494dd
  • matograine's avatar
    CI : remove GET params at the end of assets URLs (!37) · 9460516b
    matograine authored and Moul's avatar Moul committed
    * CI : remove GET params at the end of assets URLs
    9460516b
  • Moul's avatar
    Revert "CI : remove GET params at the end of assets URLs (clients/rust/gcli-v2s!37)" · 4e90dae3
    Moul authored
    This reverts commit 9460516b.
    
    Does not solve the issue, the links do not work anymore:
    They need `?job=$job_name` at the end in which the artifacts have been created
    https://git.duniter.org/clients/rust/gcli-v2s/-/releases/0.3.1
    4e90dae3
  • Moul's avatar
    Build deb and macos pkgs in parallel · a11ca34f
    Moul authored
    to speed up the process
    The runner is not overloaded with one build
    a11ca34f
  • Nicolas80's avatar
    Fixing precision issue when converting the u64 cents amount into f32. (!39) · 8f67e583
    Nicolas80 authored and Hugo Trentesaux's avatar Hugo Trentesaux committed
    * Fixing precision issue when converting the u64 cents amount into f32.
    Now composing the displayed value with integer part and fractional part separately (keeping left padding of 0 for the decimal part for the amount of decimals required)
    8f67e583
  • Nicolas80's avatar
    Adding db persistence for all SecretFormat of vault keys as well as supporting derivations · badf52ce
    Nicolas80 authored
    * Added "/.idea" exclusion in .gitignore (for when using JetBrains IDEs)
    * Added dialoguer dependency for easier user input handling (see in inputs.rs)
    * Added sea-orm dependency to allow having DB entity mappings and use a local sqlite file database
    * Added rstest test dependency for parameterized tests support
    * Added derivation tests for each SecretFormat (including cesium v1 key derivation, using sp_core::ed25519::Pair)
    * Made a lot of changes to add vault_account and vault_derivation db tables to persist vault keys & derivations
    * Added support for KeyPair::Ed25519 linking to sp_core::ed25519::Pair which can be created from secret seed retrieved from nacl::sign::Keypair (which is created from cesium id + secret)
    ** This was necessary to allow deriving keys from "cesium v1" keys (to be reviewed - it might be a bad idea to permit that from a security point of view)
    * Only kept original (substrate) keyfiles support for migration (use "vault list-files" and "vault migrate")
    * Added possibility to give either "-a" Address or "-v" Vault Name as general option
    * Added extra commands in Vault
    ** list-files: (deprecated)List available key files (needs to be migrated with command "vault migrate" in order to use them)
    ** migrate: (deprecated)Migrate old key files into db (will have to provide password for each key)
    ** 'list' now has sub-commands 'all' or 'root' to show all keys or only root keys (without derivation path)
    ** use: "Use specific vault key (changes the config address)", which will have the same behaviour as `gcli <-a <Address>|-v <VaultName>> config save` (left a FIXME in there to review)
    ** derivation: Add a derivation to an existing (root) vault key
    ** rename: Give a meaningful vault name to a vault key or derivation
    ** remove: Remove a vault key (and potential derivations if it's a root key)
    * Had to bubble up "await" and "async" in a lot of places
    * ...
    badf52ce
  • Nicolas80's avatar
  • Nicolas80's avatar
    Small rewordings to be consistent · 30ebcf10
    Nicolas80 authored
    30ebcf10
  • Nicolas80's avatar
    Reusing `inquire` dependency (which I didn't see in the first place) for user inputs · 747e02da
    Nicolas80 authored
    * Had to bump up the dependency since version 0.6.2 had a bug for the password confirmation - see https://github.com/mikaelmello/inquire/issues/149
    * Removed `dialoguer` dependency
    * We may want to replace all `rpassword` usage with `inquire` in the future
    747e02da
  • Nicolas80's avatar
    * Adapted to have more coherent commands descriptions and added `long_about`... · cf7a4292
    Nicolas80 authored
    * Adapted to have more coherent commands descriptions and added `long_about` more detailed description for `import` and `derivation`
    * Added the `vault list for` command
    * Added display of "format" of <Root> derivations in all `vault list` commands
    * Only allowing derivations for format "substrate" and "seed"
    cf7a4292
  • Nicolas80's avatar
    * Fixed small bug after switching from `dialoguer` to `inquire`: using... · 262ea4c5
    Nicolas80 authored
    * Fixed small bug after switching from `dialoguer` to `inquire`: using `prompt_skippable()` only returns `None` if the user presses `Esc` (returned "" when user just pressed enter)
    * Now using `prompt()` and checking empty string again.
    262ea4c5
  • Nicolas80's avatar
    * Added a test to verify we don't need the nacl::sign::Keypair to handle... · b3c0e13c
    Nicolas80 authored
    * Added a test to verify we don't need the nacl::sign::Keypair to handle cesium v1 (we can keep using scrypt to retrieve the seed and then sp_core::ed25519::Pair)
    ** This means we could remove some code linked to that and possibly the `nacl` dependency.
    b3c0e13c
  • Nicolas80's avatar
    * Renaming to refer to "<Account>" instead of "<Root> derivation" to avoid confusion. · 90f5f2aa
    Nicolas80 authored
    * Simply using "name" for the name given to an SS58 Address in the vault
    90f5f2aa
  • Nicolas80's avatar
    * Small refactorings & rewordings · da66773d
    Nicolas80 authored
    da66773d
  • Nicolas80's avatar
    Removed `nacl` dependency and now using sp_core::ed25519::Pair instead of nacl::sign::Keypair. · 4eafec2a
    Nicolas80 authored
    * Cleaned-up code in several places
    * Now retrieving secret value in "substrate uri" format from the different prompt_xxx_and_compute_keypair methods
    4eafec2a
  • Nicolas80's avatar
  • Nicolas80's avatar
  • Nicolas80's avatar
    Made an extra check of derivation path to make sure it's not linking to the... · a5069df9
    Nicolas80 authored
    Made an extra check of derivation path to make sure it's not linking to the same SS58 Address as "root" suri when doing `vault import|migrate`
    a5069df9
  • Nicolas80's avatar
    Small refactorings from MR comments · f132287f
    Nicolas80 authored
    f132287f
  • Nicolas80's avatar
    Small cleanup for data's db connection; adding method connect_db that returns... · 9c57fb7c
    Nicolas80 authored
    Small cleanup for data's db connection; adding method connect_db that returns a &DatabaseConnection (or panics with explanation message)
    
    Also changed some methods visibility so only connect_db is visible for usage.
    9c57fb7c
  • Nicolas80's avatar
    223ec22b
  • Nicolas80's avatar
    Small cleanup of todo · a205dce4
    Nicolas80 authored
    a205dce4
  • Nicolas80's avatar
    * Added sc_cli::arg_enums::CryptoScheme partial copy in keys.rs · 3d7b15c0
    Nicolas80 authored
    * Started to investigate being able to make subkey command and trying to use sp_core::crypto::CryptoType instead of custom KeyPair
    * Big refactoring to have all in one vault_account db table; using recursion through `parent` property
    * Added AccountTreeNode object and related methods to be able to more easily handle whole tree of accounts
    * Removed now unused vault_derivation
    * Replaced remaining usages of `rpassword` and removed the dependency
    * Added `indoc` dependency to support cleaner display of multi-line strings in tests
    3d7b15c0
  • Nicolas80's avatar
    * Added replacement options for `import` and `derive` · 0c1a3104
    Nicolas80 authored
    * Relaxed "update" restrictions in vault_account.rs before_save checks
    0c1a3104
  • Nicolas80's avatar
    * Small cleanup refactoring · 0b9222c2
    Nicolas80 authored
    0b9222c2
  • Nicolas80's avatar
    * Small clean up of `clap` arguments · ab6169b1
    Nicolas80 authored
       * Put back simple `address` and `name` arguments in main.rs (with conflicts_with statement to prevent their usage at the same time)
       * Declared conflicts between indexer <=> no-indexer, indexer <=> network, url <=> network
       * Kept AddressOrVaultNameGroup args for vault usage since it's the only way to define one required arg within a group cleanly
    ab6169b1
  • Nicolas80's avatar
    Apply 1 suggestion(s) to 1 file(s) · e3f91e0f
    Nicolas80 authored
    
    Co-authored-by: default avatarHugo Trentesaux <hugo.trentesaux@lilo.org>
    e3f91e0f
  • Nicolas80's avatar
    Apply 1 suggestion(s) to 1 file(s) · 01f1c63d
    Nicolas80 authored
    
    Co-authored-by: default avatarHugo Trentesaux <hugo.trentesaux@lilo.org>
    01f1c63d
  • Nicolas80's avatar
    Apply 1 suggestion(s) to 1 file(s) · 921b92cc
    Nicolas80 authored
    
    Co-authored-by: default avatarHugo Trentesaux <hugo.trentesaux@lilo.org>
    921b92cc
  • Nicolas80's avatar
    * Small code reviews · 6555eb6f
    Nicolas80 authored
    6555eb6f
  • Nicolas80's avatar
  • Nicolas80's avatar
    * Added support to show g1v1 base58 public key from (ed25519) ss58 address,... · 66c7c2a8
    Nicolas80 authored
    * Added support to show g1v1 base58 public key from (ed25519) ss58 address, AccountId, ed25519::Public with tests for those
    * Renamed SecretFormat.Cesium to SecretFormat.G1v1
       * Adapted `clap` display help to reflect the change
       * Still supporting using "cesium" as "-S" secret format argument and mapping it to SecretFormat.G1v1
    * Adapted display of vault
       * Changed column "Format" into "Crypto", showing either "ed25519" or "sr25519" instead of "cesium" or "substrate"
       * Adapted 1st row header to "SS58 Address/G1v1 public key"
       * For "ed25519" account, showing a 2nd row just below containing "└ G1v1: <base58 public key value>"
       * Adapted test cases and added a G1v1 account example
    * Adapted (String) Display of vault_account to include "g1v1_pub_key" value when crypto_scheme is Ed25519
    66c7c2a8
  • Nicolas80's avatar
    * Adapted data::keypair() method so it doesn't block the user's terminal anymore · 07ea8692
    Nicolas80 authored
       * Now checking if GcliError Input message was for doing "ctrl+c" or "Esc" key in a prompt; in wich case we terminate the execution with the message.
       * Small correction in vault_account::compute_suri_account_tree_node where it's better to return GcliError instead of panic using unwrap if the password was incorrect.
    * Renamed `clap` arguments "value_name" in different places where it wasn't clear what kind of value was expected.
       * Using "ADDRESS" everytime we expect an AccountId
       * Using "USERNAME" everytime we expect a Username (most were requesting "TARGET")
    * Small corrections in `clap` help messages for `vault derive`
    * Added print of selected Vault item when using vault::try_fetch_key_pair method; just before requesting it's associated password (whenever we will try to sign for an action mostly)
    07ea8692
  • Nicolas80's avatar
    * Re-did the mapping of DbAccountId so that we don't have to rely on derive... · 89bde1dd
    Nicolas80 authored
    * Re-did the mapping of DbAccountId so that we don't have to rely on derive macro FromJsonQueryResult that resulted in using JSON_TEXT in database column instead of VARCHAR
       * Tricky part I missed the first time was in impl of sea_orm::TryGetable::try_get_by where we should return Err TryGetError::Null in case the value is not present
       * Was otherwise throwing an exception whenever `parent` field (Option<DbAccountId>) was None when trying to persist the case in DB.
    89bde1dd
  • Nicolas80's avatar
    * Bumped version to 0.4.0 · e9348bac
    Nicolas80 authored
    * Added a CHANGELOG.md file
    * Adapted config.md example of vault usage
    * Adapted some of the command descriptions to be more consistent
    e9348bac
  • Nicolas80's avatar
    * Adapted vault display to have a space before address value (for... · 8d3cbb70
    Nicolas80 authored
    * Adapted vault display to have a space before address value (for derivations); which fixes the incorrect selection when double-clicking an address in the terminal
    8d3cbb70
  • Nicolas80's avatar
    * Small changes in doc · bf6f5d70
    Nicolas80 authored
    bf6f5d70
  • Moul's avatar
    Adapt linux build now depending on libssl-dev. Introduce tests job (#45, #46)... · 5dd41657
    Moul authored
    Adapt linux build now depending on libssl-dev. Introduce tests job (#45, #46) (!42)
    
    * Adapt linux build now depending on libssl-dev (#45)
    
    native-tls transitive dependency introduced in !41
    which requires libssl-dev package installed
    for the build to find ssl components
    
    Switching to non-slim Debian image which comes
    with libssl-dev pre-installed
    
    Introduce linux tests job: to run tests (#46)
    and prevent similar issue in the future
    
    Update changelog
    5dd41657
  • poka's avatar
    feat: Can choose between ed25519 ans sr25519 (!44) · bb54cc00
    poka authored and Nicolas80's avatar Nicolas80 committed
    * * Updated CHANGELOG.md
    
    * * Updated CHANGELOG.md with `vault inspect` changes
    
    * * Added extra data in `vault inspect` command
      * Secret seed/mini-secret (if no soft derivation is used)
      * Public key (hex)
      * SS58 Address
      * (potential G1v1 public key if inspecting a <Base> account with ed25519 crypto-scheme)
    * Does most changes mentioned in Issue #28 (except the network id)
    
    * * Small change to be in line with the adapted parameter descriptions
    
    * * Refactored method get_keypair_from_secret_provider into SecretProvider internal method get_keypair
    * Added long_about for `LinkAccount` and `ChangeOwnerKey` to explain the target identity/account is provided with the options of those commands.
    * Applied cargo fmt
    
    * * Renamed AccountLinkParams to SecretProvider and adapted descriptions to "target account" instead of "account to link" which makes it a bit more generic
    * Added generic method get_keypair_from_secret_provider that returns the keypair or an error
    * Adapted `LinkAccount` & `ChangeOwnerKey` to use those
    * Not sure the best place for the SecretProvider and new method - leaving in identity for now
    
    * * Small refactoring to move method to vault.rs
    
    * * Small change to show the linked `<Base>` account if different from the one we inspect.
    
    * * Updated CHANGELOG.md
    
    * Code review:
    
    * Adapted commands identity `LinkAccount` & `ChangeOwnerKey`
      * Added possibility to provide
        * `-a` address of vault account to link
        * `-v` name of vault account to link
      * `-S` (secret_format) doesn't have a default anymore since it conflicts with using `-a` or `-v`
      * Added an error message if none of the params are provided
    
    * * Small clippy cleanup
    
    * * Changed sorting of children account so that they are sorted by Path value (makes more sense when viewing derivations of one account)
    * Added display of "Crypto scheme" when making `vault inspect` so that it is more coherent
    
    * Code review:
    
    * Cleanup of keys.rs get_keypair method since it always gets a crypto_scheme.
      * Removed "default" values in the method
      * Relying on "default" value of `-c` / `--crypto-scheme` argument (present in several places) which is ed25519
    
    * Code review:
    
    * Small comment cleanup
    * Code cleanup removed unnecessary empty cells in "g1v1" row
    * Added doc on prompt_secret_substrate_and_compute_keypair method to explain the values returned in the tuple.
    
    * * Updated version to 0.4.1
    * Added Changelog entry for the new version
    * Adapted some of the examples in config.md to take into account the new `-c` argument
    ** Did a simple addition of "-c sr25519" so that current examples still make sense and link to the same SS58 addresses
    
    * Added extra message when the DB parsing of DbAccountId fails, so we know for which string it failed.
    
    * * reverted most of the commit e9cd6a99: "Add secret format in database and display"
    
    * * Adapted catch_known of predefined derivations to properly handle both sr25519 and ed25519 versions of those keys.
    
    * * Added some logic between arguments of `vault import`; can't provide both `password` and `no-password`
    ** Added extra validation of non-interactive `name` argument value (same validation as when interactive: no '<', '>', '/' characters)
    * Added possibility to make a non-interactive derivation (given proper arguments are given and there is no issue found during the process)
    ** Added same validation for non-interactive `derivation_path` argument as when interactive
    ** If the same resulting address is already in the vault; interaction is still mandatory to make a choice
    * Had to change the name of argument AddressOrVaultNameGroup.name => vault_name to avoid conflict in `vault derive`
    ** Not changing the `-v` shortcut so no impact on existing commands
    * Allowing to pass "" empty string as non-interactive `name` argument and considering it as None (does a trim before checking empty; so only spaces will be considered as None as well)
    
    * * Adding `-c` crypto scheme parameter (with default ed25519) in different places
    ** as global parameter (taken into account if `-S` parameter is given
    ** as extra parameter for identity.rs commands LinkAccount & ChangeOwnerKey
    *** Also added a simple display of "target" address and crypto-scheme when performing those commands
    
    * * Fix for `vault migrate` that should use sr25519 scheme to be consistent
    
    * * Small fix in doc of function
    * Applied `cargo fmt`
    
    * add non interactive mode
    
    * remove unused methods
    
    * Add secret format in database and display
    
    * apply nico review
    
    * feat: Can choose between ed25519 ans sr25519
    bb54cc00
  • Nicolas80's avatar
    gcli command auto completion and arm64 build · bc740162
    Nicolas80 authored
    - Extra command `completion` added which takes a `--shell` argument to generate a completions script for a specified shell.
    - Adapted the Linux (amd64) build to:
      - generate the `gcli-completion.bash`, `gcli-completion.zsh`, `gcli-completion.fish`, `gcli-completion.ps1` completion scripts
      - add the `bash`, `zsh` and `fish` completion scripts in the `.deb` package
    - Added the ARM64 build generating a binary and a `.deb` package that also include those completion scripts.
    bc740162
  • Nicolas80's avatar
    gcli command auto completion and arm64 build · 3cecb009
    Nicolas80 authored
    - Added detailed instructions for generating the completion script and registering it for your shell when calling `gcli completion --help`
    - Added that information in the CHANGELOG.md
    - Moved `indoc` crate dependency in Cargo.toml to make it explicit it's now also used outside of tests.
    3cecb009
  • Nicolas80's avatar
    Small change to assign proper link_type to generated assets; so that all... · 4010a9e4
    Nicolas80 authored
    Small change to assign proper link_type to generated assets; so that all binary & packages are assigned to "package" and completion scripts stay in "other".
    4010a9e4
Showing with 20081 additions and 6431 deletions
/target
/.idea
\ No newline at end of file
......@@ -2,18 +2,31 @@
# https://hub.docker.com/r/library/rust/tags/
stages:
- build_linux
- build_macos
- tests
- build
- release
tests_linux:
stage: tests
image: rust:buster
script:
- cargo test
build_linux:
stage: build_linux
image: rust:slim-buster
stage: build
image: rust:buster
script:
# Build the project for Linux
- cargo build --release
# Create Debian package
# Create completion scripts for different shells
- ./target/release/gcli completion --shell bash > gcli-completion.bash
- ./target/release/gcli completion --shell zsh > gcli-completion.zsh
- ./target/release/gcli completion --shell fish > gcli-completion.fish
- ./target/release/gcli completion --shell powershell > gcli-completion.ps1
# Dependency to create Debian package
- cargo install cargo-deb
# Create Debian package
# Should include completion scripts assets which are declared in Cargo.toml in [package.metadata.deb] section
- cargo deb --no-build
- ls target/debian/*.deb | head -n 1 > debian_package.txt
artifacts:
......@@ -21,6 +34,10 @@ build_linux:
- target/release/gcli
- target/debian/*.deb
- debian_package.txt
- gcli-completion.bash
- gcli-completion.zsh
- gcli-completion.fish
- gcli-completion.ps1
cache:
key: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
paths:
......@@ -29,8 +46,53 @@ build_linux:
only:
- tags
build_linux_arm64:
stage: build
image: rust:buster
# Needs the completion scripts built with build_linux
needs:
- job: build_linux
artifacts: true
script:
# Add the arm64 architecture
- dpkg --add-architecture arm64
# Also include libssl-dev necessary for openssl-sys
- >
apt-get update && apt-get install -y
gcc-aarch64-linux-gnu
libssl-dev:arm64
pkg-config
- export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc
# Tells Cargo to use the ARM64-specific pkg-config wrapper for the aarch64-unknown-linux-gnu target.
- export PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig
# Specifies the sysroot directory where the ARM64 libraries (e.g., /usr/aarch64-linux-gnu/lib) are located, helping pkg-config find the correct paths.
- export PKG_CONFIG_SYSROOT_DIR=/usr/aarch64-linux-gnu
# Rust toolchain should includes support for the aarch64-unknown-linux-gnu target
- rustup target add aarch64-unknown-linux-gnu
# Build the project for Linux ARM64
- cargo build --release --target aarch64-unknown-linux-gnu
# Dependency to create Debian package
- cargo install cargo-deb
# Create Debian package
# Should include completion scripts assets which are declared in Cargo.toml in [package.metadata.deb] section
# Those assets are built during build_linux which is run before (see the "needs" declaration here)
- cargo deb --no-build --target aarch64-unknown-linux-gnu
- ls target/aarch64-unknown-linux-gnu/debian/*.deb | head -n 1 > debian_package_arm64.txt
artifacts:
paths:
- target/aarch64-unknown-linux-gnu/release/gcli
- target/aarch64-unknown-linux-gnu/debian/*.deb
- debian_package_arm64.txt
cache:
key: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
paths:
- target/aarch64-unknown-linux-gnu/release
- target/aarch64-unknown-linux-gnu/debian
only:
- tags
build_macos:
stage: build_macos
stage: build
image: poka/rust-osxcross:latest
script:
# Install the required dependencies
......@@ -77,15 +139,39 @@ release:
links:
- name: "gcli v$CI_COMMIT_TAG for Linux (binary)"
url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/target/release/gcli?job=build_linux"
link_type: "package"
- name: "gcli v$CI_COMMIT_TAG Debian Package"
url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/$(cat debian_package.txt)?job=build_linux"
link_type: "package"
- name: "gcli v$CI_COMMIT_TAG for Linux ARM64 (binary)"
url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/target/aarch64-unknown-linux-gnu/release/gcli?job=build_linux_arm64"
link_type: "package"
- name: "gcli v$CI_COMMIT_TAG Debian Package ARM64"
url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/$(cat debian_package_arm64.txt)?job=build_linux_arm64"
link_type: "package"
- name: "gcli v$CI_COMMIT_TAG for macOS"
url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/target/macos/gcli.zip?job=build_macos"
link_type: "package"
# Make the completions scripts available for download
- name: "gcli v$CI_COMMIT_TAG Bash completion"
url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/gcli-completion.bash?job=build_linux"
link_type: "other"
- name: "gcli v$CI_COMMIT_TAG Zsh completion"
url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/gcli-completion.zsh?job=build_linux"
link_type: "other"
- name: "gcli v$CI_COMMIT_TAG Fish completion"
url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/gcli-completion.fish?job=build_linux"
link_type: "other"
- name: "gcli v$CI_COMMIT_TAG PowerShell completion"
url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/gcli-completion.ps1?job=build_linux"
link_type: "other"
only:
- tags
dependencies:
- build_linux
- build_linux_arm64
- build_macos
artifacts:
paths:
- debian_package.txt
- debian_package_arm64.txt
# Changelog
List of changelogs ordered from latest to oldest
## [0.4.2] - 2025-05-16
### Added / Changed
- Extra command `completion` added which takes a `--shell` argument to generate a completions script for a specified shell.
- Calling this command with `gcli completion --help` will provide detailed instructions to generate the completion script and register it for your shell (not necessary when using the `.deb` package that include and registers the completion scripts for `bash`, `zsh` and `fish`)
### CI/CD
- Adapted the Linux (amd64) build to:
- generate the `gcli-completion.bash`, `gcli-completion.zsh`, `gcli-completion.fish`, `gcli-completion.ps1` completion scripts
- add the `bash`, `zsh` and `fish` completion scripts in the `.deb` package
- Added the ARM64 build generating a binary and a `.deb` package that also include those completion scripts.
### Fixed
- None
### Deprecated
- Two commands are still deprecated and will be removed in a future release:
- `gcli vault list-files`
- `gcli vault migrate`
### Removed
- None
## [0.4.1] - 2025-04-08
### Added / Changed
- We now use `ed25519` crypto scheme by default for all commands. It means that if you import your substrate mnemonic without giving a specific argument to change the crypto scheme, the resulting SS58 address will not be the same as before (it was using `sr25519` for substrate mnemonic previously)
- Extra `-c` / `--crypto-scheme` argument allows to specify which crypto scheme to use (`sr25519` or `ed25519`) and having a default value of `ed25519` in most places.
- this argument is present in all places where you could provide `-S` / `--secret-format` argument
- Due to that change, the display of the vault (`vault list ...` commands) will not display the g1v1 public key of all `ed25519` \<Base\> keys by default anymore; you will have to provide an extra `--show-g1v1` argument for that.
- Another impact is that we can now `vault derive` any key; including the ones with `ed25519` crypto-scheme.
- It is still highly recommended to **only derive** keys based on a **substrate mnemonic**; as old `g1v1` keys with their _manual_ `id` & `secret` are not as secure as using a generated substrate mnemonic.
- There is an exception to the impacted commands: `vault migrate` will still import old key files as `sr25519` crypto-scheme keys; as it would otherwise not correspond to the SS58 Address of those key files.
- It is now possible to perform `vault import` and `vault derive` commands without interactive prompts if all necessary optional arguments are provided.
- Please check for more details with commands:
- `vault import --help`
- `vault derive --help`
- If the command tries to override an existing vault entry, then it will still require manual input from the user!
- Adapted commands `identity link-account` and `identity change-owner-key`
- Made it clear that the arguments are meant to "target" another account
- Added possibility to provide the "target" account from the vault
- `-a` SS58 Address of target vault account
- `-v` Name of target vault account
- `-S` (secret_format) doesn't have a default anymore since it conflicts with using `-a` or `-v`
- Adapted `vault inspect` command to display more information
- Substrate URI (was already present)
- Crypto scheme: to be more coherent since both the `substrate uri` and `crypto-scheme` are needed to create the key with the proper `address`
- Secret seed/mini-secret: only computed if no `soft` (single '/') derivation are used
- Public key (hex)
- SS58 Address
- (potential G1v1 public key if inspecting a \<Base\> account with ed25519 crypto-scheme)
- Small changes
- In the vault, changed sorting of children account so that they are sorted by derivation `Path` value (makes more sense when viewing derivations of one account)
### Fixed
- None
### Deprecated
- Two commands are still deprecated and will be removed in a future release:
- `gcli vault list-files`
- `gcli vault migrate`
### Removed
- None
### CI/CD
- None
## [0.4.0] - 2025-02-xx
### Changed
- Old key files cannot be used directly anymore, they have to be migrated to the SQLite file database. You can use the following commands for that:
- `gcli vault list-files` lists _old_ key files from previous versions
- `gcli vault migrate` which allows to migrate _old_ key files into the vault database
- Some arguments and commands were adapted
- Arguments
- **SecretFormat** (`-S`): _cesium_ was renamed to _g1v1_ - but it will still work properly if using _cesium_
- Several arguments were renamed for clarity. Examples:
- `<TARGET>` => `<USERNAME>`
- `<ACCOUNT_ID>` => `<ADDRESS>`
- Commands
- `gcli vault import` now has an optional **SecretFormat** `-S` argument with _substrate_ as default value
- It is now possible to import _substrate_ URI, _seed_, _g1v1_ id/secret (old "cesium") keys into the vault.
- `gcli vault list` now has sub-commands and only shows Addresses from the SQLite file database
### Added
- Support for SQLite file database to persist vault data
- global `-v <NAME>` argument to select a vault Address by name (mutually exclusive with `-a <ADDRESS>` argument)
- Already mentioned in the "Changed" section above, but it is now possible to add different kind of keys to the vault when doing `vault import`
- Default providing _substrate_ URI (or `-S substrate`): can be a mnemonic or a mini-secret ('0x' prefixed seed) together with optional derivation path; using Sr25519 crypto scheme
- `-S seed`: using the 32 character hexadecimal secret seed; using Sr25519 crypto scheme
- `-S g1v1` (or `-S cesium`): allows to input G1v1 `id` and `secret`; using Ed25519 crypto scheme
- Added possibility to `derive` non _g1v1_/_cesium_ Addresses (see `gcli vault derive`)
- Some commands were added
- `gcli vault list all` List all \<Base\> SS58 Addresses and their linked derivations in the vault
- `gcli vault list for` List \<Base\> and Derivation SS58 Addresses linked to the selected one
- `gcli vault list base` List all \<Base\> SS58 Addresses in the vault
- `gcli vault use` Use specific SS58 Address (changes the config Address)
- `gcli vault derive` Add a derivation to an existing SS58 Address
- `gcli vault rename` Give a meaningful name to an SS58 Address in the vault
- `gcli vault remove` Remove an SS58 Address from the vault together with its linked derivations
- `gcli vault inspect` Inspect a vault entry, retrieving its Substrate URI (will provide more data in a future version)
- `gcli vault list-files` (deprecated) List available key files (needs to be migrated with command `vault migrate` in order to use them)
- `gcli vault migrate` (deprecated) Migrate old key files into db (will have to provide password for each key)
### Fixed
- None
### Deprecated
- Two commands are now deprecated and will be removed in a future release
- `gcli vault list-files`
- `gcli vault migrate`
### Removed
- None
### CI/CD
- #45, !42:
- In linux build job, switch to "non-slim" Debian image which provides `libssl-dev` now required
- Introduce linux tests job (#46)
- !38: Build deb and macos pkgs in parallel
## [0.3.0] - 2024-10-10
### Added
- Previous version without changelog
This diff is collapsed.
......@@ -10,48 +10,53 @@ license = "AGPL-3.0-only"
name = "gcli"
repository = "https://git.duniter.org/clients/rust/gcli-v2s"
description = "A command-line interface for Duniter v2s uses"
version = "0.2.12"
version = "0.4.2"
[dependencies]
# subxt is main dependency
subxt = { git = 'https://github.com/duniter/subxt', branch = 'subxt-v0.35.3-duniter-substrate-v1.11.0', default-features = false, features = [
subxt = { git = 'https://github.com/duniter/subxt', branch = 'subxt-v0.37.0-duniter-substrate-v1.14.0', default-features = false, features = [
"substrate-compat",
"native",
"jsonrpsee",
] }
# substrate primitives dependencies
sp-core = { git = "https://github.com/duniter/duniter-polkadot-sdk.git", branch = "duniter-substrate-v1.11.0" }
sp-runtime = { git = "https://github.com/duniter/duniter-polkadot-sdk.git", branch = "duniter-substrate-v1.11.0" }
sp-core = { git = "https://github.com/duniter/duniter-polkadot-sdk.git", branch = "duniter-substrate-v1.14.0" }
sp-runtime = { git = "https://github.com/duniter/duniter-polkadot-sdk.git", branch = "duniter-substrate-v1.14.0" }
# crates.io dependencies
anyhow = "^1.0"
clap = { version = "^4.5.4", features = ["derive"] }
clap = { version = "^4.5.19", features = ["derive"] }
clap_complete = "^4.5.19"
codec = { package = "parity-scale-codec", version = "^3.6.12" }
env_logger = "^0.10"
futures = "^0.3.30"
graphql_client = { version = "^0.13.0", features = ["reqwest-rustls"] }
hex = "^0.4.3"
log = "^0.4.21"
log = "^0.4.22"
reqwest = { version = "^0.11.27", default-features = false, features = [
"rustls-tls",
] }
rpassword = "^7.3.1"
inquire = "^0.7.5"
serde = { version = "^1.0", features = ["derive"] }
serde_json = "^1.0.117"
tokio = { version = "^1.37.0", features = ["macros"] }
serde_json = "^1.0.128"
tokio = { version = "^1.40.0", features = ["macros"] }
confy = "^0.5.1"
bs58 = "^0.5.1"
inquire = "^0.6.2"
directories = "^5.0.1"
comfy-table = "^7.1.1"
sea-orm = { version = "1.1.0", features = [ "sqlx-sqlite", "runtime-tokio-native-tls", "macros" ] }
indoc = "2.0.5"
# crypto
scrypt = { version = "^0.11", default-features = false } # for old-style key generation
nacl = { version = "^0.5.3" } # for old-style key generation
# this is beta crate for password-encrypted files
age = { default-features = false, version = "^0.10.0", features = ["armor"] }
bip39 = { version = "^2.0.0", features = ["rand"] } # mnemonic
colored = "2.1.0"
# Tests
rstest = "0.23.0"
# allows to build gcli for different runtimes and with different predefined networks
[features]
......@@ -64,3 +69,22 @@ g1 = []
name = "gcli"
identifier = "com.axiomteam.gcli"
icon = ["gcli.png"]
# Used by gitlab ci to add extra assets in the .deb packages (both amd64 & arm64)
# Those gcli-completion.* assets are created during gitlab ci "build_linux"
#Documentation in https://github.com/kornelski/cargo-deb
[package.metadata.deb]
assets = [
# Examples
#target/release path is special, and gets replaced by cargo-deb with the actual target dir path.
#["target/release/cargo-deb", "usr/bin/", "755"],
#both array and object syntaxes are equivalent:
#{ source = "README.md", dest = "usr/share/doc/cargo-deb/README", mode = "644"},
# Bin has to be manually added since we override the default "assets"
{ source = "target/release/gcli", dest = "usr/bin/", mode = "755" },
# The extra shell completion script assets
{ source = "gcli-completion.bash", dest = "/etc/bash_completion.d/gcli", mode = "644" },
{ source = "gcli-completion.zsh", dest = "/usr/local/share/zsh/site-functions/_gcli", mode = "644" },
{ source = "gcli-completion.fish", dest = "/usr/share/fish/vendor_completions.d/gcli.fish", mode = "644" }
]
\ No newline at end of file
......@@ -6,8 +6,18 @@ Using
- https://github.com/duniter/substrate
- https://github.com/duniter/subxt
## Install
Download from [release](https://git.duniter.org/clients/rust/gcli-v2s/-/releases) or build with `cargo build`.
On debian derived systems you can also :
check on [release](https://git.duniter.org/clients/rust/gcli-v2s/-/releases) page for latest version then in bash cli :
```
GCLI_VERSION={change me with latest version (0.2.14 in 2024 summer) and remove {}}
wget https://git.duniter.org/clients/rust/gcli-v2s/-/jobs/artifacts/$GCLI_VERSION/raw/target/debian/gcli_$GCLI_VERSION-1_amd64.deb?job=build_linux
mv gcli_* gcli_package.deb
dpkg -i gcli_package.deb
```
## Usage
If using a different runtime, update the metadata for the client to compile:
......@@ -22,7 +32,7 @@ List certifications and session keys that will expire within one month:
cargo run -- --url wss://gdev.p2p.legal:443/ws smith expire --blocks 432000
For more examples see [in the doc](./doc/). `cargo run --` is replaced by `gcli` as if the binary was added to your path.
For more examples see [in the doc](./doc). `cargo run --` is replaced by `gcli` as if the binary was added to your path.
#### Log level
......@@ -66,3 +76,7 @@ Secret and/or public keys can always be passed using `--secret` and `--address`.
Secret key format can be changed using `--secret-format` with the following values:
* `substrate`: a Substrate secret address (optionally followed by a derivation path), or BIP39 mnemonic
* `seed`: a 32-bytes seed in hexadecimal (Duniter v1 compatible)
## Changelog
For a detailed list of changes, see the [CHANGELOG](./CHANGELOG.md).
\ No newline at end of file
......@@ -5,14 +5,14 @@ Some Ğcli commands require to have an address configured (for example to get ac
```sh
# save Alice address to config file
gcli -S predefined -s Alice config save
gcli -S predefined -s Alice -c sr25519 config save
# show config
gcli config show
# [stdout]
# Ğcli config
# duniter endpoint ws://localhost:9944
# indexer endpoint http://localhost:4350/graphql
# indexer endpoint http://localhost:8080/v1/graphql
# address 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
# use different address in command line
......@@ -20,7 +20,7 @@ gcli --address 5Fxune7f71ZbpP2FoY3mhYcmM596Erhv1gRue4nsPwkxMR4n config show
# [stdout]
# Ğcli config
# duniter endpoint ws://localhost:9944
# indexer endpoint http://localhost:4350/graphql
# indexer endpoint http://localhost:8080/v1/graphql
# address 5Fxune7f71ZbpP2FoY3mhYcmM596Erhv1gRue4nsPwkxMR4n
```
......@@ -36,20 +36,78 @@ gcli account transfer 1 5Fxune7f71ZbpP2FoY3mhYcmM596Erhv1gRue4nsPwkxMR4n
# no need for password to sign transaction
```
but in general usage, you want to store your secret in the local vault. This goes like this:
but in general usage, you want to store your secret in the local vault.
Here is an example that:
* adds a base _substrate_ account
* adds a derivation on it
* lists all available Addresses in the vault
* selects that derivation Address
* makes a transfer from selected Address
```sh
# add a new secret to the vault using substrate uri and crypto scheme sr25519
gcli vault import -c sr25519
# [stdout]
# Substrate URI can be a mnemonic or a mini-secret ('0x' prefixed seed) together with optional derivation path
# > Substrate URI: ********
#
# Trying to import for SS58 address :'5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV'
#
# Enter password to protect the key
# > Password ********
# (Optional) Enter a name for the vault entry
# > Name: test-mnemonic
# Creating <Base> account Base[address:5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV, name:Some("test-mnemonic"), crypto_scheme:Some(Sr25519)]
# Change done
```
```sh
# add a derivation to that Address and give it name "firstDerive"
gcli vault derive -a 5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV
# [stdout]
# Adding derivation to: Base[address:5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV, name:Some("test-mnemonic"), crypto_scheme:Some(Sr25519)]
#
# Its parent hierarchy is this:
# ┌─────────────────────────────────────────────────────────────────────────────────────┐
# │ SS58 Address/G1v1 public key Crypto Path Name │
# ╞═════════════════════════════════════════════════════════════════════════════════════╡
# │ 5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV sr25519 <Base> test-mnemonic │
# └─────────────────────────────────────────────────────────────────────────────────────┘
#
# The linked <Base> account is Base[address:5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV, name:Some("test-mnemonic"), crypto_scheme:Some(Sr25519)]
# Enter password to decrypt the <Base> account key
# > Password ********
#
# > Derivation path: //1
#
# Trying to create derivation with address '5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o'
#
# (Optional) Enter a name for the vault entry
# > Name: firstDerive
# Creating derivation account Derivation[address:5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o, name:Some("firstDerive"), path:Some("//1"), parent:Some("5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV")]
# Change done
```
```sh
# list available keys in the vault
gcli vault list
# list available Addresses in the vault
gcli vault list all
# [stdout]
# available keys:
# 5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV
# available SS58 Addresses:
# ┌───────────────────────────────────────────────────────────────────────────────────────┐
# │ SS58 Address/G1v1 public key Crypto Path Name │
# ╞═══════════════════════════════════════════════════════════════════════════════════════╡
# │ 5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV sr25519 <Base> test-mnemonic │
# │ ├ 5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o //1 firstDerive │
# └───────────────────────────────────────────────────────────────────────────────────────┘
```
# add a new secret to the vault
gcli vault import
```sh
# Use "firstDerive" derivation Address (changes the config Address)
gcli vault use -v firstDerive
# [stdout]
# Mnemonic: <enter mnemonic>
# Password: <enter password>
# Using: Derivation[address:5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o, name:Some("firstDerive"), path:Some("//1"), parent:Some("5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV")]
# Configuration updated!
```
After saving your secret to the vault, you will be able to unlock it with the password:
......@@ -57,10 +115,10 @@ After saving your secret to the vault, you will be able to unlock it with the pa
```sh
gcli account transfer 123 5Fxune7f71ZbpP2FoY3mhYcmM596Erhv1gRue4nsPwkxMR4n
# [stdout]
# Enter password to unlock account 5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV
# Password: <enter password>
# (Vault: Derivation[address:5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o, name:Some("firstDerive"), path:Some("//1"), parent:Some("5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV")])
# > Password ********
# transaction submitted to the network, waiting 6 seconds...
# transfered 1.23 ĞD (5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV → 5Fxune7f71ZbpP2FoY3mhYcmM596Erhv1gRue4nsPwkxMR4n)
# transfered 1.23 ĞD (5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o → 5Fxune7f71ZbpP2FoY3mhYcmM596Erhv1gRue4nsPwkxMR4n)
```
You can display the secret files location:
......@@ -70,3 +128,107 @@ gcli vault where
# [stdout]
# /home/hugo/.local/share/gcli
```
---
There are more commands and options available; please use `--help` argument in any of the commands to get their description.
A few examples:
```sh
gcli --help
# [stdout]
# A command-line interface for Duniter v2s uses
#
# Usage: gcli [OPTIONS] <COMMAND>
#
# Commands:
# account Account (balance, transfer...)
# identity Identity (get, create, confirm, revoke...)
# smith Smith (certify, go-online, go-offline...)
# tech Tech (list members, proposals, vote...)
# ud Universal Dividend (claim...)
# oneshot Oneshot account (balance, create, consume...)
# blockchain Blockchain (current block, runtime info...)
# indexer Indexer (check, latest block)
# config Config (show, save...)
# vault Key management (import, generate, list...)
# help Print this message or the help of the given subcommand(s)
#
# Options:
# -i, --indexer <INDEXER> Overwrite indexer endpoint
# --no-indexer Do not use indexer
# -S, --secret-format <SECRET_FORMAT> Secret key format (seed, substrate, g1v1)
# -s, --secret <SECRET> Secret key or BIP39 mnemonic (only used when secret format is compatible) (eventually followed by derivation path)
# -c, --crypto-scheme <CRYPTO_SCHEME> Crypto scheme to use (sr25519, ed25519) [default: ed25519]
# -a <ADDRESS> SS58 Address
# -v <NAME> Name of an SS58 Address in the vault
# -u, --url <URL> Overwrite duniter websocket RPC endpoint
# -n, --network <NETWORK> Target network (local, gdev, gtest...)
# --no-wait prevent waiting for extrinsic completion
# -o, --output-format <OUTPUT_FORMAT> Output format (human, json, ...) [default: human]
# -h, --help Print help
# -V, --version Print version
```
```sh
gcli vault --help
# [stdout]
# Key management (import, generate, list...)
#
# Usage: gcli vault <COMMAND>
#
# Commands:
# list List available SS58 Addresses in the vault
# use Use specific SS58 Address (changes the config Address)
# generate Generate a mnemonic
# import Import key from (substrate uri) or other format with interactive prompt
# derive Add a derivation to an existing SS58 Address
# rename Give a meaningful name to an SS58 Address in the vault
# remove Remove an SS58 Address from the vault together with its linked derivations
# inspect Inspect a vault entry, retrieving its Substrate URI (will provide more data in a future version)
# list-files (deprecated) List available key files (needs to be migrated with command `vault migrate` in order to use them)
# migrate (deprecated) Migrate old key files into db (will have to provide password for each key)
# where Show where vault db (or old keys) is stored
# help Print this message or the help of the given subcommand(s)
#
# Options:
# -h, --help Print help
```
And some commands have a more detailed description when requesting `--help` from them:
```sh
gcli vault derive --help
# [stdout]
# Add a derivation to an existing SS58 Address.
#
# Both "sr25519" and "ed25519" crypto schemes are supported
#
# Use command `vault list base` to see available <Base> account and their crypto scheme
# And then use command 'vault list for' to find all accounts linked to that <Base> account
#
# Usage: gcli vault derive [OPTIONS] <-a <ADDRESS>|-v <VAULT_NAME>>
#
# Options:
# -a <ADDRESS>
# SS58 Address
#
# -v <VAULT_NAME>
# Name of an SS58 Address in the vault
#
# -d, --derivation-path <DERIVATION_PATH>
# Derivation path (non-interactive mode)
#
# -p, --password <PASSWORD>
# Password to decrypt the <Base> account key (non-interactive mode)
#
# --no-password
# Use empty password to decrypt the <Base> account key (non-interactive mode)
#
# -n, --name <NAME>
# Name for the wallet entry (non-interactive mode) - "" empty string will be considered as None
#
# -h, --help
# Print help (see a summary with '-h')
```
\ No newline at end of file
......@@ -8,7 +8,7 @@ Update the schema with:
# install graphql client cli
cargo install graphql_client_cli
# download schema from node
graphql-client introspect-schema https://subsquid.gdev.coinduf.eu/graphql --output ./res/indexer-schema.json
graphql-client introspect-schema https://squid.gdev.coinduf.eu/v1/graphql --output ./res/indexer-schema.json
```
...
......
......@@ -14,18 +14,12 @@ query NamesByIndexes($indexes: [Int!]!) {
query IdentityInfo($index: Int!) {
identity(where: { index: { _eq: $index } }) {
name
certIssued(
orderBy: { expireOn: DESC }
where: { isActive: { _eq: true } }
) {
certIssued(orderBy: { expireOn: DESC }, where: { isActive: { _eq: true } }) {
receiver {
name
}
}
certReceived(
orderBy: { expireOn: DESC }
where: { isActive: { _eq: true } }
) {
certReceived(orderBy: { expireOn: DESC }, where: { isActive: { _eq: true } }) {
issuer {
name
}
......@@ -33,18 +27,25 @@ query IdentityInfo($index: Int!) {
linkedAccount {
id
}
smith {
smithStatus
smithCertIssued(orderBy: { createdOn: DESC }) {
receiver {
identity {
name
}
}
}
smithCertReceived(orderBy: { createdOn: DESC }) {
issuer {
identity {
name
}
}
}
}
}
}
query IdentityNameByPubkey($pubkey: String!) {
identity(where: { account: { id: { _eq: $pubkey } } }) {
......
This diff is collapsed.
No preview for this file type
......@@ -11,6 +11,7 @@ pub enum Subcommand {
/// Amount to transfer
amount: u64,
/// Destination address
#[clap(value_name = "ADDRESS")]
dest: AccountId,
/// Prevent from going below account existential deposit
#[clap(short = 'k', long = "keep-alive")]
......@@ -20,11 +21,12 @@ pub enum Subcommand {
is_ud: bool,
},
/// Transfer the same amount for each space-separated address.
/// If an address appears mutiple times, it will get multiple times the same amount
/// If an address appears multiple times, it will get multiple times the same amount
TransferMultiple {
/// Amount given to each destination address
amount: u64,
/// List of target addresses
#[clap(value_name = "ADDRESSES")]
dests: Vec<AccountId>,
},
/// Unlink the account from the linked identity
......@@ -56,7 +58,7 @@ pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliE
}
/// get balance
pub async fn get_balance(data: Data) -> Result<(), anyhow::Error> {
pub async fn get_balance(data: Data) -> Result<(), subxt::Error> {
let account_id = data.address();
let account_info = get_account_info(data.client(), &account_id).await?;
if let Some(account_info) = account_info {
......@@ -87,7 +89,7 @@ pub async fn get_account_info(
pub async fn unlink_account(data: &Data) -> Result<(), subxt::Error> {
submit_call_and_look_event::<
runtime::account::events::AccountUnlinked,
Payload<runtime::account::calls::types::UnlinkIdentity>,
StaticPayload<runtime::account::calls::types::UnlinkIdentity>,
>(data, &runtime::tx().account().unlink_identity())
.await
}
......@@ -4,7 +4,7 @@ use crate::*;
pub async fn certify(data: &Data, target: IdtyId) -> Result<(), subxt::Error> {
submit_call_and_look_event::<
runtime::certification::events::CertAdded,
Payload<runtime::certification::calls::types::AddCert>,
StaticPayload<runtime::certification::calls::types::AddCert>,
>(data, &runtime::tx().certification().add_cert(target))
.await
}
......@@ -13,7 +13,7 @@ pub async fn certify(data: &Data, target: IdtyId) -> Result<(), subxt::Error> {
pub async fn renew(data: &Data, target: IdtyId) -> Result<(), subxt::Error> {
submit_call_and_look_event::<
runtime::certification::events::CertRenewed,
Payload<runtime::certification::calls::types::RenewCert>,
StaticPayload<runtime::certification::calls::types::RenewCert>,
>(data, &runtime::tx().certification().renew_cert(target))
.await
}
use crate::*;
use crate::data::Data;
use crate::keys;
use crate::keys::KeyPair;
use crate::runtime_config::AccountId;
use crate::utils::GcliError;
use bs58;
use sp_core::{ed25519, Pair};
use std::str::FromStr;
/// define cesium subcommands
#[derive(Clone, Default, Debug, clap::Parser)]
......@@ -33,52 +39,109 @@ pub async fn handle_command(_data: Data, command: Subcommand) -> Result<(), Gcli
println!("Address (SS58): {}", address);
}
Subcommand::Prompt => {
let keypair = prompt_secret_cesium();
println!("Pubkey: {}", bs58::encode(keypair.pkey).into_string());
let address: AccountId = keypair.pkey.into();
let pair = keys::prompt_secret_cesium();
println!(
"Pubkey: {}",
compute_g1v1_public_key_from_ed25519_pair(&pair)
);
let address: AccountId = pair.public().into();
println!("Address: {}", address);
}
}
Ok(())
}
pub struct CesiumSigner<T: subxt::Config> {
account_id: T::AccountId,
keypair: nacl::sign::Keypair,
/// Computes G1v1 public key from a KeyPair of type sp_core::ed25519::Pair - fails otherwise
pub fn compute_g1v1_public_key(key_pair: &KeyPair) -> Result<String, GcliError> {
match key_pair {
KeyPair::Sr25519(_) => Err(GcliError::Logic(
"key pair is not of type ed25519".to_string(),
)),
KeyPair::Ed25519(key_pair) => Ok(compute_g1v1_public_key_from_ed25519_pair(key_pair)),
}
impl<T> CesiumSigner<T>
where
T: subxt::Config,
T::AccountId: From<[u8; 32]>,
{
pub fn new(keypair: nacl::sign::Keypair) -> Self {
Self {
account_id: T::AccountId::from(keypair.pkey),
keypair,
}
/// Computes G1v1 public key from an ed25519 Pair
pub fn compute_g1v1_public_key_from_ed25519_pair(ed25519_key_pair: &ed25519::Pair) -> String {
compute_g1v1_public_key_from_ed25519_public(&ed25519_key_pair.public())
}
/// Computes G1v1 public key from an ed25519 Public
pub fn compute_g1v1_public_key_from_ed25519_public(ed25519_public: &ed25519::Public) -> String {
bs58::encode(ed25519_public).into_string()
}
impl<T> subxt::tx::Signer<T> for CesiumSigner<T>
where
T: subxt::Config,
T::Address: From<T::AccountId>,
T::Signature: From<sp_core::ed25519::Signature>,
{
fn account_id(&self) -> T::AccountId {
self.account_id.clone()
/// Computes G1v1 public key from an ed25519 AccountId
pub fn compute_g1v1_public_key_from_ed25519_account_id(ed25519_account_id: &AccountId) -> String {
let ed25519_public: ed25519::Public = ed25519::Public::from(ed25519_account_id.0);
bs58::encode(ed25519_public).into_string()
}
fn address(&self) -> T::Address {
self.account_id.clone().into()
/// Computes G1v1 public key from an ed25519 SS58 Address
#[allow(unused)]
pub fn compute_g1v1_public_key_from_ed25519_ss58_address(
ed25519_ss58_address: &str,
) -> Result<String, GcliError> {
Ok(compute_g1v1_public_key_from_ed25519_account_id(
&AccountId::from_str(ed25519_ss58_address).map_err(|e| GcliError::Input(e.to_string()))?,
))
}
fn sign(&self, payload: &[u8]) -> T::Signature {
sp_core::ed25519::Signature::from_raw(
nacl::sign::signature(payload, &self.keypair.skey)
.unwrap()
.try_into()
.expect("could not read signature"),
)
.into()
// Unit tests
#[cfg(test)]
mod tests {
use super::*;
/// Test data:
/// cesium_id = "test_cesium_id"
/// cesium_pwd = "test_cesium_pwd"
///
/// G1v1 base58 public key: 86pW1doyJPVH3jeDPZNQa1UZFBo5zcdvHERcaeE758W7
///
/// ```
/// subkey inspect --scheme ed25519
/// URI:
/// Secret Key URI `0x2101d2bc68de9ad149c06293bfe489c8608de576c88927aa5439a81be17aae84` is account:
/// Network ID: substrate
/// Secret seed: 0x2101d2bc68de9ad149c06293bfe489c8608de576c88927aa5439a81be17aae84
/// Public key (hex): 0x697f6bd16ddebf142384e503fd3f3efc39fe5c7be7c693bd98d982403bb6eb74
/// Account ID: 0x697f6bd16ddebf142384e503fd3f3efc39fe5c7be7c693bd98d982403bb6eb74
/// Public key (SS58): 5ET2jhgJFoNQUpgfdSkdwftK8DKWdqZ1FKm5GKWdPfMWhPr4
/// SS58 Address: 5ET2jhgJFoNQUpgfdSkdwftK8DKWdqZ1FKm5GKWdPfMWhPr4
/// ```
#[test]
fn test_compute_g1v1_public_key() {
let expected_base58_public_key = "86pW1doyJPVH3jeDPZNQa1UZFBo5zcdvHERcaeE758W7";
let ss58_address = "5ET2jhgJFoNQUpgfdSkdwftK8DKWdqZ1FKm5GKWdPfMWhPr4";
assert_eq!(
expected_base58_public_key,
compute_g1v1_public_key_from_ed25519_ss58_address(ss58_address).unwrap()
);
let account_id = AccountId::from_str(ss58_address).unwrap();
assert_eq!(
expected_base58_public_key,
compute_g1v1_public_key_from_ed25519_account_id(&account_id)
);
let ed25519_public = ed25519::Public::from(account_id.0);
assert_eq!(
expected_base58_public_key,
compute_g1v1_public_key_from_ed25519_public(&ed25519_public)
);
let cesium_id = "test_cesium_id".to_string();
let cesium_pwd = "test_cesium_pwd".to_string();
let seed = keys::seed_from_cesium(&cesium_id, &cesium_pwd);
let ed25519_pair_from_seed = ed25519::Pair::from_seed(&seed);
assert_eq!(
expected_base58_public_key,
compute_g1v1_public_key_from_ed25519_pair(&ed25519_pair_from_seed)
);
}
}
......@@ -22,7 +22,7 @@ pub enum Subcommand {
}
/// handle technical committee commands
pub async fn handle_command(data: Data, command: Subcommand) -> anyhow::Result<(), GcliError> {
pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliError> {
let data = data.build_client().await?.build_indexer().await?;
match command {
Subcommand::Members => technical_committee_members(&data).await?,
......@@ -46,7 +46,7 @@ pub async fn handle_command(data: Data, command: Subcommand) -> anyhow::Result<(
}
/// list technical committee members
pub async fn technical_committee_members(data: &Data) -> Result<(), anyhow::Error> {
pub async fn technical_committee_members(data: &Data) -> Result<(), subxt::Error> {
let client = data.client();
let indexer = &data.indexer;
......@@ -85,7 +85,6 @@ pub async fn technical_committee_members(data: &Data) -> Result<(), anyhow::Erro
.unwrap_or_else(|| account_id.to_string(),)
);
}
Ok(())
}
......@@ -93,7 +92,7 @@ pub async fn technical_committee_members(data: &Data) -> Result<(), anyhow::Erro
// TODO:
// * better formatting (format pubkeys to SS58 and add usernames)
// * display proposals indices
pub async fn technical_committee_proposals(client: &Client) -> anyhow::Result<()> {
pub async fn technical_committee_proposals(client: &Client) -> Result<(), subxt::Error> {
let parent_hash = client
.storage()
.at_latest()
......@@ -112,7 +111,6 @@ pub async fn technical_committee_proposals(client: &Client) -> anyhow::Result<()
println!("{:#?}", item.value);
println!();
}
Ok(())
}
......@@ -122,10 +120,10 @@ pub async fn technical_committee_vote(
proposal_hash: Hash,
proposal_index: u32,
vote: bool,
) -> anyhow::Result<(), subxt::Error> {
) -> Result<(), subxt::Error> {
submit_call_and_look_event::<
runtime::technical_committee::events::Voted,
Payload<runtime::technical_committee::calls::types::Vote>,
StaticPayload<runtime::technical_committee::calls::types::Vote>,
>(
data,
&runtime::tx()
......@@ -137,17 +135,14 @@ pub async fn technical_committee_vote(
/// propose call given as hexadecimal
/// can be generated with `subxt explore` for example
pub async fn technical_committee_propose(
data: &Data,
proposal: &str,
) -> anyhow::Result<(), subxt::Error> {
pub async fn technical_committee_propose(data: &Data, proposal: &str) -> Result<(), subxt::Error> {
let raw_call = hex::decode(proposal).expect("invalid hex");
let call = codec::decode_from_bytes(raw_call.into()).expect("invalid call");
let payload = runtime::tx().technical_committee().propose(5, call, 100);
submit_call_and_look_event::<
runtime::technical_committee::events::Proposed,
Payload<runtime::technical_committee::calls::types::Propose>,
StaticPayload<runtime::technical_committee::calls::types::Propose>,
>(data, &payload)
.await
}
......@@ -4,7 +4,7 @@ use crate::*;
pub async fn request_distance_evaluation(data: &Data) -> Result<(), subxt::Error> {
submit_call_and_look_event::<
runtime::distance::events::EvaluationRequested,
Payload<runtime::distance::calls::types::RequestDistanceEvaluation>,
StaticPayload<runtime::distance::calls::types::RequestDistanceEvaluation>,
>(
data,
&runtime::tx().distance().request_distance_evaluation(),
......@@ -19,7 +19,7 @@ pub async fn request_distance_evaluation_for(
) -> Result<(), subxt::Error> {
submit_call_and_look_event::<
runtime::distance::events::EvaluationRequested,
Payload<runtime::distance::calls::types::RequestDistanceEvaluationFor>,
StaticPayload<runtime::distance::calls::types::RequestDistanceEvaluationFor>,
>(
data,
&runtime::tx()
......
......@@ -2,7 +2,11 @@ use crate::{indexer::*, *};
use futures::join;
use std::collections::BTreeMap;
pub async fn monitor_expirations(data: &Data, blocks: u32, _sessions: u32) -> anyhow::Result<()> {
pub async fn monitor_expirations(
data: &Data,
blocks: u32,
_sessions: u32,
) -> Result<(), subxt::Error> {
let client = data.client();
let indexer = data.indexer.clone();
......@@ -119,7 +123,7 @@ impl IdentityCache {
}
}
pub async fn fetch_identity(&mut self, identity_id: IdtyId) -> anyhow::Result<String> {
pub async fn fetch_identity(&mut self, identity_id: IdtyId) -> Result<String, GcliError> {
Ok(match self.identities.entry(identity_id) {
hash_map::Entry::Occupied(entry) => entry.get().clone(),
hash_map::Entry::Vacant(entry) => entry
......
use crate::*;
use crate::commands::vault::retrieve_account_tree_node_for_name;
use crate::{
commands::revocation::generate_revoc_doc,
runtime::runtime_types::{
......@@ -18,7 +19,7 @@ pub enum Subcommand {
Show,
/// Fetch identity
Get {
#[clap(short = 'a', long = "address")]
#[clap(short = 'a', long = "address", value_name = "ADDRESS")]
account_id: Option<AccountId>,
#[clap(short = 'i', long = "identity")]
identity_id: Option<IdtyId>,
......@@ -28,7 +29,10 @@ pub enum Subcommand {
/// Create and certify an identity
///
/// Caller must be member, and the target account must exist.
Create { target: AccountId },
Create {
#[clap(value_name = "ADDRESS")]
target: AccountId,
},
/// Confirm an identity
///
/// To be called by the certified not-yet-member account, to become member.
......@@ -37,40 +41,92 @@ pub enum Subcommand {
/// make sure that it's ok otherwise currency is slashed
RequestDistanceEvaluation,
/// Request distance evaluation for unvalidated identity
RequestDistanceEvaluationFor { target: String },
RequestDistanceEvaluationFor {
#[clap(value_name = "USERNAME")]
target: String,
},
/// Certify an identity
#[clap(alias = "cert")]
Certify { target: String },
Certify {
#[clap(value_name = "USERNAME")]
target: String,
},
/// Renew a certification
#[clap(alias = "renew")]
RenewCert { target: String },
RenewCert {
#[clap(value_name = "USERNAME")]
target: String,
},
/// Revoke an identity immediately
Revoke,
/// Generate a revocation document for the provided account
GenRevocDoc,
/// Display member count
MemberCount,
/// Link an account to the identity
LinkAccount {
/// Secret key format (seed, substrate)
#[clap(short = 'S', long, default_value = SecretFormat::Substrate)]
secret_format: SecretFormat,
/// Secret of account to link
/// most likely different from the one owning the identity
#[clap(short, long)]
secret: Option<String>,
},
/// Migrate identity to another account
/// Change Owner Key
ChangeOwnerKey {
/// Secret key format (seed, substrate)
#[clap(short = 'S', long, default_value = SecretFormat::Substrate)]
secret_format: SecretFormat,
/// Secret of account to link
/// most likely different from the one owning the identity
/// Link an account to the [target] identity
#[clap(long_about = "Link an account to the [target] identity.\n\
\n\
The target identity can be passed as argument using any of the suggested options.")]
LinkAccount(SecretProvider),
/// Migrate identity to another [target] account
#[clap(long_about = "Migrate identity to another [target] account.\n\
\n\
The target account can be passed as argument using any of the suggested options.")]
ChangeOwnerKey(SecretProvider),
}
#[derive(clap::Args, Clone, Debug)]
pub struct SecretProvider {
/// SS58 Address of target vault account
#[clap(short, conflicts_with_all=["vault_name","secret_format", "secret", "crypto_scheme"])]
address: Option<AccountId>,
/// Name of target vault account
#[clap(short = 'v', conflicts_with_all=["secret_format", "secret", "crypto_scheme"])]
vault_name: Option<String>,
/// Secret key format of target account (seed, substrate)
#[clap(short = 'S', long)]
secret_format: Option<SecretFormat>,
/// Secret of target account
#[clap(short, long)]
secret: Option<String>,
},
/// Crypto scheme of target account (sr25519, ed25519)
#[clap(short = 'c', long, required = false, default_value = CryptoScheme::Ed25519)]
crypto_scheme: CryptoScheme,
}
impl SecretProvider {
/// Analyses the SecretProvider data and tries to retrieve a keypair.
///
/// Will potentially request a password to decrypt the secret in keystore if it was asked to use a vault account.
///
/// Or it could request the `secret` if using `secret-format` without also providing the `secret`.
///
/// Will return an error if no data was provided or if it encountered another issue in the process.
async fn get_keypair(&self, data: &Data) -> Result<KeyPair, GcliError> {
let key_pair = if let Some(address) = self.address.clone() {
commands::vault::fetch_vault_keypair_for_address(data, address).await?
} else if let Some(vault_name) = self.vault_name.clone() {
let account_tree_node =
retrieve_account_tree_node_for_name(data.connect_db(), &vault_name).await?;
let address = account_tree_node.borrow().account.address.0.clone();
commands::vault::fetch_vault_keypair_for_address(data, address).await?
} else if let Some(secret_format) = self.secret_format {
let keypair = get_keypair(secret_format, self.secret.as_deref(), self.crypto_scheme)?;
println!(
"target address:'{}' (using crypto-scheme:{})",
keypair.address(),
<&'static str>::from(self.crypto_scheme)
);
keypair
} else {
return Err(GcliError::Input(
"One of `address`/`vault_name`/`secret_format`(and optional `secret` & `crypto_scheme`) must be provided".to_string(),
));
};
Ok(key_pair)
}
}
/// handle identity commands
......@@ -124,7 +180,7 @@ pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliE
}
Subcommand::GenRevocDoc => {
data = data.fetch_idty_index().await?;
commands::revocation::print_revoc_sig(&data)
commands::revocation::print_revoc_sig(&data).await
}
Subcommand::MemberCount => {
println!(
......@@ -138,23 +194,21 @@ pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliE
.unwrap()
)
}
Subcommand::LinkAccount {
secret_format,
secret,
} => {
let keypair = get_keypair(secret_format, secret.as_deref())?;
let address = keypair.address();
data = data.fetch_idty_index().await?; // idty index required for payload
link_account(&data, address, keypair).await?;
}
Subcommand::ChangeOwnerKey {
secret_format,
secret,
} => {
let keypair = get_keypair(secret_format, secret.as_deref())?;
let address = keypair.address();
data = data.fetch_idty_index().await?; // idty index required for payload
change_owner_key(&data, address, keypair).await?;
Subcommand::LinkAccount(secret_provider) => {
let target_keypair = secret_provider.get_keypair(&data).await?;
println!("Trying to make the link");
let address = target_keypair.address();
let data = data.fetch_idty_index().await?; // idty index required for payload
link_account(&data, address, target_keypair).await?;
}
Subcommand::ChangeOwnerKey(secret_provider) => {
let target_keypair = secret_provider.get_keypair(&data).await?;
println!("Trying to change owner key");
let address = target_keypair.address();
let data = data.fetch_idty_index().await?; // idty index required for payload
change_owner_key(&data, address, target_keypair).await?;
}
};
......@@ -250,18 +304,19 @@ pub async fn get_identity(
let indexer = data.indexer.clone();
// get idty_id
let index =
match (identity_id, &account_id, &pseudo) {
let index = match (identity_id, &account_id, &pseudo) {
// idty_id
(Some(index), None, None) => index,
// account_id → idty_id
(None, Some(account_id), None) => get_idty_index_by_account_id(client, account_id)
.await?
.ok_or_else(|| anyhow!("no identity for account '{account_id}'"))?,
.ok_or_else(|| {
GcliError::Duniter(format!("no identity for account '{account_id}'"))
})?,
// pseudo → idty_id
(None, None, Some(pseudo)) => get_idty_index_by_name(client, pseudo)
.await?
.ok_or_else(|| anyhow!("no identity for name '{pseudo}'"))?,
.ok_or_else(|| GcliError::Indexer(format!("no identity for name '{pseudo}'")))?,
_ => {
return Err(GcliError::Logic(
"One and only one argument is needed to fetch the identity.".to_string(),
......@@ -271,14 +326,15 @@ pub async fn get_identity(
// idty_id → value
let value = get_identity_by_index(client, index)
.await?
.ok_or_else(|| anyhow!("no identity value for index {index}"))?;
.ok_or_else(|| GcliError::Duniter(format!("no identity value for index {index}")))?;
// pseudo
let pseudo = pseudo.unwrap_or(if let Some(indexer) = &indexer {
indexer
.username_by_index(index)
.await
.ok_or_else(|| anyhow!("indexer does not have username for this index {index}"))?
indexer.username_by_index(index).await.ok_or_else(|| {
GcliError::Indexer(format!(
"indexer does not have username for this index {index}"
))
})?
} else {
"<no indexer>".to_string()
});
......@@ -297,10 +353,20 @@ pub async fn get_identity(
.expect("expected cert meta");
// get certs if possible
let (cert_issued, cert_received, linked_account, smith_cert_issued, smith_cert_received) =
if let Some(indexer) = &indexer {
let info = indexer.identity_info(index).await.expect("no info");
let (cert_issued, cert_received, linked_account, smith_info) = if let Some(indexer) = &indexer {
let info = indexer
.identity_info(index)
.await
.ok_or_else(|| GcliError::Indexer(format!("no info for identity {index}")))?;
Ok::<
(
Vec<String>,
Vec<String>,
Vec<AccountId>,
Option<crate::indexer::queries::identity_info::IdentityInfoIdentitySmith>,
),
GcliError,
>((
info.cert_issued
.into_iter()
.map(|i| i.receiver.unwrap().name.to_string())
......@@ -313,28 +379,52 @@ pub async fn get_identity(
.into_iter()
.map(|i| AccountId::from_str(&i.id).unwrap())
.collect(),
info.smith_cert_issued
info.smith,
))
} else {
Ok((vec![], vec![], vec![], None))
}?;
// get smith info
let smith_meta = get_smith(client, index).await?;
let smith = match (smith_meta, smith_info) {
(None, None) => Ok(None),
(Some(s), Some(i)) => Ok(Some(SmithView {
status: s.status,
cert_issued_count: s.issued_certs.len(),
cert_issued: i
.smith_cert_issued
.into_iter()
.map(|i| i.receiver.unwrap().name.to_string())
.map(|i| i.receiver.unwrap().identity.unwrap().name.to_string())
.collect(),
info.smith_cert_received
cert_received_count: s.received_certs.len(),
cert_received: i
.smith_cert_received
.into_iter()
.map(|i| i.issuer.unwrap().name.to_string())
.map(|i| i.issuer.unwrap().identity.unwrap().name.to_string())
.collect(),
)
} else {
(vec![], vec![], vec![], vec![], vec![])
};
// get smith info
let smith = get_smith(client, index).await?;
let smith = smith.map(|s| SmithView {
})),
(Some(s), None) => match indexer {
Some(_) => Err(GcliError::Indexer(format!(
"Duniter and Indexer do not agree if {index} is smith"
))),
None => Ok(Some(SmithView {
status: s.status,
cert_issued_count: s.issued_certs.len(),
cert_issued: smith_cert_issued,
cert_issued: s.issued_certs.into_iter().map(|e| e.to_string()).collect(),
cert_received_count: s.received_certs.len(),
cert_received: smith_cert_received,
});
cert_received: s
.received_certs
.into_iter()
.map(|e| e.to_string())
.collect(),
})),
},
(None, Some(_)) => Err(GcliError::Indexer(format!(
"Duniter and Indexer do not agree if {pseudo} is smith"
))),
}?;
// build view
let view = IdtyView {
......@@ -431,7 +521,7 @@ pub async fn get_identity_by_index(
pub async fn create_identity(data: &Data, target: AccountId) -> Result<(), subxt::Error> {
submit_call_and_look_event::<
runtime::identity::events::IdtyCreated,
Payload<runtime::identity::calls::types::CreateIdentity>,
StaticPayload<runtime::identity::calls::types::CreateIdentity>,
>(data, &runtime::tx().identity().create_identity(target))
.await
}
......@@ -440,7 +530,7 @@ pub async fn create_identity(data: &Data, target: AccountId) -> Result<(), subxt
pub async fn confirm_identity(data: &Data, name: String) -> Result<(), subxt::Error> {
submit_call_and_look_event::<
runtime::identity::events::IdtyConfirmed,
Payload<runtime::identity::calls::types::ConfirmIdentity>,
StaticPayload<runtime::identity::calls::types::ConfirmIdentity>,
>(
data,
&runtime::tx()
......@@ -452,16 +542,15 @@ pub async fn confirm_identity(data: &Data, name: String) -> Result<(), subxt::Er
/// generate revokation document and submit it immediately
pub async fn revoke_identity(data: &Data) -> Result<(), subxt::Error> {
let (_payload, signature) = generate_revoc_doc(data);
let (_payload, signature) = generate_revoc_doc(data).await;
// Transform signature to MultiSignature
// TODO: this is a hack, we should be able to use the signature directly
let signature = runtime::runtime_types::sp_core::sr25519::Signature(signature.0);
let multisign = MultiSignature::Sr25519(signature);
// TODO: allow other signature formats
let multisign = MultiSignature::Sr25519(signature.into());
submit_call_and_look_event::<
runtime::identity::events::IdtyRemoved,
Payload<runtime::identity::calls::types::RevokeIdentity>,
StaticPayload<runtime::identity::calls::types::RevokeIdentity>,
>(
data,
&runtime::tx()
......@@ -484,9 +573,9 @@ pub fn generate_link_account(
let signature = keypair.sign(&payload);
(payload, Signature::Sr25519(signature))
}
KeyPair::Nacl(keypair) => {
let signature = nacl::sign::signature(&payload, &keypair.skey).expect("could not sign");
(payload, Signature::Nacl(signature))
KeyPair::Ed25519(keypair) => {
let signature = keypair.sign(&payload);
(payload, Signature::Ed25519(signature))
}
}
}
......@@ -510,10 +599,9 @@ pub fn generate_chok_payload(
let signature = keypair.sign(&payload);
(payload, Signature::Sr25519(signature))
}
KeyPair::Nacl(keypair) => {
// should not migrate to Nacl
let signature = nacl::sign::signature(&payload, &keypair.skey).expect("could not sign");
(payload, Signature::Nacl(signature))
KeyPair::Ed25519(keypair) => {
let signature = keypair.sign(&payload);
(payload, Signature::Ed25519(signature))
}
}
}
......@@ -526,20 +614,15 @@ pub async fn link_account(
) -> Result<(), subxt::Error> {
let (_payload, signature) = generate_link_account(data, address.clone(), keypair);
// this is a hack, see
// https://substrate.stackexchange.com/questions/10309/how-to-use-core-crypto-types-instead-of-runtime-types
// TODO cleaner way to manage signature
let signature = match signature {
Signature::Sr25519(signature) => MultiSignature::Sr25519(
runtime::runtime_types::sp_core::sr25519::Signature(signature.0),
),
Signature::Nacl(signature) => MultiSignature::Ed25519(
runtime::runtime_types::sp_core::ed25519::Signature(signature.try_into().unwrap()),
),
Signature::Sr25519(signature) => MultiSignature::Sr25519(signature.into()),
Signature::Ed25519(signature) => MultiSignature::Ed25519(signature.into()),
};
submit_call_and_look_event::<
runtime::account::events::AccountLinked,
Payload<runtime::identity::calls::types::LinkAccount>,
StaticPayload<runtime::identity::calls::types::LinkAccount>,
>(
data,
&runtime::tx().identity().link_account(address, signature),
......@@ -555,20 +638,15 @@ pub async fn change_owner_key(
) -> Result<(), subxt::Error> {
let (_payload, signature) = generate_chok_payload(data, address.clone(), keypair);
// this is a hack, see
// https://substrate.stackexchange.com/questions/10309/how-to-use-core-crypto-types-instead-of-runtime-types
// TODO cleaner way to manage signature
let signature = match signature {
Signature::Sr25519(signature) => MultiSignature::Sr25519(
runtime::runtime_types::sp_core::sr25519::Signature(signature.0),
),
Signature::Nacl(signature) => MultiSignature::Ed25519(
runtime::runtime_types::sp_core::ed25519::Signature(signature.try_into().unwrap()),
),
Signature::Sr25519(signature) => MultiSignature::Sr25519(signature.into()),
Signature::Ed25519(signature) => MultiSignature::Ed25519(signature.into()),
};
submit_call_and_look_event::<
runtime::identity::events::IdtyChangedOwnerKey,
Payload<runtime::identity::calls::types::ChangeOwnerKey>,
StaticPayload<runtime::identity::calls::types::ChangeOwnerKey>,
>(
data,
&runtime::tx()
......
......@@ -4,7 +4,7 @@ use sp_core::DeriveJunction;
use subxt::ext::sp_runtime::MultiAddress;
pub async fn repart(data: &Data, target: u32, actual_repart: Option<u32>) -> anyhow::Result<()> {
let KeyPair::Sr25519(keypair) = data.keypair() else {
let KeyPair::Sr25519(keypair) = data.keypair().await else {
panic!("Cesium keys not implemented there")
};
let mut pairs = Vec::new();
......@@ -43,7 +43,7 @@ pub async fn repart(data: &Data, target: u32, actual_repart: Option<u32>) -> any
}
pub async fn spam_roll(data: &Data, actual_repart: usize) -> anyhow::Result<()> {
let KeyPair::Sr25519(keypair) = data.keypair() else {
let KeyPair::Sr25519(keypair) = data.keypair().await else {
panic!("Cesium keys not implemented there")
};
let client = data.client();
......
......@@ -65,7 +65,7 @@ pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliE
}
/// get balance of oneshot account
pub async fn oneshot_account_balance(data: &Data) -> Result<(), anyhow::Error> {
pub async fn oneshot_account_balance(data: &Data) -> Result<(), subxt::Error> {
println!(
"balance of oneshot account {} is: {}",
data.address(),
......@@ -93,7 +93,7 @@ pub async fn create_oneshot_account(
) -> Result<(), subxt::Error> {
submit_call_and_look_event::<
runtime::oneshot_account::events::OneshotAccountCreated,
Payload<runtime::oneshot_account::calls::types::CreateOneshotAccount>,
StaticPayload<runtime::oneshot_account::calls::types::CreateOneshotAccount>,
>(
data,
&runtime::tx()
......@@ -127,7 +127,7 @@ pub async fn consume_oneshot_account(
);
submit_call_and_look_event::<
runtime::oneshot_account::events::OneshotAccountConsumed,
Payload<runtime::oneshot_account::calls::types::ConsumeOneshotAccount>,
StaticPayload<runtime::oneshot_account::calls::types::ConsumeOneshotAccount>,
>(data, payload)
.await
}
......@@ -174,7 +174,7 @@ pub async fn consume_oneshot_account_with_remaining(
submit_call_and_look_event::<
runtime::oneshot_account::events::OneshotAccountConsumed,
Payload<runtime::oneshot_account::calls::types::ConsumeOneshotAccountWithRemaining>,
StaticPayload<runtime::oneshot_account::calls::types::ConsumeOneshotAccountWithRemaining>,
>(data, payload)
.await
}