├── .github
├── ISSUE_TEMPLATE
│ ├── bug-report.md
│ └── feature-request.md
├── dependabot.yml
├── labels.yml
├── pull_request_template.md
├── release-drafter.yml
└── workflows
│ ├── add-issues-to-devx-project.yml
│ ├── build-release.yaml
│ ├── ci.yml
│ ├── dependent-issues.yml
│ ├── publish-release.yml
│ ├── release-drafter.yml
│ └── sync-labels.yml
├── .gitignore
├── .golangci.yml
├── .goreleaser.yaml
├── CODEOWNERS
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── NOTICE
├── README.md
├── SECURITY.md
├── build
└── build.go
├── check-headers.sh
├── cli-banner.svg
├── cli.gif
├── cmd
└── flow
│ └── main.go
├── docs
├── README.md
├── account-add-contract.md
├── account-remove-contract.md
├── account-staking-info.md
├── account-update-contract.md
├── build-transactions.md
├── complex-transactions.md
├── configuration.md
├── create-accounts.md
├── data-collection.md
├── decode-keys.md
├── decode-transactions.md
├── deploy-project-contracts.md
├── derive-keys.md
├── developer-updates
│ ├── release-notes-v17.md
│ ├── release-notes-v18.md
│ ├── release-notes-v19.md
│ ├── release-notes-v21.md
│ ├── release-notes-v24.md
│ ├── release-notes-v26.md
│ └── release-notes-v28.md
├── emulator-snapshot.md
├── execute-scripts.md
├── generate-keys.md
├── get-accounts.md
├── get-blocks.md
├── get-collections.md
├── get-events.md
├── get-status.md
├── get-transactions.md
├── index.md
├── initialize-configuration.md
├── install.md
├── manage-configuration.md
├── project-app.md
├── project-contracts.md
├── run-tests.md
├── security.md
├── send-signed-transactions.md
├── send-transactions.md
├── sign-transaction.md
├── signature-generate.md
├── signature-verify.md
├── snapshot-save.md
├── start-emulator.md
├── super-commands.md
├── template.md
└── tools.md
├── flowkit
├── README.md
└── schema.json
├── go.mod
├── go.sum
├── install.ps1
├── install.sh
├── internal
├── accounts
│ ├── accounts.go
│ ├── accounts_test.go
│ ├── contract-add.go
│ ├── contract-remove.go
│ ├── contract-update.go
│ ├── create-interactive.go
│ ├── create.go
│ ├── fund.go
│ ├── get.go
│ └── staking-info.go
├── blocks
│ ├── blocks.go
│ ├── blocks_test.go
│ └── get.go
├── cadence
│ ├── cadence.go
│ ├── languageserver
│ │ └── languageserver.go
│ ├── lint.go
│ ├── lint_test.go
│ └── linter.go
├── collections
│ ├── collections.go
│ ├── collections_test.go
│ └── get.go
├── command
│ ├── command.go
│ ├── global_flags.go
│ ├── global_flags_test.go
│ ├── result.go
│ └── template.go
├── config
│ ├── add-account.go
│ ├── add-contract.go
│ ├── add-deployment.go
│ ├── add-network.go
│ ├── add.go
│ ├── config.go
│ ├── init.go
│ ├── remove-account.go
│ ├── remove-contract.go
│ ├── remove-deployment.go
│ ├── remove-network.go
│ └── remove.go
├── dependencymanager
│ ├── add.go
│ ├── dependencies.go
│ ├── dependencyinstaller.go
│ ├── dependencyinstaller_test.go
│ ├── discover.go
│ └── install.go
├── emulator
│ ├── snapshot.go
│ └── start.go
├── events
│ ├── events.go
│ ├── events_test.go
│ └── get.go
├── evm
│ └── gateway.go
├── keys
│ ├── decode.go
│ ├── derive.go
│ ├── generate.go
│ ├── keys.go
│ └── keys_test.go
├── project
│ ├── deploy.go
│ ├── project.go
│ └── project_test.go
├── prompt
│ ├── prompt.go
│ ├── select-options.go
│ └── text-input.go
├── quick
│ ├── deploy.go
│ └── run.go
├── scripts
│ ├── execute.go
│ ├── scripts.go
│ └── scripts_test.go
├── settings
│ ├── cmd.go
│ ├── defaults.go
│ ├── metrics.go
│ └── settings.go
├── signatures
│ ├── generate.go
│ ├── signatures.go
│ ├── signatures_test.go
│ └── verify.go
├── snapshot
│ ├── save.go
│ └── snapshot.go
├── status
│ └── status.go
├── super
│ ├── dev.go
│ ├── files.go
│ ├── files_test.go
│ ├── flix.go
│ ├── flix_test.go
│ ├── generate.go
│ ├── generator
│ │ ├── contract_template.go
│ │ ├── file_template.go
│ │ ├── fixtures
│ │ │ ├── README_no_deps.md
│ │ │ └── README_with_deps.md
│ │ ├── generator.go
│ │ ├── generator_test.go
│ │ ├── script_template.go
│ │ ├── templates
│ │ │ ├── README.md.tmpl
│ │ │ ├── contract_counter.cdc.tmpl
│ │ │ ├── contract_init.cdc.tmpl
│ │ │ ├── contract_init_test.cdc.tmpl
│ │ │ ├── empty_test.cdc.tmpl
│ │ │ ├── script_counter.cdc.tmpl
│ │ │ ├── script_init.cdc.tmpl
│ │ │ ├── transaction_counter.cdc.tmpl
│ │ │ └── transaction_init.cdc.tmpl
│ │ ├── test_template.go
│ │ └── transaction_template.go
│ ├── output.go
│ ├── project.go
│ ├── scaffolds.go
│ └── setup.go
├── test
│ ├── test.go
│ └── test_test.go
├── tools
│ ├── flowser.go
│ └── wallet.go
├── transactions
│ ├── build.go
│ ├── decode.go
│ ├── get-system.go
│ ├── get.go
│ ├── send-signed.go
│ ├── send.go
│ ├── sign.go
│ ├── transactions.go
│ └── transactions_test.go
├── util
│ ├── checker_environment.go
│ ├── emoji.go
│ ├── files.go
│ ├── test.go
│ └── util.go
└── version
│ └── version.go
├── scaffolds.json
├── testing
└── better
│ └── README.md
└── version.txt
/.github/ISSUE_TEMPLATE/bug-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Reporting a Problem/Bug
3 | about: Reporting a Problem/Bug
4 | title: ''
5 | labels: bug
6 | ---
7 | ### Instructions
8 |
9 | Please fill out the template below to the best of your ability and include a label indicating which tool/service you were working with when you encountered the problem.
10 |
11 | ### Problem
12 |
13 |
14 |
15 | ### Steps to Reproduce
16 |
17 |
18 |
19 | ### Acceptance Criteria
20 |
21 |
22 |
23 | ### Context
24 |
25 |
26 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Requesting a Feature or Improvement
3 | about: "For feature requests. Please search for existing issues first. Also see CONTRIBUTING.md"
4 | title: ''
5 | labels: Feature
6 | ---
7 |
8 | ## Instructions
9 |
10 | Please fill out the template below to the best of your ability.
11 |
12 | ### Issue To Be Solved
13 |
14 | (Replace this text:
15 | Please present a concise description of the problem to be addressed by this feature request.
16 | Please be clear what parts of the problem are considered to be in-scope and out-of-scope.)
17 |
18 | ### (Optional): Suggest A Solution
19 |
20 | (Replace this text: A concise description of your preferred solution. Things to address include:
21 |
22 | * Details of the technical implementation
23 | * Tradeoffs made in design decisions
24 | * Caveats and considerations for the future
25 |
26 | If there are multiple solutions, please present each one separately. Save comparisons for the very end.)
27 |
28 | ### (Optional): Context
29 |
30 | (Replace this text:
31 | What are you currently working on that this is blocking?)
32 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "github-actions"
4 | directory: "/"
5 | schedule:
6 | interval: "custom"
7 | interval-count: 14
8 | time: "12:00" # Adjust the time to your preferred schedule
9 |
10 | - package-ecosystem: "gomod"
11 | allow:
12 | - dependency-type: "direct"
13 | update-type: "semver-minor"
14 | - dependency-type: "direct"
15 | update-type: "semver-major"
16 | directory: "/"
17 | schedule:
18 | interval: "custom"
19 | interval-count: 14
20 | time: "12:00" # Adjust the time to your preferred schedule
21 | ignore:
22 | - dependency-name: "github.com/onflow/flow-go"
23 | - dependency-name: "github.com/onflow/cadence"
24 |
--------------------------------------------------------------------------------
/.github/labels.yml:
--------------------------------------------------------------------------------
1 | - color: 3E4B9E
2 | description: ""
3 | name: Epic
4 | - color: 0e8a16
5 | description: A new user feature or a new package API
6 | name: Feature
7 | - color: d4c5f9
8 | description: ""
9 | name: Feedback
10 | - color: 1d76db
11 | description: Technical work without new features, refactoring, improving tests
12 | name: Improvement
13 | - color: d73a4a
14 | description: The issue represents a bug, malfunction, regression
15 | name: Bug
16 | - color: 0075ca
17 | description: The issue in documentation, missing docs, invalid docs, outdated docs
18 | name: Documentation
19 | - color: c2e0c6
20 | description: A feature we want the help from community
21 | name: Help wanted
22 | - color: cccccc
23 | description: The issue was not well defined, waiting for more information from the submittor
24 | name: Needs information
25 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | Closes #???
2 |
3 | ## Description
4 |
5 |
9 |
10 | ______
11 |
12 | For contributor use:
13 |
14 | - [ ] Targeted PR against `master` branch
15 | - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work
16 | - [ ] Code follows the [standards mentioned here](https://github.com/onflow/flow-cli/blob/master/CONTRIBUTING.md#styleguides)
17 | - [ ] Updated relevant documentation
18 | - [ ] Re-reviewed `Files changed` in the Github PR explorer
19 | - [ ] Added appropriate labels
20 |
--------------------------------------------------------------------------------
/.github/release-drafter.yml:
--------------------------------------------------------------------------------
1 | name-template: 'Version $NEXT_PATCH_VERSION'
2 | tag-template: 'v$NEXT_PATCH_VERSION'
3 | change-template: '- $TITLE (#$NUMBER) @$AUTHOR'
4 | template: |
5 | ## ⬆️ Install or Upgrade
6 | Follow the [Flow CLI installation guide](https://developers.flow.com/tools/flow-cli/install) for instructions on how to install or upgrade the CLI.
7 |
8 | $CHANGES
9 | categories:
10 | - title: 💥 Breaking Changes
11 | label: Breaking Change
12 | - title: ⭐ Features
13 | label: Feature
14 | - title: 🛠 Improvements
15 | label: Improvement
16 | - title: 🐞 Bug Fixes
17 | label: Bugfix
18 | - title: 📖 Documentation
19 | label: Documentation
20 |
--------------------------------------------------------------------------------
/.github/workflows/add-issues-to-devx-project.yml:
--------------------------------------------------------------------------------
1 | name: Adds all issues to the DevEx project board.
2 |
3 | on:
4 | issues:
5 | types:
6 | - opened
7 |
8 | jobs:
9 | add-to-project:
10 | name: Add issue to project
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/add-to-project@v1.0.2
14 | with:
15 | project-url: https://github.com/orgs/onflow/projects/85
16 | github-token: ${{ secrets.GH_ACTION_FOR_PROJECTS }}
17 |
--------------------------------------------------------------------------------
/.github/workflows/build-release.yaml:
--------------------------------------------------------------------------------
1 | name: Build Release
2 |
3 | on:
4 | release:
5 | types: [published]
6 |
7 | env:
8 | GO_VERSION: "1.24"
9 |
10 | jobs:
11 | release:
12 | name: Release Go Binary
13 | runs-on: ubuntu-latest
14 | steps:
15 | # See https://github.com/onflow/flow-cli/pull/1431 for more information
16 | - name: Delete unnecessary cache
17 | run: rm -rf ${RUNNER_TOOL_CACHE}
18 | - uses: actions/checkout@v3
19 | - name: Codebase security check
20 | continue-on-error: true
21 | uses: snyk/actions/golang@master
22 | with:
23 | go-version: ${{ env.GO_VERSION }}
24 | env:
25 | SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
26 | - name: Setup Release Environment
27 | run: |-
28 | echo 'MIXPANEL_PROJECT_TOKEN=${{ secrets.MIXPANEL_PROJECT_TOKEN }}' > .release-env
29 | echo 'LILICO_TOKEN=${{ secrets.LILICO_TOKEN }}' >> .release-env
30 | echo 'APP_VERSION=$(basename ${GITHUB_REF})' >> .release-env
31 | echo 'BUILD_TIME=$(date --iso-8601=seconds)' >> .release-env
32 | echo 'VERSION=${{ github.event.release.tag_name }}' >> .release-env
33 | echo 'GITHUB_TOKEN=${{ secrets.FLOW_CLI_RELEASE }}' >> .release-env
34 | - name: Build and Release
35 | run: make release
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | # Controls when the action will run. Triggers the workflow on push or pull request
4 | # events but only for the master branch
5 | on:
6 | push:
7 | branches:
8 | - master
9 | - 'feature/**'
10 | pull_request:
11 | branches:
12 | - master
13 | - 'feature/**'
14 |
15 | # We need to set this explicitly to make sure the CI works on Windows
16 | # Default shell does not terminate on error in GitHub Actions
17 | # https://github.com/actions/runner-images/issues/6668
18 | defaults:
19 | run:
20 | shell: bash
21 |
22 | env:
23 | GO_VERSION: "1.24"
24 |
25 | jobs:
26 | test:
27 | strategy:
28 | matrix:
29 | os: [ubuntu-latest, windows-latest]
30 | runs-on: ${{ matrix.os }}
31 | steps:
32 | - uses: actions/checkout@v4
33 | - uses: actions/setup-go@v5
34 | with:
35 | go-version: ${{ env.GO_VERSION }}
36 | - name: Run tests
37 | run: |
38 | make ci
39 | make check-tidy
40 | make check-headers
41 | - name: Upload coverage report
42 | uses: codecov/codecov-action@v5
43 | with:
44 | file: ./coverage.txt
45 | flags: unittests
46 | token: ${{ secrets.CODECOV_TOKEN }}
47 | if: matrix.os == 'ubuntu-latest'
48 |
49 | lint:
50 | runs-on: ubuntu-latest
51 | steps:
52 | - uses: actions/checkout@v4
53 | - uses: actions/setup-go@v5
54 | with:
55 | go-version: ${{ env.GO_VERSION }}
56 | - name: generate
57 | run: make generate
58 | - uses: golangci/golangci-lint-action@v6.5.0
59 | with:
60 | version: v1.64.8
61 | only-new-issues: true
62 | skip-pkg-cache: true
63 | args: --timeout=3m
64 |
--------------------------------------------------------------------------------
/.github/workflows/dependent-issues.yml:
--------------------------------------------------------------------------------
1 | name: Dependent Issues
2 |
3 | on:
4 | issues:
5 | types:
6 | - opened
7 | - edited
8 | - closed
9 | - reopened
10 | pull_request_target:
11 | types:
12 | - opened
13 | - edited
14 | - closed
15 | - reopened
16 | - synchronize
17 | schedule:
18 | - cron: '0 0 * * *'
19 |
20 | jobs:
21 | check:
22 | runs-on: ubuntu-latest
23 | steps:
24 | - uses: z0al/dependent-issues@v1
25 | env:
26 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
27 | with:
28 | label: dependent
29 | comment: >
30 | This PR/issue depends on:
31 |
32 | {{ dependencies }}
33 |
34 | By **[Dependent Issues](https://github.com/z0al/dependent-issues)** (🤖).
35 |
--------------------------------------------------------------------------------
/.github/workflows/publish-release.yml:
--------------------------------------------------------------------------------
1 | name: Publish Release
2 |
3 | on:
4 | release:
5 | types: [published]
6 | jobs:
7 | homebrew:
8 | if: "!github.event.release.prerelease"
9 | name: Bump Homebrew formula
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: mislav/bump-homebrew-formula-action@v3
13 | with:
14 | formula-name: flow-cli
15 | env:
16 | COMMITTER_TOKEN: ${{ secrets.COMMITTER_TOKEN }}
17 |
--------------------------------------------------------------------------------
/.github/workflows/release-drafter.yml:
--------------------------------------------------------------------------------
1 | name: Release Drafter
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 |
8 | jobs:
9 | update_release_draft:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: release-drafter/release-drafter@v5
13 | env:
14 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
15 |
--------------------------------------------------------------------------------
/.github/workflows/sync-labels.yml:
--------------------------------------------------------------------------------
1 | name: Sync Labels
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | paths:
8 | - .github/labels.yml
9 |
10 | jobs:
11 | build:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v3
15 | - uses: micnncim/action-label-syncer@v1
16 | env:
17 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
18 | with:
19 | manifest: .github/labels.yml
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Test binary, build with `go test -c`
2 | *.test
3 |
4 | # Output of the go coverage tool, specifically when used with LiteIDE
5 | *.out
6 |
7 | # Coverage artifacts
8 | coverage.zip
9 | coverage.txt
10 | cover.json
11 | cover-summary
12 | index.html
13 |
14 | # Binaries
15 | /cmd/flow/flow*
16 |
17 | .DS_Store
18 |
19 | # Ignore flow json config
20 | flow.json
21 | flow*.json
22 | !tests/flow.json
23 |
24 | # IDE related files
25 | .idea
26 | .vscode
27 | git
28 |
29 | # Ignore built CLI
30 | main
31 | *.pkey
32 |
33 | # Local development file generation folder
34 | imports
35 |
36 | # Goreleaser .env
37 | .release-env
--------------------------------------------------------------------------------
/.golangci.yml:
--------------------------------------------------------------------------------
1 | linters:
2 | disable-all: true
3 | enable:
4 | - govet
5 | - errcheck
6 | - ineffassign
7 | - typecheck
8 | - misspell
9 | - goimports
10 | linters-settings:
11 | goimports:
12 | # put imports beginning with prefix after 3rd-party package
13 | local-prefixes: github.com/onflow/flow-cli
14 |
--------------------------------------------------------------------------------
/.goreleaser.yaml:
--------------------------------------------------------------------------------
1 | before:
2 | hooks:
3 | - make generate
4 |
5 | builds:
6 | - id: flow-cli
7 | main: ./cmd/flow
8 | goos:
9 | - darwin
10 | - linux
11 | - windows
12 | goarch:
13 | - amd64
14 | - arm64
15 | env:
16 | - CGO_CFLAGS=-O2 -D__BLST_PORTABLE__
17 | - CGO_ENABLED=1
18 | - CC_darwin_amd64=o64-clang
19 | - CXX_darwin_amd64=o64-clang+
20 | - CC_darwin_arm64=oa64-clang
21 | - CXX_darwin_arm64=oa64-clang++
22 | - CC_linux_amd64=x86_64-linux-gnu-gcc
23 | - CXX_linux_amd64=x86_64-linux-gnu-g++
24 | - CC_linux_arm64=aarch64-linux-gnu-gcc
25 | - CXX_linux_arm64=aarch64-linux-gnu-g++
26 | - CC_windows_amd64=x86_64-w64-mingw32-gcc
27 | - CXX_windows_amd64=x86_64-w64-mingw32-g++
28 | - CC_windows_arm64=/llvm-mingw/bin/aarch64-w64-mingw32-gcc
29 | - CXX_windows_arm64=/llvm-mingw/bin/aarch64-w64-mingw32-g++
30 | - 'CC={{ index .Env (print "CC_" .Os "_" .Arch) }}'
31 | - 'CXX={{ index .Env (print "CXX_" .Os "_" .Arch) }}'
32 | flags:
33 | - -mod=readonly
34 | ldflags:
35 | - -X github.com/onflow/flow-cli/build.semver={{ .Env.VERSION }} -X github.com/onflow/flow-cli/internal/command.MixpanelToken={{ .Env.MIXPANEL_PROJECT_TOKEN }} -X github.com/onflow/flow-cli/internal/accounts.accountToken={{ .Env.LILICO_TOKEN }}
36 |
37 | archives:
38 | - id: golang-cross
39 | builds:
40 | - flow-cli
41 | name_template: "{{ .ProjectName }}-v{{ .Version }}-{{ .Os }}-{{ .Arch }}"
42 | format: tar.gz
43 | format_overrides:
44 | - goos: windows
45 | format: zip
46 | wrap_in_directory: false
47 | snapshot:
48 | name_template: "{{ .Tag }}"
49 | changelog:
50 | skip: true
51 | checksum:
52 | name_template: "checksums.txt"
53 | release:
54 | github:
55 | owner: onflow
56 | name: flow-cli
57 | prerelease: auto
58 | draft: false
59 |
--------------------------------------------------------------------------------
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @Kay-Zee @janezpodhostnik @chasefleming @nvdtf @bluesign @bjartek @jribbink @mfbz
2 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # Configuration for goreleaser
2 | PACKAGE_NAME := github.com/onflow/flow-cli
3 | GOLANG_CROSS_VERSION ?= v1.22.0
4 |
5 | # The tag of the current commit, otherwise empty
6 | VERSION := $(shell git describe --tags --abbrev=0 --exact-match 2>/dev/null)
7 | # Name of the cover profile
8 | COVER_PROFILE := coverage.txt
9 | # Disable go sum database lookup for private repos
10 | GOPRIVATE := github.com/dapperlabs/*
11 | # Ensure go bin path is in path (Especially for CI)
12 | GOPATH ?= $(HOME)/go
13 | PATH := $(PATH):$(GOPATH)/bin
14 | # OS
15 | UNAME := $(shell uname)
16 |
17 | MIXPANEL_PROJECT_TOKEN := 3fae49de272be1ceb8cf34119f747073
18 | ACCOUNT_TOKEN := lilico:sF60s3wughJBmNh2
19 |
20 | BINARY ?= ./cmd/flow/flow
21 |
22 | .PHONY: binary
23 | binary: $(BINARY)
24 |
25 | .PHONY: install-tools
26 | install-tools:
27 | cd '${GOPATH}'; \
28 | mkdir -p '${GOPATH}'; \
29 | GO111MODULE=on go install github.com/axw/gocov/gocov@latest; \
30 | GO111MODULE=on go install github.com/matm/gocov-html/cmd/gocov-html@latest; \
31 | GO111MODULE=on go install github.com/sanderhahn/gozip/cmd/gozip@latest; \
32 | GO111MODULE=on go install github.com/vektra/mockery/v2@v2.43.2;
33 |
34 | .PHONY: test
35 | test:
36 | GO111MODULE=on go test -coverprofile=$(COVER_PROFILE) $(if $(JSON_OUTPUT),-json,) ./...
37 |
38 | .PHONY: test-e2e-emulator
39 | test-e2e-emulator:
40 | flow -f tests/flow.json emulator start
41 |
42 | .PHONY: coverage
43 | coverage:
44 | ifeq ($(COVER), true)
45 | # file has to be called index.html
46 | gocov convert $(COVER_PROFILE) > cover.json
47 | ./cover-summary.sh
48 | gocov-html cover.json > index.html
49 | # coverage.zip will automatically be picked up by teamcity
50 | gozip -c coverage.zip index.html
51 | endif
52 |
53 | .PHONY: ci
54 | ci: install-tools generate test coverage
55 |
56 | $(BINARY):
57 | CGO_ENABLED=1 \
58 | CGO_CFLAGS="-O2 -D__BLST_PORTABLE__" \
59 | GO111MODULE=on go build \
60 | -trimpath \
61 | -ldflags \
62 | "-X github.com/onflow/flow-cli/build.semver=$(VERSION) -X github.com/onflow/flow-cli/internal/accounts.accountToken=${ACCOUNT_TOKEN} -X github.com/onflow/flow-cli/internal/command.MixpanelToken=${MIXPANEL_PROJECT_TOKEN}" \
63 | -o $(BINARY) ./cmd/flow
64 |
65 | .PHONY: versioned-binaries
66 | versioned-binaries: generate
67 | $(MAKE) OS=linux ARCH=amd64 ARCHNAME=x86_64 versioned-binary
68 | $(MAKE) OS=linux ARCH=arm64 versioned-binary
69 | $(MAKE) OS=darwin ARCH=amd64 ARCHNAME=x86_64 versioned-binary
70 | $(MAKE) OS=darwin ARCH=arm64 versioned-binary
71 | $(MAKE) OS=windows ARCH=amd64 ARCHNAME=x86_64 versioned-binary
72 |
73 | .PHONY: versioned-binary
74 | versioned-binary:
75 | GOOS=$(OS) GOARCH=$(ARCH) $(MAKE) BINARY=./cmd/flow/flow-$(or ${ARCHNAME},${ARCHNAME},${ARCH})-$(OS)-$(VERSION) binary
76 |
77 | .PHONY: publish
78 | publish:
79 | gsutil -m cp cmd/flow/flow-*-$(VERSION) gs://flow-cli
80 |
81 | .PHONY: clean
82 | clean:
83 | rm ./cmd/flow/flow*
84 |
85 | .PHONY: lint
86 | lint: generate
87 | golangci-lint run -v ./...
88 |
89 | .PHONY: fix-lint
90 | fix-lint:
91 | golangci-lint run -v --fix ./...
92 |
93 | .PHONY: check-headers
94 | check-headers:
95 | @./check-headers.sh
96 |
97 | .PHONY: check-tidy
98 | check-tidy:
99 | go mod tidy
100 |
101 | .PHONY: generate
102 | generate: install-tools
103 | go generate ./...
104 |
105 | .PHONY: release
106 | release:
107 | docker run \
108 | --rm \
109 | --env-file .release-env \
110 | -v /var/run/docker.sock:/var/run/docker.sock \
111 | -v `pwd`:/go/src/$(PACKAGE_NAME) \
112 | -v `pwd`/sysroot:/sysroot \
113 | -w /go/src/$(PACKAGE_NAME) \
114 | ghcr.io/goreleaser/goreleaser-cross:${GOLANG_CROSS_VERSION} \
115 | release --clean
--------------------------------------------------------------------------------
/NOTICE:
--------------------------------------------------------------------------------
1 | Flow CLI
2 | Copyright 2019-2024 Flow Foundation
3 |
4 | This product includes software developed at the Flow Foundation (https://flow.com/flow-foundation).
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Flow CLI brings Flow to your terminal. Easily interact with the network and build your dapps.
9 |
10 | Read the docs»
11 |
12 |
13 | Report Bug
14 | ·
15 | Contribute
16 | ·
17 | Read Guidelines
18 |
19 |
20 |
21 |
22 |
23 | ## Installation
24 |
25 | To install the Flow CLI, follow the [installation instructions](https://developers.flow.com/tools/flow-cli/install) on the Flow documentation website.
26 |
27 | ## Documentation
28 |
29 | You can find the CLI documentation on the [CLI documentation website](https://developers.flow.com/tools/flow-cli).
30 |
31 | ## Features
32 | The Flow CLI is a command line tool that allows you to interact with the Flow blockchain.
33 | Read about supported commands in the [CLI documentation website](https://developers.flow.com/tools/flow-cli).
34 |
35 | ```
36 | Usage:
37 | flow [command]
38 |
39 | 👋 Welcome Flow developer!
40 | If you are starting a new flow project use our super commands, start by running 'flow init'.
41 |
42 | 🔥 Super Commands
43 | generate Generate template files for common Cadence code
44 | init Start a new Flow project
45 |
46 | 📦 Flow Entities
47 | accounts Create and retrieve accounts and deploy contracts
48 | blocks Retrieve blocks
49 | collections Retrieve collections
50 | events Retrieve events
51 |
52 | 💬 Flow Interactions
53 | scripts Execute Cadence scripts
54 | transactions Build, sign, send and retrieve transactions
55 |
56 | 🔨 Flow Tools
57 | cadence Execute Cadence code
58 | dev-wallet Run a development wallet
59 | emulator Run Flow network for development
60 | flix execute, generate, package
61 | flowser Run Flowser project explorer
62 | test Run Cadence tests
63 |
64 | 🏄 Flow Project
65 | deploy Deploy all project contracts
66 | project Manage your Cadence project
67 | run Start emulator and deploy all project contracts
68 |
69 | 🔒 Flow Security
70 | keys Generate and decode Flow keys
71 | signatures Signature verification and creation
72 |
73 | 🔗 Dependency Manager
74 | dependencies Manage contracts and dependencies
75 | ```
76 |
77 | The Flow CLI includes several commands to interact with Flow networks, such as querying account information, or sending transactions. It also includes the [Flow Emulator](https://developers.flow.com/tools/emulator).
78 |
79 |
80 | 
81 |
82 | ## Contributing
83 |
84 | Read [contributing](./CONTRIBUTING.md) document.
85 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 | # Responsible Disclosure Policy
3 |
4 | Flow was built from the ground up with security in mind. Our code, infrastructure, and development methodology helps us keep our users safe.
5 |
6 | We really appreciate the community's help. Responsible disclosure of vulnerabilities helps to maintain the security and privacy of everyone.
7 |
8 | If you care about making a difference, please follow the guidelines below.
9 |
10 | # **Guidelines For Responsible Disclosure**
11 |
12 | We ask that all researchers adhere to these guidelines [here](https://flow.com/flow-responsible-disclosure)
13 |
--------------------------------------------------------------------------------
/build/build.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | // Package build contains information about the build that injected at build-time.
20 | //
21 | // To use this package, simply import it in your program, then add build
22 | // arguments like the following:
23 | //
24 | // go build -ldflags "-X github.com/onflow/flow-go/version.semver=v1.0.0"
25 | package build
26 |
27 | // Default value for build-time-injected version strings.
28 | const undefined = "undefined"
29 |
30 | // The following variables are injected at build-time using ldflags.
31 | var (
32 | semver string
33 | commit string
34 | )
35 |
36 | // Semver returns the semantic version of this build.
37 | func Semver() string {
38 | return semver
39 | }
40 |
41 | // Commit returns the commit at which this build was created.
42 | func Commit() string {
43 | return commit
44 | }
45 |
46 | // IsDefined determines whether a version string is defined. Inputs should
47 | // have been produced from this package.
48 | func IsDefined(v string) bool {
49 | return v != undefined
50 | }
51 |
52 | // If any of the build-time-injected variables are empty at initialization,
53 | // mark them as undefined.
54 | func init() {
55 | if len(semver) == 0 {
56 | semver = undefined
57 | }
58 | if len(commit) == 0 {
59 | commit = undefined
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/check-headers.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | files=$(find . -name \*.go -type f -print0 | xargs -0 grep -L -E '(Licensed under the Apache License)|(Code generated (from|by))')
4 | if [ -n "$files" ]; then
5 | echo "Missing license header in:"
6 | echo "$files"
7 | exit 1
8 | fi
--------------------------------------------------------------------------------
/cli.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onflow/flow-cli/89109c41db1d6132f26637c16a4293dd51c60e01/cli.gif
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/README.md
4 |
--------------------------------------------------------------------------------
/docs/account-add-contract.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/account-add-contract.md
4 |
--------------------------------------------------------------------------------
/docs/account-remove-contract.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/account-remove-contract.md
4 |
--------------------------------------------------------------------------------
/docs/account-staking-info.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/account-staking-info.md
4 |
--------------------------------------------------------------------------------
/docs/account-update-contract.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/account-update-contract.md
4 |
--------------------------------------------------------------------------------
/docs/build-transactions.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/build-transactions.md
4 |
--------------------------------------------------------------------------------
/docs/complex-transactions.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/complex-transactions.md
4 |
--------------------------------------------------------------------------------
/docs/configuration.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/configuration.md
4 |
--------------------------------------------------------------------------------
/docs/create-accounts.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/create-accounts.md
4 |
--------------------------------------------------------------------------------
/docs/data-collection.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/data-collection.md
4 |
--------------------------------------------------------------------------------
/docs/decode-keys.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/decode-keys.md
4 |
--------------------------------------------------------------------------------
/docs/decode-transactions.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/decode-transactions.md
4 |
--------------------------------------------------------------------------------
/docs/deploy-project-contracts.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/deploy-project-contracts.md
4 |
--------------------------------------------------------------------------------
/docs/derive-keys.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/derive-keys.md
4 |
--------------------------------------------------------------------------------
/docs/developer-updates/release-notes-v17.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/developer-updates/release-notes-v17.md
4 |
--------------------------------------------------------------------------------
/docs/developer-updates/release-notes-v18.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/developer-updates/release-notes-v18.md
4 |
--------------------------------------------------------------------------------
/docs/developer-updates/release-notes-v19.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/developer-updates/release-notes-v19.md
4 |
--------------------------------------------------------------------------------
/docs/developer-updates/release-notes-v21.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/developer-updates/release-notes-v21.md
4 |
--------------------------------------------------------------------------------
/docs/developer-updates/release-notes-v24.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/developer-updates/release-notes-v24.md
4 |
--------------------------------------------------------------------------------
/docs/developer-updates/release-notes-v26.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/developer-updates/release-notes-v26.md
4 |
--------------------------------------------------------------------------------
/docs/developer-updates/release-notes-v28.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/developer-updates/release-notes-v28.md
4 |
--------------------------------------------------------------------------------
/docs/emulator-snapshot.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/emulator-snapshot.md
4 |
--------------------------------------------------------------------------------
/docs/execute-scripts.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/execute-scripts.md
4 |
--------------------------------------------------------------------------------
/docs/generate-keys.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/generate-keys.md
4 |
--------------------------------------------------------------------------------
/docs/get-accounts.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/get-accounts.md
4 |
--------------------------------------------------------------------------------
/docs/get-blocks.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/get-blocks.md
4 |
--------------------------------------------------------------------------------
/docs/get-collections.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/get-collections.md
4 |
--------------------------------------------------------------------------------
/docs/get-events.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/get-events.md
4 |
--------------------------------------------------------------------------------
/docs/get-status.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/get-status.md
4 |
--------------------------------------------------------------------------------
/docs/get-transactions.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/get-transactions.md
4 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/index.md
4 |
--------------------------------------------------------------------------------
/docs/initialize-configuration.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/initialize-configuration.md
4 |
--------------------------------------------------------------------------------
/docs/install.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/install.md
4 |
--------------------------------------------------------------------------------
/docs/manage-configuration.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/manage-configuration.md
4 |
--------------------------------------------------------------------------------
/docs/project-app.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/project-app.md
4 |
--------------------------------------------------------------------------------
/docs/project-contracts.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/project-contracts.md
4 |
--------------------------------------------------------------------------------
/docs/run-tests.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/run-tests.md
4 |
--------------------------------------------------------------------------------
/docs/security.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/security.md
4 |
--------------------------------------------------------------------------------
/docs/send-signed-transactions.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/send-signed-transactions.md
4 |
--------------------------------------------------------------------------------
/docs/send-transactions.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/send-transactions.md
4 |
--------------------------------------------------------------------------------
/docs/sign-transaction.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/sign-transaction.md
4 |
--------------------------------------------------------------------------------
/docs/signature-generate.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/signature-generate.md
4 |
--------------------------------------------------------------------------------
/docs/signature-verify.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/signature-verify.md
4 |
--------------------------------------------------------------------------------
/docs/snapshot-save.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/snapshot-save.md
4 |
--------------------------------------------------------------------------------
/docs/start-emulator.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/start-emulator.md
4 |
--------------------------------------------------------------------------------
/docs/super-commands.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/super-commands.md
4 |
--------------------------------------------------------------------------------
/docs/template.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/template.md
4 |
--------------------------------------------------------------------------------
/docs/tools.md:
--------------------------------------------------------------------------------
1 | # This document has been moved to a new location:
2 |
3 | https://github.com/onflow/docs/tree/main/docs/tooling/flow-cli/tools.md
4 |
--------------------------------------------------------------------------------
/flowkit/README.md:
--------------------------------------------------------------------------------
1 | ## Flowkit
2 |
3 | Note: This module has been migrated to github.com/onflow/flowkit. The latest supported version is v1.13.0. Please use the new module github.com/onflow/flowkit instead for any future updates. Version v1.13.0 is equivalent to version v1.13.0 on the new module.
4 |
--------------------------------------------------------------------------------
/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Exit as soon as any command fails
4 | set -e
5 |
6 | REPO="onflow/flow-cli"
7 | ASSETS_URL="https://github.com/$REPO/releases/download/"
8 | # The version to install (defaults to args[1])
9 | VERSION="$1"
10 | # The architecture string, set by get_architecture
11 | ARCH=""
12 |
13 | # Optional environment variable for Github API token
14 | # If GITHUB_TOKEN is set, use it in the curl requests to avoid rate limiting
15 | github_token_header=""
16 | if [ -n "$GITHUB_TOKEN" ]; then
17 | github_token_header="Authorization: Bearer $GITHUB_TOKEN"
18 | fi
19 |
20 | # Get the architecture (CPU, OS) of the current system as a string.
21 | # Only MacOS/x86_64/ARM64 and Linux/x86_64/ARM64 architectures are supported.
22 | get_architecture() {
23 | _ostype="$(uname -s)"
24 | _cputype="$(uname -m)"
25 | _targetpath=""
26 | if [ "$_ostype" = Darwin ] && [ "$_cputype" = i386 ]; then
27 | if sysctl hw.optional.x86_64 | grep -q ': 1'; then
28 | _cputype=x86_64
29 | fi
30 | fi
31 | case "$_ostype" in
32 | Linux)
33 | _ostype=linux
34 | _targetpath=$HOME/.local/bin
35 | ;;
36 | Darwin)
37 | _ostype=darwin
38 | _targetpath=/usr/local/bin
39 | ;;
40 | *)
41 | echo "unrecognized OS type: $_ostype"
42 | return 1
43 | ;;
44 | esac
45 | case "$_cputype" in
46 | x86_64 | x86-64 | x64 | amd64)
47 | _cputype=amd64
48 | ;;
49 | arm64 | aarch64)
50 | _cputype=arm64
51 | ;;
52 | *)
53 | echo "unknown CPU type: $_cputype"
54 | return 1
55 | ;;
56 | esac
57 | _arch="${_ostype}-${_cputype}"
58 | ARCH="${_arch}"
59 | TARGET_PATH="${_targetpath}"
60 | }
61 |
62 | get_latest() {
63 | local version=""
64 |
65 | response=$(curl -H "$github_token_header" -s "https://api.github.com/repos/$REPO/releases/latest" -w "%{http_code}")
66 |
67 | status=$(echo "$response" | tail -n 1)
68 | if [ "$status" -eq "403" ] && [ -n "$github_token_header" ]
69 | then
70 | echo "Failed to get latest release from Github API, is your GITHUB_TOKEN valid? Re-trying without authentication ..."
71 | github_token_header=""
72 | get_latest
73 | fi
74 |
75 | if [ "$status" -ne "200" ]
76 | then
77 | echo "Failed to get latest release from Github API, please manually specify a version to install as an argument to this script."
78 | return 1
79 | fi
80 |
81 | echo "$response" | grep -E 'tag_name' | grep -E "$search_term" | head -n 1 | cut -d '"' -f 4
82 | }
83 |
84 | # Function to download and install a specified version
85 | install_version() {
86 | local version="$1"
87 | local target_name="$2"
88 |
89 | echo "Installing version $version ..."
90 |
91 | tmpfile=$(mktemp 2>/dev/null || mktemp -t flow)
92 | url="$ASSETS_URL$version/flow-cli-$version-$ARCH.tar.gz"
93 | curl -H "$github_token_header" -L --progress-bar "$url" -o "$tmpfile"
94 |
95 | # Ensure we don't receive a not found error as response.
96 | if grep -q "Not Found" "$tmpfile"
97 | then
98 | echo "Version $version could not be found"
99 | exit 1
100 | fi
101 |
102 | [ -d "$TARGET_PATH" ] || mkdir -p "$TARGET_PATH"
103 |
104 | tar -xf "$tmpfile" -C "$TARGET_PATH"
105 | mv "$TARGET_PATH/flow-cli" "$TARGET_PATH/$target_name"
106 | chmod +x "$TARGET_PATH/$target_name"
107 | }
108 |
109 | # Determine the system architecture, download the appropriate binaries, and
110 | # install them in `/usr/local/bin` on macOS and `~/.local/bin` on Linux
111 | # with executable permissions.
112 | main() {
113 | get_architecture || exit 1
114 |
115 | if [ -z "$VERSION" ]
116 | then
117 | echo "Getting version of latest stable release ..."
118 |
119 | VERSION=$(get_latest || exit 1)
120 | fi
121 |
122 | install_version "$VERSION" "flow"
123 |
124 | echo "Successfully installed Flow CLI $VERSION as 'flow' in $TARGET_PATH."
125 | echo "Make sure $TARGET_PATH is in your \$PATH environment variable."
126 | }
127 |
128 | main
--------------------------------------------------------------------------------
/internal/accounts/contract-remove.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package accounts
20 |
21 | import (
22 | "context"
23 | "fmt"
24 |
25 | "github.com/onflow/flow-cli/internal/prompt"
26 |
27 | "github.com/spf13/cobra"
28 |
29 | "github.com/onflow/flowkit/v2"
30 | "github.com/onflow/flowkit/v2/output"
31 |
32 | "github.com/onflow/flow-cli/internal/command"
33 | )
34 |
35 | type flagsRemoveContract struct {
36 | Signer string `default:"emulator-account" flag:"signer" info:"Account name from configuration used to sign the transaction"`
37 | Include []string `default:"" flag:"include" info:"Fields to include in the output. Valid values: contracts."`
38 | Network string `default:"" flag:"network" info:"Network name from configuration to use"`
39 | }
40 |
41 | var flagsRemove = flagsRemoveContract{}
42 |
43 | var removeCommand = &command.Command{
44 | Cmd: &cobra.Command{
45 | Use: "remove-contract ",
46 | Short: "Remove a contract deployed to an account",
47 | Example: `flow accounts remove-contract FungibleToken`,
48 | Args: cobra.ExactArgs(1),
49 | },
50 | Flags: &flagsRemove,
51 | RunS: removeContract,
52 | }
53 |
54 | func removeContract(
55 | args []string,
56 | _ command.GlobalFlags,
57 | logger output.Logger,
58 | flow flowkit.Services,
59 | state *flowkit.State,
60 | ) (command.Result, error) {
61 | contractName := args[0]
62 |
63 | from, err := state.Accounts().ByName(flagsRemove.Signer)
64 | if err != nil {
65 | return nil, err
66 | }
67 |
68 | id, err := flow.RemoveContract(context.Background(), from, contractName)
69 | if err != nil {
70 | return nil, err
71 | }
72 |
73 | removeFromState := prompt.RemoveContractFromFlowJSONPrompt(contractName)
74 |
75 | if removeFromState {
76 | // If a network flag is provided, remove from that networks deployments
77 | // Otherwise, remove from all deployments
78 | if flagsRemove.Network != "" {
79 | state.Deployments().ByAccountAndNetwork(from.Name, flagsRemove.Network).RemoveContract(contractName)
80 | } else {
81 | for i := range state.Deployments().All() {
82 | if state.Deployments().All()[i].Account == from.Name {
83 | state.Deployments().All()[i].RemoveContract(contractName)
84 | }
85 | }
86 | }
87 |
88 | err = state.SaveDefault()
89 | if err != nil {
90 | return nil, err
91 | }
92 | }
93 |
94 | logger.Info(fmt.Sprintf(
95 | "Contract %s removed from account %s with transaction ID: %s.",
96 | contractName,
97 | from.Address,
98 | id.String(),
99 | ))
100 |
101 | account, err := flow.GetAccount(context.Background(), from.Address)
102 | if err != nil {
103 | return nil, err
104 | }
105 | return &accountResult{
106 | Account: account,
107 | include: flagsRemove.Include,
108 | }, nil
109 | }
110 |
--------------------------------------------------------------------------------
/internal/accounts/contract-update.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package accounts
20 |
21 | import (
22 | "github.com/spf13/cobra"
23 |
24 | "github.com/onflow/flow-cli/internal/command"
25 | )
26 |
27 | var updateContractFlags = deployContractFlags{}
28 |
29 | var updateCommand = &command.Command{
30 | Cmd: &cobra.Command{
31 | Use: "update-contract ",
32 | Short: "Update a contract deployed to an account",
33 | Example: `flow accounts update-contract ./FungibleToken.cdc helloArg`,
34 | Args: cobra.MinimumNArgs(1),
35 | },
36 | Flags: &updateContractFlags,
37 | RunS: deployContract(true, &updateContractFlags),
38 | }
39 |
--------------------------------------------------------------------------------
/internal/accounts/fund.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package accounts
20 |
21 | import (
22 | "fmt"
23 | "time"
24 |
25 | flowsdk "github.com/onflow/flow-go-sdk"
26 |
27 | "github.com/pkg/browser"
28 | "github.com/spf13/cobra"
29 |
30 | "github.com/onflow/flowkit/v2"
31 | "github.com/onflow/flowkit/v2/output"
32 |
33 | "github.com/onflow/flow-cli/internal/command"
34 | )
35 |
36 | type flagsFund struct {
37 | Include []string `default:"" flag:"include" info:"Fields to include in the output. Valid values: contracts."`
38 | }
39 |
40 | var fundFlags = flagsFund{}
41 |
42 | var fundCommand = &command.Command{
43 | Cmd: &cobra.Command{
44 | Use: "fund ",
45 | Short: "Funds an account by address through the Testnet Faucet",
46 | Example: "flow accounts fund 8e94eaa81771313a",
47 | Args: cobra.ExactArgs(1),
48 | },
49 | Flags: &fundFlags,
50 | Run: fund,
51 | }
52 |
53 | func fund(
54 | args []string,
55 | _ command.GlobalFlags,
56 | logger output.Logger,
57 | _ flowkit.ReaderWriter,
58 | flow flowkit.Services,
59 | ) (command.Result, error) {
60 | address := flowsdk.HexToAddress(args[0])
61 | if !address.IsValid(flowsdk.Testnet) {
62 | return nil, fmt.Errorf("unsupported address %s, faucet can only work for valid Testnet addresses", address.String())
63 | }
64 |
65 | logger.Info(
66 | fmt.Sprintf(
67 | "Opening the Testnet faucet to fund 0x%s on your native browser."+
68 | "\n\nIf there is an issue, please use this link instead: %s",
69 | address.String(),
70 | testnetFaucetURL(address),
71 | ))
72 | // wait for the user to read the message
73 | time.Sleep(5 * time.Second)
74 |
75 | if err := browser.OpenURL(testnetFaucetURL(address)); err != nil {
76 | return nil, err
77 | }
78 |
79 | return nil, nil
80 | }
81 |
--------------------------------------------------------------------------------
/internal/accounts/get.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package accounts
20 |
21 | import (
22 | "context"
23 | "fmt"
24 |
25 | flowsdk "github.com/onflow/flow-go-sdk"
26 | "github.com/spf13/cobra"
27 |
28 | "github.com/onflow/flowkit/v2"
29 | "github.com/onflow/flowkit/v2/output"
30 |
31 | "github.com/onflow/flow-cli/internal/command"
32 | )
33 |
34 | type flagsGet struct {
35 | Include []string `default:"" flag:"include" info:"Fields to include in the output. Valid values: contracts."`
36 | }
37 |
38 | var getFlags = flagsGet{}
39 |
40 | var getCommand = &command.Command{
41 | Cmd: &cobra.Command{
42 | Use: "get ",
43 | Short: "Gets an account by address",
44 | Example: "flow accounts get f8d6e0586b0a20c7",
45 | Args: cobra.ExactArgs(1),
46 | },
47 | Flags: &getFlags,
48 | Run: get,
49 | }
50 |
51 | func get(
52 | args []string,
53 | _ command.GlobalFlags,
54 | logger output.Logger,
55 | _ flowkit.ReaderWriter,
56 | flow flowkit.Services,
57 | ) (command.Result, error) {
58 | address := flowsdk.HexToAddress(args[0])
59 |
60 | logger.StartProgress(fmt.Sprintf("Loading account %s...", address))
61 | defer logger.StopProgress()
62 |
63 | account, err := flow.GetAccount(context.Background(), address)
64 | if err != nil {
65 | return nil, err
66 | }
67 |
68 | return &accountResult{
69 | Account: account,
70 | include: getFlags.Include,
71 | }, nil
72 | }
73 |
--------------------------------------------------------------------------------
/internal/blocks/blocks.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package blocks
20 |
21 | import (
22 | "bytes"
23 | "fmt"
24 |
25 | "github.com/onflow/flow-go-sdk"
26 | "github.com/spf13/cobra"
27 |
28 | "github.com/onflow/flow-cli/internal/command"
29 | "github.com/onflow/flow-cli/internal/events"
30 | "github.com/onflow/flow-cli/internal/util"
31 | )
32 |
33 | var Cmd = &cobra.Command{
34 | Use: "blocks",
35 | Short: "Retrieve blocks",
36 | TraverseChildren: true,
37 | GroupID: "resources",
38 | }
39 |
40 | func init() {
41 | getCommand.AddToParent(Cmd)
42 | }
43 |
44 | type blockResult struct {
45 | block *flow.Block
46 | events []flow.BlockEvents
47 | collections []*flow.Collection
48 | included []string
49 | }
50 |
51 | func (r *blockResult) JSON() any {
52 | result := make(map[string]any)
53 | result["blockId"] = r.block.ID.String()
54 | result["parentId"] = r.block.ParentID.String()
55 | result["height"] = r.block.Height
56 | result["totalSeals"] = len(r.block.Seals)
57 | result["totalCollections"] = len(r.block.CollectionGuarantees)
58 |
59 | collections := make([]any, 0, len(r.block.CollectionGuarantees))
60 | for i, guarantee := range r.block.CollectionGuarantees {
61 | collection := make(map[string]any)
62 | collection["id"] = guarantee.CollectionID.String()
63 |
64 | if command.ContainsFlag(r.included, "transactions") {
65 | txs := make([]string, 0)
66 | for _, tx := range r.collections[i].TransactionIDs {
67 | txs = append(txs, tx.String())
68 | }
69 | collection["transactions"] = txs
70 | }
71 |
72 | collections = append(collections, collection)
73 | }
74 |
75 | result["collection"] = collections
76 | return result
77 | }
78 |
79 | func blockStatusToString(code flow.BlockStatus) string {
80 | switch code {
81 | case 1:
82 | return "Finalized"
83 | case 2:
84 | return "Sealed"
85 | default:
86 | return "Unknown"
87 | }
88 | }
89 |
90 | func (r *blockResult) String() string {
91 | var b bytes.Buffer
92 | writer := util.CreateTabWriter(&b)
93 |
94 | _, _ = fmt.Fprintf(writer, "Block ID\t%s\n", r.block.ID)
95 | _, _ = fmt.Fprintf(writer, "Parent ID\t%s\n", r.block.ParentID)
96 | _, _ = fmt.Fprintf(writer, "Proposal Timestamp\t%s\n", r.block.Timestamp)
97 | _, _ = fmt.Fprintf(writer, "Proposal Timestamp Unix\t%d\n", r.block.Timestamp.Unix())
98 | _, _ = fmt.Fprintf(writer, "Height\t%v\n", r.block.Height)
99 | _, _ = fmt.Fprintf(writer, "Status\t%s\n", blockStatusToString(r.block.Status))
100 |
101 | _, _ = fmt.Fprintf(writer, "Total Seals\t%v\n", len(r.block.Seals))
102 |
103 | _, _ = fmt.Fprintf(writer, "Total Collections\t%v\n", len(r.block.CollectionGuarantees))
104 |
105 | for i, guarantee := range r.block.CollectionGuarantees {
106 | _, _ = fmt.Fprintf(writer, " Collection %d:\t%s\n", i, guarantee.CollectionID)
107 |
108 | if command.ContainsFlag(r.included, "transactions") {
109 | for x, tx := range r.collections[i].TransactionIDs {
110 | _, _ = fmt.Fprintf(writer, " Transaction %d: %s\n", x, tx)
111 | }
112 | }
113 | }
114 |
115 | if len(r.events) > 0 {
116 | _, _ = fmt.Fprintf(writer, "\n")
117 |
118 | e := events.EventResult{BlockEvents: r.events}
119 | _, _ = fmt.Fprintf(writer, "%s", e.String())
120 | }
121 |
122 | _ = writer.Flush()
123 | return b.String()
124 | }
125 |
126 | func (r *blockResult) Oneliner() string {
127 | return r.block.ID.String()
128 | }
129 |
--------------------------------------------------------------------------------
/internal/blocks/blocks_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package blocks
20 |
21 | import (
22 | "strings"
23 | "testing"
24 |
25 | "github.com/onflow/flow-go-sdk"
26 | "github.com/stretchr/testify/assert"
27 | "github.com/stretchr/testify/mock"
28 |
29 | "github.com/onflow/flowkit/v2"
30 | "github.com/onflow/flowkit/v2/tests"
31 |
32 | "github.com/onflow/flow-cli/internal/command"
33 | "github.com/onflow/flow-cli/internal/util"
34 | )
35 |
36 | func Test_GetBlock(t *testing.T) {
37 | srv, _, rw := util.TestMocks(t)
38 |
39 | t.Run("Success", func(t *testing.T) {
40 | inArgs := []string{"100"}
41 | blockFlags.Events = "A.foo"
42 | blockFlags.Include = []string{"transactions"}
43 |
44 | srv.GetEvents.Run(func(args mock.Arguments) {
45 | assert.Equal(t, "A.foo", args.Get(1).([]string)[0])
46 | assert.Equal(t, uint64(100), args.Get(2).(uint64))
47 | assert.Equal(t, uint64(100), args.Get(3).(uint64))
48 | }).Return(nil, nil)
49 |
50 | srv.GetCollection.Return(nil, nil)
51 |
52 | returnBlock := tests.NewBlock()
53 | returnBlock.Height = uint64(100)
54 |
55 | srv.GetBlock.Run(func(args mock.Arguments) {
56 | assert.Equal(t, uint64(100), args.Get(1).(flowkit.BlockQuery).Height)
57 | }).Return(returnBlock, nil)
58 |
59 | result, err := get(inArgs, command.GlobalFlags{}, util.NoLogger, rw, srv.Mock)
60 | assert.NotNil(t, result)
61 | assert.NoError(t, err)
62 | })
63 | }
64 |
65 | func Test_Result(t *testing.T) {
66 | result := blockResult{
67 | block: tests.NewBlock(),
68 | collections: []*flow.Collection{tests.NewCollection()},
69 | }
70 |
71 | assert.Equal(t, strings.TrimPrefix(`
72 | Block ID 0303030303030303030303030303030303030303030303030303030303030303
73 | Parent ID 0404040404040404040404040404040404040404040404040404040404040404
74 | Proposal Timestamp 2020-06-04 16:43:21 +0000 UTC
75 | Proposal Timestamp Unix 1591289001
76 | Height 1
77 | Status Unknown
78 | Total Seals 1
79 | Total Collections 3
80 | Collection 0: 0202020202020202020202020202020202020202020202020202020202020202
81 | Collection 1: 0404040404040404040404040404040404040404040404040404040404040404
82 | Collection 2: 0606060606060606060606060606060606060606060606060606060606060606
83 | `, "\n"), result.String())
84 |
85 | assert.Equal(
86 | t,
87 | map[string]any{
88 | "blockId": "0303030303030303030303030303030303030303030303030303030303030303",
89 | "collection": []any{
90 | map[string]any{"id": "0202020202020202020202020202020202020202020202020202020202020202"},
91 | map[string]any{"id": "0404040404040404040404040404040404040404040404040404040404040404"},
92 | map[string]any{"id": "0606060606060606060606060606060606060606060606060606060606060606"},
93 | },
94 | "height": uint64(1),
95 | "parentId": "0404040404040404040404040404040404040404040404040404040404040404",
96 | "totalCollections": 3,
97 | "totalSeals": 1,
98 | },
99 | result.JSON(),
100 | )
101 | }
102 |
--------------------------------------------------------------------------------
/internal/blocks/get.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package blocks
20 |
21 | import (
22 | "context"
23 |
24 | flowsdk "github.com/onflow/flow-go-sdk"
25 | "github.com/spf13/cobra"
26 |
27 | "github.com/onflow/flowkit/v2"
28 | "github.com/onflow/flowkit/v2/output"
29 |
30 | "github.com/onflow/flow-cli/internal/command"
31 | )
32 |
33 | type flagsBlocks struct {
34 | Events string `default:"" flag:"events" info:"List events of this type for the block"`
35 | Include []string `default:"" flag:"include" info:"Fields to include in the output. Valid values: transactions."`
36 | }
37 |
38 | var blockFlags = flagsBlocks{}
39 |
40 | var getCommand = &command.Command{
41 | Cmd: &cobra.Command{
42 | Use: "get ",
43 | Short: "Get block info",
44 | Example: "flow blocks get latest --network testnet",
45 | Args: cobra.ExactArgs(1),
46 | },
47 | Flags: &blockFlags,
48 | Run: get,
49 | }
50 |
51 | func get(
52 | args []string,
53 | _ command.GlobalFlags,
54 | logger output.Logger,
55 | _ flowkit.ReaderWriter,
56 | flow flowkit.Services,
57 | ) (command.Result, error) {
58 |
59 | query, err := flowkit.NewBlockQuery(args[0])
60 | if err != nil {
61 | return nil, err
62 | }
63 |
64 | logger.StartProgress("Fetching Block...")
65 | defer logger.StopProgress()
66 | block, err := flow.GetBlock(context.Background(), query)
67 | if err != nil {
68 | return nil, err
69 | }
70 |
71 | var events []flowsdk.BlockEvents
72 | if blockFlags.Events != "" {
73 | events, err = flow.GetEvents(
74 | context.Background(),
75 | []string{blockFlags.Events},
76 | block.Height,
77 | block.Height,
78 | nil,
79 | )
80 | if err != nil {
81 | return nil, err
82 | }
83 | }
84 |
85 | collections := make([]*flowsdk.Collection, 0)
86 | if command.ContainsFlag(blockFlags.Include, "transactions") {
87 | for _, guarantee := range block.CollectionGuarantees {
88 | collection, err := flow.GetCollection(context.Background(), guarantee.CollectionID)
89 | if err != nil {
90 | return nil, err
91 | }
92 | collections = append(collections, collection)
93 | }
94 | }
95 |
96 | return &blockResult{
97 | block: block,
98 | events: events,
99 | collections: collections,
100 | included: blockFlags.Include,
101 | }, nil
102 | }
103 |
--------------------------------------------------------------------------------
/internal/cadence/cadence.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package cadence
20 |
21 | import (
22 | "github.com/onflow/cadence/cmd/execute"
23 | "github.com/spf13/cobra"
24 |
25 | "github.com/onflow/flow-cli/internal/cadence/languageserver"
26 | )
27 |
28 | var Cmd = &cobra.Command{
29 | Use: "cadence",
30 | Short: "Execute Cadence code",
31 | GroupID: "tools",
32 | Run: func(cmd *cobra.Command, args []string) {
33 | if len(args) > 0 {
34 | execute.Execute(args, nil)
35 | } else {
36 | repl, err := execute.NewConsoleREPL()
37 | if err != nil {
38 | panic(err)
39 | }
40 | repl.Run()
41 | }
42 | },
43 | }
44 |
45 | func init() {
46 | Cmd.AddCommand(languageserver.Cmd)
47 | lintCommand.AddToParent(Cmd)
48 | }
49 |
--------------------------------------------------------------------------------
/internal/cadence/languageserver/languageserver.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package languageserver
20 |
21 | import (
22 | "log"
23 |
24 | "github.com/onflow/cadence-tools/languageserver"
25 | "github.com/psiemens/sconfig"
26 | "github.com/spf13/cobra"
27 |
28 | "github.com/onflow/flow-cli/internal/util"
29 | )
30 |
31 | type config struct {
32 | EnableFlowClient bool `default:"true" flag:"enable-flow-client" info:"Enable Flow client functionality"`
33 | }
34 |
35 | var conf config
36 |
37 | var Cmd = &cobra.Command{
38 | Use: "language-server",
39 | Short: "Start the Cadence language server",
40 | Run: func(cmd *cobra.Command, args []string) {
41 | languageserver.RunWithStdio(conf.EnableFlowClient)
42 | },
43 | }
44 |
45 | func init() {
46 | initConfig()
47 | }
48 |
49 | func initConfig() {
50 | err := sconfig.New(&conf).
51 | FromEnvironment(util.EnvPrefix).
52 | BindFlags(Cmd.PersistentFlags()).
53 | Parse()
54 | if err != nil {
55 | log.Fatal(err)
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/internal/collections/collections.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package collections
20 |
21 | import (
22 | "bytes"
23 | "fmt"
24 | "strings"
25 |
26 | "github.com/onflow/flow-go-sdk"
27 | "github.com/spf13/cobra"
28 |
29 | "github.com/onflow/flow-cli/internal/util"
30 | )
31 |
32 | var Cmd = &cobra.Command{
33 | Use: "collections",
34 | Short: "Retrieve collections",
35 | TraverseChildren: true,
36 | GroupID: "resources",
37 | }
38 |
39 | func init() {
40 | getCommand.AddToParent(Cmd)
41 | }
42 |
43 | type collectionResult struct {
44 | *flow.Collection
45 | }
46 |
47 | func (c *collectionResult) JSON() any {
48 | txIDs := make([]string, 0)
49 |
50 | for _, tx := range c.Collection.TransactionIDs {
51 | txIDs = append(txIDs, tx.String())
52 | }
53 |
54 | return txIDs
55 | }
56 |
57 | func (c *collectionResult) String() string {
58 | var b bytes.Buffer
59 | writer := util.CreateTabWriter(&b)
60 |
61 | _, _ = fmt.Fprintf(writer, "Collection ID %s:\n", c.Collection.ID())
62 |
63 | for _, tx := range c.Collection.TransactionIDs {
64 | _, _ = fmt.Fprintf(writer, "%s\n", tx.String())
65 | }
66 |
67 | _ = writer.Flush()
68 |
69 | return b.String()
70 | }
71 |
72 | func (c *collectionResult) Oneliner() string {
73 | return strings.Join(c.JSON().([]string), ",")
74 | }
75 |
--------------------------------------------------------------------------------
/internal/collections/collections_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package collections
20 |
21 | import (
22 | "testing"
23 |
24 | "github.com/onflow/flow-go-sdk"
25 | "github.com/stretchr/testify/assert"
26 | "github.com/stretchr/testify/mock"
27 | "github.com/stretchr/testify/require"
28 |
29 | "github.com/onflow/flow-cli/internal/command"
30 | "github.com/onflow/flow-cli/internal/util"
31 | )
32 |
33 | func Test_Get(t *testing.T) {
34 | srv, _, rw := util.TestMocks(t)
35 |
36 | t.Run("Success", func(t *testing.T) {
37 | inArgs := []string{util.TestID.String()}
38 |
39 | srv.GetCollection.Run(func(args mock.Arguments) {
40 | id := args.Get(1).(flow.Identifier)
41 | assert.Equal(t, inArgs[0], id.String())
42 | })
43 |
44 | result, err := get(inArgs, command.GlobalFlags{}, util.NoLogger, rw, srv.Mock)
45 | require.NoError(t, err)
46 | require.NotNil(t, result)
47 | })
48 | }
49 |
--------------------------------------------------------------------------------
/internal/collections/get.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package collections
20 |
21 | import (
22 | "context"
23 | "fmt"
24 |
25 | flowsdk "github.com/onflow/flow-go-sdk"
26 | "github.com/spf13/cobra"
27 |
28 | "github.com/onflow/flowkit/v2"
29 | "github.com/onflow/flowkit/v2/output"
30 |
31 | "github.com/onflow/flow-cli/internal/command"
32 | )
33 |
34 | type flagsCollections struct{}
35 |
36 | var collectionFlags = flagsCollections{}
37 |
38 | var getCommand = &command.Command{
39 | Cmd: &cobra.Command{
40 | Use: "get ",
41 | Short: "Get collection info",
42 | Example: "flow collections get 270d...9c31e",
43 | Args: cobra.ExactArgs(1),
44 | },
45 | Flags: &collectionFlags,
46 | Run: get,
47 | }
48 |
49 | func get(
50 | args []string,
51 | _ command.GlobalFlags,
52 | logger output.Logger,
53 | _ flowkit.ReaderWriter,
54 | flow flowkit.Services,
55 | ) (command.Result, error) {
56 | id := flowsdk.HexToID(args[0])
57 |
58 | logger.StartProgress(fmt.Sprintf("Loading collection %s", id))
59 | defer logger.StopProgress()
60 |
61 | collection, err := flow.GetCollection(context.Background(), id)
62 | if err != nil {
63 | return nil, err
64 | }
65 |
66 | return &collectionResult{collection}, nil
67 | }
68 |
--------------------------------------------------------------------------------
/internal/command/global_flags.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package command
20 |
21 | import (
22 | "fmt"
23 | "os"
24 |
25 | "github.com/psiemens/sconfig"
26 | "github.com/spf13/cobra"
27 |
28 | "github.com/onflow/flowkit/v2/config"
29 |
30 | "github.com/onflow/flow-cli/internal/util"
31 | )
32 |
33 | // Flags initialized to default values.
34 | var Flags = GlobalFlags{
35 | Filter: "",
36 | Format: FormatText,
37 | Save: "",
38 | Host: "",
39 | HostNetworkKey: "",
40 | Network: config.EmulatorNetwork.Name,
41 | Log: logLevelInfo,
42 | Yes: false,
43 | ConfigPaths: config.DefaultPaths(),
44 | SkipVersionCheck: false,
45 | }
46 |
47 | // InitFlags init all the global persistent flags.
48 | func InitFlags(cmd *cobra.Command) {
49 | cmd.PersistentFlags().StringVarP(
50 | &Flags.Filter,
51 | "filter",
52 | "x",
53 | Flags.Filter,
54 | "Filter result values by property name",
55 | )
56 |
57 | cmd.PersistentFlags().StringVarP(
58 | &Flags.Format,
59 | "format",
60 | "",
61 | Flags.Format,
62 | "Format result values",
63 | )
64 |
65 | cmd.PersistentFlags().StringVarP(
66 | &Flags.Host,
67 | "host",
68 | "",
69 | Flags.Host,
70 | "Flow Access API host address",
71 | )
72 |
73 | cmd.PersistentFlags().StringVarP(
74 | &Flags.HostNetworkKey,
75 | "network-key",
76 | "",
77 | Flags.HostNetworkKey,
78 | "Flow Access API host network key for secure client connections",
79 | )
80 |
81 | cmd.PersistentFlags().StringVarP(
82 | &Flags.Format,
83 | "output",
84 | "o",
85 | Flags.Format,
86 | "Output format, options: \"text\", \"json\", \"inline\"",
87 | )
88 |
89 | cmd.PersistentFlags().StringVarP(
90 | &Flags.Save,
91 | "save",
92 | "s",
93 | Flags.Save,
94 | "Save result to a filename",
95 | )
96 |
97 | cmd.PersistentFlags().StringVarP(
98 | &Flags.Log,
99 | "log",
100 | "l",
101 | Flags.Log,
102 | "Log level, options: \"debug\", \"info\", \"error\", \"none\"",
103 | )
104 |
105 | cmd.PersistentFlags().StringSliceVarP(
106 | &Flags.ConfigPaths,
107 | "config-path",
108 | "f",
109 | Flags.ConfigPaths,
110 | "Path to flow configuration file",
111 | )
112 |
113 | cmd.PersistentFlags().StringVarP(
114 | &Flags.Network,
115 | "network",
116 | "n",
117 | Flags.Network,
118 | "Network from configuration file",
119 | )
120 |
121 | cmd.PersistentFlags().BoolVarP(
122 | &Flags.Yes,
123 | "yes",
124 | "y",
125 | Flags.Yes,
126 | "Approve any prompts",
127 | )
128 |
129 | cmd.PersistentFlags().BoolVarP(
130 | &Flags.SkipVersionCheck,
131 | "skip-version-check",
132 | "",
133 | Flags.SkipVersionCheck,
134 | "Skip version check during start up",
135 | )
136 | }
137 |
138 | // bindFlags bind all the flags needed.
139 | func bindFlags(command Command) {
140 | err := sconfig.New(command.Flags).
141 | FromEnvironment(util.EnvPrefix).
142 | BindFlags(command.Cmd.PersistentFlags()).
143 | Parse()
144 | if err != nil {
145 | fmt.Fprintln(os.Stderr, err)
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/internal/command/global_flags_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package command_test
20 |
21 | import (
22 | "fmt"
23 | "strconv"
24 | "strings"
25 | "testing"
26 |
27 | "github.com/spf13/cobra"
28 |
29 | "github.com/onflow/flow-cli/internal/command"
30 | )
31 |
32 | func TestInitFlags(t *testing.T) {
33 | cmd := &cobra.Command{}
34 | command.InitFlags(cmd)
35 |
36 | flags := []struct {
37 | name string
38 | expected string
39 | }{
40 | {"filter", command.Flags.Filter},
41 | {"format", command.Flags.Format},
42 | {"save", command.Flags.Save},
43 | {"host", command.Flags.Host},
44 | {"network-key", command.Flags.HostNetworkKey},
45 | {"network", command.Flags.Network},
46 | {"log", command.Flags.Log},
47 | {"yes", strconv.FormatBool(command.Flags.Yes)},
48 | {"config-path", fmt.Sprintf("[%s]", strings.Join(command.Flags.ConfigPaths, ","))},
49 | {"skip-version-check", strconv.FormatBool(command.Flags.SkipVersionCheck)},
50 | }
51 |
52 | for _, flag := range flags {
53 | f := cmd.PersistentFlags().Lookup(flag.name)
54 | if f == nil {
55 | t.Errorf("Flag %s was not initialized", flag.name)
56 | } else if f.DefValue != flag.expected {
57 | t.Errorf("Flag %s was not initialized with correct default value. Value: %s, Expected: %s", flag.name, f.Value.String(), flag.expected)
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/internal/command/template.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package command
20 |
21 | var UsageTemplate = `Usage:{{if .Runnable}}
22 | {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}}
23 | {{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}}
24 |
25 | Aliases:
26 | {{.NameAndAliases}}{{end}}{{if .HasExample}}
27 |
28 | Examples:
29 | {{.Example}}{{end}}
30 | {{if .HasAvailableSubCommands}}{{if (eq .Name "flow")}}
31 | [1m👋 Welcome Flow developer![0m
32 | If you are starting a new flow project use our super commands, start by running 'flow init'. {{end}}{{end}}{{if .HasAvailableSubCommands}}{{$cmds := .Commands}}{{if eq (len .Groups) 0}}
33 | Available Commands:{{range $cmds}}{{if (or .IsAvailableCommand (eq .Name "help"))}}
34 | {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{else}}{{range $group := .Groups}}
35 |
36 | [1m{{.Title}}[0m{{range $cmds}}{{if (and (eq .GroupID $group.ID) (or .IsAvailableCommand (eq .Name "help")))}}
37 | {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if not .AllChildCommandsHaveGroup}}
38 |
39 | Additional Commands:{{range $cmds}}{{if (and (eq .GroupID "") (or .IsAvailableCommand (eq .Name "help")))}}
40 | {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}}
41 |
42 | Flags:
43 | {{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}
44 |
45 | Global Flags:
46 | {{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}}
47 |
48 | Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}}
49 | {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}}
50 |
51 | Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}}
52 | `
53 |
--------------------------------------------------------------------------------
/internal/config/add-deployment.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package config
20 |
21 | import (
22 | "fmt"
23 |
24 | "github.com/onflow/flow-cli/internal/prompt"
25 |
26 | "github.com/spf13/cobra"
27 |
28 | "github.com/onflow/flowkit/v2"
29 | "github.com/onflow/flowkit/v2/config"
30 | "github.com/onflow/flowkit/v2/output"
31 |
32 | "github.com/onflow/flow-cli/internal/command"
33 | )
34 |
35 | type flagsAddDeployment struct {
36 | Network string `flag:"network" info:"Network name used for deployment"`
37 | Account string `flag:"account" info:"Account name used for deployment"`
38 | Contracts []string `flag:"contract" info:"Name of the contract to be deployed"`
39 | }
40 |
41 | var addDeploymentFlags = flagsAddDeployment{}
42 |
43 | var addDeploymentCommand = &command.Command{
44 | Cmd: &cobra.Command{
45 | Use: "deployment",
46 | Short: "Add deployment to configuration",
47 | Example: "flow config add deployment",
48 | Args: cobra.NoArgs,
49 | },
50 | Flags: &addDeploymentFlags,
51 | RunS: addDeployment,
52 | }
53 |
54 | func addDeployment(
55 | _ []string,
56 | globalFlags command.GlobalFlags,
57 | _ output.Logger,
58 | _ flowkit.Services,
59 | state *flowkit.State,
60 | ) (command.Result, error) {
61 | raw, flagsProvided, err := flagsToDeploymentData(addDeploymentFlags)
62 | if err != nil {
63 | return nil, err
64 | }
65 |
66 | if !flagsProvided {
67 | raw = prompt.NewDeploymentPrompt(*state.Networks(), state.Config().Accounts, *state.Contracts())
68 | }
69 |
70 | deployment := state.Deployments().ByAccountAndNetwork(raw.Account, raw.Network)
71 | if deployment == nil {
72 | // add deployment if non-existing
73 | state.Deployments().AddOrUpdate(config.Deployment{
74 | Network: raw.Network,
75 | Account: raw.Account,
76 | })
77 | deployment = state.Deployments().ByAccountAndNetwork(raw.Account, raw.Network)
78 | }
79 |
80 | for _, c := range raw.Contracts {
81 | deployment.AddContract(config.ContractDeployment{Name: c})
82 | }
83 |
84 | err = state.SaveEdited(globalFlags.ConfigPaths)
85 | if err != nil {
86 | return nil, err
87 | }
88 |
89 | return &result{
90 | result: "Deployment added to the configuration.\nYou can deploy using 'flow project deploy' command",
91 | }, nil
92 | }
93 |
94 | func flagsToDeploymentData(flags flagsAddDeployment) (*prompt.DeploymentData, bool, error) {
95 | if flags.Network == "" && flags.Account == "" && len(flags.Contracts) == 0 {
96 | return nil, false, nil
97 | }
98 |
99 | if flags.Network == "" {
100 | return nil, true, fmt.Errorf("network name must be provided")
101 | } else if flags.Account == "" {
102 | return nil, true, fmt.Errorf("account name must be provided")
103 | } else if len(flags.Contracts) == 0 {
104 | return nil, true, fmt.Errorf("at least one contract name must be provided")
105 | }
106 |
107 | return &prompt.DeploymentData{
108 | Network: flags.Network,
109 | Account: flags.Account,
110 | Contracts: flags.Contracts,
111 | }, true, nil
112 | }
113 |
--------------------------------------------------------------------------------
/internal/config/add-network.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package config
20 |
21 | import (
22 | "fmt"
23 | "net/url"
24 |
25 | "github.com/onflow/flow-cli/internal/prompt"
26 |
27 | "github.com/spf13/cobra"
28 |
29 | "github.com/onflow/flowkit/v2"
30 | "github.com/onflow/flowkit/v2/config"
31 | "github.com/onflow/flowkit/v2/output"
32 |
33 | "github.com/onflow/flow-cli/internal/command"
34 | "github.com/onflow/flow-cli/internal/util"
35 | )
36 |
37 | type flagsAddNetwork struct {
38 | Name string `flag:"name" info:"Network name"`
39 | Host string `flag:"host" info:"Flow Access API host address"`
40 | Key string `flag:"network-key" info:"Flow Access API host network key for secure client connections"`
41 | }
42 |
43 | var addNetworkFlags = flagsAddNetwork{}
44 |
45 | var addNetworkCommand = &command.Command{
46 | Cmd: &cobra.Command{
47 | Use: "network",
48 | Short: "Add network to configuration",
49 | Example: "flow config add network",
50 | Args: cobra.NoArgs,
51 | },
52 | Flags: &addNetworkFlags,
53 | RunS: addNetwork,
54 | }
55 |
56 | func addNetwork(
57 | _ []string,
58 | globalFlags command.GlobalFlags,
59 | _ output.Logger,
60 | _ flowkit.Services,
61 | state *flowkit.State,
62 | ) (command.Result, error) {
63 | raw, flagsProvided, err := flagsToNetworkData(addNetworkFlags)
64 | if err != nil {
65 | return nil, err
66 | }
67 |
68 | if !flagsProvided {
69 | raw = prompt.NewNetworkPrompt()
70 | }
71 |
72 | state.Networks().AddOrUpdate(config.Network{
73 | Name: raw["name"],
74 | Host: raw["host"],
75 | Key: raw["key"],
76 | })
77 |
78 | err = state.SaveEdited(globalFlags.ConfigPaths)
79 | if err != nil {
80 | return nil, err
81 | }
82 |
83 | return &result{
84 | result: fmt.Sprintf("Network %s added to the configuration", raw["name"]),
85 | }, nil
86 | }
87 |
88 | func flagsToNetworkData(flags flagsAddNetwork) (map[string]string, bool, error) {
89 | if flags.Name == "" && flags.Host == "" {
90 | return nil, false, nil
91 | }
92 |
93 | if flags.Name == "" {
94 | return nil, true, fmt.Errorf("name must be provided")
95 | } else if flags.Host == "" {
96 | return nil, true, fmt.Errorf("host must be provided")
97 | }
98 |
99 | _, err := url.ParseRequestURI(flags.Host)
100 | if err != nil {
101 | return nil, true, err
102 | }
103 |
104 | err = util.ValidateECDSAP256Pub(flags.Key)
105 | if err != nil {
106 | return nil, true, fmt.Errorf("invalid network-key provided")
107 | }
108 |
109 | return map[string]string{
110 | "name": flags.Name,
111 | "host": flags.Host,
112 | "key": flags.Key,
113 | }, true, nil
114 | }
115 |
--------------------------------------------------------------------------------
/internal/config/add.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package config
20 |
21 | import (
22 | "github.com/spf13/cobra"
23 | )
24 |
25 | var addCmd = &cobra.Command{
26 | Use: "add ",
27 | Short: "Add resource to configuration",
28 | Example: "flow config add account",
29 | Args: cobra.ExactArgs(1),
30 | TraverseChildren: true,
31 | }
32 |
33 | func init() {
34 | addAccountCommand.AddToParent(addCmd)
35 | addContractCommand.AddToParent(addCmd)
36 | addDeploymentCommand.AddToParent(addCmd)
37 | addNetworkCommand.AddToParent(addCmd)
38 | }
39 |
--------------------------------------------------------------------------------
/internal/config/config.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package config
20 |
21 | import (
22 | "github.com/spf13/cobra"
23 | )
24 |
25 | var Cmd = &cobra.Command{
26 | Use: "config",
27 | Short: "Utilities to manage configuration",
28 | TraverseChildren: true,
29 | }
30 |
31 | func init() {
32 | Cmd.AddCommand(addCmd)
33 | Cmd.AddCommand(removeCmd)
34 | }
35 |
36 | type result struct {
37 | result string
38 | }
39 |
40 | func (r *result) JSON() any {
41 | return nil
42 | }
43 |
44 | func (r *result) String() string {
45 | if r.result != "" {
46 | return r.result
47 | }
48 |
49 | return ""
50 | }
51 |
52 | func (r *result) Oneliner() string {
53 | return ""
54 | }
55 |
--------------------------------------------------------------------------------
/internal/config/init.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package config
20 |
21 | import (
22 | "fmt"
23 | "os"
24 |
25 | "github.com/onflow/flowkit/v2/accounts"
26 |
27 | "github.com/onflow/flow-go-sdk/crypto"
28 |
29 | "github.com/onflow/flowkit/v2"
30 | "github.com/onflow/flowkit/v2/config"
31 | )
32 |
33 | // InitConfigParameters holds all necessary parameters for initializing the configuration.
34 | type InitConfigParameters struct {
35 | ServicePrivateKey string
36 | ServiceKeySigAlgo string
37 | ServiceKeyHashAlgo string
38 | Reset bool
39 | Global bool
40 | TargetDirectory string
41 | }
42 |
43 | // InitializeConfiguration creates the Flow configuration json file based on the provided parameters.
44 | func InitializeConfiguration(params InitConfigParameters, readerWriter flowkit.ReaderWriter) (*flowkit.State, error) {
45 | var path string
46 | if params.TargetDirectory != "" {
47 | path = fmt.Sprintf("%s/flow.json", params.TargetDirectory)
48 |
49 | // Create the directory if it doesn't exist
50 | err := readerWriter.MkdirAll(params.TargetDirectory, os.ModePerm)
51 | if err != nil {
52 | return nil, fmt.Errorf("failed to create target directory: %w", err)
53 | }
54 | } else {
55 | // Otherwise, choose between the default and global paths
56 | if params.Global {
57 | path = config.GlobalPath()
58 | } else {
59 | path = config.DefaultPath
60 | }
61 | }
62 |
63 | sigAlgo := crypto.StringToSignatureAlgorithm(params.ServiceKeySigAlgo)
64 | if sigAlgo == crypto.UnknownSignatureAlgorithm {
65 | return nil, fmt.Errorf("invalid signature algorithm: %s", params.ServiceKeySigAlgo)
66 | }
67 |
68 | hashAlgo := crypto.StringToHashAlgorithm(params.ServiceKeyHashAlgo)
69 | if hashAlgo == crypto.UnknownHashAlgorithm {
70 | return nil, fmt.Errorf("invalid hash algorithm: %s", params.ServiceKeyHashAlgo)
71 | }
72 |
73 | state, err := flowkit.Init(readerWriter)
74 | if err != nil {
75 | return nil, err
76 | }
77 |
78 | emulatorAccount, err := accounts.NewEmulatorAccount(readerWriter, crypto.ECDSA_P256, crypto.SHA3_256, params.TargetDirectory)
79 | if err != nil {
80 | return nil, err
81 | }
82 |
83 | state.Accounts().AddOrUpdate(emulatorAccount)
84 |
85 | if params.ServicePrivateKey != "" {
86 | privateKey, err := crypto.DecodePrivateKeyHex(sigAlgo, params.ServicePrivateKey)
87 | if err != nil {
88 | return nil, fmt.Errorf("invalid private key: %w", err)
89 | }
90 |
91 | state.SetEmulatorKey(privateKey)
92 | }
93 |
94 | if config.Exists(path) && !params.Reset {
95 | return nil, fmt.Errorf(
96 | "configuration already exists at: %s, if you want to reset configuration use the reset flag",
97 | path,
98 | )
99 | }
100 |
101 | return state, nil
102 | }
103 |
--------------------------------------------------------------------------------
/internal/config/remove-account.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package config
20 |
21 | import (
22 | "github.com/spf13/cobra"
23 |
24 | "github.com/onflow/flow-cli/internal/prompt"
25 |
26 | "github.com/onflow/flowkit/v2"
27 | "github.com/onflow/flowkit/v2/output"
28 |
29 | "github.com/onflow/flow-cli/internal/command"
30 | )
31 |
32 | type flagsRemoveAccount struct{}
33 |
34 | var removeAccountFlags = flagsRemoveAccount{}
35 |
36 | var removeAccountCommand = &command.Command{
37 | Cmd: &cobra.Command{
38 | Use: "account ",
39 | Short: "Remove account from configuration",
40 | Example: "flow config remove account Foo",
41 | Args: cobra.MaximumNArgs(1),
42 | },
43 | Flags: &removeAccountFlags,
44 | RunS: removeAccount,
45 | }
46 |
47 | func removeAccount(
48 | args []string,
49 | globalFlags command.GlobalFlags,
50 | _ output.Logger,
51 | _ flowkit.Services,
52 | state *flowkit.State,
53 | ) (command.Result, error) {
54 | name := ""
55 | if len(args) == 1 {
56 | name = args[0]
57 | } else {
58 | name = prompt.RemoveAccountPrompt(state.Config().Accounts)
59 | }
60 |
61 | err := state.Accounts().Remove(name)
62 | if err != nil {
63 | return nil, err
64 | }
65 |
66 | err = state.SaveEdited(globalFlags.ConfigPaths)
67 | if err != nil {
68 | return nil, err
69 | }
70 |
71 | return &result{
72 | result: "account removed",
73 | }, nil
74 | }
75 |
--------------------------------------------------------------------------------
/internal/config/remove-contract.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package config
20 |
21 | import (
22 | "github.com/spf13/cobra"
23 |
24 | "github.com/onflow/flow-cli/internal/prompt"
25 |
26 | "github.com/onflow/flowkit/v2"
27 | "github.com/onflow/flowkit/v2/output"
28 |
29 | "github.com/onflow/flow-cli/internal/command"
30 | )
31 |
32 | type flagsRemoveContract struct{}
33 |
34 | var removeContractFlags = flagsRemoveContract{}
35 |
36 | var removeContractCommand = &command.Command{
37 | Cmd: &cobra.Command{
38 | Use: "contract ",
39 | Short: "Remove contract from configuration",
40 | Example: "flow config remove contract Foo",
41 | Args: cobra.MaximumNArgs(1),
42 | },
43 | Flags: &removeContractFlags,
44 | RunS: removeContract,
45 | }
46 |
47 | func removeContract(
48 | args []string,
49 | globalFlags command.GlobalFlags,
50 | _ output.Logger,
51 | _ flowkit.Services,
52 | state *flowkit.State,
53 | ) (command.Result, error) {
54 | name := ""
55 | if len(args) == 1 {
56 | name = args[0]
57 | } else {
58 | name = prompt.RemoveContractPrompt(*state.Contracts())
59 | }
60 |
61 | err := state.Contracts().Remove(name)
62 | if err != nil {
63 | return nil, err
64 | }
65 |
66 | err = state.SaveEdited(globalFlags.ConfigPaths)
67 | if err != nil {
68 | return nil, err
69 | }
70 |
71 | return &result{
72 | result: "contract removed",
73 | }, nil
74 | }
75 |
--------------------------------------------------------------------------------
/internal/config/remove-deployment.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package config
20 |
21 | import (
22 | "github.com/spf13/cobra"
23 |
24 | "github.com/onflow/flow-cli/internal/prompt"
25 |
26 | "github.com/onflow/flowkit/v2"
27 | "github.com/onflow/flowkit/v2/output"
28 |
29 | "github.com/onflow/flow-cli/internal/command"
30 | )
31 |
32 | type flagsRemoveDeployment struct{}
33 |
34 | var removeDeploymentFlags = flagsRemoveDeployment{}
35 |
36 | var removeDeploymentCommand = &command.Command{
37 | Cmd: &cobra.Command{
38 | Use: "deployment ",
39 | Short: "Remove deployment from configuration",
40 | Example: "flow config remove deployment Foo testnet",
41 | Args: cobra.MaximumNArgs(2),
42 | },
43 | Flags: &removeDeploymentFlags,
44 | RunS: removeDeployment,
45 | }
46 |
47 | func removeDeployment(
48 | args []string,
49 | globalFlags command.GlobalFlags,
50 | _ output.Logger,
51 | _ flowkit.Services,
52 | state *flowkit.State,
53 | ) (command.Result, error) {
54 | account := ""
55 | network := ""
56 | if len(args) == 2 {
57 | account = args[0]
58 | network = args[1]
59 | } else {
60 | account, network = prompt.RemoveDeploymentPrompt(*state.Deployments())
61 | }
62 |
63 | err := state.Deployments().Remove(account, network)
64 | if err != nil {
65 | return nil, err
66 | }
67 |
68 | err = state.SaveEdited(globalFlags.ConfigPaths)
69 | if err != nil {
70 | return nil, err
71 | }
72 |
73 | return &result{
74 | result: "deployment removed",
75 | }, nil
76 | }
77 |
--------------------------------------------------------------------------------
/internal/config/remove-network.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package config
20 |
21 | import (
22 | "github.com/spf13/cobra"
23 |
24 | "github.com/onflow/flow-cli/internal/prompt"
25 |
26 | "github.com/onflow/flowkit/v2"
27 | "github.com/onflow/flowkit/v2/output"
28 |
29 | "github.com/onflow/flow-cli/internal/command"
30 | )
31 |
32 | type flagsRemoveNetwork struct{}
33 |
34 | var removeNetworkFlags = flagsRemoveNetwork{}
35 |
36 | var removeNetworkCommand = &command.Command{
37 | Cmd: &cobra.Command{
38 | Use: "network ",
39 | Short: "Remove network from configuration",
40 | Example: "flow config remove network Foo",
41 | Args: cobra.MaximumNArgs(1),
42 | },
43 | Flags: &removeNetworkFlags,
44 | RunS: removeNetwork,
45 | }
46 |
47 | func removeNetwork(
48 | args []string,
49 | globalFlags command.GlobalFlags,
50 | _ output.Logger,
51 | _ flowkit.Services,
52 | state *flowkit.State,
53 | ) (command.Result, error) {
54 | name := ""
55 | if len(args) == 1 {
56 | name = args[0]
57 | } else {
58 | name = prompt.RemoveNetworkPrompt(*state.Networks())
59 | }
60 |
61 | err := state.Networks().Remove(name)
62 | if err != nil {
63 | return nil, err
64 | }
65 |
66 | err = state.SaveEdited(globalFlags.ConfigPaths)
67 | if err != nil {
68 | return nil, err
69 | }
70 |
71 | return &result{
72 | result: "network removed",
73 | }, nil
74 | }
75 |
--------------------------------------------------------------------------------
/internal/config/remove.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package config
20 |
21 | import (
22 | "github.com/spf13/cobra"
23 | )
24 |
25 | var removeCmd = &cobra.Command{
26 | Use: "remove ",
27 | Short: "Remove resource from configuration",
28 | Example: "flow config remove account",
29 | Args: cobra.ExactArgs(1),
30 | TraverseChildren: true,
31 | }
32 |
33 | func init() {
34 | removeAccountCommand.AddToParent(removeCmd)
35 | removeContractCommand.AddToParent(removeCmd)
36 | removeDeploymentCommand.AddToParent(removeCmd)
37 | removeNetworkCommand.AddToParent(removeCmd)
38 | }
39 |
--------------------------------------------------------------------------------
/internal/dependencymanager/add.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package dependencymanager
20 |
21 | import (
22 | "fmt"
23 |
24 | "github.com/onflow/flowkit/v2"
25 | "github.com/spf13/cobra"
26 |
27 | "github.com/onflow/flow-cli/internal/util"
28 |
29 | "github.com/onflow/flowkit/v2/output"
30 |
31 | "github.com/onflow/flow-cli/internal/command"
32 | )
33 |
34 | var addCommand = &command.Command{
35 | Cmd: &cobra.Command{
36 | Use: "add",
37 | Short: "This command has been deprecated.",
38 | Long: "The 'add' command has been deprecated. Please use the 'install' command instead.",
39 | Deprecated: "This command is deprecated. Use 'install' to manage dependencies.",
40 | },
41 | RunS: add,
42 | Flags: &struct{}{},
43 | }
44 |
45 | func add(
46 | _ []string,
47 | _ command.GlobalFlags,
48 | logger output.Logger,
49 | _ flowkit.Services,
50 | _ *flowkit.State,
51 | ) (command.Result, error) {
52 | logger.Info(fmt.Sprintf("%s The 'add' command has been deprecated. Please use 'install' instead.", util.PrintEmoji("⚠️")))
53 | return nil, nil
54 | }
55 |
--------------------------------------------------------------------------------
/internal/dependencymanager/dependencies.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package dependencymanager
20 |
21 | import (
22 | "github.com/spf13/cobra"
23 | )
24 |
25 | var Cmd = &cobra.Command{
26 | Use: "dependencies",
27 | Short: "Manage contracts and dependencies",
28 | TraverseChildren: true,
29 | GroupID: "manager",
30 | Aliases: []string{"deps"},
31 | }
32 |
33 | func init() {
34 | addCommand.AddToParent(Cmd)
35 | installCommand.AddToParent(Cmd)
36 | discoverCommand.AddToParent(Cmd)
37 | }
38 |
--------------------------------------------------------------------------------
/internal/dependencymanager/discover.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package dependencymanager
20 |
21 | import (
22 | "fmt"
23 | "slices"
24 |
25 | flowsdk "github.com/onflow/flow-go-sdk"
26 | "github.com/onflow/flow-go/fvm/systemcontracts"
27 |
28 | "github.com/spf13/cobra"
29 |
30 | "github.com/onflow/flowkit/v2"
31 | "github.com/onflow/flowkit/v2/output"
32 |
33 | flowGo "github.com/onflow/flow-go/model/flow"
34 | flowkitConfig "github.com/onflow/flowkit/v2/config"
35 |
36 | "github.com/onflow/flow-cli/internal/command"
37 | "github.com/onflow/flow-cli/internal/prompt"
38 | "github.com/onflow/flow-cli/internal/util"
39 | )
40 |
41 | type DiscoverResult struct {
42 | Contracts []string `json:"contracts"`
43 | }
44 |
45 | var discoverCommand = &command.Command{
46 | Cmd: &cobra.Command{
47 | Use: "discover",
48 | Short: "Discover available contracts to add to your project.",
49 | Example: "flow dependencies discover",
50 | Args: cobra.NoArgs,
51 | },
52 | RunS: discover,
53 | Flags: &struct{}{},
54 | }
55 |
56 | func discover(
57 | _ []string,
58 | globalFlags command.GlobalFlags,
59 | logger output.Logger,
60 | flow flowkit.Services,
61 | state *flowkit.State,
62 | ) (command.Result, error) {
63 | installedDeps := state.Dependencies()
64 | if installedDeps == nil {
65 | installedDeps = new(flowkitConfig.Dependencies)
66 | }
67 |
68 | installedContracts := make([]string, 0)
69 | for _, dep := range *installedDeps {
70 | installedContracts = append(installedContracts, dep.Name)
71 | }
72 |
73 | err := PromptInstallCoreContracts(logger, state, "", installedContracts)
74 | if err != nil {
75 | return nil, err
76 | }
77 |
78 | err = state.SaveDefault()
79 | return nil, err
80 | }
81 |
82 | func PromptInstallCoreContracts(logger output.Logger, state *flowkit.State, targetDir string, excludeContracts []string) error {
83 | // Prompt to ask which core contracts should be installed
84 | sc := systemcontracts.SystemContractsForChain(flowGo.Mainnet)
85 | promptMessage := "Select any core contracts you would like to install or skip to continue."
86 |
87 | contractNames := make([]string, 0)
88 |
89 | for _, contract := range sc.All() {
90 | if slices.Contains(excludeContracts, contract.Name) {
91 | continue
92 | }
93 | contractNames = append(contractNames, contract.Name)
94 | }
95 |
96 | selectedContractNames, err := prompt.RunSelectOptions(contractNames, promptMessage)
97 | if err != nil {
98 | return fmt.Errorf("error running dependency selection: %v\n", err)
99 | }
100 |
101 | var dependencies []flowkitConfig.Dependency
102 |
103 | // Loop standard contracts and add them to the dependencies if selected
104 | for _, contract := range sc.All() {
105 | if slices.Contains(selectedContractNames, contract.Name) {
106 | dependencies = append(dependencies, flowkitConfig.Dependency{
107 | Name: contract.Name,
108 | Source: flowkitConfig.Source{
109 | NetworkName: flowkitConfig.MainnetNetwork.Name,
110 | Address: flowsdk.HexToAddress(contract.Address.String()),
111 | ContractName: contract.Name,
112 | },
113 | })
114 | }
115 | }
116 |
117 | logger.Info("")
118 | logger.Info(util.MessageWithEmojiPrefix("🔄", "Installing selected core contracts and dependencies..."))
119 |
120 | // Add the selected core contracts as dependencies
121 | installer, err := NewDependencyInstaller(logger, state, false, targetDir, Flags{})
122 | if err != nil {
123 | return err
124 | }
125 |
126 | if err := installer.AddMany(dependencies); err != nil {
127 | return err
128 | }
129 |
130 | return nil
131 | }
132 |
--------------------------------------------------------------------------------
/internal/events/events_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package events
20 |
21 | import (
22 | "encoding/json"
23 | "strings"
24 | "testing"
25 |
26 | "github.com/onflow/cadence"
27 | "github.com/onflow/flow-go-sdk"
28 | "github.com/stretchr/testify/assert"
29 | "github.com/stretchr/testify/mock"
30 |
31 | "github.com/onflow/flowkit/v2"
32 | "github.com/onflow/flowkit/v2/tests"
33 |
34 | "github.com/onflow/flow-cli/internal/command"
35 | "github.com/onflow/flow-cli/internal/util"
36 | )
37 |
38 | func Test_Get(t *testing.T) {
39 | srv, _, rw := util.TestMocks(t)
40 |
41 | t.Run("Success", func(t *testing.T) {
42 | inArgs := []string{"test.event"}
43 | eventsFlags.Start = 10
44 | eventsFlags.End = 20
45 |
46 | result, err := get(inArgs, command.GlobalFlags{}, util.NoLogger, rw, srv.Mock)
47 | assert.NoError(t, err)
48 | assert.NotNil(t, result)
49 | })
50 |
51 | t.Run("Success not passed start end", func(t *testing.T) {
52 | inArgs := []string{"test.event"}
53 | eventsFlags.Start = 0
54 | eventsFlags.End = 0
55 |
56 | srv.GetBlock.Run(func(args mock.Arguments) {
57 | query := args.Get(1).(flowkit.BlockQuery)
58 | assert.True(t, query.Latest)
59 | }).Return(tests.NewBlock(), nil)
60 |
61 | result, err := get(inArgs, command.GlobalFlags{}, util.NoLogger, rw, srv.Mock)
62 | assert.NoError(t, err)
63 | assert.NotNil(t, result)
64 | })
65 |
66 | t.Run("Fail invalid range", func(t *testing.T) {
67 | inArgs := []string{"test.event"}
68 | eventsFlags.Start = 20
69 | eventsFlags.End = 0
70 |
71 | result, err := get(inArgs, command.GlobalFlags{}, util.NoLogger, rw, srv.Mock)
72 | assert.EqualError(t, err, "please provide either both start and end for range or only last flag")
73 | assert.Nil(t, result)
74 | })
75 |
76 | }
77 |
78 | func Test_Result(t *testing.T) {
79 | block := tests.NewBlock()
80 | event := EventResult{
81 | BlockEvents: []flow.BlockEvents{{
82 | BlockID: block.ID,
83 | Height: block.Height,
84 | BlockTimestamp: block.Timestamp,
85 | Events: []flow.Event{
86 | *tests.NewEvent(
87 | 0,
88 | "A.foo",
89 | []cadence.Field{{Type: cadence.StringType, Identifier: "bar"}},
90 | []cadence.Value{cadence.NewInt(1)},
91 | ),
92 | },
93 | }},
94 | }
95 |
96 | assert.Equal(t, strings.TrimPrefix(`
97 | Events Block #1:
98 | Index 0
99 | Type A.foo
100 | Tx ID 0000000000000000000000000000000000000000000000000000000000000000
101 | Values
102 | - bar (String): 1
103 |
104 | `, "\n"), event.String())
105 |
106 | assert.Equal(t, []any{map[string]any{
107 | "blockID": uint64(1),
108 | "index": 0,
109 | "transactionId": "0000000000000000000000000000000000000000000000000000000000000000",
110 | "type": "A.foo",
111 | "values": json.RawMessage{0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x7b, 0x22, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x41, 0x2e, 0x66, 0x6f, 0x6f, 0x22, 0x2c, 0x22, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x22, 0x31, 0x22, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x49, 0x6e, 0x74, 0x22, 0x7d, 0x2c, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x22, 0x62, 0x61, 0x72, 0x22, 0x7d, 0x5d, 0x7d, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x7d, 0xa},
112 | }}, event.JSON())
113 | }
114 |
--------------------------------------------------------------------------------
/internal/events/get.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package events
20 |
21 | import (
22 | "context"
23 | "fmt"
24 |
25 | "github.com/spf13/cobra"
26 |
27 | "github.com/onflow/flowkit/v2"
28 | "github.com/onflow/flowkit/v2/output"
29 |
30 | "github.com/onflow/flow-cli/internal/command"
31 | )
32 |
33 | type flagsEvents struct {
34 | Start uint64 `flag:"start" info:"Start block height"`
35 | End uint64 `flag:"end" info:"End block height"`
36 | Last uint64 `default:"10" flag:"last" info:"Fetch number of blocks relative to the last block. Ignored if the start flag is set. Used as a default if no flags are provided"`
37 | Workers int `default:"10" flag:"workers" info:"Number of workers to use when fetching events in parallel"`
38 | Batch uint64 `default:"25" flag:"batch" info:"Number of blocks each worker will fetch"`
39 | }
40 |
41 | var eventsFlags = flagsEvents{}
42 |
43 | var getCommand = &command.Command{
44 | Cmd: &cobra.Command{
45 | Use: "get ",
46 | Short: "Get events in a block range",
47 | Args: cobra.MinimumNArgs(1),
48 | Example: `#fetch events from the latest 10 blocks is the default behavior
49 | flow events get A.1654653399040a61.FlowToken.TokensDeposited
50 |
51 | #specify manual start and stop blocks
52 | flow events get A.1654653399040a61.FlowToken.TokensDeposited --start 11559500 --end 11559600
53 |
54 | #in order to get and event from the 20 latest blocks on a network run
55 | flow events get A.1654653399040a61.FlowToken.TokensDeposited --last 20 --network mainnet
56 |
57 | #if you want to fetch multiple event types that is done by sending in more events. Even fetching will be done in parallel.
58 | flow events get A.1654653399040a61.FlowToken.TokensDeposited A.1654653399040a61.FlowToken.TokensWithdrawn
59 | `,
60 | },
61 | Flags: &eventsFlags,
62 | Run: get,
63 | }
64 |
65 | func get(
66 | args []string,
67 | _ command.GlobalFlags,
68 | logger output.Logger,
69 | _ flowkit.ReaderWriter,
70 | flow flowkit.Services,
71 | ) (command.Result, error) {
72 | var err error
73 | start := eventsFlags.Start
74 | end := eventsFlags.End
75 | last := eventsFlags.Last
76 |
77 | // handle if not passing start and end
78 | if start == 0 && end == 0 {
79 | latest, err := flow.GetBlock(
80 | context.Background(),
81 | flowkit.BlockQuery{Latest: true},
82 | )
83 | if err != nil {
84 | return nil, err
85 | }
86 | end = latest.Height
87 |
88 | start = end - last
89 | if end < last {
90 | start = 0
91 | }
92 | } else if start == 0 || end == 0 {
93 | return nil, fmt.Errorf("please provide either both start and end for range or only last flag")
94 | }
95 |
96 | logger.StartProgress("Fetching events...")
97 | defer logger.StopProgress()
98 |
99 | events, err := flow.GetEvents(
100 | context.Background(),
101 | args,
102 | start,
103 | end,
104 | &flowkit.EventWorker{
105 | Count: eventsFlags.Workers,
106 | BlocksPerWorker: eventsFlags.Batch,
107 | },
108 | )
109 | if err != nil {
110 | return nil, err
111 | }
112 |
113 | return &EventResult{BlockEvents: events}, nil
114 | }
115 |
--------------------------------------------------------------------------------
/internal/keys/decode.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package keys
20 |
21 | import (
22 | "encoding/hex"
23 | "fmt"
24 | "strings"
25 |
26 | "github.com/onflow/flow-go-sdk"
27 | "github.com/onflow/flow-go-sdk/crypto"
28 | "github.com/spf13/cobra"
29 |
30 | "github.com/onflow/flowkit/v2"
31 | "github.com/onflow/flowkit/v2/output"
32 |
33 | "github.com/onflow/flow-cli/internal/command"
34 | )
35 |
36 | type flagsDecode struct {
37 | SigAlgo string `default:"ECDSA_P256" flag:"sig-algo" info:"Signature algorithm"`
38 | FromFile string `default:"" flag:"from-file" info:"Load key from file"`
39 | }
40 |
41 | var decodeFlags = flagsDecode{}
42 |
43 | var decodeCommand = &command.Command{
44 | Cmd: &cobra.Command{
45 | Use: "decode ",
46 | Short: "Decode an encoded public key",
47 | Args: cobra.RangeArgs(1, 2),
48 | ValidArgs: []string{"rlp", "pem"},
49 | Example: "flow keys decode rlp f847b8408...2402038203e8",
50 | },
51 | Flags: &decodeFlags,
52 | Run: decode,
53 | }
54 |
55 | func decode(
56 | args []string,
57 | _ command.GlobalFlags,
58 | _ output.Logger,
59 | reader flowkit.ReaderWriter,
60 | _ flowkit.Services,
61 | ) (command.Result, error) {
62 | encoding := args[0]
63 | fromFile := decodeFlags.FromFile
64 |
65 | var encoded string
66 | if len(args) > 1 {
67 | encoded = args[1]
68 | }
69 |
70 | /* TODO(sideninja) from file flag should be remove and should be replaced with $(echo file)
71 | but cobra has an issue with parsing pem content as it recognize it as flag due to ---- characters */
72 | if encoded != "" && fromFile != "" {
73 | return nil, fmt.Errorf("can not pass both command argument and from file flag")
74 | }
75 | if encoded == "" && fromFile == "" {
76 | return nil, fmt.Errorf("provide argument for encoded key or use from file flag")
77 | }
78 |
79 | if fromFile != "" {
80 | e, err := reader.ReadFile(fromFile)
81 | if err != nil {
82 | return nil, err
83 | }
84 | encoded = strings.TrimSpace(string(e))
85 | }
86 |
87 | var accountKey *flow.AccountKey
88 | var err error
89 | switch strings.ToLower(encoding) {
90 | case "pem":
91 | sigAlgo := crypto.StringToSignatureAlgorithm(decodeFlags.SigAlgo)
92 | if sigAlgo == crypto.UnknownSignatureAlgorithm {
93 | return nil, fmt.Errorf("invalid signature algorithm: %s", decodeFlags.SigAlgo)
94 | }
95 |
96 | accountKey, err = decodePEM(encoded, sigAlgo)
97 | case "rlp":
98 | accountKey, err = decodeRLP(encoded)
99 | default:
100 | return nil, fmt.Errorf("encoding type not supported. Valid encoding: RLP and PEM")
101 | }
102 |
103 | if err != nil {
104 | return nil, err
105 | }
106 |
107 | return &keyResult{
108 | publicKey: accountKey.PublicKey,
109 | sigAlgo: accountKey.SigAlgo,
110 | hashAlgo: accountKey.HashAlgo,
111 | weight: accountKey.Weight,
112 | }, err
113 | }
114 |
115 | func decodePEM(pubKey string, sigAlgo crypto.SignatureAlgorithm) (*flow.AccountKey, error) {
116 | pk, err := crypto.DecodePublicKeyPEM(sigAlgo, pubKey)
117 | if err != nil {
118 | return nil, err
119 | }
120 |
121 | return &flow.AccountKey{
122 | PublicKey: pk,
123 | SigAlgo: sigAlgo,
124 | Weight: -1,
125 | }, nil
126 | }
127 |
128 | func decodeRLP(pubKey string) (*flow.AccountKey, error) {
129 | publicKeyBytes, err := hex.DecodeString(pubKey)
130 | if err != nil {
131 | return nil, fmt.Errorf("failed to decode public key: %w", err)
132 | }
133 |
134 | accountKey, err := flow.DecodeAccountKey(publicKeyBytes)
135 | if err != nil {
136 | return nil, fmt.Errorf("failed to decode: %w", err)
137 | }
138 |
139 | return accountKey, nil
140 | }
141 |
--------------------------------------------------------------------------------
/internal/keys/derive.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package keys
20 |
21 | import (
22 | "fmt"
23 |
24 | "github.com/onflow/flow-go-sdk/crypto"
25 | "github.com/spf13/cobra"
26 |
27 | "github.com/onflow/flowkit/v2"
28 | "github.com/onflow/flowkit/v2/output"
29 |
30 | "github.com/onflow/flow-cli/internal/command"
31 | )
32 |
33 | type flagsDerive struct {
34 | KeySigAlgo string `default:"ECDSA_P256" flag:"sig-algo" info:"Signature algorithm"`
35 | }
36 |
37 | var deriveFlags = flagsDerive{}
38 |
39 | var deriveCommand = &command.Command{
40 | Cmd: &cobra.Command{
41 | Use: "derive ",
42 | Short: "Derive public key from a private key",
43 | Args: cobra.ExactArgs(1),
44 | Example: "flow keys derive 4247b8408...2402038203e8",
45 | },
46 | Flags: &deriveFlags,
47 | Run: derive,
48 | }
49 |
50 | func derive(
51 | args []string,
52 | _ command.GlobalFlags,
53 | _ output.Logger,
54 | _ flowkit.ReaderWriter,
55 | _ flowkit.Services,
56 | ) (command.Result, error) {
57 |
58 | sigAlgo := crypto.StringToSignatureAlgorithm(deriveFlags.KeySigAlgo)
59 | if sigAlgo == crypto.UnknownSignatureAlgorithm {
60 | return nil, fmt.Errorf("invalid signature algorithm: %s", deriveFlags.KeySigAlgo)
61 | }
62 |
63 | parsedPrivateKey, err := crypto.DecodePrivateKeyHex(sigAlgo, args[0])
64 | if err != nil {
65 | return nil, fmt.Errorf("failed to decode private key: %w", err)
66 | }
67 |
68 | return &keyResult{privateKey: parsedPrivateKey, publicKey: parsedPrivateKey.PublicKey()}, nil
69 | }
70 |
--------------------------------------------------------------------------------
/internal/keys/generate.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package keys
20 |
21 | import (
22 | "context"
23 | "fmt"
24 |
25 | "github.com/onflow/flow-go-sdk/crypto"
26 | "github.com/spf13/cobra"
27 |
28 | "github.com/onflow/flowkit/v2"
29 | "github.com/onflow/flowkit/v2/output"
30 |
31 | "github.com/onflow/flow-cli/internal/command"
32 | )
33 |
34 | type flagsGenerate struct {
35 | Mnemonic string `flag:"mnemonic" info:"Mnemonic seed to use"`
36 | DerivationPath string `default:"m/44'/539'/0'/0/0" flag:"derivationPath" info:"Derivation path"`
37 | KeySigAlgo string `default:"ECDSA_P256" flag:"sig-algo" info:"Signature algorithm"`
38 | }
39 |
40 | var generateFlags = flagsGenerate{}
41 |
42 | var generateCommand = &command.Command{
43 | Cmd: &cobra.Command{
44 | Use: "generate",
45 | Short: "Generate a new key-pair",
46 | Example: "flow keys generate",
47 | },
48 | Flags: &generateFlags,
49 | Run: generate,
50 | }
51 |
52 | func generate(
53 | _ []string,
54 | _ command.GlobalFlags,
55 | _ output.Logger,
56 | _ flowkit.ReaderWriter,
57 | flow flowkit.Services,
58 | ) (command.Result, error) {
59 | sigAlgo := crypto.StringToSignatureAlgorithm(generateFlags.KeySigAlgo)
60 | if sigAlgo == crypto.UnknownSignatureAlgorithm {
61 | return nil, fmt.Errorf("invalid signature algorithm: %s", generateFlags.KeySigAlgo)
62 | }
63 |
64 | var err error
65 | mnemonic := generateFlags.Mnemonic
66 | if mnemonic == "" {
67 | _, mnemonic, err = flow.GenerateMnemonicKey(context.Background(), sigAlgo, generateFlags.DerivationPath)
68 | if err != nil {
69 | return nil, err
70 | }
71 | }
72 |
73 | privateKey, err := flow.DerivePrivateKeyFromMnemonic(
74 | context.Background(),
75 | mnemonic,
76 | sigAlgo,
77 | generateFlags.DerivationPath,
78 | )
79 | if err != nil {
80 | return nil, err
81 | }
82 |
83 | return &keyResult{
84 | privateKey: privateKey,
85 | publicKey: privateKey.PublicKey(),
86 | sigAlgo: sigAlgo,
87 | mnemonic: mnemonic,
88 | derivationPath: generateFlags.DerivationPath,
89 | }, nil
90 | }
91 |
--------------------------------------------------------------------------------
/internal/keys/keys.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package keys
20 |
21 | import (
22 | "bytes"
23 | "encoding/hex"
24 | "fmt"
25 |
26 | "github.com/onflow/flow-go-sdk/crypto"
27 | "github.com/spf13/cobra"
28 |
29 | "github.com/onflow/flowkit/v2/output"
30 |
31 | "github.com/onflow/flow-cli/internal/util"
32 | )
33 |
34 | var Cmd = &cobra.Command{
35 | Use: "keys",
36 | Short: "Generate and decode Flow keys",
37 | TraverseChildren: true,
38 | GroupID: "security",
39 | }
40 |
41 | func init() {
42 | generateCommand.AddToParent(Cmd)
43 | decodeCommand.AddToParent(Cmd)
44 | deriveCommand.AddToParent(Cmd)
45 | }
46 |
47 | type keyResult struct {
48 | privateKey crypto.PrivateKey
49 | publicKey crypto.PublicKey
50 | sigAlgo crypto.SignatureAlgorithm
51 | hashAlgo crypto.HashAlgorithm
52 | weight int
53 | mnemonic string
54 | derivationPath string
55 | }
56 |
57 | func (k *keyResult) JSON() any {
58 | result := make(map[string]any)
59 | result["public"] = hex.EncodeToString(k.privateKey.PublicKey().Encode())
60 |
61 | if k.privateKey != nil {
62 | result["private"] = hex.EncodeToString(k.privateKey.Encode())
63 | }
64 |
65 | if k.mnemonic != "" {
66 | result["mnemonic"] = k.mnemonic
67 | }
68 |
69 | if k.derivationPath != "" {
70 | result["derivationPath"] = k.derivationPath
71 | }
72 |
73 | return result
74 | }
75 |
76 | func (k *keyResult) String() string {
77 | var b bytes.Buffer
78 | writer := util.CreateTabWriter(&b)
79 |
80 | if k.privateKey != nil {
81 | _, _ = fmt.Fprintf(writer, "%s Store private key safely and don't share with anyone! \n", output.StopEmoji())
82 | _, _ = fmt.Fprintf(writer, "Private Key \t %x \n", k.privateKey.Encode())
83 | }
84 |
85 | _, _ = fmt.Fprintf(writer, "Public Key \t %x \n", k.publicKey.Encode())
86 |
87 | if k.mnemonic != "" {
88 | _, _ = fmt.Fprintf(writer, "Mnemonic \t %s \n", k.mnemonic)
89 | }
90 |
91 | if k.derivationPath != "" {
92 | _, _ = fmt.Fprintf(writer, "Derivation Path \t %s \n", k.derivationPath)
93 | }
94 |
95 | if k.sigAlgo != crypto.UnknownSignatureAlgorithm {
96 | _, _ = fmt.Fprintf(writer, "Signature Algorithm \t %s\n", k.sigAlgo)
97 | }
98 |
99 | if k.hashAlgo != crypto.UnknownHashAlgorithm {
100 | _, _ = fmt.Fprintf(writer, "Hash Algorithm \t %s\n", k.hashAlgo)
101 | }
102 |
103 | if k.weight > 0 {
104 | _, _ = fmt.Fprintf(writer, "Weight \t %d\n", k.weight)
105 | }
106 |
107 | _ = writer.Flush()
108 |
109 | return b.String()
110 | }
111 |
112 | func (k *keyResult) Oneliner() string {
113 | result := fmt.Sprintf("Public Key: %x, ", k.publicKey.Encode())
114 |
115 | if k.privateKey != nil {
116 | result += fmt.Sprintf("Private Key: %x, ", k.privateKey.Encode())
117 | }
118 |
119 | if k.mnemonic != "" {
120 | result += fmt.Sprintf("Mnemonic: %s, ", k.mnemonic)
121 | }
122 |
123 | if k.derivationPath != "" {
124 | result += fmt.Sprintf("Derivation Path: %s", k.derivationPath)
125 | }
126 |
127 | return result
128 | }
129 |
--------------------------------------------------------------------------------
/internal/project/project.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package project
20 |
21 | import (
22 | "github.com/spf13/cobra"
23 | )
24 |
25 | var Cmd = &cobra.Command{
26 | Use: "project",
27 | Short: "Manage your Cadence project",
28 | TraverseChildren: true,
29 | GroupID: "project",
30 | }
31 |
32 | func init() {
33 | DeployCommand.AddToParent(Cmd)
34 | }
35 |
--------------------------------------------------------------------------------
/internal/project/project_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package project
20 |
21 | import (
22 | "testing"
23 |
24 | "github.com/onflow/flow-go-sdk"
25 | "github.com/stretchr/testify/assert"
26 | "github.com/stretchr/testify/require"
27 |
28 | "github.com/onflow/flowkit/v2"
29 | "github.com/onflow/flowkit/v2/accounts"
30 | "github.com/onflow/flowkit/v2/config"
31 |
32 | "github.com/onflow/flow-cli/internal/command"
33 | "github.com/onflow/flow-cli/internal/util"
34 | )
35 |
36 | func Test_ProjectDeploy(t *testing.T) {
37 | srv, state, rw := util.TestMocks(t)
38 |
39 | t.Run("Fail contract errors", func(t *testing.T) {
40 | srv.DeployProject.Return(nil, &flowkit.ProjectDeploymentError{})
41 | _, err := deploy([]string{}, command.GlobalFlags{}, util.NoLogger, srv.Mock, state)
42 | assert.EqualError(t, err, "failed deploying all contracts")
43 | })
44 |
45 | t.Run("Success replace standard contracts", func(t *testing.T) {
46 | const ft = "FungibleToken"
47 | const acc = "mainnet-account"
48 | state.Contracts().AddOrUpdate(config.Contract{
49 | Name: ft,
50 | Location: "./ft.cdc",
51 | })
52 | _ = rw.WriteFile("./ft.cdc", []byte("test"), 0677) // mock the file
53 | state.Accounts().AddOrUpdate(&accounts.Account{Name: acc, Address: flow.HexToAddress("0x01")})
54 |
55 | state.Deployments().AddOrUpdate(config.Deployment{
56 | Network: config.MainnetNetwork.Name,
57 | Account: acc,
58 | Contracts: []config.ContractDeployment{{Name: ft}},
59 | })
60 |
61 | state.Deployments().AddOrUpdate(config.Deployment{
62 | Network: config.EmulatorNetwork.Name,
63 | Account: config.DefaultEmulator.ServiceAccount,
64 | Contracts: []config.ContractDeployment{{Name: ft}},
65 | })
66 |
67 | err := checkForStandardContractUsageOnMainnet(state, util.NoLogger, true)
68 | require.NoError(t, err)
69 |
70 | assert.Len(t, state.Deployments().ByNetwork(config.MainnetNetwork.Name), 0) // should remove it
71 | assert.Len(t, state.Deployments().ByNetwork(config.EmulatorNetwork.Name), 1) // should not remove it
72 | c, err := state.Contracts().ByName(ft)
73 | assert.NoError(t, err)
74 | assert.NotNil(t, c.Aliases)
75 |
76 | assert.Equal(t, "f233dcee88fe0abe", c.Aliases.ByNetwork(config.MainnetNetwork.Name).Address.String())
77 | })
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/internal/prompt/select-options.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package prompt
20 |
21 | import (
22 | "fmt"
23 | "strings"
24 |
25 | tea "github.com/charmbracelet/bubbletea"
26 | )
27 |
28 | // optionSelectModel represents the prompt state but is now private
29 | type optionSelectModel struct {
30 | message string // message to display
31 | cursor int // position of the cursor
32 | choices []string // items on the list
33 | selected map[int]struct{} // which items are selected
34 | }
35 |
36 | // selectOptions creates a prompt for selecting multiple options but is now private
37 | func selectOptions(options []string, message string) optionSelectModel {
38 | return optionSelectModel{
39 | message: message,
40 | choices: options,
41 | selected: make(map[int]struct{}),
42 | }
43 | }
44 |
45 | func (m optionSelectModel) Init() tea.Cmd {
46 | return nil // No initial command
47 | }
48 |
49 | func (m optionSelectModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
50 | switch msg := msg.(type) {
51 | case tea.KeyMsg:
52 | switch msg.Type {
53 | case tea.KeyCtrlC, tea.KeyEsc: // Quit the program
54 | return m, tea.Quit
55 |
56 | case tea.KeyUp: // Navigate up
57 | if m.cursor > 0 {
58 | m.cursor--
59 | }
60 |
61 | case tea.KeyDown: // Navigate down
62 | if m.cursor < len(m.choices)-1 {
63 | m.cursor++
64 | }
65 |
66 | case tea.KeySpace: // Select an item
67 | // Toggle selection
68 | if _, ok := m.selected[m.cursor]; ok {
69 | delete(m.selected, m.cursor) // Deselect
70 | } else {
71 | m.selected[m.cursor] = struct{}{} // Select
72 | }
73 |
74 | case tea.KeyEnter: // Confirm selection
75 | return m, tea.Quit // Quit and process selections in main
76 | }
77 | }
78 |
79 | return m, nil
80 | }
81 |
82 | func (m optionSelectModel) View() string {
83 | var b strings.Builder
84 | b.WriteString(fmt.Sprintf("%s\n", m.message))
85 | b.WriteString("Use arrow keys to navigate, space to select, enter to confirm or skip, q to quit:\n\n")
86 | for i, choice := range m.choices {
87 | if m.cursor == i {
88 | b.WriteString("> ")
89 | } else {
90 | b.WriteString(" ")
91 | }
92 | // Mark selected items
93 | if _, ok := m.selected[i]; ok {
94 | b.WriteString("[x] ")
95 | } else {
96 | b.WriteString("[ ] ")
97 | }
98 | b.WriteString(choice + "\n")
99 | }
100 | return b.String()
101 | }
102 |
103 | // RunSelectOptions remains public and is the interface for external usage.
104 | func RunSelectOptions(options []string, message string) ([]string, error) {
105 | model := selectOptions(options, message)
106 | p := tea.NewProgram(model)
107 | finalModel, err := p.Run()
108 | if err != nil {
109 | return nil, err
110 | }
111 |
112 | final := finalModel.(optionSelectModel)
113 | selectedChoices := make([]string, 0)
114 | for i := range final.selected {
115 | selectedChoices = append(selectedChoices, final.choices[i])
116 | }
117 | return selectedChoices, nil
118 | }
119 |
--------------------------------------------------------------------------------
/internal/prompt/text-input.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package prompt
20 |
21 | import (
22 | "fmt"
23 |
24 | "github.com/charmbracelet/bubbles/textinput"
25 | tea "github.com/charmbracelet/bubbletea"
26 | )
27 |
28 | // textInputModel is now private, only accessible within the 'prompt' package.
29 | type textInputModel struct {
30 | textInput textinput.Model
31 | err error
32 | customMsg string
33 | }
34 |
35 | // newTextInput is a private function that initializes a new text input model.
36 | func newTextInput(customMsg, placeholder string) textInputModel {
37 | ti := textinput.New()
38 | ti.Placeholder = placeholder
39 | ti.Focus()
40 | ti.CharLimit = 256
41 | ti.Width = 30
42 |
43 | return textInputModel{
44 | textInput: ti,
45 | customMsg: customMsg,
46 | }
47 | }
48 |
49 | func (m textInputModel) Init() tea.Cmd {
50 | return textinput.Blink
51 | }
52 |
53 | func (m textInputModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
54 | switch msg := msg.(type) {
55 | case tea.KeyMsg:
56 | switch msg.Type {
57 | case tea.KeyEnter, tea.KeyCtrlC, tea.KeyEsc:
58 | return m, tea.Quit
59 | }
60 | var cmd tea.Cmd
61 | m.textInput, cmd = m.textInput.Update(msg)
62 | return m, cmd
63 | }
64 |
65 | return m, nil
66 | }
67 |
68 | func (m textInputModel) View() string {
69 | return fmt.Sprintf("%s\n\n%s\n\n%s", m.customMsg, m.textInput.View(), "(Enter to submit, Esc to quit)")
70 | }
71 |
72 | // RunTextInput remains public. It's the entry point for external usage.
73 | func RunTextInput(customMsg, placeholder string) (string, error) {
74 | model := newTextInput(customMsg, placeholder)
75 | p := tea.NewProgram(model)
76 |
77 | if finalModel, err := p.Run(); err != nil {
78 | return "", err
79 | } else {
80 | final := finalModel.(textInputModel)
81 | return final.textInput.Value(), nil
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/internal/quick/deploy.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package quick
20 |
21 | import (
22 | "github.com/spf13/cobra"
23 |
24 | "github.com/onflow/flow-cli/internal/command"
25 | "github.com/onflow/flow-cli/internal/project"
26 | )
27 |
28 | var DeployCommand = &command.Command{
29 | Cmd: &cobra.Command{
30 | Use: "deploy",
31 | Short: "Deploy all project contracts",
32 | Example: "flow deploy",
33 | GroupID: "project",
34 | },
35 | Flags: project.DeployCommand.Flags,
36 | RunS: project.DeployCommand.RunS,
37 | }
38 |
--------------------------------------------------------------------------------
/internal/quick/run.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package quick
20 |
21 | import (
22 | "fmt"
23 |
24 | "github.com/spf13/cobra"
25 |
26 | "github.com/onflow/flowkit/v2"
27 | "github.com/onflow/flowkit/v2/output"
28 |
29 | "github.com/onflow/flow-cli/internal/command"
30 | )
31 |
32 | type flagsRun struct {
33 | }
34 |
35 | var runFlags = flagsRun{}
36 |
37 | // RunCommand This command will act as an alias for running the emulator and deploying the contracts
38 | var RunCommand = &command.Command{
39 | Cmd: &cobra.Command{
40 | Use: "run",
41 | Short: "Start emulator and deploy all project contracts",
42 | Example: "flow run",
43 | GroupID: "project",
44 | },
45 | Flags: &runFlags,
46 | Run: func(
47 | _ []string,
48 | _ command.GlobalFlags,
49 | _ output.Logger,
50 | _ flowkit.ReaderWriter,
51 | _ flowkit.Services,
52 | ) (command.Result, error) {
53 | fmt.Println("⚠️Deprecation notice: Use 'flow dev' command.")
54 | return &runResult{}, nil
55 | },
56 | }
57 |
58 | type runResult struct{}
59 |
60 | func (r *runResult) JSON() any {
61 | return nil
62 | }
63 |
64 | func (r *runResult) String() string {
65 | return ""
66 | }
67 |
68 | func (r *runResult) Oneliner() string {
69 | return ""
70 | }
71 |
--------------------------------------------------------------------------------
/internal/scripts/execute.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package scripts
20 |
21 | import (
22 | "context"
23 | "fmt"
24 |
25 | "github.com/onflow/cadence"
26 | flowsdk "github.com/onflow/flow-go-sdk"
27 | "github.com/spf13/cobra"
28 |
29 | "github.com/onflow/flowkit/v2"
30 | "github.com/onflow/flowkit/v2/arguments"
31 | "github.com/onflow/flowkit/v2/output"
32 |
33 | "github.com/onflow/flow-cli/internal/command"
34 | )
35 |
36 | type Flags struct {
37 | ArgsJSON string `default:"" flag:"args-json" info:"arguments in JSON-Cadence format"`
38 | BlockID string `default:"" flag:"block-id" info:"block ID to execute the script at"`
39 | BlockHeight uint64 `default:"" flag:"block-height" info:"block height to execute the script at"`
40 | }
41 |
42 | var flags = Flags{}
43 |
44 | var executeCommand = &command.Command{
45 | Cmd: &cobra.Command{
46 | Use: "execute [ ...]",
47 | Short: "Execute a script",
48 | Example: `flow scripts execute script.cdc "Meow" "Woof"`,
49 | Args: cobra.MinimumNArgs(1),
50 | },
51 | Flags: &flags,
52 | Run: execute,
53 | }
54 |
55 | func execute(
56 | args []string,
57 | _ command.GlobalFlags,
58 | _ output.Logger,
59 | readerWriter flowkit.ReaderWriter,
60 | flow flowkit.Services,
61 | ) (command.Result, error) {
62 | filename := args[0]
63 |
64 | code, err := readerWriter.ReadFile(filename)
65 | if err != nil {
66 | return nil, fmt.Errorf("error loading script file: %w", err)
67 | }
68 |
69 | return SendScript(code, args[1:], filename, flow, flags)
70 | }
71 |
72 | func SendScript(code []byte, argsArr []string, location string, flow flowkit.Services, scriptFlags Flags) (command.Result, error) {
73 | var cadenceArgs []cadence.Value
74 | var err error
75 | if scriptFlags.ArgsJSON != "" {
76 | cadenceArgs, err = arguments.ParseJSON(scriptFlags.ArgsJSON)
77 | } else {
78 | cadenceArgs, err = arguments.ParseWithoutType(argsArr, code, location)
79 | }
80 |
81 | if err != nil {
82 | return nil, fmt.Errorf("error parsing script arguments: %w", err)
83 | }
84 |
85 | query := flowkit.ScriptQuery{}
86 | if scriptFlags.BlockHeight != 0 {
87 | query.Height = scriptFlags.BlockHeight
88 | } else if scriptFlags.BlockID != "" {
89 | query.ID = flowsdk.HexToID(scriptFlags.BlockID)
90 | } else {
91 | query.Latest = true
92 | }
93 |
94 | value, err := flow.ExecuteScript(
95 | context.Background(),
96 | flowkit.Script{
97 | Code: code,
98 | Args: cadenceArgs,
99 | Location: location,
100 | },
101 | query,
102 | )
103 | if err != nil {
104 | return nil, err
105 | }
106 |
107 | return &scriptResult{value}, nil
108 | }
109 |
--------------------------------------------------------------------------------
/internal/scripts/scripts.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package scripts
20 |
21 | import (
22 | "bytes"
23 | "encoding/json"
24 | "fmt"
25 |
26 | "github.com/onflow/cadence"
27 | jsoncdc "github.com/onflow/cadence/encoding/json"
28 | "github.com/spf13/cobra"
29 |
30 | "github.com/onflow/flow-cli/internal/util"
31 | )
32 |
33 | var Cmd = &cobra.Command{
34 | Use: "scripts",
35 | Short: "Execute Cadence scripts",
36 | TraverseChildren: true,
37 | GroupID: "interactions",
38 | }
39 |
40 | func init() {
41 | executeCommand.AddToParent(Cmd)
42 | }
43 |
44 | type scriptResult struct {
45 | cadence.Value
46 | }
47 |
48 | func NewScriptResult(value cadence.Value) *scriptResult {
49 | return &scriptResult{Value: value}
50 | }
51 |
52 | func (r *scriptResult) JSON() any {
53 | return json.RawMessage(
54 | jsoncdc.MustEncode(r.Value),
55 | )
56 | }
57 |
58 | func (r *scriptResult) String() string {
59 | var b bytes.Buffer
60 | writer := util.CreateTabWriter(&b)
61 |
62 | _, _ = fmt.Fprintf(writer, "Result: %s\n", r.Value)
63 |
64 | _ = writer.Flush()
65 |
66 | return b.String()
67 | }
68 |
69 | func (r *scriptResult) Oneliner() string {
70 | return r.Value.String()
71 | }
72 |
--------------------------------------------------------------------------------
/internal/scripts/scripts_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package scripts
20 |
21 | import (
22 | "fmt"
23 | "testing"
24 |
25 | "github.com/onflow/cadence"
26 | "github.com/stretchr/testify/assert"
27 | "github.com/stretchr/testify/mock"
28 |
29 | "github.com/onflow/flowkit/v2"
30 | "github.com/onflow/flowkit/v2/tests"
31 |
32 | "github.com/onflow/flow-cli/internal/command"
33 | "github.com/onflow/flow-cli/internal/util"
34 | )
35 |
36 | func Test_Execute(t *testing.T) {
37 | srv, _, rw := util.TestMocks(t)
38 |
39 | t.Run("Success", func(t *testing.T) {
40 | inArgs := []string{tests.ScriptArgString.Filename, "foo"}
41 |
42 | srv.ExecuteScript.Run(func(args mock.Arguments) {
43 | script := args.Get(1).(flowkit.Script)
44 | assert.Equal(t, fmt.Sprintf("\"%s\"", inArgs[1]), script.Args[0].String())
45 | assert.Equal(t, tests.ScriptArgString.Filename, script.Location)
46 | }).Return(cadence.NewInt(1), nil)
47 |
48 | result, err := execute(inArgs, command.GlobalFlags{}, util.NoLogger, rw, srv.Mock)
49 | assert.NotNil(t, result)
50 | assert.NoError(t, err)
51 | })
52 |
53 | t.Run("Fail non-existing file", func(t *testing.T) {
54 | inArgs := []string{"non-existing"}
55 | result, err := execute(inArgs, command.GlobalFlags{}, util.NoLogger, rw, srv.Mock)
56 | assert.Nil(t, result)
57 | assert.EqualError(t, err, "error loading script file: open non-existing: file does not exist")
58 | })
59 |
60 | t.Run("Fail parsing invalid JSON args", func(t *testing.T) {
61 | inArgs := []string{tests.TestScriptSimple.Filename}
62 | flags.ArgsJSON = "invalid"
63 |
64 | result, err := execute(inArgs, command.GlobalFlags{}, util.NoLogger, rw, srv.Mock)
65 | assert.Nil(t, result)
66 | assert.EqualError(t, err, "error parsing script arguments: invalid character 'i' looking for beginning of value")
67 | })
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/internal/settings/cmd.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package settings
20 |
21 | import (
22 | "github.com/spf13/cobra"
23 | )
24 |
25 | var Cmd = &cobra.Command{
26 | Use: "settings",
27 | Short: "Manage persisted global settings",
28 | TraverseChildren: true,
29 | }
30 |
31 | func init() {
32 | Cmd.AddCommand(metricsSettings)
33 | }
34 |
--------------------------------------------------------------------------------
/internal/settings/defaults.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package settings
20 |
21 | import (
22 | "fmt"
23 | "os/user"
24 | "runtime"
25 | )
26 |
27 | const (
28 | metricsEnabled = "MetricsEnabled"
29 | flowserPath = "FlowserPath"
30 | )
31 |
32 | // defaults holds the default values for global settings
33 | var defaults = map[string]any{
34 | metricsEnabled: true,
35 | flowserPath: getDefaultInstallDir(),
36 | }
37 |
38 | const (
39 | Darwin = "darwin"
40 | Windows = "windows"
41 | Linux = "linux"
42 | )
43 |
44 | // getDefaultInstallDir returns default installation directory based on the OS.
45 | func getDefaultInstallDir() string {
46 | switch runtime.GOOS {
47 | case Darwin:
48 | return "/Applications"
49 | case Windows:
50 | // https://superuser.com/questions/1327037/what-choices-do-i-have-about-where-to-install-software-on-windows-10
51 | usr, _ := user.Current() // safe to ignore cache errors
52 | return fmt.Sprintf(`%s\AppData\Local\Programs`, usr.HomeDir)
53 | case Linux:
54 | // https://unix.stackexchange.com/questions/127076/into-which-directory-should-i-install-programs-in-linux
55 | usr, _ := user.Current() // safe to ignore cache errors
56 | // Use path in users home folder to not require sudo permissions for installation
57 | return fmt.Sprintf(`%s/.local/bin`, usr.HomeDir)
58 | default:
59 | return ""
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/internal/settings/metrics.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package settings
20 |
21 | import (
22 | "fmt"
23 |
24 | "github.com/pkg/errors"
25 | "github.com/spf13/cobra"
26 | )
27 |
28 | const enable = "enable"
29 |
30 | const disable = "disable"
31 |
32 | var metricsSettings = &cobra.Command{
33 | Use: "metrics",
34 | Short: "Configure command usage metrics settings",
35 | Example: "flow settings metrics disable \nflow settings metrics enable",
36 | Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
37 | ValidArgs: []string{enable, disable},
38 | RunE: handleMetricsSettings,
39 | }
40 |
41 | // handleMetricsSettings sets global settings for metrics
42 | func handleMetricsSettings(
43 | _ *cobra.Command,
44 | args []string,
45 | ) error {
46 | enabled := args[0] == enable
47 | if err := Set(metricsEnabled, enabled); err != nil {
48 | return errors.Wrap(err, "failed to update metrics settings")
49 | }
50 |
51 | fmt.Println(fmt.Sprintf(
52 | "Command usage tracking is %sd. Settings were updated in %s \n",
53 | args[0],
54 | FileName()))
55 |
56 | return nil
57 | }
58 |
--------------------------------------------------------------------------------
/internal/settings/settings.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package settings
20 |
21 | import (
22 | "errors"
23 | "fmt"
24 | "os"
25 | "path/filepath"
26 |
27 | "github.com/spf13/viper"
28 | )
29 |
30 | const settingsFile = "flow-cli.settings"
31 |
32 | const settingsDir = "flow-cli"
33 |
34 | const settingsType = "yaml"
35 |
36 | // viperLoaded only load settings file once
37 | var viperLoaded = false
38 |
39 | func init() {
40 | viper.SetConfigName(settingsFile)
41 | viper.SetConfigType(settingsType)
42 | viper.AddConfigPath(FileDir())
43 | }
44 |
45 | func FileName() string {
46 | return fmt.Sprintf("%s.%s", settingsFile, settingsType)
47 | }
48 |
49 | func FileDir() string {
50 | dir, err := os.UserConfigDir()
51 | if err != nil {
52 | dir = "."
53 | }
54 | return filepath.Join(dir, settingsDir)
55 | }
56 |
57 | // Set updates settings file with new value for provided key
58 | func Set(key string, val any) error {
59 | if err := loadViper(); err != nil {
60 | return err
61 | }
62 |
63 | viper.Set(key, val)
64 | if err := viper.WriteConfig(); err != nil {
65 | return err
66 | }
67 |
68 | return nil
69 | }
70 |
71 | // loadViper loads the global settings file
72 | func loadViper() error {
73 | if viperLoaded {
74 | return nil
75 | }
76 | viperLoaded = true
77 |
78 | if err := createSettingsDir(); err != nil {
79 | return err
80 | }
81 |
82 | err := viper.MergeConfigMap(defaults)
83 | if err != nil {
84 | return err
85 | }
86 |
87 | // Load settings file
88 | if err := viper.MergeInConfig(); err != nil {
89 | switch err.(type) {
90 | case viper.ConfigFileNotFoundError:
91 | // Create settings file for the first time
92 | if err = viper.SafeWriteConfig(); err != nil {
93 | return err
94 | }
95 | default:
96 | return err
97 | }
98 | }
99 |
100 | return nil
101 | }
102 |
103 | // createSettingsDir creates settings dir if it doesn't exist
104 | func createSettingsDir() error {
105 | if _, err := os.Stat(FileDir()); errors.Is(err, os.ErrNotExist) {
106 | err = os.Mkdir(FileDir(), os.ModePerm)
107 | if err != nil {
108 | return err
109 | }
110 | }
111 | return nil
112 | }
113 |
114 | // GetFlowserPath gets set Flowser install path with sensible default.
115 | func GetFlowserPath() (string, error) {
116 | if err := loadViper(); err != nil {
117 | return "", err
118 | }
119 | return viper.GetString(flowserPath), nil
120 | }
121 |
122 | func SetFlowserPath(path string) error {
123 | return Set(flowserPath, path)
124 | }
125 |
126 | // MetricsEnabled checks whether metric tracking is enabled.
127 | func MetricsEnabled() bool {
128 | if err := loadViper(); err != nil {
129 | return true
130 | }
131 | return viper.GetBool(metricsEnabled)
132 | }
133 |
--------------------------------------------------------------------------------
/internal/signatures/generate.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package signatures
20 |
21 | import (
22 | "bytes"
23 | "context"
24 | "fmt"
25 |
26 | "github.com/onflow/flowkit/v2/accounts"
27 |
28 | "github.com/spf13/cobra"
29 |
30 | "github.com/onflow/flowkit/v2"
31 | "github.com/onflow/flowkit/v2/output"
32 |
33 | "github.com/onflow/flow-cli/internal/command"
34 | "github.com/onflow/flow-cli/internal/util"
35 | )
36 |
37 | type flagsGenerate struct {
38 | Signer string `default:"emulator-account" flag:"signer" info:"name of the account used to sign"`
39 | }
40 |
41 | var generateFlags = flagsGenerate{}
42 |
43 | var generateCommand = &command.Command{
44 | Cmd: &cobra.Command{
45 | Use: "generate ",
46 | Short: "Generate the message signature",
47 | Example: "flow signatures generate 'The quick brown fox jumps over the lazy dog' --signer alice",
48 | Args: cobra.ExactArgs(1),
49 | },
50 | Flags: &generateFlags,
51 | RunS: sign,
52 | }
53 |
54 | func sign(
55 | args []string,
56 | _ command.GlobalFlags,
57 | _ output.Logger,
58 | _ flowkit.Services,
59 | state *flowkit.State,
60 | ) (command.Result, error) {
61 | message := []byte(args[0])
62 | accountName := generateFlags.Signer
63 | acc, err := state.Accounts().ByName(accountName)
64 | if err != nil {
65 | return nil, err
66 | }
67 |
68 | s, err := acc.Key.Signer(context.Background())
69 | if err != nil {
70 | return nil, err
71 | }
72 |
73 | signed, err := s.Sign(message)
74 | if err != nil {
75 | return nil, err
76 | }
77 |
78 | return &signatureResult{
79 | result: string(signed),
80 | message: string(message),
81 | key: acc.Key,
82 | }, nil
83 | }
84 |
85 | type signatureResult struct {
86 | result string
87 | message string
88 | key accounts.Key
89 | }
90 |
91 | func (s *signatureResult) pubKey() string {
92 | pkey, err := s.key.PrivateKey()
93 | if err == nil {
94 | return (*pkey).PublicKey().String()
95 | }
96 |
97 | return "ERR"
98 | }
99 |
100 | func (s *signatureResult) JSON() any {
101 | return map[string]string{
102 | "signature": fmt.Sprintf("%x", s.result),
103 | "message": s.message,
104 | "hashAlgo": s.key.HashAlgo().String(),
105 | "sigAlgo": s.key.SigAlgo().String(),
106 | "pubKey": s.pubKey(),
107 | }
108 | }
109 |
110 | func (s *signatureResult) String() string {
111 | var b bytes.Buffer
112 | writer := util.CreateTabWriter(&b)
113 |
114 | _, _ = fmt.Fprintf(writer, "Signature \t %x\n", s.result)
115 | _, _ = fmt.Fprintf(writer, "Message \t %s\n", s.message)
116 | _, _ = fmt.Fprintf(writer, "Public Key \t %s\n", s.pubKey())
117 | _, _ = fmt.Fprintf(writer, "Hash Algorithm \t %s\n", s.key.HashAlgo())
118 | _, _ = fmt.Fprintf(writer, "Signature Algorithm \t %s\n", s.key.SigAlgo())
119 |
120 | _ = writer.Flush()
121 | return b.String()
122 | }
123 |
124 | func (s *signatureResult) Oneliner() string {
125 |
126 | return fmt.Sprintf(
127 | "signature: %x, message: %s, hashAlgo: %s, sigAlgo: %s, pubKey: %s",
128 | s.result, s.message, s.key.HashAlgo(), s.key.SigAlgo(), s.pubKey(),
129 | )
130 | }
131 |
--------------------------------------------------------------------------------
/internal/signatures/signatures.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package signatures
20 |
21 | import (
22 | "github.com/spf13/cobra"
23 | )
24 |
25 | var Cmd = &cobra.Command{
26 | Use: "signatures",
27 | Short: "Signature verification and creation",
28 | TraverseChildren: true,
29 | GroupID: "security",
30 | }
31 |
32 | func init() {
33 | generateCommand.AddToParent(Cmd)
34 | verifyCommand.AddToParent(Cmd)
35 | }
36 |
--------------------------------------------------------------------------------
/internal/signatures/signatures_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package signatures
20 |
21 | import (
22 | "testing"
23 |
24 | "github.com/stretchr/testify/assert"
25 |
26 | "github.com/onflow/flow-cli/internal/command"
27 | "github.com/onflow/flow-cli/internal/util"
28 | )
29 |
30 | func Test_Verify(t *testing.T) {
31 | srv, state, _ := util.TestMocks(t)
32 |
33 | t.Run("Success", func(t *testing.T) {
34 | inArgs := []string{
35 | "test signature",
36 | "f80f6007dbe6795bcf343e5586d40d0ba26a6c1d7edda5653cbdb377c9c20034cdbf899bb20fa2388d4993f6c88b5c97cbe05963d6d9799e6868902c2c14bc22",
37 | "0xab70e9e341a38861fd7f9fb1cda4c560465cfeb3ce4abcd2be552550c85ebbef9a2a9cac731c6bfa73b10c701c93038f0c18253487d4962d3bc6d5291f9c5eae",
38 | }
39 |
40 | result, err := verify(inArgs, command.GlobalFlags{}, util.NoLogger, srv.Mock, state)
41 | assert.NoError(t, err)
42 | assert.NotNil(t, result)
43 | })
44 |
45 | t.Run("Invalid signature", func(t *testing.T) {
46 | inArgsTests := []struct {
47 | args []string
48 | err string
49 | }{{
50 | args: []string{"invalid", "invalid"},
51 | err: "invalid message signature: encoding/hex: invalid byte: U+0069 'i'",
52 | }, {
53 | args: []string{"invalid", "0xaaaa", "invalid"},
54 | err: "invalid public key: encoding/hex: invalid byte: U+0069 'i'",
55 | }, {
56 | args: []string{"invalid", "0xaaaa", "0x1234"},
57 | err: "invalid public key: input has incorrect ECDSA_P256 key size, got 2, expects 64",
58 | }}
59 |
60 | for _, test := range inArgsTests {
61 | result, err := verify(test.args, command.GlobalFlags{}, util.NoLogger, srv.Mock, state)
62 | assert.EqualError(t, err, test.err)
63 | assert.Nil(t, result)
64 | }
65 | })
66 |
67 | }
68 |
69 | func Test_Sign(t *testing.T) {
70 | srv, state, _ := util.TestMocks(t)
71 |
72 | t.Run("Success", func(t *testing.T) {
73 | inArgs := []string{"test message"}
74 |
75 | result, err := sign(inArgs, command.GlobalFlags{}, util.NoLogger, srv.Mock, state)
76 | assert.NoError(t, err)
77 | assert.NotNil(t, result)
78 | })
79 |
80 | t.Run("Fail unknown signer", func(t *testing.T) {
81 | inArgs := []string{"test message"}
82 | generateFlags.Signer = "invalid"
83 | result, err := sign(inArgs, command.GlobalFlags{}, util.NoLogger, srv.Mock, state)
84 | assert.EqualError(t, err, "could not find account with name invalid in the configuration")
85 | assert.Nil(t, result)
86 | })
87 | }
88 |
--------------------------------------------------------------------------------
/internal/snapshot/save.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package snapshot
20 |
21 | import (
22 | "context"
23 | "fmt"
24 | "path/filepath"
25 |
26 | "github.com/spf13/cobra"
27 |
28 | "github.com/onflow/flowkit/v2"
29 | "github.com/onflow/flowkit/v2/output"
30 |
31 | "github.com/onflow/flow-cli/internal/command"
32 | )
33 |
34 | var saveCommand = &command.Command{
35 | Cmd: &cobra.Command{
36 | Use: "save",
37 | Short: "Get the latest finalized protocol snapshot",
38 | Example: "flow snapshot save /tmp/snapshot.json",
39 | Args: cobra.ExactArgs(1),
40 | },
41 | Flags: &struct{}{},
42 | Run: save,
43 | }
44 |
45 | func save(
46 | args []string,
47 | _ command.GlobalFlags,
48 | logger output.Logger,
49 | writer flowkit.ReaderWriter,
50 | flow flowkit.Services,
51 | ) (command.Result, error) {
52 | fileName := args[0]
53 |
54 | logger.StartProgress("Downloading protocol snapshot...")
55 | defer logger.StopProgress()
56 | if !flow.Gateway().SecureConnection() {
57 | logger.Info(fmt.Sprintf("%s warning: using insecure client connection to download snapshot, you should use a secure network configuration...", output.WarningEmoji()))
58 | }
59 | ctx := context.Background()
60 | snapshotBytes, err := flow.Gateway().GetLatestProtocolStateSnapshot(ctx)
61 | if err != nil {
62 | return nil, fmt.Errorf("failed to get latest finalized protocol snapshot from gateway: %w", err)
63 | }
64 |
65 | logger.StopProgress()
66 |
67 | outputPath, err := filepath.Abs(fileName)
68 | if err != nil {
69 | return nil, fmt.Errorf("failed to get absolute output path for protocol snapshot")
70 | }
71 |
72 | err = writer.WriteFile(outputPath, snapshotBytes, 0644)
73 | if err != nil {
74 | return nil, fmt.Errorf("failed to write protocol snapshot file to %s: %w", outputPath, err)
75 | }
76 |
77 | return &saveResult{OutputPath: outputPath}, nil
78 | }
79 |
--------------------------------------------------------------------------------
/internal/snapshot/snapshot.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package snapshot
20 |
21 | import (
22 | "fmt"
23 |
24 | "github.com/spf13/cobra"
25 | )
26 |
27 | var Cmd = &cobra.Command{
28 | Use: "snapshot",
29 | Short: "Retrieve the protocol state snapshot",
30 | TraverseChildren: true,
31 | }
32 |
33 | func init() {
34 | saveCommand.AddToParent(Cmd)
35 | }
36 |
37 | // saveResult represents the result of the snapshot save command.
38 | type saveResult struct {
39 | OutputPath string
40 | }
41 |
42 | func (r *saveResult) JSON() any {
43 | return map[string]string{"path": r.OutputPath}
44 | }
45 |
46 | func (r *saveResult) String() string {
47 | return fmt.Sprintf("snapshot saved: %s", r.OutputPath)
48 | }
49 |
50 | func (r *saveResult) Oneliner() string {
51 | return fmt.Sprintf("snapshot saved: %s", r.OutputPath)
52 | }
53 |
--------------------------------------------------------------------------------
/internal/status/status.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package status
20 |
21 | import (
22 | "bytes"
23 | "fmt"
24 |
25 | "github.com/spf13/cobra"
26 |
27 | "github.com/onflow/flowkit/v2"
28 | "github.com/onflow/flowkit/v2/output"
29 |
30 | "github.com/onflow/flow-cli/internal/command"
31 | "github.com/onflow/flow-cli/internal/util"
32 | )
33 |
34 | type flagsStatus struct {
35 | }
36 |
37 | var statusFlags = flagsStatus{}
38 |
39 | var Command = &command.Command{
40 | Cmd: &cobra.Command{
41 | Use: "status",
42 | Short: "Display the status of the Flow network",
43 | },
44 | Flags: &statusFlags,
45 | RunS: status,
46 | }
47 |
48 | func status(
49 | _ []string,
50 | _ command.GlobalFlags,
51 | _ output.Logger,
52 | flow flowkit.Services,
53 | _ *flowkit.State,
54 | ) (command.Result, error) {
55 | err := flow.Ping()
56 |
57 | return &result{
58 | network: flow.Network().Name,
59 | accessNode: flow.Network().Host,
60 | err: err,
61 | }, nil
62 | }
63 |
64 | type result struct {
65 | network string
66 | accessNode string
67 | err error
68 | }
69 |
70 | // getStatus returns string representation for Flow network status.
71 | func (r *result) getStatus() string {
72 | if r.err == nil {
73 | return "ONLINE"
74 | }
75 |
76 | return "OFFLINE"
77 | }
78 |
79 | // getColoredStatus returns colored string representation for Flow network status.
80 | func (r *result) getColoredStatus() string {
81 | if r.err == nil {
82 | return output.Green(r.getStatus())
83 | }
84 |
85 | return output.Red(output.Red(r.getStatus()))
86 | }
87 |
88 | // getIcon returns emoji icon representing Flow network status.
89 | func (r *result) getIcon() string {
90 | if r.err == nil {
91 | return output.GoEmoji()
92 | }
93 |
94 | return output.StopEmoji()
95 | }
96 |
97 | // String converts result to a string.
98 | func (r *result) String() string {
99 | var b bytes.Buffer
100 | writer := util.CreateTabWriter(&b)
101 |
102 | _, _ = fmt.Fprintf(writer, "Status:\t %s %s\n", r.getIcon(), r.getColoredStatus())
103 | _, _ = fmt.Fprintf(writer, "Network:\t %s\n", r.network)
104 | _, _ = fmt.Fprintf(writer, "Access Node:\t %s\n", r.accessNode)
105 |
106 | _ = writer.Flush()
107 | return b.String()
108 | }
109 |
110 | // JSON converts result to a JSON.
111 | func (r *result) JSON() any {
112 | result := make(map[string]string)
113 |
114 | result["network"] = r.network
115 | result["accessNode"] = r.accessNode
116 | result["status"] = r.getStatus()
117 |
118 | return result
119 | }
120 |
121 | // Oneliner returns result as one liner grep friendly.
122 | func (r *result) Oneliner() string {
123 | return r.getStatus()
124 | }
125 |
--------------------------------------------------------------------------------
/internal/super/dev.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package super
20 |
21 | import (
22 | "errors"
23 | "fmt"
24 | "os"
25 | "strings"
26 |
27 | "github.com/onflow/cadence/parser"
28 | "github.com/onflow/flowkit/v2"
29 | "github.com/onflow/flowkit/v2/output"
30 | "github.com/spf13/cobra"
31 |
32 | "github.com/onflow/flow-cli/internal/command"
33 | )
34 |
35 | type flagsDev struct{}
36 |
37 | var devFlags = flagsDev{}
38 |
39 | var DevCommand = &command.Command{
40 | Cmd: &cobra.Command{
41 | Use: "dev",
42 | Short: "Build your Flow project",
43 | Args: cobra.ExactArgs(0),
44 | Example: "flow dev",
45 | GroupID: "super",
46 | Deprecated: "The 'dev' command is deprecated and will be removed in a future release.",
47 | },
48 | Flags: &devFlags,
49 | RunS: dev,
50 | }
51 |
52 | func dev(
53 | _ []string,
54 | _ command.GlobalFlags,
55 | logger output.Logger,
56 | flow flowkit.Services,
57 | state *flowkit.State,
58 | ) (command.Result, error) {
59 | dir, err := os.Getwd()
60 | if err != nil {
61 | return nil, err
62 | }
63 |
64 | err = flow.Ping()
65 | if err != nil {
66 | logger.Error("Error connecting to emulator. Make sure you started an emulator using 'flow emulator' command.")
67 | logger.Info(fmt.Sprintf("%s This tool requires emulator to function. Emulator needs to be run inside the project root folder where the configuration file ('flow.json') exists.\n\n", output.TryEmoji()))
68 | return nil, nil
69 | }
70 |
71 | serviceAccount, err := state.EmulatorServiceAccount()
72 | if err != nil {
73 | return nil, err
74 | }
75 |
76 | flow.SetLogger(output.NewStdoutLogger(output.NoneLog))
77 |
78 | project, err := newProject(
79 | *serviceAccount,
80 | flow,
81 | state,
82 | newProjectFiles(dir),
83 | )
84 | if err != nil {
85 | fmt.Printf("%s Failed to run the command, please make sure you ran 'flow setup' command first and that you are running this command inside the project ROOT folder.\n\n", output.TryEmoji())
86 | return nil, err
87 | }
88 |
89 | err = project.startup()
90 | if err != nil {
91 | if strings.Contains(err.Error(), "does not have a valid signature") {
92 | fmt.Printf("%s Failed to run the command, please make sure you started the emulator inside the project ROOT folder by running 'flow emulator'.\n\n", output.TryEmoji())
93 | return nil, nil
94 | }
95 |
96 | var parseErr parser.Error
97 | if errors.As(err, &parseErr) {
98 | fmt.Println(err) // we just print the error but keep watching files for changes, since they might fix the issue
99 | } else {
100 | return nil, err
101 | }
102 | }
103 |
104 | err = project.watch()
105 | if err != nil {
106 | return nil, err
107 | }
108 |
109 | return nil, nil
110 | }
111 |
--------------------------------------------------------------------------------
/internal/super/files_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package super
20 |
21 | import (
22 | "fmt"
23 | "path/filepath"
24 | "testing"
25 |
26 | "github.com/stretchr/testify/assert"
27 | )
28 |
29 | func Test_AccountFromPath(t *testing.T) {
30 | paths := [][]string{ // first is path, second is account name
31 | {"cadence/contracts/alice/foo.cdc", "alice"},
32 | {"cadence/contracts/alice", "alice"},
33 | {"cadence/contracts/alice/boo/foo.cdc", ""},
34 | {"cadence/contracts/foo.cdc", ""},
35 | {"cadence/contracts/foo/bar/goo/foo", ""},
36 | }
37 |
38 | for i, test := range paths {
39 | name, ok := accountFromPath(filepath.FromSlash(test[0]))
40 | assert.Equal(t, test[1] != "", ok) // if we don't provide a name we mean it shouldn't be returned
41 | assert.Equal(t, test[1], name, fmt.Sprintf("failed test %d", i))
42 | }
43 | }
44 |
45 | func Test_RelativeProjectPath(t *testing.T) {
46 | cdcDir := "/Users/Mike/Dev/my-project/cadence"
47 | paths := [][]string{
48 | {filepath.Join(cdcDir, "/contracts/foo.cdc"), "cadence/contracts/foo.cdc"},
49 | {filepath.Join(cdcDir, "/contracts/alice/foo.cdc"), "cadence/contracts/alice/foo.cdc"},
50 | {filepath.Join(cdcDir, "/scripts/bar.cdc"), "cadence/scripts/bar.cdc"},
51 | {filepath.Join(cdcDir, "/bar.cdc"), "cadence/bar.cdc"},
52 | }
53 |
54 | f := &projectFiles{
55 | cadencePath: cdcDir,
56 | }
57 |
58 | for i, test := range paths {
59 | rel, err := f.relProjectPath(filepath.FromSlash(test[0]))
60 | assert.NoError(t, err)
61 | assert.Equal(t, filepath.FromSlash(test[1]), rel, fmt.Sprintf("test %d failed", i))
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/internal/super/generator/contract_template.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package generator
20 |
21 | import (
22 | "fmt"
23 | "maps"
24 | "path/filepath"
25 |
26 | flowsdk "github.com/onflow/flow-go-sdk"
27 | "github.com/onflow/flowkit/v2"
28 | "github.com/onflow/flowkit/v2/config"
29 |
30 | "github.com/onflow/flow-cli/internal/util"
31 | )
32 |
33 | const (
34 | DefaultContractDirectory = "contracts"
35 | DefaultTestAddress = "0x0000000000000007"
36 | )
37 |
38 | // Contract contains properties for contracts
39 | type ContractTemplate struct {
40 | Name string
41 | Account string
42 | TemplatePath string
43 | Data map[string]interface{}
44 | SkipTests bool
45 | SaveState bool
46 | }
47 |
48 | var _ TemplateItem = ContractTemplate{}
49 | var _ TemplateItemWithStateUpdate = ContractTemplate{}
50 | var _ TemplateItemWithChildren = ContractTemplate{}
51 |
52 | func (c ContractTemplate) GetType() string {
53 | return "contract"
54 | }
55 |
56 | func (c ContractTemplate) GetTemplatePath() string {
57 | if c.TemplatePath == "" {
58 | return "contract_init.cdc.tmpl"
59 | }
60 |
61 | return c.TemplatePath
62 | }
63 |
64 | func (c ContractTemplate) GetData() map[string]interface{} {
65 | data := map[string]interface{}{
66 | "Name": c.Name,
67 | }
68 | maps.Copy(data, c.Data)
69 | return data
70 | }
71 |
72 | func (c ContractTemplate) GetTargetPath() string {
73 | return filepath.Join(DefaultCadenceDirectory, DefaultContractDirectory, c.Account, util.AddCDCExtension(c.Name))
74 | }
75 |
76 | func (c ContractTemplate) UpdateState(state *flowkit.State) error {
77 | var aliases config.Aliases
78 |
79 | if c.SkipTests != true {
80 | aliases = config.Aliases{{
81 | Network: config.TestingNetwork.Name,
82 | Address: flowsdk.HexToAddress(DefaultTestAddress),
83 | }}
84 | }
85 |
86 | contract := config.Contract{
87 | Name: c.Name,
88 | Location: c.GetTargetPath(),
89 | Aliases: aliases,
90 | }
91 |
92 | state.Contracts().AddOrUpdate(contract)
93 |
94 | if c.SaveState {
95 | err := state.SaveDefault() // TODO: Support adding a target project directory
96 | if err != nil {
97 | return fmt.Errorf("error saving to flow.json: %w", err)
98 | }
99 | }
100 |
101 | return nil
102 | }
103 |
104 | func (c ContractTemplate) GetChildren() []TemplateItem {
105 | if c.SkipTests {
106 | return []TemplateItem{}
107 | }
108 |
109 | return []TemplateItem{
110 | TestTemplate{
111 | Name: c.Name,
112 | TemplatePath: "contract_init_test.cdc.tmpl",
113 | Data: map[string]interface{}{
114 | "ContractName": c.Name,
115 | },
116 | },
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/internal/super/generator/file_template.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package generator
20 |
21 | import (
22 | "github.com/onflow/flowkit/v2"
23 | )
24 |
25 | // FileTemplate is a template for raw
26 | type FileTemplate struct {
27 | TemplatePath string
28 | TargetPath string
29 | Data map[string]interface{}
30 | }
31 |
32 | func NewFileTemplate(
33 | templatePath string,
34 | targetPath string,
35 | data map[string]interface{},
36 | ) FileTemplate {
37 | return FileTemplate{
38 | TemplatePath: templatePath,
39 | TargetPath: targetPath,
40 | Data: data,
41 | }
42 | }
43 |
44 | var _ TemplateItem = FileTemplate{}
45 |
46 | // GetType returns the type of the contract
47 | func (c FileTemplate) GetType() string {
48 | return "file"
49 | }
50 |
51 | func (c FileTemplate) GetTemplatePath() string {
52 | return c.TemplatePath
53 | }
54 |
55 | // GetData returns the data of the contract
56 | func (c FileTemplate) GetData() map[string]interface{} {
57 | return c.Data
58 | }
59 |
60 | func (c FileTemplate) GetTargetPath() string {
61 | return c.TargetPath
62 | }
63 |
64 | func (c FileTemplate) UpdateState(state *flowkit.State) error {
65 | return nil
66 | }
67 |
--------------------------------------------------------------------------------
/internal/super/generator/script_template.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package generator
20 |
21 | import (
22 | "path/filepath"
23 |
24 | "github.com/onflow/flow-cli/internal/util"
25 | )
26 |
27 | const (
28 | DefaultScriptDirectory = "scripts"
29 | )
30 |
31 | type ScriptTemplate struct {
32 | Name string
33 | TemplatePath string
34 | Data map[string]interface{}
35 | }
36 |
37 | var _ TemplateItem = ScriptTemplate{}
38 |
39 | func (o ScriptTemplate) GetType() string {
40 | return "script"
41 | }
42 |
43 | func (o ScriptTemplate) GetTemplatePath() string {
44 | if o.TemplatePath == "" {
45 | return "script_init.cdc.tmpl"
46 | }
47 |
48 | return o.TemplatePath
49 | }
50 |
51 | func (o ScriptTemplate) GetData() map[string]interface{} {
52 | return o.Data
53 | }
54 |
55 | func (o ScriptTemplate) GetTargetPath() string {
56 | return filepath.Join(DefaultCadenceDirectory, DefaultScriptDirectory, util.AddCDCExtension(o.Name))
57 | }
58 |
--------------------------------------------------------------------------------
/internal/super/generator/templates/contract_counter.cdc.tmpl:
--------------------------------------------------------------------------------
1 | access(all) contract {{ .Name }} {
2 |
3 | access(all) var count: Int
4 |
5 | // Event to be emitted when the counter is incremented
6 | access(all) event CounterIncremented(newCount: Int)
7 |
8 | // Event to be emitted when the counter is decremented
9 | access(all) event CounterDecremented(newCount: Int)
10 |
11 | init() {
12 | self.count = 0
13 | }
14 |
15 | // Public function to increment the counter
16 | access(all) fun increment() {
17 | self.count = self.count + 1
18 | emit CounterIncremented(newCount: self.count)
19 | }
20 |
21 | // Public function to decrement the counter
22 | access(all) fun decrement() {
23 | self.count = self.count - 1
24 | emit CounterDecremented(newCount: self.count)
25 | }
26 |
27 | // Public function to get the current count
28 | view access(all) fun getCount(): Int {
29 | return self.count
30 | }
31 | }
--------------------------------------------------------------------------------
/internal/super/generator/templates/contract_init.cdc.tmpl:
--------------------------------------------------------------------------------
1 | access(all)
2 | contract {{ .Name }} {
3 | init() {}
4 | }
--------------------------------------------------------------------------------
/internal/super/generator/templates/contract_init_test.cdc.tmpl:
--------------------------------------------------------------------------------
1 | import Test
2 |
3 | access(all) let account = Test.createAccount()
4 |
5 | access(all) fun testContract() {
6 | let err = Test.deployContract(
7 | name: "{{ .ContractName }}",
8 | path: "../contracts/{{ .ContractName }}.cdc",
9 | arguments: [],
10 | )
11 |
12 | Test.expect(err, Test.beNil())
13 | }
--------------------------------------------------------------------------------
/internal/super/generator/templates/empty_test.cdc.tmpl:
--------------------------------------------------------------------------------
1 | import Test
2 |
3 | access(all) let account = Test.createAccount()
4 |
5 | access(all) fun testExample() {
6 | // Test something
7 | Test.expect(true, true)
8 | }
--------------------------------------------------------------------------------
/internal/super/generator/templates/script_counter.cdc.tmpl:
--------------------------------------------------------------------------------
1 | import "{{ .ContractName }}"
2 |
3 | access(all)
4 | fun main(): Int {
5 | return {{ .ContractName }}.getCount()
6 | }
7 |
--------------------------------------------------------------------------------
/internal/super/generator/templates/script_init.cdc.tmpl:
--------------------------------------------------------------------------------
1 | access(all)
2 | fun main() {
3 | // Script details here
4 | }
--------------------------------------------------------------------------------
/internal/super/generator/templates/transaction_counter.cdc.tmpl:
--------------------------------------------------------------------------------
1 | import "{{ .ContractName }}"
2 |
3 | transaction {
4 |
5 | prepare(acct: &Account) {
6 | // Authorizes the transaction
7 | }
8 |
9 | execute {
10 | // Increment the counter
11 | Counter.increment()
12 |
13 | // Retrieve the new count and log it
14 | let newCount = Counter.getCount()
15 | log("New count after incrementing: ".concat(newCount.toString()))
16 | }
17 | }
--------------------------------------------------------------------------------
/internal/super/generator/templates/transaction_init.cdc.tmpl:
--------------------------------------------------------------------------------
1 | transaction() {
2 | prepare(account: &Account) {}
3 |
4 | execute {}
5 | }
--------------------------------------------------------------------------------
/internal/super/generator/test_template.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package generator
20 |
21 | import (
22 | "path/filepath"
23 |
24 | "github.com/onflow/flow-cli/internal/util"
25 | )
26 |
27 | const (
28 | DefaultTestDirectory = "tests"
29 | )
30 |
31 | type TestTemplate struct {
32 | Name string
33 | TemplatePath string
34 | Data map[string]interface{}
35 | }
36 |
37 | var _ TemplateItem = TestTemplate{}
38 |
39 | func (t TestTemplate) GetType() string {
40 | return "test"
41 | }
42 |
43 | // GetTemplatePath returns an empty string for scripts and transactions
44 | func (t TestTemplate) GetTemplatePath() string {
45 | if t.TemplatePath == "" {
46 | return "empty_test.cdc.tmpl"
47 | }
48 |
49 | return t.TemplatePath
50 | }
51 |
52 | // GetData returns the data of the script or transaction
53 | func (t TestTemplate) GetData() map[string]interface{} {
54 | return t.Data
55 | }
56 |
57 | func (t TestTemplate) GetTargetPath() string {
58 | baseName := t.Name + "_test"
59 | return filepath.Join(DefaultCadenceDirectory, DefaultTestDirectory, util.AddCDCExtension(baseName))
60 | }
61 |
--------------------------------------------------------------------------------
/internal/super/generator/transaction_template.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package generator
20 |
21 | import (
22 | "path/filepath"
23 |
24 | "github.com/onflow/flow-cli/internal/util"
25 | )
26 |
27 | const (
28 | DefaultTransactionDirectory = "transactions"
29 | )
30 |
31 | // TransactionTemplate contains only a name property for scripts and transactions
32 | type TransactionTemplate struct {
33 | Name string
34 | TemplatePath string
35 | Data map[string]interface{}
36 | }
37 |
38 | var _ TemplateItem = TransactionTemplate{}
39 |
40 | func (o TransactionTemplate) GetType() string {
41 | return "transaction"
42 | }
43 |
44 | // GetTemplatePath returns an empty string for scripts and transactions
45 | func (o TransactionTemplate) GetTemplatePath() string {
46 | if o.TemplatePath == "" {
47 | return "transaction_init.cdc.tmpl"
48 | }
49 |
50 | return o.TemplatePath
51 | }
52 |
53 | // GetData returns the data of the script or transaction
54 | func (o TransactionTemplate) GetData() map[string]interface{} {
55 | return o.Data
56 | }
57 |
58 | func (o TransactionTemplate) GetTargetPath() string {
59 | return filepath.Join(DefaultCadenceDirectory, DefaultTransactionDirectory, util.AddCDCExtension(o.Name))
60 | }
61 |
--------------------------------------------------------------------------------
/internal/tools/flowser.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package tools
20 |
21 | import (
22 | "fmt"
23 | "os"
24 | "runtime"
25 |
26 | "github.com/onflow/flow-cli/internal/prompt"
27 |
28 | "github.com/onflowser/flowser/v3/pkg/flowser"
29 | "github.com/spf13/cobra"
30 |
31 | "github.com/onflow/flowkit/v2"
32 | "github.com/onflow/flowkit/v2/config"
33 | "github.com/onflow/flowkit/v2/output"
34 |
35 | "github.com/onflow/flow-cli/internal/command"
36 | "github.com/onflow/flow-cli/internal/settings"
37 | )
38 |
39 | type flagsFlowser struct{}
40 |
41 | var flowserFlags = flagsWallet{}
42 |
43 | var Flowser = &command.Command{
44 | Cmd: &cobra.Command{
45 | Use: "flowser",
46 | Short: "Run Flowser project explorer",
47 | Example: "flow flowser",
48 | Args: cobra.ExactArgs(0),
49 | GroupID: "tools",
50 | },
51 | Flags: &flowserFlags,
52 | Run: runFlowser,
53 | }
54 |
55 | func runFlowser(
56 | _ []string,
57 | _ command.GlobalFlags,
58 | _ output.Logger,
59 | reader flowkit.ReaderWriter,
60 | _ flowkit.Services,
61 | ) (command.Result, error) {
62 | flowser := flowser.New()
63 |
64 | installPath, err := settings.GetFlowserPath()
65 | if err != nil {
66 | return nil, fmt.Errorf("failure reading setting: %w", err)
67 | }
68 |
69 | if !flowser.Installed(installPath) {
70 | installPath, err = installFlowser(flowser, installPath)
71 | if err != nil {
72 | return nil, err
73 | }
74 | }
75 |
76 | projectPath, err := os.Getwd()
77 | if err != nil {
78 | return nil, err
79 | }
80 |
81 | // check if current directory is existing flow project if not then don't pass project path to Flowser, so user can choose a project
82 | _, err = reader.ReadFile(config.DefaultPath)
83 | if os.IsNotExist(err) {
84 | projectPath = ""
85 | }
86 |
87 | fmt.Printf("%s Starting up Flowser, please wait...\n", output.SuccessEmoji())
88 | err = flowser.Run(installPath, projectPath)
89 | if err != nil {
90 | return nil, err
91 | }
92 |
93 | return nil, nil
94 | }
95 |
96 | func installFlowser(flowser *flowser.App, installPath string) (string, error) {
97 | fmt.Println("It looks like Flowser is not yet installed on your system.")
98 | installChoice := prompt.InstallPrompt()
99 | if installChoice == prompt.CancelInstall {
100 | return "", fmt.Errorf("user denied install")
101 | }
102 |
103 | // if user says it already installed it we only ask for path and return it
104 | if installChoice == prompt.AlreadyInstalled {
105 | installPath = prompt.InstallPathPrompt(installPath)
106 | _ = settings.SetFlowserPath(installPath)
107 | return installPath, nil
108 | }
109 |
110 | // MacOS apps must always be installed inside Application folder
111 | if runtime.GOOS != settings.Darwin {
112 | installPath = prompt.InstallPathPrompt(installPath)
113 | _ = settings.SetFlowserPath(installPath)
114 | }
115 |
116 | logger := output.NewStdoutLogger(output.InfoLog)
117 | logger.StartProgress(fmt.Sprintf("%s Installing Flowser, this may take few minutes, please wait ", output.TryEmoji()))
118 | defer logger.StopProgress()
119 |
120 | // create all folders if they don't exist, does nothing if they exist
121 | err := os.MkdirAll(installPath, os.ModePerm)
122 | if err != nil {
123 | return "", err
124 | }
125 |
126 | err = flowser.Install(installPath)
127 | if err != nil {
128 | return "", fmt.Errorf("could not install Flowser: %w", err)
129 | }
130 |
131 | return installPath, nil
132 | }
133 |
--------------------------------------------------------------------------------
/internal/tools/wallet.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package tools
20 |
21 | import (
22 | "fmt"
23 | "strings"
24 |
25 | devWallet "github.com/onflow/fcl-dev-wallet/go/wallet"
26 | "github.com/spf13/cobra"
27 |
28 | "github.com/onflow/flowkit/v2"
29 | "github.com/onflow/flowkit/v2/output"
30 |
31 | "github.com/onflow/flow-cli/internal/command"
32 | )
33 |
34 | type flagsWallet struct {
35 | Port uint `default:"8701" flag:"port" info:"Dev wallet port to listen on"`
36 | Host string `default:"http://localhost:8888" flag:"emulator-host" info:"Host for access node connection"`
37 | }
38 |
39 | var walletFlags = flagsWallet{}
40 |
41 | var DevWallet = &command.Command{
42 | Cmd: &cobra.Command{
43 | Use: "dev-wallet",
44 | Short: "Run a development wallet",
45 | Example: "flow dev-wallet",
46 | Args: cobra.ExactArgs(0),
47 | GroupID: "tools",
48 | },
49 | Flags: &walletFlags,
50 | RunS: wallet,
51 | }
52 |
53 | func wallet(
54 | _ []string,
55 | _ command.GlobalFlags,
56 | _ output.Logger,
57 | _ flowkit.Services,
58 | state *flowkit.State,
59 | ) (command.Result, error) {
60 | service, err := state.EmulatorServiceAccount()
61 | if err != nil {
62 | return nil, err
63 | }
64 |
65 | privateKey, err := service.Key.PrivateKey()
66 | if err != nil {
67 | return nil, err
68 | }
69 |
70 | conf := devWallet.FlowConfig{
71 | Address: fmt.Sprintf("0x%s", service.Address.String()),
72 | PrivateKey: strings.TrimPrefix((*privateKey).String(), "0x"),
73 | PublicKey: strings.TrimPrefix((*privateKey).PublicKey().String(), "0x"),
74 | AccessNode: walletFlags.Host,
75 | }
76 |
77 | srv, err := devWallet.NewHTTPServer(walletFlags.Port, &conf)
78 | if err != nil {
79 | return nil, err
80 | }
81 |
82 | fmt.Printf("%s Starting dev wallet server on port %d\n", output.SuccessEmoji(), walletFlags.Port)
83 | fmt.Printf("%s Make sure the emulator is running\n", output.WarningEmoji())
84 |
85 | srv.Start()
86 | return nil, nil
87 | }
88 |
--------------------------------------------------------------------------------
/internal/transactions/decode.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package transactions
20 |
21 | import (
22 | "fmt"
23 |
24 | "github.com/onflow/flowkit/v2/transactions"
25 |
26 | "github.com/spf13/cobra"
27 |
28 | "github.com/onflow/flowkit/v2"
29 | "github.com/onflow/flowkit/v2/output"
30 |
31 | "github.com/onflow/flow-cli/internal/command"
32 | )
33 |
34 | type flagsDecode struct {
35 | Include []string `default:"" flag:"include" info:"Fields to include in the output. Valid values: signatures, code, payload."`
36 | }
37 |
38 | var decodeFlags = flagsDecode{}
39 |
40 | var decodeCommand = &command.Command{
41 | Cmd: &cobra.Command{
42 | Use: "decode ",
43 | Short: "Decode a transaction",
44 | Example: "flow transactions decode ./transaction.rlp",
45 | Args: cobra.ExactArgs(1),
46 | },
47 | Flags: &decodeFlags,
48 | Run: decode,
49 | }
50 |
51 | func decode(
52 | args []string,
53 | _ command.GlobalFlags,
54 | _ output.Logger,
55 | reader flowkit.ReaderWriter,
56 | _ flowkit.Services,
57 | ) (command.Result, error) {
58 | filename := args[0]
59 | payload, err := reader.ReadFile(filename)
60 | if err != nil {
61 | return nil, fmt.Errorf("failed to read transaction from %s: %v", filename, err)
62 | }
63 |
64 | tx, err := transactions.NewFromPayload(payload)
65 | if err != nil {
66 | return nil, err
67 | }
68 |
69 | return &transactionResult{
70 | tx: tx.FlowTransaction(),
71 | include: decodeFlags.Include,
72 | }, nil
73 | }
74 |
--------------------------------------------------------------------------------
/internal/transactions/get-system.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package transactions
20 |
21 | import (
22 | "context"
23 |
24 | "github.com/spf13/cobra"
25 |
26 | "github.com/onflow/flowkit/v2"
27 | "github.com/onflow/flowkit/v2/output"
28 |
29 | "github.com/onflow/flow-cli/internal/command"
30 | )
31 |
32 | type flagsGetSystem struct {
33 | Include []string `default:"" flag:"include" info:"Fields to include in the output. Valid values: signatures, code, payload, fee-events."`
34 | Exclude []string `default:"" flag:"exclude" info:"Fields to exclude from the output. Valid values: events."`
35 | }
36 |
37 | var getSystemFlags = flagsGetSystem{}
38 |
39 | var getSystemCommand = &command.Command{
40 | Cmd: &cobra.Command{
41 | Use: "get-system ",
42 | Short: "Get the system transaction by block info",
43 | Example: "flow transactions get-system a1b2c3...",
44 | Args: cobra.ExactArgs(1),
45 | },
46 | Flags: &getSystemFlags,
47 | Run: getSystemTransaction,
48 | }
49 |
50 | func getSystemTransaction(
51 | args []string,
52 | _ command.GlobalFlags,
53 | logger output.Logger,
54 | _ flowkit.ReaderWriter,
55 | flow flowkit.Services,
56 | ) (command.Result, error) {
57 | query, err := flowkit.NewBlockQuery(args[0])
58 | if err != nil {
59 | return nil, err
60 | }
61 |
62 | logger.StartProgress("Fetching Block...")
63 | defer logger.StopProgress()
64 | block, err := flow.GetBlock(context.Background(), query)
65 | if err != nil {
66 | return nil, err
67 | }
68 |
69 | tx, result, err := flow.GetSystemTransaction(context.Background(), block.ID)
70 | if err != nil {
71 | return nil, err
72 | }
73 |
74 | return &transactionResult{
75 | result: result,
76 | tx: tx,
77 | include: getSystemFlags.Include,
78 | exclude: getSystemFlags.Exclude,
79 | }, nil
80 | }
81 |
--------------------------------------------------------------------------------
/internal/transactions/get.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package transactions
20 |
21 | import (
22 | "context"
23 | "strings"
24 |
25 | flowsdk "github.com/onflow/flow-go-sdk"
26 | "github.com/spf13/cobra"
27 |
28 | "github.com/onflow/flowkit/v2"
29 | "github.com/onflow/flowkit/v2/output"
30 |
31 | "github.com/onflow/flow-cli/internal/command"
32 | )
33 |
34 | type flagsGet struct {
35 | Sealed bool `default:"true" flag:"sealed" info:"Wait for a sealed result"`
36 | Include []string `default:"" flag:"include" info:"Fields to include in the output. Valid values: signatures, code, payload, fee-events."`
37 | Exclude []string `default:"" flag:"exclude" info:"Fields to exclude from the output. Valid values: events."`
38 | }
39 |
40 | var getFlags = flagsGet{}
41 |
42 | var getCommand = &command.Command{
43 | Cmd: &cobra.Command{
44 | Use: "get ",
45 | Aliases: []string{"status"},
46 | Short: "Get the transaction by ID",
47 | Example: "flow transactions get 07a8...b433",
48 | Args: cobra.ExactArgs(1),
49 | },
50 | Flags: &getFlags,
51 | Run: get,
52 | }
53 |
54 | func get(
55 | args []string,
56 | _ command.GlobalFlags,
57 | _ output.Logger,
58 | _ flowkit.ReaderWriter,
59 | flow flowkit.Services,
60 | ) (command.Result, error) {
61 | id := flowsdk.HexToID(strings.TrimPrefix(args[0], "0x"))
62 |
63 | tx, result, err := flow.GetTransactionByID(context.Background(), id, getFlags.Sealed)
64 | if err != nil {
65 | return nil, err
66 | }
67 |
68 | return &transactionResult{
69 | result: result,
70 | tx: tx,
71 | include: getFlags.Include,
72 | exclude: getFlags.Exclude,
73 | }, nil
74 | }
75 |
--------------------------------------------------------------------------------
/internal/transactions/send-signed.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package transactions
20 |
21 | import (
22 | "context"
23 | "fmt"
24 |
25 | "github.com/onflow/flow-cli/internal/prompt"
26 |
27 | "github.com/onflow/flowkit/v2/transactions"
28 |
29 | "github.com/spf13/cobra"
30 |
31 | "github.com/onflow/flowkit/v2"
32 | "github.com/onflow/flowkit/v2/output"
33 |
34 | "github.com/onflow/flow-cli/internal/command"
35 | )
36 |
37 | type flagsSendSigned struct {
38 | Include []string `default:"" flag:"include" info:"Fields to include in the output. Valid values: signatures, code, payload."`
39 | Exclude []string `default:"" flag:"exclude" info:"Fields to exclude from the output (events)"`
40 | }
41 |
42 | var sendSignedFlags = flagsSendSigned{}
43 |
44 | var sendSignedCommand = &command.Command{
45 | Cmd: &cobra.Command{
46 | Use: "send-signed ",
47 | Short: "Send signed transaction",
48 | Args: cobra.ExactArgs(1),
49 | Example: `flow transactions send-signed signed.rlp`,
50 | },
51 | Flags: &sendSignedFlags,
52 | Run: sendSigned,
53 | }
54 |
55 | func sendSigned(
56 | args []string,
57 | globalFlags command.GlobalFlags,
58 | logger output.Logger,
59 | reader flowkit.ReaderWriter,
60 | flow flowkit.Services,
61 | ) (command.Result, error) {
62 | filename := args[0]
63 |
64 | code, err := reader.ReadFile(filename)
65 | if err != nil {
66 | return nil, fmt.Errorf("error loading transaction payload: %w", err)
67 | }
68 |
69 | tx, err := transactions.NewFromPayload(code)
70 | if err != nil {
71 | return nil, err
72 | }
73 |
74 | if !globalFlags.Yes && !prompt.ApproveTransactionForSendingPrompt(tx.FlowTransaction()) {
75 | return nil, fmt.Errorf("transaction was not approved for sending")
76 | }
77 |
78 | logger.StartProgress(fmt.Sprintf("Sending transaction with ID: %s", tx.FlowTransaction().ID()))
79 | defer logger.StopProgress()
80 |
81 | sentTx, result, err := flow.SendSignedTransaction(context.Background(), tx)
82 | if err != nil {
83 | return nil, err
84 | }
85 |
86 | return &transactionResult{
87 | result: result,
88 | tx: sentTx,
89 | include: sendSignedFlags.Include,
90 | exclude: sendSignedFlags.Exclude,
91 | }, nil
92 | }
93 |
--------------------------------------------------------------------------------
/internal/util/emoji.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package util
20 |
21 | import (
22 | "fmt"
23 | "runtime"
24 | )
25 |
26 | func PrintEmoji(emoji string) string {
27 | if runtime.GOOS == "windows" {
28 | return ""
29 | }
30 |
31 | return emoji
32 | }
33 |
34 | func MessageWithEmojiPrefix(emoji string, message string) string {
35 | return fmt.Sprintf("%s%s", PrintEmoji(emoji+" "), message)
36 | }
37 |
--------------------------------------------------------------------------------
/internal/util/files.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package util
20 |
21 | import (
22 | "fmt"
23 | "path/filepath"
24 | "strings"
25 | )
26 |
27 | func AddCDCExtension(name string) string {
28 | if strings.HasSuffix(name, ".cdc") {
29 | return name
30 | }
31 | return fmt.Sprintf("%s.cdc", name)
32 | }
33 |
34 | func StripCDCExtension(name string) string {
35 | return strings.TrimSuffix(name, filepath.Ext(name))
36 | }
37 |
--------------------------------------------------------------------------------
/internal/util/test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package util
20 |
21 | import (
22 | "testing"
23 |
24 | "github.com/onflow/flow-go-sdk/crypto"
25 | "github.com/onflow/flowkit/v2/accounts"
26 |
27 | "github.com/onflow/flow-go-sdk"
28 | "github.com/stretchr/testify/require"
29 |
30 | "github.com/onflow/flowkit/v2"
31 | "github.com/onflow/flowkit/v2/mocks"
32 | "github.com/onflow/flowkit/v2/output"
33 | "github.com/onflow/flowkit/v2/tests"
34 | )
35 |
36 | var NoLogger = output.NewStdoutLogger(output.NoneLog)
37 |
38 | var TestID = flow.HexToID("24993fc99f81641c45c0afa307e683b4f08d407d90041aa9439f487acb33d633")
39 |
40 | // TestMocks creates mock flowkit services, an empty state and a mock reader writer
41 | func TestMocks(t *testing.T) (*mocks.MockServices, *flowkit.State, flowkit.ReaderWriter) {
42 | services := mocks.DefaultMockServices()
43 | rw, _ := tests.ReaderWriter()
44 | state, err := flowkit.Init(rw)
45 | require.NoError(t, err)
46 |
47 | emulatorAccount, _ := accounts.NewEmulatorAccount(rw, crypto.ECDSA_P256, crypto.SHA3_256, "")
48 | state.Accounts().AddOrUpdate(emulatorAccount)
49 |
50 | return services, state, rw
51 | }
52 |
--------------------------------------------------------------------------------
/internal/version/version.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Flow CLI
3 | *
4 | * Copyright Flow Foundation
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package version
20 |
21 | import (
22 | "encoding/json"
23 | "fmt"
24 | "runtime/debug"
25 | "strings"
26 |
27 | "github.com/spf13/cobra"
28 |
29 | "github.com/onflow/flow-cli/build"
30 | "github.com/onflow/flow-cli/internal/command"
31 | )
32 |
33 | var verboseFlag bool
34 |
35 | func init() {
36 | Cmd.Flags().BoolVarP(&verboseFlag, "verbose", "v", false, "Show detailed dependency information")
37 | }
38 |
39 | type versionCmd struct {
40 | Version string
41 | Dependencies []debug.Module
42 | }
43 |
44 | // Print prints the version information in the given format.
45 | func (c versionCmd) Print(format string) error {
46 | switch format {
47 | case command.FormatInline, command.FormatText:
48 | var txtBuilder strings.Builder
49 | txtBuilder.WriteString(fmt.Sprintf("Version: %s\n", c.Version))
50 |
51 | if verboseFlag {
52 | txtBuilder.WriteString("\nFlow Package Dependencies \n")
53 | for _, dep := range c.Dependencies {
54 | txtBuilder.WriteString(fmt.Sprintf("%s %s\n", dep.Path, dep.Version))
55 | }
56 | }
57 |
58 | fmt.Println(txtBuilder.String())
59 |
60 | return nil
61 |
62 | case command.FormatJSON:
63 | jsonRes, err := c.MarshalJSON()
64 | if err != nil {
65 | return err
66 | }
67 |
68 | fmt.Println(string(jsonRes))
69 |
70 | return nil
71 |
72 | default:
73 | return fmt.Errorf("unsupported format: %s", format)
74 | }
75 | }
76 |
77 | // MarshalJSON returns the JSON encoding of the cmdPrint.
78 | func (c *versionCmd) MarshalJSON() ([]byte, error) {
79 | js := struct {
80 | Version string `json:"version"`
81 | Dependencies []struct {
82 | Package string `json:"package"`
83 | Version string `json:"version"`
84 | } `json:"dependencies"`
85 | }{
86 | Version: c.Version,
87 | }
88 |
89 | for _, dep := range c.Dependencies {
90 | js.Dependencies = append(js.Dependencies, struct {
91 | Package string `json:"package"`
92 | Version string `json:"version"`
93 | }{
94 | Package: dep.Path,
95 | Version: dep.Version,
96 | })
97 | }
98 |
99 | return json.Marshal(js)
100 | }
101 |
102 | var Cmd = &cobra.Command{
103 | Use: "version",
104 | Short: "View version information",
105 | RunE: func(cmd *cobra.Command, args []string) error {
106 | semver := build.Semver()
107 |
108 | v := &versionCmd{
109 | Version: semver,
110 | }
111 |
112 | bi, ok := debug.ReadBuildInfo()
113 | if !ok {
114 | return fmt.Errorf("failed to read build info")
115 | }
116 |
117 | // only add dependencies from github.com/onflow
118 | for _, dep := range bi.Deps {
119 | if strings.Contains(dep.Path, "github.com/onflow/") {
120 | v.Dependencies = append(v.Dependencies, *dep)
121 | }
122 | }
123 |
124 | if err := v.Print(command.Flags.Format); err != nil {
125 | return err
126 | }
127 |
128 | return nil
129 | },
130 | }
131 |
--------------------------------------------------------------------------------
/scaffolds.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "name": "FCL Web Dapp",
4 | "repo": "https://github.com/chasefleming/fcl-next-scaffold.git",
5 | "description": "Simple TypeScript web application using next.js, FCL, and Cadence.",
6 | "commit": "7a2b4347471f96d02d90c80ca8c76148d9ce1a70",
7 | "type": "web"
8 | },
9 | {
10 | "name": "Simple Cadence Project",
11 | "repo": "https://github.com/sideninja/flow-basic-scaffold.git",
12 | "description": "Scaffold contains required folder structure as well as some example Cadence code.",
13 | "commit": "8065287e55bc298d776665bef98a577ceb4a226c"
14 | },
15 | {
16 | "name": "Cadence NFT Project",
17 | "repo": "https://github.com/nvdtf/flow-nft-scaffold.git",
18 | "description": "Scaffold contains the ExampleNFT sample NFT contract.",
19 | "commit": "ef9437c05549e3f581cf619dec9d59d8c7f6e3ec"
20 | }
21 | ]
22 |
--------------------------------------------------------------------------------
/version.txt:
--------------------------------------------------------------------------------
1 | v1.18.0
2 |
--------------------------------------------------------------------------------