From c1b20cea54a4dc45a2c86727ff719d82666fa939 Mon Sep 17 00:00:00 2001 From: kompotkot Date: Tue, 15 Aug 2023 12:52:59 +0000 Subject: [PATCH] Generate config for API waggle server CLI, updated README --- README.md | 176 +++++++++++++++++++++++++++++++----------------------- cmd.go | 61 ++++++++++++++++++- 2 files changed, 160 insertions(+), 77 deletions(-) diff --git a/README.md b/README.md index 160e444..86abf61 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,15 @@ 2. Manage signing accounts 3. Send drop claims to the Moonstream Engine API -### Installation +## Installation -``` +```bash go install github.com/moonstream-to/waggle@latest ``` -### Usage +## Usage as CLI -``` +```bash waggle -h ``` @@ -22,7 +22,7 @@ waggle -h You can import a signing account from an external wallet using its private key: -``` +```bash waggle accounts import -k ``` @@ -63,34 +63,34 @@ claims (`batch.json` below): ```json [ - { - "dropId": "2", - "requestID": "5", - "claimant": "0x000000000000000000000000000000000000dEaD", - "blockDeadline": "40000000", - "amount": "3000000000000000000" - }, - { - "dropId": "2", - "requestID": "6", - "claimant": "0x000000000000000000000000000000000000dEaD", - "blockDeadline": "40000000", - "amount": "3000000000000000000" - }, - { - "dropId": "2", - "requestID": "7", - "claimant": "0x000000000000000000000000000000000000dEaD", - "blockDeadline": "40000000", - "amount": "3000000000000000000" - }, - { - "dropId": "2", - "requestID": "8", - "claimant": "0x000000000000000000000000000000000000dEaD", - "blockDeadline": "40000000", - "amount": "3000000000000000000" - } + { + "dropId": "2", + "requestID": "5", + "claimant": "0x000000000000000000000000000000000000dEaD", + "blockDeadline": "40000000", + "amount": "3000000000000000000" + }, + { + "dropId": "2", + "requestID": "6", + "claimant": "0x000000000000000000000000000000000000dEaD", + "blockDeadline": "40000000", + "amount": "3000000000000000000" + }, + { + "dropId": "2", + "requestID": "7", + "claimant": "0x000000000000000000000000000000000000dEaD", + "blockDeadline": "40000000", + "amount": "3000000000000000000" + }, + { + "dropId": "2", + "requestID": "8", + "claimant": "0x000000000000000000000000000000000000dEaD", + "blockDeadline": "40000000", + "amount": "3000000000000000000" + } ] ``` @@ -108,42 +108,42 @@ This results in a file that looks like this: ```json [ - { - "dropId": "2", - "requestID": "5", - "claimant": "0x000000000000000000000000000000000000dEaD", - "blockDeadline": "40000000", - "amount": "3000000000000000000", - "signature": "408...", - "signer": "" - }, - { - "dropId": "2", - "requestID": "6", - "claimant": "0x000000000000000000000000000000000000dEaD", - "blockDeadline": "40000000", - "amount": "3000000000000000000", - "signature": "667...", - "signer": "" - }, - { - "dropId": "2", - "requestID": "7", - "claimant": "0x000000000000000000000000000000000000dEaD", - "blockDeadline": "40000000", - "amount": "3000000000000000000", - "signature": "5c6...", - "signer": "" - }, - { - "dropId": "2", - "requestID": "8", - "claimant": "0x000000000000000000000000000000000000dEaD", - "blockDeadline": "40000000", - "amount": "3000000000000000000", - "signature": "85f...", - "signer": "" - } + { + "dropId": "2", + "requestID": "5", + "claimant": "0x000000000000000000000000000000000000dEaD", + "blockDeadline": "40000000", + "amount": "3000000000000000000", + "signature": "408...", + "signer": "" + }, + { + "dropId": "2", + "requestID": "6", + "claimant": "0x000000000000000000000000000000000000dEaD", + "blockDeadline": "40000000", + "amount": "3000000000000000000", + "signature": "667...", + "signer": "" + }, + { + "dropId": "2", + "requestID": "7", + "claimant": "0x000000000000000000000000000000000000dEaD", + "blockDeadline": "40000000", + "amount": "3000000000000000000", + "signature": "5c6...", + "signer": "" + }, + { + "dropId": "2", + "requestID": "8", + "claimant": "0x000000000000000000000000000000000000dEaD", + "blockDeadline": "40000000", + "amount": "3000000000000000000", + "signature": "85f...", + "signer": "" + } ] ``` @@ -160,7 +160,7 @@ You can generate an access token at https://moonstream.to/app Then: -``` +```bash waggle moonstream drop \ --contract-id a035f3f8-7301-45b7-940a-109585419774 \ --infile signed_batch.json @@ -183,10 +183,9 @@ https://engineapi.moonstream.to/contracts/requests?contract_id=$CONTRACT_ID&call Here, `$CONTRACT_ID` should be the same contract ID you used in `waggle moonstream drop`. `$USER_ADDRESS` is the user's Ethereum account address. - #### Get claim requests from Bugout journal -``` +```bash waggle sign dropper pull \ --cursor \ -j \ @@ -196,7 +195,7 @@ waggle sign dropper pull \ This expects a `BUGOUT_ACCESS_TOKEN` environment variable to be set. You can generate an access token at https://bugout.dev/account/tokens. Once you have generated a token, set it in your shell session using: -``` +```bash export BUGOUT_ACCESS_TOKEN= ``` @@ -215,7 +214,7 @@ dropId,requestID,claimant,blockDeadline,amount,signer,signature You can sign this using the `waggle sign dropper batch command` by passing the CSV file as the `--infile` argument and setting the `--csv` flag: -``` +```bash waggle sign dropper batch -k signer.json \ --chain-id 80001 \ --dropper 0x4ec36E288E1b5d6914851a141cb041152Cf95328 \ @@ -227,13 +226,38 @@ waggle sign dropper batch -k signer.json \ ### Build -``` +```bash go build ./... ./waggle -h ``` ### Test -``` +```bash go test ./... -v ``` + +## Usage as API server + +Example of server configuration file `config.json`: + +```json +[ + { + "keyfile_path": "dev.json", + "keyfile_password_path": "password.txt" + } +] +``` + +Config also could be generated with command: + +```bash +waggle accounts config --keyfile dev.json --outfile config.json +``` + +Run server: + +```bash +waggle server run --host 0.0.0.0 --config config.json +``` diff --git a/cmd.go b/cmd.go index a19f955..6962bde 100644 --- a/cmd.go +++ b/cmd.go @@ -9,9 +9,12 @@ import ( "io" "log" "os" + "path/filepath" + "strings" bugout "github.com/bugout-dev/bugout-go/pkg" "github.com/spf13/cobra" + "golang.org/x/term" ) func CreateRootCommand() *cobra.Command { @@ -128,7 +131,63 @@ func CreateAccountsCommand() *cobra.Command { }, } - accountsCommand.AddCommand(importCommand) + var password, outfile string + + configCommand := &cobra.Command{ + Use: "config", + Short: "Prepare configuration for waggle API server.", + RunE: func(cmd *cobra.Command, args []string) error { + serverSignerConfigs := []ServerSignerConfig{} + var passwordRaw []byte + var err error + if password == "" { + fmt.Print("Enter password for keyfile (it will not be displayed on screen): ") + passwordRaw, err = term.ReadPassword(int(os.Stdin.Fd())) + fmt.Print("\n") + if err != nil { + return fmt.Errorf("error reading password from input: %s", err.Error()) + } + } else { + passwordRaw = []byte(password) + } + + keyfilePath := strings.TrimSuffix(keyfile, "/") + _, err = os.Stat(keyfilePath) + if err != nil { + if os.IsNotExist(err) { + return fmt.Errorf("file %s not found, err: %v", keyfilePath, err) + } + return fmt.Errorf("error due checking keyfile path %s, err: %v", keyfilePath, err) + } + dir, file := filepath.Split(keyfilePath) + passwordFilePath := fmt.Sprintf("%spassword-%s", dir, file) + os.WriteFile(passwordFilePath, passwordRaw, 0640) + + // TODO(kompotkot): Provide functionality to generate config with multiple keyfiles + serverSignerConfigs = append(serverSignerConfigs, ServerSignerConfig{ + KeyfilePath: keyfile, + KeyfilePasswordPath: passwordFilePath, + }) + resultJSON, err := json.Marshal(serverSignerConfigs) + if err != nil { + return err + } + + if outfile != "" { + os.WriteFile(outfile, resultJSON, 0644) + } else { + os.Stdout.Write(resultJSON) + } + + return nil + }, + } + + configCommand.PersistentFlags().StringVarP(&keyfile, "keystore", "k", "", "Path to keystore file (this should be a JSON file)") + configCommand.PersistentFlags().StringVarP(&password, "password", "p", "", "Password for keystore file. If not provided, you will be prompted for it when you sign with the key") + configCommand.PersistentFlags().StringVarP(&outfile, "outfile", "o", "config.json", "Config file output path") + + accountsCommand.AddCommand(importCommand, configCommand) return accountsCommand }