├── .cz.toml ├── .github ├── DISCUSSION_TEMPLATE │ └── milestone.yml ├── ISSUE_TEMPLATE │ ├── bug.yml │ ├── config.yml │ └── to-do.md ├── PULL_REQUEST_TEMPLATE.md ├── deploy │ ├── bootstrap.sh │ ├── config.yml │ └── devbox.json ├── pr-labeler.yml ├── scopes.json └── workflows │ ├── check-pr.yml │ └── merge-group.yml ├── .gitignore ├── .goreleaser.yaml ├── .taskfiles └── Default.yml ├── .trunk ├── .gitignore ├── configs │ ├── .golangci.yaml │ ├── .hadolint.yaml │ ├── .markdownlint.yaml │ ├── .rustfmt.toml │ ├── .shellcheckrc │ └── .yamllint.yaml └── trunk.yaml ├── CHANGELOG.md ├── CLAUDE.md ├── CONVENTIONS.md ├── Dockerfile ├── Makefile ├── README.md ├── api ├── did │ ├── module │ │ └── v1 │ │ │ └── module.pulsar.go │ └── v1 │ │ ├── genesis.pulsar.go │ │ ├── query.pulsar.go │ │ ├── query_grpc.pb.go │ │ ├── state.cosmos_orm.go │ │ ├── state.pulsar.go │ │ ├── tx.pulsar.go │ │ └── tx_grpc.pb.go ├── dwn │ ├── module │ │ └── v1 │ │ │ └── module.pulsar.go │ └── v1 │ │ ├── genesis.pulsar.go │ │ ├── query.pulsar.go │ │ ├── query_grpc.pb.go │ │ ├── state.cosmos_orm.go │ │ ├── state.pulsar.go │ │ ├── tx.pulsar.go │ │ └── tx_grpc.pb.go └── svc │ ├── module │ └── v1 │ │ └── module.pulsar.go │ └── v1 │ ├── genesis.pulsar.go │ ├── query.pulsar.go │ ├── query_grpc.pb.go │ ├── state.cosmos_orm.go │ ├── state.pulsar.go │ ├── tx.pulsar.go │ └── tx_grpc.pb.go ├── app ├── ante.go ├── app.go ├── app_test.go ├── decorators │ ├── msg_filter_template.go │ ├── msg_filter_test.go │ └── setup.go ├── encoding.go ├── export.go ├── genesis.go ├── params │ ├── doc.go │ ├── encoding.go │ └── proto.go ├── sim_test.go ├── test_helpers.go ├── test_support.go ├── upgrades.go └── upgrades │ ├── noop │ └── upgrades.go │ └── types.go ├── buf.work.yaml ├── cmd ├── commands.go ├── root.go └── testnet.go ├── devbox.json ├── devbox.lock ├── go.mod ├── go.sum ├── internal ├── accounts │ ├── api_builder.go │ ├── context.go │ ├── encoding.go │ ├── implementation.go │ ├── interface.go │ └── protoaccount.go ├── address │ ├── bip32.go │ └── codec.go ├── appmodule │ └── environment.go ├── branch │ └── branch.go ├── didcrypto │ ├── crypto.go │ ├── did.go │ └── did_test.go ├── ipfsnode │ ├── config.go │ └── ipfsnode.go ├── log │ └── logger.go ├── prefixstore │ └── prefixstore.go ├── router │ └── service.go └── transaction │ ├── service.go │ └── transaction.go ├── main.go ├── proto ├── README.md ├── buf.gen.gogo.yaml ├── buf.gen.pulsar.yaml ├── buf.lock ├── buf.yaml ├── did │ ├── module │ │ └── v1 │ │ │ └── module.proto │ └── v1 │ │ ├── genesis.proto │ │ ├── query.proto │ │ ├── state.proto │ │ └── tx.proto ├── dwn │ ├── module │ │ └── v1 │ │ │ └── module.proto │ └── v1 │ │ ├── genesis.proto │ │ ├── query.proto │ │ ├── state.proto │ │ └── tx.proto └── svc │ ├── module │ └── v1 │ │ └── module.proto │ └── v1 │ ├── genesis.proto │ ├── query.proto │ ├── state.proto │ └── tx.proto ├── scripts ├── install.sh ├── json_to_pkl.sh ├── protocgen.sh ├── test_ics_node.sh ├── test_node.sh └── validate_tag.sh └── x ├── did ├── README.md ├── autocli.go ├── depinject.go ├── keeper │ ├── genesis.go │ ├── genesis_test.go │ ├── keeper.go │ ├── keeper_test.go │ ├── querier.go │ └── rpc.go ├── module.go └── types │ ├── accounts.go │ ├── address.go │ ├── codec.go │ ├── errors.go │ ├── format.go │ ├── genesis.go │ ├── genesis.pb.go │ ├── genesis_test.go │ ├── msgs.go │ ├── params.go │ ├── pubkey.go │ ├── query.pb.go │ ├── query.pb.gw.go │ ├── signer.go │ ├── state.pb.go │ └── tx.pb.go ├── dwn ├── README.md ├── autocli.go ├── client │ └── cli │ │ ├── query.go │ │ └── tx.go ├── depinject.go ├── keeper │ ├── genesis_test.go │ ├── keeper.go │ ├── keeper_test.go │ ├── msg_server.go │ ├── msg_server_test.go │ └── query_server.go ├── module.go └── types │ ├── attns.go │ ├── codec.go │ ├── embed │ ├── codec.go │ ├── index.html │ ├── main.js │ ├── sw.js │ ├── utils.go │ └── webworker.go │ ├── genesis.go │ ├── genesis.pb.go │ ├── genesis_test.go │ ├── keys.go │ ├── msgs.go │ ├── params.go │ ├── query.pb.go │ ├── query.pb.gw.go │ ├── state.pb.go │ └── tx.pb.go └── svc ├── README.md ├── autocli.go ├── client └── cli │ ├── query.go │ └── tx.go ├── depinject.go ├── keeper ├── genesis_test.go ├── keeper.go ├── keeper_test.go ├── msg_server.go ├── msg_server_test.go └── query_server.go ├── module.go └── types ├── codec.go ├── genesis.go ├── genesis.pb.go ├── genesis_test.go ├── keys.go ├── msgs.go ├── params.go ├── query.pb.go ├── query.pb.gw.go ├── state.pb.go └── tx.pb.go /.cz.toml: -------------------------------------------------------------------------------- 1 | [tool.commitizen] 2 | name = "cz_conventional_commits" 3 | tag_format = "v$version" 4 | version_scheme = "semver" 5 | version_provider = "scm" 6 | update_changelog_on_bump = true 7 | major_version_zero = true 8 | -------------------------------------------------------------------------------- /.github/DISCUSSION_TEMPLATE/milestone.yml: -------------------------------------------------------------------------------- 1 | title: "[Milestone] " 2 | labels: ["#OKR", "#PLANNING"] 3 | body: 4 | - type: input 5 | id: has-version 6 | attributes: 7 | label: Version 8 | description: A tag for the associated milestone. 9 | placeholder: v0.6.0 10 | validations: 11 | required: true 12 | - type: textarea 13 | attributes: 14 | label: Objective 15 | description: Explain the objective of the OKR in less than 100 characters. 16 | placeholder: Ethereum IBC integration with Sonr. 17 | render: markdown 18 | validations: 19 | required: true 20 | - type: textarea 21 | attributes: 22 | label: Task List 23 | description: | 24 | Break down the objective into a list of tasks to be completed. 25 | value: | 26 | - [ ] # 27 | - [ ] # 28 | - [ ] # 29 | validations: 30 | required: true 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: File a bug report. 3 | title: "ERROR: " 4 | labels: ["#BUG", "#HELP"] 5 | projects: ["onsonr/39"] 6 | body: 7 | - type: textarea 8 | attributes: 9 | label: Operating System 10 | description: What operating system are you using? 11 | placeholder: "Example: macOS Big Sur" 12 | value: operating system 13 | validations: 14 | required: true 15 | - type: dropdown 16 | attributes: 17 | label: Network 18 | description: What network are you using? 19 | multiple: false 20 | options: 21 | - LocalNet 22 | - TestNet 23 | - MainNet 24 | default: 0 25 | validations: 26 | required: true 27 | - type: checkboxes 28 | attributes: 29 | label: Code of Conduct 30 | description: 31 | The Code of Conduct helps create a safe space for everyone. We require 32 | that everyone agrees to it. 33 | options: 34 | - label: I agree to follow this project's [Code of Conduct](link/to/coc) 35 | required: true 36 | - type: markdown 37 | attributes: 38 | value: "Thanks for completing our form!" 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Community Discussions 4 | url: https://github.com/orgs/onsonr/discussions 5 | about: Please submit ideas and suggestions here. 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/to-do.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Default Todo 3 | about: Break down feature requirements into tasks. 4 | title: "Name of the new task" 5 | labels: 6 | - "#TODO" 7 | - "#OKR" 8 | assignees: "prnk28" 9 | projects: "onsonr/37" 10 | --- 11 | 12 | ### Description 13 | 14 | The expected deliverable of the task. 15 | 16 | ### Associated Files 17 | 18 | These files will be modified by this task. 19 | 20 | ### References 21 | 22 | Use these documents to help you complete the task. 23 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Description 4 | 5 | 6 | 7 | ## Related Issue(s) 8 | 9 | 10 | 11 | 12 | 13 | 14 | ## Motivation and Context 15 | 16 | 17 | 18 | 19 | ## How Has This Been Tested? 20 | 21 | 22 | 23 | 24 | 25 | ## Screenshots (if appropriate): 26 | -------------------------------------------------------------------------------- /.github/deploy/bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | # Ensure we're in the right directory 6 | ROOT_DIR=$(git rev-parse --show-toplevel) 7 | cd $ROOT_DIR 8 | 9 | DOPPLER_TOKEN=$(skate get DOPPLER_NETWORK) 10 | 11 | ACC0=$(doppler secrets get KEY0_NAME --plain --project sonr --config test) 12 | ACC1=$(doppler secrets get KEY1_NAME --plain --project sonr --config test) 13 | MNEM0=$(doppler secrets get KEY0_MNEMONIC --plain --project sonr --config test) 14 | MNEM1=$(doppler secrets get KEY1_MNEMONIC --plain --project sonr --config test) 15 | CHAIN_ID=$(doppler secrets get CHAIN_ID --plain --project sonr --config test) 16 | TX_INDEX_INDEXER=$(doppler secrets get TX_INDEXER --plain --project sonr --config test) 17 | TX_INDEX_PSQL_CONN=$(doppler secrets get TX_PSQL_CONN --plain --project sonr --config test) 18 | 19 | # Run the node setup with all variables properly exported 20 | CLEAN=true KEY0_NAME=$ACC0 KEY0_MNEMONIC=$MNEM0 KEY1_NAME=$ACC1 KEY1_MNEMONIC=$MNEM1 CHAIN_ID=$CHAIN_ID TX_INDEX_INDEXER=$TX_INDEX_INDEXER TX_INDEX_PSQL_CONN=$TX_INDEX_PSQL_CONN sh ./start.sh 21 | 22 | -------------------------------------------------------------------------------- /.github/deploy/config.yml: -------------------------------------------------------------------------------- 1 | name: sonr-testnet 2 | version: 0.2.20 3 | 4 | chains: 5 | - id: sonr-1 6 | prettyName: Sonr 7 | name: custom 8 | image: ghcr.io/onsonr/sonr:latest 9 | home: /root/.sonr 10 | binary: sonrd 11 | prefix: idx 12 | denom: usnr 13 | hdPath: m/44'/118'/0'/0/0 14 | coinType: 118 15 | coins: 100000000000000usnr,100000000000000snr 16 | repo: https://github.com/sonr-io/snrd 17 | numValidators: 1 18 | ports: 19 | rest: 1317 20 | rpc: 26657 21 | faucet: 8001 22 | 23 | - id: osmosis-1 24 | name: osmosis 25 | numValidators: 1 26 | ports: 27 | rest: 1313 28 | rpc: 26653 29 | faucet: 8003 30 | 31 | relayers: 32 | - name: hermes-osmo-atom-sonr 33 | type: hermes 34 | image: ghcr.io/cosmology-tech/starship/hermes:1.10.0 35 | replicas: 1 36 | chains: 37 | - osmosis-1 38 | - sonr-1 39 | 40 | registry: 41 | enabled: true 42 | image: ghcr.io/cosmology-tech/starship/registry:20230614-7173db2 43 | resources: 44 | cpu: 0.5 45 | memory: 200M 46 | -------------------------------------------------------------------------------- /.github/deploy/devbox.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/jetify-com/devbox/0.13.7/.schema/devbox.schema.json", 3 | "packages": [ 4 | "go@latest", 5 | "cargo@latest", 6 | "uv@latest", 7 | "bun@latest", 8 | "yarn@latest", 9 | "doppler@latest" 10 | ], 11 | "env": { 12 | "PATH": "$HOME/.cargo/bin:$HOME/go/bin:$HOME/.local/bin:$HOME/.bun/bin:$PATH", 13 | "GITHUB_TOKEN": "$GITHUB_TOKEN", 14 | "GOPATH": "$HOME/go", 15 | "GOBIN": "$GOPATH/bin", 16 | "GHQ_ROOT": "$CLONEDIR" 17 | }, 18 | "shell": { 19 | "init_hook": [], 20 | "scripts": { 21 | "up": ["yarn starship start --config config.yaml"], 22 | "down": ["yarn starship stop --config config.yaml"] 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.github/pr-labeler.yml: -------------------------------------------------------------------------------- 1 | "feature": ["feature/*", "feat/*"] 2 | "bugfix": fix/* 3 | "enhancement": enhancement/* 4 | -------------------------------------------------------------------------------- /.github/workflows/check-pr.yml: -------------------------------------------------------------------------------- 1 | name: Check PR 2 | 3 | on: 4 | pull_request: 5 | merge_group: 6 | 7 | permissions: 8 | contents: read # for TimonVS/pr-labeler-action to read config file 9 | pull-requests: write # for TimonVS/pr-labeler-action to add labels in PR 10 | 11 | jobs: 12 | verify-pr: 13 | name: Test Lints 14 | if: github.event_name == 'pull_request' 15 | permissions: 16 | contents: read # for TimonVS/pr-labeler-action to read config file 17 | pull-requests: write # for TimonVS/pr-labeler-action to add labels in PR 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v4 21 | with: 22 | fetch-depth: 0 # Required to fetch all history for merging 23 | - uses: TimonVS/pr-labeler-action@v5 24 | with: 25 | repo-token: ${{ secrets.GITHUB_TOKEN }} 26 | configuration-path: .github/pr-labeler.yml # optional, .github/pr-labeler.yml is the default value 27 | - name: Trunk Check 28 | uses: trunk-io/trunk-action@v1 29 | 30 | test-builds: 31 | if: github.event_name == 'pull_request' 32 | runs-on: ubuntu-latest 33 | name: Test Builds 34 | steps: 35 | - name: Checkout repository 36 | uses: actions/checkout@v4 37 | with: 38 | fetch-depth: 0 39 | fetch-tags: true 40 | 41 | - uses: actions/setup-go@v5 42 | with: 43 | go-version: "1.24" 44 | check-latest: true 45 | - name: Run Sonrd Build 46 | run: make build 47 | 48 | test-unit: 49 | if: github.event_name == 'pull_request' 50 | runs-on: ubuntu-latest 51 | name: Test Unit 52 | steps: 53 | - name: Checkout repository 54 | uses: actions/checkout@v4 55 | with: 56 | fetch-depth: 0 57 | fetch-tags: true 58 | 59 | - uses: actions/setup-go@v5 60 | with: 61 | go-version: "1.24" 62 | check-latest: true 63 | - run: make test-unit 64 | -------------------------------------------------------------------------------- /.github/workflows/merge-group.yml: -------------------------------------------------------------------------------- 1 | name: Merge Group 2 | 3 | on: 4 | merge_group: 5 | 6 | permissions: 7 | contents: read # for TimonVS/pr-labeler-action to read config file 8 | pull-requests: write # for TimonVS/pr-labeler-action to add labels in PR 9 | 10 | jobs: 11 | test-race: 12 | runs-on: ubuntu-latest 13 | if: github.event_name == 'merge_group' 14 | name: Test Race 15 | continue-on-error: true 16 | steps: 17 | - name: Checkout repository 18 | uses: actions/checkout@v4 19 | with: 20 | fetch-depth: 0 21 | fetch-tags: true 22 | - name: Install devbox 23 | uses: jetify-com/devbox-install-action@v0.12.0 24 | - run: make test-race 25 | 26 | test-cover: 27 | runs-on: ubuntu-latest 28 | if: github.event_name == 'merge_group' 29 | name: Test Coverage 30 | steps: 31 | - name: Checkout repository 32 | uses: actions/checkout@v4 33 | with: 34 | repository: onsonr/sonr 35 | fetch-depth: 0 36 | fetch-tags: true 37 | 38 | - uses: actions/setup-go@v5 39 | with: 40 | go-version: "1.23" 41 | check-latest: true 42 | - run: make test-cover 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.aiderscript 2 | 3 | # Aider related generated files 4 | .aider-context 5 | bin 6 | .env 7 | 8 | # Binaries 9 | .task 10 | no 11 | .data 12 | schemas 13 | *.db 14 | tools-stamp 15 | *.exe 16 | *.exe~ 17 | *.dll 18 | *.so 19 | *.dylib 20 | *.app 21 | .DS_Store 22 | .session.vim 23 | aof* 24 | dist 25 | **/.haptic 26 | static 27 | pkg/webapp/dist 28 | .agent 29 | 30 | # Test binary 31 | *.test 32 | .devon* 33 | **/.DS_Store 34 | .task 35 | .wrangler 36 | 37 | # Output of the go coverage tool 38 | *.out 39 | tmp 40 | # Exclude embedded files 41 | !internal/files/dist 42 | 43 | # Dependency directories 44 | node_modules/ 45 | 46 | # Go workspace file 47 | go.work 48 | go.work.sum 49 | 50 | # Environment files 51 | .env 52 | **/*.env 53 | **/sonr.log 54 | 55 | 56 | # Terraform 57 | **/.terraform/* 58 | .terraform 59 | *.tfstate 60 | *.tfstate.* 61 | crash.log 62 | crash.*.log 63 | *.tfvars 64 | *.tfvars.json 65 | override.tf 66 | override.tf.json 67 | *_override.tf 68 | *_override.tf.json 69 | 70 | .terraformrc 71 | terraform.rc 72 | flake.lock 73 | 74 | # Misc 75 | .DS_Store 76 | .tmp/ 77 | tmp/ 78 | **/*tmp*/ 79 | *.tmp 80 | *.log 81 | *.dot 82 | *.pem 83 | dist/ 84 | bin/ 85 | build/ 86 | .devbox 87 | .ignore 88 | .opencommitignore 89 | heighliner* 90 | sonr 91 | deploy/**/data 92 | x/.DS_Store 93 | .aider* 94 | buildenv* 95 | node_modules 96 | cmd/gateway/node_modules 97 | pkg/nebula/node_modules 98 | configs/logs.json 99 | 100 | mprocs.yaml 101 | build 102 | sonr.wiki 103 | 104 | !devbox.lock 105 | !buf.lock 106 | 107 | .air.toml 108 | mprocs.yaml 109 | mprocs.log 110 | tools-stamp 111 | sonr.log 112 | deploy/conf 113 | 114 | interchaintest-downloader 115 | .haptic 116 | -------------------------------------------------------------------------------- /.goreleaser.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://goreleaser.com/static/schema-pro.json 2 | version: 2 3 | project_name: sonr 4 | builds: 5 | - id: sonr 6 | binary: snrd 7 | mod_timestamp: "{{ .CommitTimestamp }}" 8 | goos: 9 | - linux 10 | - darwin 11 | goarch: 12 | - amd64 13 | - arm64 14 | goamd64: 15 | - v1 16 | flags: 17 | - -mod=readonly 18 | - -trimpath 19 | ldflags: 20 | - -X github.com/cosmos/cosmos-sdk/version.Name=sonr 21 | - -X github.com/cosmos/cosmos-sdk/version.AppName=snrd 22 | - -X github.com/cosmos/cosmos-sdk/version.Version={{.Version}} 23 | - -X github.com/cosmos/cosmos-sdk/version.Commit={{.Commit}} 24 | - -X "github.com/cosmos/cosmos-sdk/version.BuildTags=netgo,ledger" 25 | tags: 26 | - netgo 27 | - ledger 28 | 29 | archives: 30 | - id: sonr 31 | name_template: >- 32 | sonr_{{ .Os }}_{{- if eq .Arch "amd64" }}x86_64 33 | {{- else if eq .Arch "386" }}i386 34 | {{- else }}{{ .Arch }}{{ end }} 35 | formats: ["tar.gz"] 36 | files: 37 | - src: README* 38 | wrap_in_directory: true 39 | 40 | nfpms: 41 | - id: sonr 42 | package_name: snrd 43 | file_name_template: "sonr_{{ .Os }}_{{ .Arch }}{{ .ConventionalExtension }}" 44 | vendor: Sonr 45 | homepage: "https://sonr.io" 46 | maintainer: "Sonr " 47 | description: "Sonr is a decentralized, permissionless, and censorship-resistant identity network." 48 | license: "Apache 2.0" 49 | formats: 50 | - rpm 51 | - deb 52 | - apk 53 | dependencies: 54 | - ipfs 55 | contents: 56 | - src: README* 57 | dst: /usr/share/doc/snrd 58 | bindir: /usr/bin 59 | section: net 60 | priority: optional 61 | # Add these lines to match build config 62 | 63 | brews: 64 | - name: snrd 65 | ids: [sonr] 66 | commit_author: 67 | name: goreleaserbot 68 | email: bot@goreleaser.com 69 | directory: Formula 70 | caveats: "Run a local sonr node and access it with the hway proxy" 71 | homepage: "https://sonr.io" 72 | description: "Sonr is a decentralized, permissionless, and censorship-resistant identity network." 73 | dependencies: 74 | - name: ipfs 75 | repository: 76 | owner: sonr-io 77 | name: homebrew-tap 78 | branch: master 79 | token: "{{ .Env.GITHUB_PAT_TOKEN }}" 80 | 81 | release: 82 | github: 83 | owner: sonr-io 84 | name: snrd 85 | name_template: "{{ .Tag }}" 86 | draft: false 87 | replace_existing_draft: true 88 | replace_existing_artifacts: true 89 | extra_files: 90 | - glob: ./README* 91 | - glob: ./scripts/install.sh 92 | - glob: ./scripts/test_node.sh 93 | - glob: ./scripts/test_ics_node.sh 94 | 95 | announce: 96 | telegram: 97 | enabled: true 98 | chat_id: -1002222617755 99 | -------------------------------------------------------------------------------- /.taskfiles/Default.yml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://taskfile.dev/schema.json 2 | version: "3" 3 | silent: true 4 | dotenv: 5 | - .env 6 | 7 | vars: 8 | NEXT_PATCH_VERSION: 9 | sh: cz bump --get-next --increment PATCH 10 | NEXT_MINOR_VERSION: 11 | sh: cz bump --get-next --increment MINOR 12 | PROJECT_VERSION: 13 | sh: cz version -p 14 | MILESTONE: 15 | sh: gh milestone list --json title,number --jq ".[]" | rg 'v{{.NEXT_MINOR_VERSION}}' | jq -r ".number" 16 | MILESTONE_TITLE: 17 | sh: gh milestone list --json title,number --jq ".[]" | rg 'v{{.NEXT_MINOR_VERSION}}' | jq -r ".title" 18 | MILESTONE_PROGRESS: 19 | sh: gh milestone list --json title,progressPercentage --jq ".[]" | rg 'v{{.NEXT_MINOR_VERSION}}' | jq -r ".progressPercentage" 20 | 21 | tasks: 22 | default: 23 | cmds: 24 | - echo "{{.VERSION}}" 25 | - echo "{{.MILESTONE}}" 26 | - echo "{{.MILESTONE_TITLE}}" 27 | - echo "{{.MILESTONE_PROGRESS}}" 28 | - echo "{{.BUMP_INCREMENT}}" 29 | silent: true 30 | 31 | bump: 32 | dotenv: 33 | - .env 34 | preconditions: 35 | - sh: goreleaser check 36 | msg: goreleaser check failed 37 | - sh: git diff --exit-code 38 | msg: git state is dirty 39 | - sh: cz bump --dry-run --increment PATCH 40 | msg: cz bump test failed 41 | vars: 42 | BUMP_INCREMENT: 43 | sh: | 44 | if [ "{{.MILESTONE_PROGRESS}}" = "100" ]; then 45 | echo "MINOR" 46 | else 47 | echo "PATCH" 48 | fi 49 | cmds: 50 | - gum format "# [1/4] Bump Version" 51 | - cz bump --yes --increment {{.BUMP_INCREMENT}} --allow-no-commit 52 | - task: publish:buf 53 | - task: publish:docker 54 | - gum format "# [4/4] Run GoReleaser" 55 | - goreleaser release --clean 56 | 57 | publish:buf: 58 | internal: true 59 | dir: proto 60 | vars: 61 | VERSION: 62 | sh: cz version -p 63 | TAG: v{{.VERSION}} 64 | cmds: 65 | - gum format "# [2/4] Publish Protobuf Schemas" 66 | - buf build 67 | - buf push --label {{.TAG}} 68 | 69 | publish:docker: 70 | internal: true 71 | vars: 72 | VERSION: 73 | sh: cz version -p 74 | cmds: 75 | - gum format "# [3/4] Publish Docker Images" 76 | - gum spin --title "Running docker build..." -- docker build . -t onsonr/snrd:latest -t onsonr/snrd:{{.VERSION}} -t ghcr.io/sonr-io/snrd:latest -t ghcr.io/sonr-io/snrd:{{.VERSION}} 77 | - docker push ghcr.io/sonr-io/snrd:latest 78 | - docker push ghcr.io/sonr-io/snrd:{{.VERSION}} 79 | - docker push onsonr/snrd:latest 80 | - docker push onsonr/snrd:{{.VERSION}} 81 | -------------------------------------------------------------------------------- /.trunk/.gitignore: -------------------------------------------------------------------------------- 1 | *out 2 | *logs 3 | *actions 4 | *notifications 5 | *tools 6 | plugins 7 | user_trunk.yaml 8 | user.yaml 9 | tmp 10 | -------------------------------------------------------------------------------- /.trunk/configs/.golangci.yaml: -------------------------------------------------------------------------------- 1 | linters: 2 | disable: 3 | - unused # Disables unreachable code checking 4 | 5 | run: 6 | # Exclude test files from analysis 7 | tests: false 8 | 9 | # Define which files and directories to exclude 10 | issues: 11 | exclude-rules: 12 | # Exclude all test files 13 | - path: _test\.go 14 | linters: 15 | - all 16 | 17 | # Exclude specific directories 18 | exclude-dirs: 19 | - api/did/v1 20 | - api/dwn/v1 21 | - api/svc/v1 22 | - internal 23 | 24 | # Exclude specific file patterns 25 | exclude-files: 26 | - ".*\\.pb\\.go$" 27 | - ".*_templ\\.go$" 28 | -------------------------------------------------------------------------------- /.trunk/configs/.hadolint.yaml: -------------------------------------------------------------------------------- 1 | # Following source doesn't work in most setups 2 | ignored: 3 | - SC1090 4 | - SC1091 5 | -------------------------------------------------------------------------------- /.trunk/configs/.markdownlint.yaml: -------------------------------------------------------------------------------- 1 | # Prettier friendly markdownlint config (all formatting rules disabled) 2 | extends: markdownlint/style/prettier 3 | -------------------------------------------------------------------------------- /.trunk/configs/.rustfmt.toml: -------------------------------------------------------------------------------- 1 | edition = "2021" 2 | -------------------------------------------------------------------------------- /.trunk/configs/.shellcheckrc: -------------------------------------------------------------------------------- 1 | enable=all 2 | source-path=SCRIPTDIR 3 | disable=SC2154 4 | 5 | # If you're having issues with shellcheck following source, disable the errors via: 6 | # disable=SC1090 7 | # disable=SC1091 8 | -------------------------------------------------------------------------------- /.trunk/configs/.yamllint.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | quoted-strings: 3 | required: only-when-needed 4 | extra-allowed: ["{|}"] 5 | key-duplicates: {} 6 | octal-values: 7 | forbid-implicit-octal: true 8 | -------------------------------------------------------------------------------- /.trunk/trunk.yaml: -------------------------------------------------------------------------------- 1 | # This file controls the behavior of Trunk: https://docs.trunk.io/cli 2 | # To learn more about the format of this file, see https://docs.trunk.io/reference/trunk-yaml 3 | version: 0.1 4 | cli: 5 | version: 1.22.8 6 | # Trunk provides extensibility via plugins. (https://docs.trunk.io/plugins) 7 | plugins: 8 | sources: 9 | - id: trunk 10 | ref: v1.6.6 11 | uri: https://github.com/trunk-io/plugins 12 | # Many linters and tools depend on runtimes - configure them here. (https://docs.trunk.io/runtimes) 13 | runtimes: 14 | enabled: 15 | - go@1.23.0 16 | - node@18.20.5 17 | - python@3.10.8 18 | # This is the section where you manage your linters. (https://docs.trunk.io/check/configuration) 19 | lint: 20 | enabled: 21 | - actionlint@1.7.6 22 | - checkov@3.2.347 23 | - clippy@1.65.0 24 | - git-diff-check 25 | - gofmt@1.20.4 26 | - golangci-lint@1.62.2 27 | - hadolint@2.12.1-beta 28 | # - markdownlint@0.43.0 29 | - osv-scanner@1.9.2 30 | - prettier@3.4.2 31 | - rustfmt@1.65.0 32 | # - shellcheck@0.10.0 33 | # - shfmt@3.6.0 34 | - taplo@0.9.3 35 | - trufflehog@3.88.0 36 | actions: 37 | enabled: 38 | - trunk-announce 39 | - trunk-check-pre-push 40 | - trunk-fmt-pre-commit 41 | - trunk-upgrade-available 42 | -------------------------------------------------------------------------------- /CLAUDE.md: -------------------------------------------------------------------------------- 1 | # CLAUDE.md 2 | 3 | This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. 4 | 5 | ## Build Commands 6 | - `make build` - Build application binary 7 | - `make install` - Install application 8 | - `make proto-gen` - Generate Protobuf files 9 | - `make mod-tidy` - Run go mod tidy 10 | 11 | ## Test Commands 12 | - `make test` - Run unit tests 13 | - `make test-unit` - Run all unit tests 14 | - `make test-race` - Run tests with race detection 15 | - For single test: `go test -v -run TestName ./path/to/package` 16 | 17 | ## Lint Commands 18 | - `make lint` - Run golangci-lint and formatting checks 19 | - `make format` - Format code using gofumpt, misspell and gci 20 | 21 | ## Code Style Guidelines 22 | - **Imports**: Group by standard library, third-party, then project-specific with blank lines 23 | - **Error Handling**: Use custom errors from `types/errors.go` with `sdkerrors.Register` 24 | - **Naming**: camelCase for variables, PascalCase for functions/exported types, prefix errors with `Err` 25 | - **Organization**: Follow Cosmos SDK module pattern (`x/{module}/`, `types/`, `keeper/`) 26 | - **Types**: Prefer explicit types over interface{}, use pointers for mutable state 27 | - **Documentation**: Document public APIs thoroughly with standard Go doc comments 28 | - **Formatting**: Run `make format` before committing 29 | 30 | This project follows standard Go conventions and Cosmos SDK patterns with clear organization and consistent error handling. -------------------------------------------------------------------------------- /CONVENTIONS.md: -------------------------------------------------------------------------------- 1 | # CLAUDE.md - Developer Guidelines for SNRD Codebase 2 | 3 | ## Build & Test Commands 4 | - `make build` - Build application binary 5 | - `make install` - Install application 6 | - `make test` - Run unit tests 7 | - `make test-unit` - Run all unit tests 8 | - `make test-race` - Run tests with race detection 9 | - `make test-cover` - Run tests with coverage 10 | - `make lint` - Run golangci-lint and formatting checks 11 | - `make format` - Format code using gofumpt 12 | - `make proto-gen` - Generate Protobuf files 13 | - `make testnet` - Setup and run local testnet with IBC 14 | 15 | ## Code Style Guidelines 16 | - **Imports**: Group by standard library, third-party, then project-specific with blank lines between 17 | - **Error Handling**: Use custom errors from `types/errors.go` with `sdkerrors.Register` and prefix errors with `Err` 18 | - **Naming**: Use camelCase for variables, PascalCase for functions/exported types 19 | - **Organization**: Follow Cosmos SDK module pattern (`x/{module}/`, `types/`, `keeper/`) 20 | - **Documentation**: Use standard Go doc comments, document public APIs thoroughly 21 | - **Types**: Prefer explicit types over interface{}, use pointers for mutable state 22 | - **Design**: Follow dependency injection pattern for module components 23 | - **Formatting**: Run `make format` before committing 24 | 25 | Follows standard Go conventions and Cosmos SDK patterns with clear organization and consistent error handling. -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.24-alpine AS go-builder 2 | 3 | SHELL ["/bin/sh", "-ecuxo", "pipefail"] 4 | 5 | RUN apk add --no-cache ca-certificates build-base git 6 | 7 | WORKDIR /code 8 | 9 | COPY go.mod go.sum ./ 10 | RUN set -eux; \ 11 | export ARCH=$(uname -m); \ 12 | WASM_VERSION=$(go list -m all | grep github.com/CosmWasm/wasmvm || true); \ 13 | if [ ! -z "${WASM_VERSION}" ]; then \ 14 | WASMVM_REPO=$(echo $WASM_VERSION | awk '{print $1}');\ 15 | WASMVM_VERS=$(echo $WASM_VERSION | awk '{print $2}');\ 16 | wget -O /lib/libwasmvm_muslc.a https://${WASMVM_REPO}/releases/download/${WASMVM_VERS}/libwasmvm_muslc.$(uname -m).a;\ 17 | fi; \ 18 | go mod download; 19 | 20 | # Copy over code 21 | COPY . /code 22 | 23 | # force it to use static lib (from above) not standard libgo_cosmwasm.so file 24 | # then log output of file /code/bin/sonrd 25 | # then ensure static linking 26 | RUN LEDGER_ENABLED=false BUILD_TAGS=muslc LINK_STATICALLY=true make build \ 27 | && file /code/bin/snrd \ 28 | && echo "Ensuring binary is statically linked ..." \ 29 | && (file /code/bin/snrd | grep "statically linked") 30 | 31 | # -------------------------------------------------------- 32 | FROM alpine:3.17 33 | 34 | LABEL org.opencontainers.image.title="snrd" 35 | LABEL org.opencontainers.image.authors="diDAO " 36 | LABEL org.opencontainers.image.source=https://github.com/sonr-io/snrd 37 | 38 | COPY --from=go-builder /code/build/sonrd /usr/bin/sonrd 39 | 40 | # Set up dependencies 41 | ENV PACKAGES="curl make bash jq sed" 42 | 43 | # Install minimum necessary dependencies 44 | RUN apk add --no-cache $PACKAGES 45 | 46 | WORKDIR /opt 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `sonr` - Sonr Chain 2 | 3 | [![Go Reference](https://pkg.go.dev/badge/github.com/sonr-io/snrd.svg)](https://pkg.go.dev/github.com/sonr-io/snrd) 4 | ![GitHub commit activity](https://img.shields.io/github/commit-activity/w/onsonr/sonr) 5 | ![GitHub Release Date - Published_At](https://img.shields.io/github/release-date/onsonr/sonr) 6 | [![Static Badge](https://img.shields.io/badge/homepage-sonr.io-blue?style=flat-square)](https://sonr.io) 7 | [![Go Report Card](https://goreportcard.com/badge/github.com/sonr-io/snrd)](https://goreportcard.com/report/github.com/sonr-io/snrd) 8 | [![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=sonrhq_sonr&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=sonr-io_sonr) 9 | 10 | > Sonr is a combination of decentralized primitives. Fundamentally, it is a peer-to-peer identity and asset management system that leverages DID documents, Webauthn, and IPFS—providing users with a secure, portable decentralized identity. 11 | 12 | # Documentation 13 | 14 | 1. [Quick Start](https://github.com/sonr-io/snrd/wiki/1-%E2%80%90-Quick-Start) 15 | 2. [Chain Modules](https://github.com/sonr-io/snrd/wiki/2-%E2%80%90-Chain-Modules) 16 | 3. [System Architecture](https://github.com/sonr-io/snrd/wiki/3-%E2%80%90-System-Architecture) 17 | 4. [Token Economy](https://github.com/sonr-io/snrd/wiki/4-%E2%80%90-Token-Economy) 18 | 5. [Service Mangement](https://github.com/sonr-io/snrd/wiki/5-%E2%80%90-Service-Management) 19 | 6. [Design System](https://github.com/sonr-io/snrd/wiki/6-%E2%80%90-Design-System) 20 | 7. [Self Custody](https://github.com/sonr-io/snrd/wiki/7-%E2%80%90-Self-Custody) 21 | 22 | # Stats 23 | 24 | ![Alt](https://repobeats.axiom.co/api/embed/e9ae6be710ea5dc1624753dc1d5edb1ffbc0fcf0.svg "Repobeats analytics image") 25 | 26 | # Acknowledgements 27 | 28 | Sonr would not have been possible without the direct and indirect support of the following individuals: 29 | 30 | - **Juan Benet**: For the IPFS Ecosystem. 31 | - **Satoshi Nakamoto**: For Bitcoin. 32 | - **Steve Jobs**: For User first UX. 33 | - **Tim Berners-Lee**: For the Internet. 34 | 35 | # Community & Support 36 | 37 | - [Forum](https://github.com/sonr-io/snrd/discussions) 38 | - [Issues](https://github.com/sonr-io/snrd/issues) 39 | - [Twitter](https://sonr.io/twitter) 40 | -------------------------------------------------------------------------------- /app/ante.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import ( 4 | "errors" 5 | 6 | ibcante "github.com/cosmos/ibc-go/v8/modules/core/ante" 7 | "github.com/cosmos/ibc-go/v8/modules/core/keeper" 8 | 9 | circuitante "cosmossdk.io/x/circuit/ante" 10 | circuitkeeper "cosmossdk.io/x/circuit/keeper" 11 | 12 | sdk "github.com/cosmos/cosmos-sdk/types" 13 | "github.com/cosmos/cosmos-sdk/x/auth/ante" 14 | stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" 15 | 16 | sdkmath "cosmossdk.io/math" 17 | poaante "github.com/strangelove-ventures/poa/ante" 18 | 19 | globalfeeante "github.com/strangelove-ventures/globalfee/x/globalfee/ante" 20 | globalfeekeeper "github.com/strangelove-ventures/globalfee/x/globalfee/keeper" 21 | ) 22 | 23 | // HandlerOptions extend the SDK's AnteHandler options by requiring the IBC 24 | // channel keeper. 25 | type HandlerOptions struct { 26 | ante.HandlerOptions 27 | IBCKeeper *keeper.Keeper 28 | CircuitKeeper *circuitkeeper.Keeper 29 | StakingKeeper *stakingkeeper.Keeper 30 | GlobalFeeKeeper globalfeekeeper.Keeper 31 | BypassMinFeeMsgTypes []string 32 | } 33 | 34 | // NewAnteHandler constructor 35 | func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { 36 | if options.AccountKeeper == nil { 37 | return nil, errors.New("account keeper is required for ante builder") 38 | } 39 | if options.BankKeeper == nil { 40 | return nil, errors.New("bank keeper is required for ante builder") 41 | } 42 | if options.SignModeHandler == nil { 43 | return nil, errors.New("sign mode handler is required for ante builder") 44 | } 45 | if options.CircuitKeeper == nil { 46 | return nil, errors.New("circuit keeper is required for ante builder") 47 | } 48 | 49 | poaDoGenTxRateValidation := false 50 | poaRateFloor := sdkmath.LegacyMustNewDecFromStr("0.05") 51 | poaRateCeil := sdkmath.LegacyMustNewDecFromStr("0.25") 52 | 53 | anteDecorators := []sdk.AnteDecorator{ 54 | ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first 55 | circuitante.NewCircuitBreakerDecorator(options.CircuitKeeper), 56 | ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker), 57 | ante.NewValidateBasicDecorator(), 58 | ante.NewTxTimeoutHeightDecorator(), 59 | ante.NewValidateMemoDecorator(options.AccountKeeper), 60 | // ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), 61 | globalfeeante.NewFeeDecorator(options.BypassMinFeeMsgTypes, options.GlobalFeeKeeper, 2_000_000), 62 | // ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), 63 | ante.NewSetPubKeyDecorator(options.AccountKeeper), // SetPubKeyDecorator must be called before all signature verification decorators 64 | ante.NewValidateSigCountDecorator(options.AccountKeeper), 65 | ante.NewSigGasConsumeDecorator(options.AccountKeeper, options.SigGasConsumer), 66 | ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler), 67 | ante.NewIncrementSequenceDecorator(options.AccountKeeper), 68 | ibcante.NewRedundantRelayDecorator(options.IBCKeeper), 69 | poaante.NewPOADisableStakingDecorator(), 70 | poaante.NewCommissionLimitDecorator(poaDoGenTxRateValidation, poaRateFloor, poaRateCeil), 71 | } 72 | 73 | return sdk.ChainAnteDecorators(anteDecorators...), nil 74 | } 75 | -------------------------------------------------------------------------------- /app/app_test.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import ( 4 | "testing" 5 | 6 | abci "github.com/cometbft/cometbft/abci/types" 7 | dbm "github.com/cosmos/cosmos-db" 8 | "github.com/stretchr/testify/require" 9 | 10 | "cosmossdk.io/log" 11 | 12 | simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" 13 | sdk "github.com/cosmos/cosmos-sdk/types" 14 | ) 15 | 16 | func TestAppExport(t *testing.T) { 17 | db := dbm.NewMemDB() 18 | logger := log.NewTestLogger(t) 19 | gapp := NewChainAppWithCustomOptions(t, false, SetupOptions{ 20 | Logger: logger.With("instance", "first"), 21 | DB: db, 22 | AppOpts: simtestutil.NewAppOptionsWithFlagHome(t.TempDir()), 23 | }) 24 | 25 | // finalize block so we have CheckTx state set 26 | _, err := gapp.FinalizeBlock(&abci.RequestFinalizeBlock{ 27 | Height: 1, 28 | }) 29 | require.NoError(t, err) 30 | 31 | _, err = gapp.Commit() 32 | require.NoError(t, err) 33 | 34 | // Making a new app object with the db, so that initchain hasn't been called 35 | newGapp := NewChainApp( 36 | logger, db, nil, true, simtestutil.NewAppOptionsWithFlagHome(t.TempDir()), 37 | ) 38 | _, err = newGapp.ExportAppStateAndValidators(false, []string{}, nil) 39 | require.NoError(t, err, "ExportAppStateAndValidators should not have an error") 40 | } 41 | 42 | // ensure that blocked addresses are properly set in bank keeper 43 | func TestBlockedAddrs(t *testing.T) { 44 | gapp := Setup(t) 45 | 46 | for acc := range BlockedAddresses() { 47 | t.Run(acc, func(t *testing.T) { 48 | var addr sdk.AccAddress 49 | if modAddr, err := sdk.AccAddressFromBech32(acc); err == nil { 50 | addr = modAddr 51 | } else { 52 | addr = gapp.AccountKeeper.GetModuleAddress(acc) 53 | } 54 | require.True(t, gapp.BankKeeper.BlockedAddr(addr), "ensure that blocked addresses are properly set in bank keeper") 55 | }) 56 | } 57 | } 58 | 59 | func TestGetMaccPerms(t *testing.T) { 60 | dup := GetMaccPerms() 61 | require.Equal(t, maccPerms, dup, "duplicated module account permissions differed from actual module account permissions") 62 | } 63 | -------------------------------------------------------------------------------- /app/decorators/msg_filter_template.go: -------------------------------------------------------------------------------- 1 | package decorators 2 | 3 | import ( 4 | "fmt" 5 | 6 | sdk "github.com/cosmos/cosmos-sdk/types" 7 | "github.com/cosmos/cosmos-sdk/x/authz" 8 | "github.com/cosmos/gogoproto/proto" 9 | ) 10 | 11 | // MsgFilterDecorator is an ante.go decorator template for filtering messages. 12 | type MsgFilterDecorator struct { 13 | blockedTypes []sdk.Msg 14 | } 15 | 16 | // FilterDecorator returns a new MsgFilterDecorator. This errors if the transaction 17 | // contains any of the blocked message types. 18 | // 19 | // Example: 20 | // - decorators.FilterDecorator(&banktypes.MsgSend{}) 21 | // This would block any MsgSend messages from being included in a transaction if set in ante.go 22 | func FilterDecorator(blockedMsgTypes ...sdk.Msg) MsgFilterDecorator { 23 | return MsgFilterDecorator{ 24 | blockedTypes: blockedMsgTypes, 25 | } 26 | } 27 | 28 | func (mfd MsgFilterDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { 29 | if mfd.HasDisallowedMessage(ctx, tx.GetMsgs()) { 30 | currHeight := ctx.BlockHeight() 31 | return ctx, fmt.Errorf("tx contains unsupported message types at height %d", currHeight) 32 | } 33 | 34 | return next(ctx, tx, simulate) 35 | } 36 | 37 | func (mfd MsgFilterDecorator) HasDisallowedMessage(ctx sdk.Context, msgs []sdk.Msg) bool { 38 | for _, msg := range msgs { 39 | // check nested messages in a recursive manner 40 | if execMsg, ok := msg.(*authz.MsgExec); ok { 41 | msgs, err := execMsg.GetMessages() 42 | if err != nil { 43 | return true 44 | } 45 | 46 | if mfd.HasDisallowedMessage(ctx, msgs) { 47 | return true 48 | } 49 | } 50 | 51 | for _, blockedType := range mfd.blockedTypes { 52 | if proto.MessageName(msg) == proto.MessageName(blockedType) { 53 | return true 54 | } 55 | } 56 | } 57 | 58 | return false 59 | } 60 | -------------------------------------------------------------------------------- /app/decorators/msg_filter_test.go: -------------------------------------------------------------------------------- 1 | package decorators_test 2 | 3 | import ( 4 | "testing" 5 | 6 | sdkmath "cosmossdk.io/math" 7 | 8 | "github.com/cometbft/cometbft/crypto/secp256k1" 9 | sdk "github.com/cosmos/cosmos-sdk/types" 10 | banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" 11 | "github.com/stretchr/testify/suite" 12 | 13 | app "github.com/sonr-io/snrd/app" 14 | "github.com/sonr-io/snrd/app/decorators" 15 | ) 16 | 17 | type AnteTestSuite struct { 18 | suite.Suite 19 | 20 | ctx sdk.Context 21 | app *app.SonrApp 22 | } 23 | 24 | func (s *AnteTestSuite) SetupTest() { 25 | isCheckTx := false 26 | s.app = app.Setup(s.T()) 27 | s.ctx = s.app.BaseApp.NewContext(isCheckTx) 28 | } 29 | 30 | func TestAnteTestSuite(t *testing.T) { 31 | suite.Run(t, new(AnteTestSuite)) 32 | } 33 | 34 | // Test the change rate decorator with standard edit msgs, 35 | func (s *AnteTestSuite) TestAnteMsgFilterLogic() { 36 | acc := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) 37 | 38 | // test blocking any BankSend Messages 39 | ante := decorators.FilterDecorator(&banktypes.MsgSend{}) 40 | msg := banktypes.NewMsgSend( 41 | acc, 42 | acc, 43 | sdk.NewCoins(sdk.NewCoin("stake", sdkmath.NewInt(1))), 44 | ) 45 | _, err := ante.AnteHandle(s.ctx, decorators.NewMockTx(msg), false, decorators.EmptyAnte) 46 | s.Require().Error(err) 47 | 48 | // validate other messages go through still (such as MsgMultiSend) 49 | msgMultiSend := banktypes.NewMsgMultiSend( 50 | banktypes.NewInput(acc, sdk.NewCoins(sdk.NewCoin("stake", sdkmath.NewInt(1)))), 51 | []banktypes.Output{banktypes.NewOutput(acc, sdk.NewCoins(sdk.NewCoin("stake", sdkmath.NewInt(1))))}, 52 | ) 53 | _, err = ante.AnteHandle(s.ctx, decorators.NewMockTx(msgMultiSend), false, decorators.EmptyAnte) 54 | s.Require().NoError(err) 55 | } 56 | -------------------------------------------------------------------------------- /app/decorators/setup.go: -------------------------------------------------------------------------------- 1 | package decorators 2 | 3 | import ( 4 | sdk "github.com/cosmos/cosmos-sdk/types" 5 | protov2 "google.golang.org/protobuf/proto" 6 | ) 7 | 8 | // Define an empty ante handle 9 | var ( 10 | EmptyAnte = func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) { 11 | return ctx, nil 12 | } 13 | ) 14 | 15 | type MockTx struct { 16 | msgs []sdk.Msg 17 | } 18 | 19 | func NewMockTx(msgs ...sdk.Msg) MockTx { 20 | return MockTx{ 21 | msgs: msgs, 22 | } 23 | } 24 | 25 | func (tx MockTx) GetMsgs() []sdk.Msg { 26 | return tx.msgs 27 | } 28 | 29 | func (tx MockTx) GetMsgsV2() ([]protov2.Message, error) { 30 | return nil, nil 31 | } 32 | 33 | func (tx MockTx) ValidateBasic() error { 34 | return nil 35 | } 36 | -------------------------------------------------------------------------------- /app/encoding.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import ( 4 | "testing" 5 | 6 | dbm "github.com/cosmos/cosmos-db" 7 | 8 | "cosmossdk.io/log" 9 | 10 | simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" 11 | 12 | "github.com/sonr-io/snrd/app/params" 13 | ) 14 | 15 | // MakeEncodingConfig creates a new EncodingConfig with all modules registered. For testing only 16 | func MakeEncodingConfig(t testing.TB) params.EncodingConfig { 17 | t.Helper() 18 | // we "pre"-instantiate the application for getting the injected/configured encoding configuration 19 | // note, this is not necessary when using app wiring, as depinject can be directly used (see root_v2.go) 20 | tempApp := NewChainApp( 21 | log.NewNopLogger(), 22 | dbm.NewMemDB(), 23 | nil, 24 | true, 25 | simtestutil.NewAppOptionsWithFlagHome(t.TempDir()), 26 | ) 27 | return makeEncodingConfig(tempApp) 28 | } 29 | 30 | func makeEncodingConfig(tempApp *SonrApp) params.EncodingConfig { 31 | encodingConfig := params.EncodingConfig{ 32 | InterfaceRegistry: tempApp.InterfaceRegistry(), 33 | Codec: tempApp.AppCodec(), 34 | TxConfig: tempApp.TxConfig(), 35 | Amino: tempApp.LegacyAmino(), 36 | } 37 | return encodingConfig 38 | } 39 | -------------------------------------------------------------------------------- /app/genesis.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import ( 4 | "encoding/json" 5 | ) 6 | 7 | // GenesisState of the blockchain is represented here as a map of raw json 8 | // messages key'd by a identifier string. 9 | // The identifier is used to determine which module genesis information belongs 10 | // to so it may be appropriately routed during init chain. 11 | // Within this application default genesis information is retrieved from 12 | // the ModuleBasicManager which populates json from each BasicModule 13 | // object provided to it during init. 14 | type GenesisState map[string]json.RawMessage 15 | -------------------------------------------------------------------------------- /app/params/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package params defines the simulation parameters in the gaia. 3 | 4 | It contains the default weights used for each transaction used on the module's 5 | simulation. These weights define the chance for a transaction to be simulated at 6 | any gived operation. 7 | 8 | You can repace the default values for the weights by providing a params.json 9 | file with the weights defined for each of the transaction operations: 10 | 11 | { 12 | "op_weight_msg_send": 60, 13 | "op_weight_msg_delegate": 100, 14 | } 15 | 16 | In the example above, the `MsgSend` has 60% chance to be simulated, while the 17 | `MsgDelegate` will always be simulated. 18 | */ 19 | package params 20 | -------------------------------------------------------------------------------- /app/params/encoding.go: -------------------------------------------------------------------------------- 1 | package params 2 | 3 | import ( 4 | "github.com/cosmos/cosmos-sdk/client" 5 | "github.com/cosmos/cosmos-sdk/codec" 6 | "github.com/cosmos/cosmos-sdk/codec/types" 7 | ) 8 | 9 | // EncodingConfig specifies the concrete encoding types to use for a given app. 10 | // This is provided for compatibility between protobuf and amino implementations. 11 | type EncodingConfig struct { 12 | InterfaceRegistry types.InterfaceRegistry 13 | Codec codec.Codec 14 | TxConfig client.TxConfig 15 | Amino *codec.LegacyAmino 16 | } 17 | -------------------------------------------------------------------------------- /app/params/proto.go: -------------------------------------------------------------------------------- 1 | package params 2 | 3 | import ( 4 | "github.com/cosmos/gogoproto/proto" 5 | 6 | "cosmossdk.io/x/tx/signing" 7 | 8 | "github.com/cosmos/cosmos-sdk/codec" 9 | "github.com/cosmos/cosmos-sdk/codec/address" 10 | "github.com/cosmos/cosmos-sdk/codec/types" 11 | sdk "github.com/cosmos/cosmos-sdk/types" 12 | "github.com/cosmos/cosmos-sdk/x/auth/tx" 13 | ) 14 | 15 | // MakeEncodingConfig creates an EncodingConfig for an amino based test configuration. 16 | func MakeEncodingConfig() EncodingConfig { 17 | amino := codec.NewLegacyAmino() 18 | interfaceRegistry, err := types.NewInterfaceRegistryWithOptions(types.InterfaceRegistryOptions{ 19 | ProtoFiles: proto.HybridResolver, 20 | SigningOptions: signing.Options{ 21 | AddressCodec: address.Bech32Codec{ 22 | Bech32Prefix: sdk.GetConfig().GetBech32AccountAddrPrefix(), 23 | }, 24 | ValidatorAddressCodec: address.Bech32Codec{ 25 | Bech32Prefix: sdk.GetConfig().GetBech32ValidatorAddrPrefix(), 26 | }, 27 | }, 28 | }) 29 | if err != nil { 30 | panic(err) 31 | } 32 | 33 | marshaler := codec.NewProtoCodec(interfaceRegistry) 34 | txCfg := tx.NewTxConfig(marshaler, tx.DefaultSignModes) 35 | 36 | return EncodingConfig{ 37 | InterfaceRegistry: interfaceRegistry, 38 | Codec: marshaler, 39 | TxConfig: txCfg, 40 | Amino: amino, 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/test_support.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import ( 4 | capabilitykeeper "github.com/cosmos/ibc-go/modules/capability/keeper" 5 | ibckeeper "github.com/cosmos/ibc-go/v8/modules/core/keeper" 6 | 7 | "github.com/cosmos/cosmos-sdk/baseapp" 8 | authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" 9 | bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" 10 | stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" 11 | ) 12 | 13 | func (app *SonrApp) GetIBCKeeper() *ibckeeper.Keeper { 14 | return app.IBCKeeper 15 | } 16 | 17 | func (app *SonrApp) GetScopedIBCKeeper() capabilitykeeper.ScopedKeeper { 18 | return app.ScopedIBCKeeper 19 | } 20 | 21 | func (app *SonrApp) GetBaseApp() *baseapp.BaseApp { 22 | return app.BaseApp 23 | } 24 | 25 | func (app *SonrApp) GetBankKeeper() bankkeeper.Keeper { 26 | return app.BankKeeper 27 | } 28 | 29 | func (app *SonrApp) GetStakingKeeper() *stakingkeeper.Keeper { 30 | return app.StakingKeeper 31 | } 32 | 33 | func (app *SonrApp) GetAccountKeeper() authkeeper.AccountKeeper { 34 | return app.AccountKeeper 35 | } 36 | -------------------------------------------------------------------------------- /app/upgrades.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import ( 4 | "fmt" 5 | 6 | upgradetypes "cosmossdk.io/x/upgrade/types" 7 | 8 | "github.com/sonr-io/snrd/app/upgrades" 9 | "github.com/sonr-io/snrd/app/upgrades/noop" 10 | ) 11 | 12 | // Upgrades list of chain upgrades 13 | var Upgrades = []upgrades.Upgrade{} 14 | 15 | // RegisterUpgradeHandlers registers the chain upgrade handlers 16 | func (app *SonrApp) RegisterUpgradeHandlers() { 17 | // setupLegacyKeyTables(&app.ParamsKeeper) 18 | if len(Upgrades) == 0 { 19 | // always have a unique upgrade registered for the current version to test in system tests 20 | Upgrades = append(Upgrades, noop.NewUpgrade(app.Version())) 21 | } 22 | 23 | keepers := upgrades.AppKeepers{ 24 | AccountKeeper: &app.AccountKeeper, 25 | DidKeeper: &app.DidKeeper, 26 | ParamsKeeper: &app.ParamsKeeper, 27 | ConsensusParamsKeeper: &app.ConsensusParamsKeeper, 28 | CapabilityKeeper: app.CapabilityKeeper, 29 | IBCKeeper: app.IBCKeeper, 30 | Codec: app.appCodec, 31 | GetStoreKey: app.GetKey, 32 | } 33 | app.GetStoreKeys() 34 | // register all upgrade handlers 35 | for _, upgrade := range Upgrades { 36 | app.UpgradeKeeper.SetUpgradeHandler( 37 | upgrade.UpgradeName, 38 | upgrade.CreateUpgradeHandler( 39 | app.ModuleManager, 40 | app.configurator, 41 | &keepers, 42 | ), 43 | ) 44 | } 45 | 46 | upgradeInfo, err := app.UpgradeKeeper.ReadUpgradeInfoFromDisk() 47 | if err != nil { 48 | panic(fmt.Sprintf("failed to read upgrade info from disk %s", err)) 49 | } 50 | 51 | if app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { 52 | return 53 | } 54 | 55 | // register store loader for current upgrade 56 | for _, upgrade := range Upgrades { 57 | if upgradeInfo.Name == upgrade.UpgradeName { 58 | app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &upgrade.StoreUpgrades)) // nolint:gosec 59 | break 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/upgrades/noop/upgrades.go: -------------------------------------------------------------------------------- 1 | package noop 2 | 3 | import ( 4 | "context" 5 | 6 | storetypes "cosmossdk.io/store/types" 7 | upgradetypes "cosmossdk.io/x/upgrade/types" 8 | 9 | "github.com/cosmos/cosmos-sdk/types/module" 10 | 11 | "github.com/sonr-io/snrd/app/upgrades" 12 | ) 13 | 14 | // NewUpgrade constructor 15 | func NewUpgrade(semver string) upgrades.Upgrade { 16 | return upgrades.Upgrade{ 17 | UpgradeName: semver, 18 | CreateUpgradeHandler: CreateUpgradeHandler, 19 | StoreUpgrades: storetypes.StoreUpgrades{ 20 | Added: []string{}, 21 | Deleted: []string{}, 22 | }, 23 | } 24 | } 25 | 26 | func CreateUpgradeHandler( 27 | mm upgrades.ModuleManager, 28 | configurator module.Configurator, 29 | ak *upgrades.AppKeepers, 30 | ) upgradetypes.UpgradeHandler { 31 | return func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { 32 | return mm.RunMigrations(ctx, configurator, fromVM) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/upgrades/types.go: -------------------------------------------------------------------------------- 1 | package upgrades 2 | 3 | import ( 4 | "context" 5 | 6 | capabilitykeeper "github.com/cosmos/ibc-go/modules/capability/keeper" 7 | ibckeeper "github.com/cosmos/ibc-go/v8/modules/core/keeper" 8 | 9 | storetypes "cosmossdk.io/store/types" 10 | upgradetypes "cosmossdk.io/x/upgrade/types" 11 | 12 | "github.com/cosmos/cosmos-sdk/codec" 13 | "github.com/cosmos/cosmos-sdk/types/module" 14 | authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" 15 | consensusparamkeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper" 16 | paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" 17 | didkeeper "github.com/sonr-io/snrd/x/did/keeper" 18 | ) 19 | 20 | type AppKeepers struct { 21 | AccountKeeper *authkeeper.AccountKeeper 22 | DidKeeper *didkeeper.Keeper 23 | ParamsKeeper *paramskeeper.Keeper 24 | ConsensusParamsKeeper *consensusparamkeeper.Keeper 25 | Codec codec.Codec 26 | GetStoreKey func(storeKey string) *storetypes.KVStoreKey 27 | CapabilityKeeper *capabilitykeeper.Keeper 28 | IBCKeeper *ibckeeper.Keeper 29 | } 30 | type ModuleManager interface { 31 | RunMigrations(ctx context.Context, cfg module.Configurator, fromVM module.VersionMap) (module.VersionMap, error) 32 | GetVersionMap() module.VersionMap 33 | } 34 | 35 | // Upgrade defines a struct containing necessary fields that a SoftwareUpgradeProposal 36 | // must have written, in order for the state migration to go smoothly. 37 | // An upgrade must implement this struct, and then set it in the app.go. 38 | // The app.go will then define the handler. 39 | type Upgrade struct { 40 | // Upgrade version name, for the upgrade handler, e.g. `v7` 41 | UpgradeName string 42 | 43 | // CreateUpgradeHandler defines the function that creates an upgrade handler 44 | CreateUpgradeHandler func(ModuleManager, module.Configurator, *AppKeepers) upgradetypes.UpgradeHandler 45 | StoreUpgrades storetypes.StoreUpgrades 46 | } 47 | -------------------------------------------------------------------------------- /buf.work.yaml: -------------------------------------------------------------------------------- 1 | version: v1 2 | directories: 3 | - proto 4 | -------------------------------------------------------------------------------- /cmd/root.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "os" 5 | 6 | "cosmossdk.io/log" 7 | dbm "github.com/cosmos/cosmos-db" 8 | "github.com/cosmos/cosmos-sdk/client" 9 | "github.com/cosmos/cosmos-sdk/client/config" 10 | "github.com/cosmos/cosmos-sdk/crypto/keyring" 11 | "github.com/cosmos/cosmos-sdk/server" 12 | simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" 13 | sdk "github.com/cosmos/cosmos-sdk/types" 14 | "github.com/cosmos/cosmos-sdk/types/tx/signing" 15 | "github.com/cosmos/cosmos-sdk/version" 16 | "github.com/cosmos/cosmos-sdk/x/auth/tx" 17 | txmodule "github.com/cosmos/cosmos-sdk/x/auth/tx/config" 18 | authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" 19 | "github.com/spf13/cobra" 20 | 21 | "github.com/sonr-io/snrd/app" 22 | "github.com/sonr-io/snrd/app/params" 23 | ) 24 | 25 | func NewRootCmd() *cobra.Command { 26 | cfg := sdk.GetConfig() 27 | cfg.SetBech32PrefixForAccount(app.Bech32PrefixAccAddr, app.Bech32PrefixAccPub) 28 | cfg.SetBech32PrefixForValidator(app.Bech32PrefixValAddr, app.Bech32PrefixValPub) 29 | cfg.SetBech32PrefixForConsensusNode(app.Bech32PrefixConsAddr, app.Bech32PrefixConsPub) 30 | cfg.Seal() 31 | // we "pre"-instantiate the application for getting the injected/configured encoding configuration 32 | // note, this is not necessary when using app wiring, as depinject can be directly used (see root_v2.go) 33 | preApp := app.NewChainApp( 34 | log.NewNopLogger(), dbm.NewMemDB(), nil, false, simtestutil.NewAppOptionsWithFlagHome(tempDir()), 35 | ) 36 | encodingConfig := params.EncodingConfig{ 37 | InterfaceRegistry: preApp.InterfaceRegistry(), 38 | Codec: preApp.AppCodec(), 39 | TxConfig: preApp.TxConfig(), 40 | Amino: preApp.LegacyAmino(), 41 | } 42 | 43 | initClientCtx := client.Context{}. 44 | WithCodec(encodingConfig.Codec). 45 | WithInterfaceRegistry(encodingConfig.InterfaceRegistry). 46 | WithTxConfig(encodingConfig.TxConfig). 47 | WithLegacyAmino(encodingConfig.Amino). 48 | WithInput(os.Stdin). 49 | WithAccountRetriever(authtypes.AccountRetriever{}). 50 | WithHomeDir(app.DefaultNodeHome). 51 | WithViper("") 52 | 53 | rootCmd := &cobra.Command{ 54 | Use: version.AppName, 55 | Short: version.AppName + " Daemon (server)", 56 | SilenceErrors: true, 57 | PersistentPreRunE: func(cmd *cobra.Command, _ []string) error { 58 | // set the default command outputs 59 | cmd.SetOut(cmd.OutOrStdout()) 60 | cmd.SetErr(cmd.ErrOrStderr()) 61 | 62 | initClientCtx = initClientCtx.WithCmdContext(cmd.Context()) 63 | initClientCtx, err := client.ReadPersistentCommandFlags(initClientCtx, cmd.Flags()) 64 | if err != nil { 65 | return err 66 | } 67 | 68 | initClientCtx, err = config.ReadFromClientConfig(initClientCtx) 69 | if err != nil { 70 | return err 71 | } 72 | 73 | // This needs to go after ReadFromClientConfig, as that function 74 | // sets the RPC client needed for SIGN_MODE_TEXTUAL. This sign mode 75 | // is only available if the client is online. 76 | if !initClientCtx.Offline { 77 | enabledSignModes := append(tx.DefaultSignModes, signing.SignMode_SIGN_MODE_TEXTUAL) 78 | txConfigOpts := tx.ConfigOptions{ 79 | EnabledSignModes: enabledSignModes, 80 | TextualCoinMetadataQueryFn: txmodule.NewGRPCCoinMetadataQueryFn(initClientCtx), 81 | } 82 | txConfig, err := tx.NewTxConfigWithOptions( 83 | initClientCtx.Codec, 84 | txConfigOpts, 85 | ) 86 | if err != nil { 87 | return err 88 | } 89 | 90 | initClientCtx = initClientCtx.WithTxConfig(txConfig) 91 | } 92 | 93 | if err := client.SetCmdClientContextHandler(initClientCtx, cmd); err != nil { 94 | return err 95 | } 96 | 97 | // Set the context chain ID and validator address 98 | // app.SetLocalChainID(initClientCtx.ChainID) 99 | // app.SetLocalValidatorAddress(initClientCtx.FromAddress.String()) 100 | 101 | customAppTemplate, customAppConfig := initAppConfig() 102 | customCMTConfig := initCometBFTConfig() 103 | 104 | return server.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig, customCMTConfig) 105 | }, 106 | } 107 | 108 | initRootCmd(rootCmd, encodingConfig.TxConfig, encodingConfig.InterfaceRegistry, preApp.BasicModuleManager) 109 | 110 | // add keyring to autocli opts 111 | autoCliOpts := preApp.AutoCliOpts() 112 | initClientCtx, _ = config.ReadFromClientConfig(initClientCtx) 113 | autoCliOpts.Keyring, _ = keyring.NewAutoCLIKeyring(initClientCtx.Keyring) 114 | autoCliOpts.ClientCtx = initClientCtx 115 | 116 | if err := autoCliOpts.EnhanceRootCommand(rootCmd); err != nil { 117 | panic(err) 118 | } 119 | 120 | return rootCmd 121 | } 122 | -------------------------------------------------------------------------------- /devbox.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/jetify-com/devbox/0.14.0/.schema/devbox.schema.json", 3 | "packages": [ 4 | "buf@latest", 5 | "go@latest", 6 | "docker@latest", 7 | "gum@latest", 8 | "go-task@latest", 9 | "goreleaser@latest", 10 | "commitizen@latest", 11 | "doppler@latest", 12 | "ripgrep@latest" 13 | ], 14 | "env": { 15 | "GOPATH": "$HOME/go", 16 | "PATH": "$PATH:$PWD/bin", 17 | "DOPPLER_TOKEN": "$DOPPLER_SONR_RELEASE_TOKEN" 18 | }, 19 | "shell": { 20 | "init_hook": [ 21 | "gh extension install valeriobelli/gh-milestone" 22 | ], 23 | "scripts": { 24 | "release": [ 25 | "doppler secrets download --no-file --format env > .env", 26 | "task -t .taskfile.dist.yml bump" 27 | ] 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /internal/accounts/api_builder.go: -------------------------------------------------------------------------------- 1 | package accounts 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | 8 | "github.com/sonr-io/snrd/internal/transaction" 9 | ) 10 | 11 | var ( 12 | errNoInitHandler = errors.New("no init handler") 13 | errNoExecuteHandler = errors.New("account does not accept messages") 14 | errInvalidMessage = errors.New("invalid message") 15 | ) 16 | 17 | // NewInitBuilder creates a new InitBuilder instance. 18 | func NewInitBuilder() *InitBuilder { 19 | return &InitBuilder{} 20 | } 21 | 22 | // InitBuilder defines a smart account's initialisation handler builder. 23 | type InitBuilder struct { 24 | // handler is the handler function that will be called when the smart account is initialized. 25 | // Although the function here is defined to take an any, the smart account will work 26 | // with a typed version of it. 27 | handler func(ctx context.Context, initRequest transaction.Msg) (initResponse transaction.Msg, err error) 28 | 29 | // schema is the schema of the message that will be passed to the handler function. 30 | schema HandlerSchema 31 | } 32 | 33 | // makeHandler returns the handler function that will be called when the smart account is initialized. 34 | // It returns an error if no handler was registered. 35 | func (i *InitBuilder) makeHandler() (func(ctx context.Context, initRequest transaction.Msg) (initResponse transaction.Msg, err error), error) { 36 | if i.handler == nil { 37 | return nil, errNoInitHandler 38 | } 39 | return i.handler, nil 40 | } 41 | 42 | // NewExecuteBuilder creates a new ExecuteBuilder instance. 43 | func NewExecuteBuilder() *ExecuteBuilder { 44 | return &ExecuteBuilder{ 45 | handlers: make(map[string]func(ctx context.Context, executeRequest transaction.Msg) (executeResponse transaction.Msg, err error)), 46 | handlersSchema: make(map[string]HandlerSchema), 47 | } 48 | } 49 | 50 | // ExecuteBuilder defines a smart account's execution router, it will be used to map an execution message 51 | // to a handler function for a specific account. 52 | type ExecuteBuilder struct { 53 | // handlers is a map of handler functions that will be called when the smart account is executed. 54 | handlers map[string]func(ctx context.Context, executeRequest transaction.Msg) (executeResponse transaction.Msg, err error) 55 | 56 | // handlersSchema is a map of schemas for the messages that will be passed to the handler functions 57 | // and the messages that will be returned by the handler functions. 58 | handlersSchema map[string]HandlerSchema 59 | 60 | // err is the error that occurred before building the handler function. 61 | err error 62 | } 63 | 64 | func (r *ExecuteBuilder) makeHandler() (func(ctx context.Context, executeRequest transaction.Msg) (executeResponse transaction.Msg, err error), error) { 65 | // if no handler is registered it's fine, it means the account will not be accepting execution or query messages. 66 | if len(r.handlers) == 0 { 67 | return func(ctx context.Context, _ transaction.Msg) (_ transaction.Msg, err error) { 68 | return nil, errNoExecuteHandler 69 | }, nil 70 | } 71 | 72 | if r.err != nil { 73 | return nil, r.err 74 | } 75 | 76 | // build the real execution handler 77 | return func(ctx context.Context, executeRequest transaction.Msg) (executeResponse transaction.Msg, err error) { 78 | messageName := MessageName(executeRequest) 79 | handler, ok := r.handlers[messageName] 80 | if !ok { 81 | return nil, fmt.Errorf("%w: no handler for message %s", errInvalidMessage, messageName) 82 | } 83 | return handler(ctx, executeRequest) 84 | }, nil 85 | } 86 | 87 | // NewQueryBuilder creates a new QueryBuilder instance. 88 | func NewQueryBuilder() *QueryBuilder { 89 | return &QueryBuilder{ 90 | er: NewExecuteBuilder(), 91 | } 92 | } 93 | 94 | // QueryBuilder defines a smart account's query router, it will be used to map a query message 95 | // to a handler function for a specific account. 96 | type QueryBuilder struct { 97 | // er is the ExecuteBuilder, since there's no difference between the execution and query handlers API. 98 | er *ExecuteBuilder 99 | } 100 | 101 | func (r *QueryBuilder) makeHandler() (func(ctx context.Context, queryRequest transaction.Msg) (queryResponse transaction.Msg, err error), error) { 102 | return r.er.makeHandler() 103 | } 104 | 105 | // IsRoutingError returns true if the error is a routing error, 106 | // which typically occurs when a message cannot be matched to a handler. 107 | func IsRoutingError(err error) bool { 108 | if err == nil { 109 | return false 110 | } 111 | return errors.Is(err, errInvalidMessage) 112 | } 113 | -------------------------------------------------------------------------------- /internal/accounts/context.go: -------------------------------------------------------------------------------- 1 | package accounts 2 | 3 | import ( 4 | "context" 5 | "encoding/binary" 6 | 7 | "cosmossdk.io/collections" 8 | "cosmossdk.io/core/store" 9 | sdk "github.com/cosmos/cosmos-sdk/types" 10 | 11 | "github.com/sonr-io/snrd/internal/prefixstore" 12 | "github.com/sonr-io/snrd/internal/transaction" 13 | ) 14 | 15 | var AccountStatePrefix = collections.NewPrefix(255) 16 | 17 | type ( 18 | ModuleExecFunc = func(ctx context.Context, sender []byte, msg transaction.Msg) (transaction.Msg, error) 19 | ModuleQueryFunc = func(ctx context.Context, queryReq transaction.Msg) (transaction.Msg, error) 20 | ) 21 | 22 | type contextKey struct{} 23 | 24 | type contextValue struct { 25 | store store.KVStore // store is the prefixed store for the account. 26 | sender []byte // sender is the address of the entity invoking the account action. 27 | whoami []byte // whoami is the address of the account being invoked. 28 | funds sdk.Coins // funds reports the coins sent alongside the request. 29 | parentContext context.Context // parentContext that was used to build the account context. 30 | moduleExec ModuleExecFunc // moduleExec is a function that executes a module message, when the resp type is unknown. 31 | moduleQuery ModuleQueryFunc // moduleQuery is a function that queries a module. 32 | } 33 | 34 | func addCtx(ctx context.Context, value contextValue) context.Context { 35 | return context.WithValue(ctx, contextKey{}, value) 36 | } 37 | 38 | func getCtx(ctx context.Context) contextValue { 39 | return ctx.Value(contextKey{}).(contextValue) 40 | } 41 | 42 | // MakeAccountContext creates a new account execution context given: 43 | // storeSvc: which fetches the x/accounts module store. 44 | // accountAddr: the address of the account being invoked, which is used to give the 45 | // account a prefixed storage. 46 | // sender: the address of entity invoking the account action. 47 | // moduleExec: a function that executes a module message. 48 | // moduleQuery: a function that queries a module. 49 | func MakeAccountContext( 50 | ctx context.Context, 51 | storeSvc store.KVStoreService, 52 | accNumber uint64, 53 | accountAddr []byte, 54 | sender []byte, 55 | funds sdk.Coins, 56 | moduleExec ModuleExecFunc, 57 | moduleQuery ModuleQueryFunc, 58 | ) context.Context { 59 | return addCtx(ctx, contextValue{ 60 | store: makeAccountStore(ctx, storeSvc, accNumber), 61 | sender: sender, 62 | whoami: accountAddr, 63 | funds: funds, 64 | parentContext: ctx, 65 | moduleExec: moduleExec, 66 | moduleQuery: moduleQuery, 67 | }) 68 | } 69 | 70 | func SetSender(ctx context.Context, sender []byte) context.Context { 71 | v := getCtx(ctx) 72 | v.sender = sender 73 | return addCtx(v.parentContext, v) 74 | } 75 | 76 | // makeAccountStore creates the prefixed store for the account. 77 | // It uses the number of the account, this gives constant size 78 | // bytes prefixes for the account state. 79 | func makeAccountStore(ctx context.Context, storeSvc store.KVStoreService, accNum uint64) store.KVStore { 80 | prefix := make([]byte, 8) 81 | binary.BigEndian.PutUint64(prefix, accNum) 82 | return prefixstore.New(storeSvc.OpenKVStore(ctx), append(AccountStatePrefix, prefix...)) 83 | } 84 | 85 | // ExecModule can be used to execute a message towards a module, when the response type is unknown. 86 | func ExecModule(ctx context.Context, msg transaction.Msg) (transaction.Msg, error) { 87 | // get sender 88 | v := getCtx(ctx) 89 | 90 | resp, err := v.moduleExec(v.parentContext, v.whoami, msg) 91 | if err != nil { 92 | return nil, err 93 | } 94 | 95 | return resp, nil 96 | } 97 | 98 | // QueryModule can be used by an account to execute a module query. 99 | func QueryModule(ctx context.Context, req transaction.Msg) (transaction.Msg, error) { 100 | // we do not need to check the sender in a query because it is not a state transition. 101 | // we also unwrap the original context. 102 | v := getCtx(ctx) 103 | resp, err := v.moduleQuery(v.parentContext, req) 104 | if err != nil { 105 | return nil, err 106 | } 107 | return resp, nil 108 | } 109 | 110 | // openKVStore returns the prefixed store for the account given the context. 111 | func openKVStore(ctx context.Context) store.KVStore { return getCtx(ctx).store } 112 | 113 | // Sender returns the address of the entity invoking the account action. 114 | func Sender(ctx context.Context) []byte { 115 | return getCtx(ctx).sender 116 | } 117 | 118 | // Whoami returns the address of the account being invoked. 119 | func Whoami(ctx context.Context) []byte { 120 | return getCtx(ctx).whoami 121 | } 122 | 123 | // Funds returns the funds associated with the execution context. 124 | func Funds(ctx context.Context) sdk.Coins { return getCtx(ctx).funds } 125 | -------------------------------------------------------------------------------- /internal/accounts/encoding.go: -------------------------------------------------------------------------------- 1 | package accounts 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "strings" 7 | 8 | codectypes "github.com/cosmos/cosmos-sdk/codec/types" 9 | "github.com/cosmos/gogoproto/proto" 10 | 11 | "github.com/sonr-io/snrd/internal/transaction" 12 | ) 13 | 14 | // ProtoMsgG is a generic interface for protobuf messages. 15 | type ProtoMsgG[T any] interface { 16 | *T 17 | transaction.Msg 18 | } 19 | 20 | type Any = codectypes.Any 21 | 22 | func FindMessageByName(name string) (transaction.Msg, error) { 23 | typ := proto.MessageType(name) 24 | if typ == nil { 25 | return nil, fmt.Errorf("no message type found for %s", name) 26 | } 27 | return reflect.New(typ.Elem()).Interface().(transaction.Msg), nil 28 | } 29 | 30 | func MessageName(msg transaction.Msg) string { 31 | return proto.MessageName(msg) 32 | } 33 | 34 | // PackAny packs a proto message into an anypb.Any. 35 | func PackAny(msg transaction.Msg) (*Any, error) { 36 | return codectypes.NewAnyWithValue(msg) 37 | } 38 | 39 | // UnpackAny unpacks an anypb.Any into a proto message. 40 | func UnpackAny[T any, PT ProtoMsgG[T]](anyPB *Any) (PT, error) { 41 | to := new(T) 42 | return to, UnpackAnyTo(anyPB, PT(to)) 43 | } 44 | 45 | func UnpackAnyTo(anyPB *Any, to transaction.Msg) error { 46 | return proto.Unmarshal(anyPB.Value, to) 47 | } 48 | 49 | func UnpackAnyRaw(anyPB *Any) (proto.Message, error) { 50 | split := strings.Split(anyPB.TypeUrl, "/") 51 | name := split[len(split)-1] 52 | typ := proto.MessageType(name) 53 | if typ == nil { 54 | return nil, fmt.Errorf("no message type found for %s", name) 55 | } 56 | to := reflect.New(typ.Elem()).Interface().(proto.Message) 57 | return to, UnpackAnyTo(anyPB, to) 58 | } 59 | 60 | func Merge(a, b transaction.Msg) { 61 | proto.Merge(a, b) 62 | } 63 | 64 | func Equal(a, b transaction.Msg) bool { 65 | return proto.Equal(a, b) 66 | } 67 | -------------------------------------------------------------------------------- /internal/accounts/interface.go: -------------------------------------------------------------------------------- 1 | package accounts 2 | 3 | // Account defines a smart account interface. 4 | type Account interface { 5 | // RegisterInitHandler allows the smart account to register an initialisation handler, using 6 | // the provided InitBuilder. The handler will be called when the smart account is initialized 7 | // (deployed). 8 | RegisterInitHandler(builder *InitBuilder) 9 | 10 | // RegisterExecuteHandlers allows the smart account to register execution handlers. 11 | // The smart account might also decide to not register any execution handler. 12 | RegisterExecuteHandlers(builder *ExecuteBuilder) 13 | 14 | // RegisterQueryHandlers allows the smart account to register query handlers. The smart account 15 | // might also decide to not register any query handler. 16 | RegisterQueryHandlers(builder *QueryBuilder) 17 | } 18 | -------------------------------------------------------------------------------- /internal/accounts/protoaccount.go: -------------------------------------------------------------------------------- 1 | package accounts 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "google.golang.org/protobuf/proto" 8 | 9 | "github.com/sonr-io/snrd/internal/transaction" 10 | ) 11 | 12 | // RegisterInitHandler registers an initialisation handler for a smart account that uses protobuf. 13 | func RegisterInitHandler[ 14 | Req any, ProtoReq ProtoMsgG[Req], Resp any, ProtoResp ProtoMsgG[Resp], 15 | ](router *InitBuilder, handler func(ctx context.Context, req ProtoReq) (ProtoResp, error), 16 | ) { 17 | reqName := MessageName(ProtoReq(new(Req))) 18 | 19 | router.handler = func(ctx context.Context, initRequest transaction.Msg) (initResponse transaction.Msg, err error) { 20 | concrete, ok := initRequest.(ProtoReq) 21 | if !ok { 22 | return nil, fmt.Errorf("%w: wanted %s, got %T", errInvalidMessage, reqName, initRequest) 23 | } 24 | return handler(ctx, concrete) 25 | } 26 | 27 | router.schema = HandlerSchema{ 28 | RequestSchema: *NewProtoMessageSchema[Req, ProtoReq](), 29 | ResponseSchema: *NewProtoMessageSchema[Resp, ProtoResp](), 30 | } 31 | } 32 | 33 | // RegisterExecuteHandler registers an execution handler for a smart account that uses protobuf. 34 | func RegisterExecuteHandler[ 35 | Req any, ProtoReq ProtoMsgG[Req], Resp any, ProtoResp ProtoMsgG[Resp], 36 | ](router *ExecuteBuilder, handler func(ctx context.Context, req ProtoReq) (ProtoResp, error), 37 | ) { 38 | reqName := MessageName(ProtoReq(new(Req))) 39 | // check if not registered already 40 | if _, ok := router.handlers[reqName]; ok { 41 | router.err = fmt.Errorf("handler already registered for message %s", reqName) 42 | return 43 | } 44 | 45 | router.handlers[reqName] = func(ctx context.Context, executeRequest transaction.Msg) (executeResponse transaction.Msg, err error) { 46 | concrete, ok := executeRequest.(ProtoReq) 47 | if !ok { 48 | return nil, fmt.Errorf("%w: wanted %s, got %T", errInvalidMessage, reqName, executeRequest) 49 | } 50 | return handler(ctx, concrete) 51 | } 52 | 53 | router.handlersSchema[reqName] = HandlerSchema{ 54 | RequestSchema: *NewProtoMessageSchema[Req, ProtoReq](), 55 | ResponseSchema: *NewProtoMessageSchema[Resp, ProtoResp](), 56 | } 57 | } 58 | 59 | // RegisterQueryHandler registers a query handler for a smart account that uses protobuf. 60 | func RegisterQueryHandler[ 61 | Req any, ProtoReq ProtoMsgG[Req], Resp any, ProtoResp ProtoMsgG[Resp], 62 | ](router *QueryBuilder, handler func(ctx context.Context, req ProtoReq) (ProtoResp, error), 63 | ) { 64 | RegisterExecuteHandler(router.er, handler) 65 | } 66 | 67 | func NewProtoMessageSchema[T any, PT ProtoMsgG[T]]() *MessageSchema { 68 | msg := PT(new(T)) 69 | if _, ok := (interface{}(msg)).(proto.Message); ok { 70 | panic("protov2 messages are not supported") 71 | } 72 | return &MessageSchema{ 73 | Name: MessageName(msg), 74 | New: func() transaction.Msg { 75 | return PT(new(T)) 76 | }, 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /internal/address/bip32.go: -------------------------------------------------------------------------------- 1 | package address 2 | 3 | import ( 4 | "crypto/hmac" 5 | "crypto/sha512" 6 | "encoding/binary" 7 | "errors" 8 | "math/big" 9 | 10 | "github.com/btcsuite/btcd/btcec/v2" 11 | ) 12 | 13 | // ComputePublicKey computes the public key of a child key given the extended public key, chain code, coin type, and index. 14 | func ComputePublicKey(extPubKey []byte, chainCode []byte, coinType uint32, index int) ([]byte, error) { 15 | // Check if the index is a hardened child key 16 | if uint32(index) >= HardenedOffset { 17 | return nil, errors.New("cannot derive hardened child key from public key") 18 | } 19 | 20 | // Serialize the public key 21 | pubKey, err := btcec.ParsePubKey(extPubKey) 22 | if err != nil { 23 | return nil, err 24 | } 25 | pubKeyBytes := pubKey.SerializeCompressed() 26 | 27 | // Serialize the index 28 | indexBytes := make([]byte, 4) 29 | binary.BigEndian.PutUint32(indexBytes, uint32(index)) 30 | 31 | // Compute the HMAC-SHA512 32 | mac := hmac.New(sha512.New, chainCode) 33 | mac.Write(pubKeyBytes) 34 | mac.Write(indexBytes) 35 | I := mac.Sum(nil) 36 | 37 | // Split I into two 32-byte sequences 38 | IL := I[:32] 39 | 40 | // Convert IL to a big integer 41 | ilNum := new(big.Int).SetBytes(IL) 42 | 43 | // Check if parse256(IL) >= n 44 | curve := btcec.S256() 45 | if ilNum.Cmp(curve.N) >= 0 { 46 | return nil, errors.New("invalid child key") 47 | } 48 | 49 | // Compute the child public key: pubKey + IL * G 50 | ilx, ily := curve.ScalarBaseMult(IL) 51 | childX, childY := curve.Add(ilx, ily, pubKey.X(), pubKey.Y()) 52 | lx := newBigIntFieldVal(childX) 53 | ly := newBigIntFieldVal(childY) 54 | 55 | // Create the child public key 56 | childPubKey := btcec.NewPublicKey(lx, ly) 57 | childPubKeyBytes := childPubKey.SerializeCompressed() 58 | return childPubKeyBytes, nil 59 | } 60 | 61 | // newBigIntFieldVal creates a new field value from a big integer. 62 | func newBigIntFieldVal(val *big.Int) *btcec.FieldVal { 63 | lx := new(btcec.FieldVal) 64 | lx.SetByteSlice(val.Bytes()) 65 | return lx 66 | } 67 | -------------------------------------------------------------------------------- /internal/address/codec.go: -------------------------------------------------------------------------------- 1 | package address 2 | 3 | type CoinType uint32 4 | 5 | const ( 6 | // Hardened offset for BIP-44 derivation 7 | HardenedOffset uint32 = 0x80000000 8 | 9 | // Registered coin types for BIP-44 10 | CoinTypeBitcoin CoinType = CoinType(0 + HardenedOffset) 11 | CoinTypeEthereum CoinType = CoinType(60 + HardenedOffset) 12 | CoinTypeSonr CoinType = CoinType(703 + HardenedOffset) 13 | ) 14 | 15 | // Uint32 returns the coin type as a uint32. 16 | func (c CoinType) Uint32() uint32 { 17 | return uint32(c) 18 | } 19 | -------------------------------------------------------------------------------- /internal/appmodule/environment.go: -------------------------------------------------------------------------------- 1 | package appmodule 2 | 3 | import ( 4 | "cosmossdk.io/core/event" 5 | "cosmossdk.io/core/gas" 6 | "cosmossdk.io/core/header" 7 | "cosmossdk.io/core/store" 8 | 9 | "github.com/sonr-io/snrd/internal/branch" 10 | "github.com/sonr-io/snrd/internal/log" 11 | "github.com/sonr-io/snrd/internal/router" 12 | "github.com/sonr-io/snrd/internal/transaction" 13 | ) 14 | 15 | // Environment is used to get all services to their respective module. 16 | // Contract: All fields of environment are always populated by runtime. 17 | type Environment struct { 18 | Logger log.Logger 19 | 20 | BranchService branch.Service 21 | EventService event.Service 22 | GasService gas.Service 23 | HeaderService header.Service 24 | QueryRouterService router.Service 25 | MsgRouterService router.Service 26 | TransactionService transaction.Service 27 | 28 | KVStoreService store.KVStoreService 29 | MemStoreService store.MemoryStoreService 30 | } 31 | -------------------------------------------------------------------------------- /internal/branch/branch.go: -------------------------------------------------------------------------------- 1 | // Package branch contains the core branch service interface. 2 | package branch 3 | 4 | import ( 5 | "context" 6 | "errors" 7 | ) 8 | 9 | // ErrGasLimitExceeded is returned when the gas limit is exceeded in a 10 | // Service.ExecuteWithGasLimit call. 11 | var ErrGasLimitExceeded = errors.New("branch: gas limit exceeded") 12 | 13 | // Service is the branch service interface. It can be used to execute 14 | // code paths in an isolated execution context that can be reverted. 15 | // A revert typically means a rollback on events and state changes. 16 | type Service interface { 17 | // Execute executes the given function in an isolated context. If the 18 | // `f` function returns an error, the execution is considered failed, 19 | // and every change made affecting the execution context is rolled back. 20 | // If the function returns nil, the execution is considered successful, and 21 | // committed. 22 | // The context.Context passed to the `f` function is a child of the context 23 | // passed to the Execute function, and is what should be used with other 24 | // core services in order to ensure the execution remains isolated. 25 | Execute(ctx context.Context, f func(ctx context.Context) error) error 26 | // ExecuteWithGasLimit executes the given function `f` in an isolated context, 27 | // with the provided gas limit, this is advanced usage and is used to disallow 28 | // an execution path to consume an indefinite amount of gas. 29 | // If the execution fails or succeeds the gas limit is still applied to the 30 | // parent context, the function returns a gasUsed value which is the amount 31 | // of gas used by the execution path. If the execution path exceeds the gas 32 | // ErrGasLimitExceeded is returned. 33 | ExecuteWithGasLimit(ctx context.Context, gasLimit uint64, f func(ctx context.Context) error) (gasUsed uint64, err error) 34 | } 35 | -------------------------------------------------------------------------------- /internal/didcrypto/did.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import ( 4 | "crypto/ecdsa" 5 | "crypto/elliptic" 6 | "crypto/x509" 7 | "fmt" 8 | "strings" 9 | 10 | crypto "github.com/libp2p/go-libp2p/core/crypto" 11 | mbase "github.com/multiformats/go-multibase" 12 | "github.com/multiformats/go-multicodec" 13 | varint "github.com/multiformats/go-varint" 14 | ) 15 | 16 | // Signature algorithms from the [did:key specification] 17 | // 18 | // [did:key specification]: https://w3c-ccg.github.io/did-method-key/#signature-method-creation-algorithm 19 | const ( 20 | X25519 = multicodec.X25519Pub 21 | Ed25519 = multicodec.Ed25519Pub // UCAN required/recommended 22 | P256 = multicodec.P256Pub // UCAN required 23 | P384 = multicodec.P384Pub 24 | P521 = multicodec.P521Pub 25 | Secp256k1 = multicodec.Secp256k1Pub // UCAN required 26 | RSA = multicodec.RsaPub 27 | ) 28 | 29 | // Undef can be used to represent a nil or undefined DID, using DID{} 30 | // directly is also acceptable. 31 | var Undef = DID{} 32 | 33 | // DID is a Decentralized Identifier of the did:key type, directly holding a cryptographic public key. 34 | // [did:key format]: https://w3c-ccg.github.io/did-method-key/ 35 | type DID struct { 36 | code multicodec.Code 37 | bytes string // as string instead of []byte to allow the == operator 38 | } 39 | 40 | // Parse returns the DID from the string representation or an error if 41 | // the prefix and method are incorrect, if an unknown encryption algorithm 42 | // is specified or if the method-specific-identifier's bytes don't 43 | // represent a public key for the specified encryption algorithm. 44 | func Parse(str string) (DID, error) { 45 | const keyPrefix = "did:key:" 46 | 47 | if !strings.HasPrefix(str, keyPrefix) { 48 | return Undef, fmt.Errorf("must start with 'did:key'") 49 | } 50 | 51 | baseCodec, bytes, err := mbase.Decode(str[len(keyPrefix):]) 52 | if err != nil { 53 | return Undef, err 54 | } 55 | if baseCodec != mbase.Base58BTC { 56 | return Undef, fmt.Errorf("not Base58BTC encoded") 57 | } 58 | code, _, err := varint.FromUvarint(bytes) 59 | if err != nil { 60 | return Undef, err 61 | } 62 | switch multicodec.Code(code) { 63 | case Ed25519, P256, Secp256k1, RSA: 64 | return DID{bytes: string(bytes), code: multicodec.Code(code)}, nil 65 | default: 66 | return Undef, fmt.Errorf("unsupported did:key multicodec: 0x%x", code) 67 | } 68 | } 69 | 70 | // MustParse is like Parse but panics instead of returning an error. 71 | func MustParse(str string) DID { 72 | did, err := Parse(str) 73 | if err != nil { 74 | panic(err) 75 | } 76 | return did 77 | } 78 | 79 | // Defined tells if the DID is defined, not equal to Undef. 80 | func (d DID) Defined() bool { 81 | return d.code != 0 || len(d.bytes) > 0 82 | } 83 | 84 | // PubKey returns the public key encapsulated by the did:key. 85 | func (d DID) PubKey() (crypto.PubKey, error) { 86 | unmarshaler, ok := map[multicodec.Code]crypto.PubKeyUnmarshaller{ 87 | X25519: crypto.UnmarshalEd25519PublicKey, 88 | Ed25519: crypto.UnmarshalEd25519PublicKey, 89 | P256: ecdsaPubKeyUnmarshaler(elliptic.P256()), 90 | P384: ecdsaPubKeyUnmarshaler(elliptic.P384()), 91 | P521: ecdsaPubKeyUnmarshaler(elliptic.P521()), 92 | Secp256k1: crypto.UnmarshalSecp256k1PublicKey, 93 | RSA: rsaPubKeyUnmarshaller, 94 | }[d.code] 95 | if !ok { 96 | return nil, fmt.Errorf("unsupported multicodec: %d", d.code) 97 | } 98 | 99 | codeSize := varint.UvarintSize(uint64(d.code)) 100 | return unmarshaler([]byte(d.bytes)[codeSize:]) 101 | } 102 | 103 | // String formats the decentralized identity document (DID) as a string. 104 | func (d DID) String() string { 105 | key, _ := mbase.Encode(mbase.Base58BTC, []byte(d.bytes)) 106 | return "did:key:" + key 107 | } 108 | 109 | func ecdsaPubKeyUnmarshaler(curve elliptic.Curve) crypto.PubKeyUnmarshaller { 110 | return func(data []byte) (crypto.PubKey, error) { 111 | x, y := elliptic.UnmarshalCompressed(curve, data) 112 | 113 | ecdsaPublicKey := &ecdsa.PublicKey{ 114 | Curve: curve, 115 | X: x, 116 | Y: y, 117 | } 118 | 119 | pkix, err := x509.MarshalPKIXPublicKey(ecdsaPublicKey) 120 | if err != nil { 121 | return nil, err 122 | } 123 | 124 | return crypto.UnmarshalECDSAPublicKey(pkix) 125 | } 126 | } 127 | 128 | func rsaPubKeyUnmarshaller(data []byte) (crypto.PubKey, error) { 129 | rsaPublicKey, err := x509.ParsePKCS1PublicKey(data) 130 | if err != nil { 131 | return nil, err 132 | } 133 | 134 | pkix, err := x509.MarshalPKIXPublicKey(rsaPublicKey) 135 | if err != nil { 136 | return nil, err 137 | } 138 | 139 | return crypto.UnmarshalRsaPublicKey(pkix) 140 | } 141 | -------------------------------------------------------------------------------- /internal/didcrypto/did_test.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestParseDIDKey(t *testing.T) { 10 | str := "did:key:z6Mkod5Jr3yd5SC7UDueqK4dAAw5xYJYjksy722tA9Boxc4z" 11 | d, err := Parse(str) 12 | require.NoError(t, err) 13 | require.Equal(t, str, d.String()) 14 | } 15 | 16 | func TestMustParseDIDKey(t *testing.T) { 17 | str := "did:key:z6Mkod5Jr3yd5SC7UDueqK4dAAw5xYJYjksy722tA9Boxc4z" 18 | require.NotPanics(t, func() { 19 | d := MustParse(str) 20 | require.Equal(t, str, d.String()) 21 | }) 22 | str = "did:key:z7Mkod5Jr3yd5SC7UDueqK4dAAw5xYJYjksy722tA9Boxc4z" 23 | require.Panics(t, func() { 24 | MustParse(str) 25 | }) 26 | } 27 | 28 | func TestEquivalence(t *testing.T) { 29 | undef0 := DID{} 30 | undef1 := Undef 31 | 32 | did0, err := Parse("did:key:z6Mkod5Jr3yd5SC7UDueqK4dAAw5xYJYjksy722tA9Boxc4z") 33 | require.NoError(t, err) 34 | did1, err := Parse("did:key:z6Mkod5Jr3yd5SC7UDueqK4dAAw5xYJYjksy722tA9Boxc4z") 35 | require.NoError(t, err) 36 | 37 | require.True(t, undef0 == undef1) 38 | require.False(t, undef0 == did0) 39 | require.True(t, did0 == did1) 40 | require.False(t, undef1 == did1) 41 | } 42 | -------------------------------------------------------------------------------- /internal/ipfsnode/config.go: -------------------------------------------------------------------------------- 1 | package ipfsnode 2 | -------------------------------------------------------------------------------- /internal/ipfsnode/ipfsnode.go: -------------------------------------------------------------------------------- 1 | package ipfsnode 2 | -------------------------------------------------------------------------------- /internal/log/logger.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | const ModuleKey = "module" 4 | 5 | // Logger defines basic logger functionality that all previous versions of the Logger interface should 6 | // support. Library users should prefer to use this interface when possible, then type case to Logger 7 | // to see if WithContext is supported. 8 | type Logger interface { 9 | // Info takes a message and a set of key/value pairs and logs with level INFO. 10 | // The key of the tuple must be a string. 11 | Info(msg string, keyVals ...any) 12 | 13 | // Warn takes a message and a set of key/value pairs and logs with level WARN. 14 | // The key of the tuple must be a string. 15 | Warn(msg string, keyVals ...any) 16 | 17 | // Error takes a message and a set of key/value pairs and logs with level ERR. 18 | // The key of the tuple must be a string. 19 | Error(msg string, keyVals ...any) 20 | 21 | // Debug takes a message and a set of key/value pairs and logs with level DEBUG. 22 | // The key of the tuple must be a string. 23 | Debug(msg string, keyVals ...any) 24 | 25 | // Impl returns the underlying logger implementation. 26 | // It is used to access the full functionalities of the underlying logger. 27 | // Advanced users can type cast the returned value to the actual logger. 28 | Impl() any 29 | } 30 | -------------------------------------------------------------------------------- /internal/router/service.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/sonr-io/snrd/internal/transaction" 7 | ) 8 | 9 | // Service is the interface that wraps the basic methods for a router. 10 | // A router can be a query router or a message router. 11 | type Service interface { 12 | // CanInvoke returns an error if the given request cannot be invoked. 13 | CanInvoke(ctx context.Context, typeURL string) error 14 | // Invoke execute a message or query. The response should be type casted by the caller to the expected response. 15 | Invoke(ctx context.Context, req transaction.Msg) (res transaction.Msg, err error) 16 | } 17 | -------------------------------------------------------------------------------- /internal/transaction/service.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import "context" 4 | 5 | // ExecMode defines the execution mode 6 | type ExecMode uint8 7 | 8 | // All possible execution modes. 9 | // For backwards compatibility and easier casting, the exec mode values must be the same as in cosmos/cosmos-sdk/types package. 10 | const ( 11 | ExecModeCheck ExecMode = iota 12 | ExecModeReCheck 13 | ExecModeSimulate 14 | _ 15 | _ 16 | _ 17 | _ 18 | ExecModeFinalize 19 | ) 20 | 21 | // Service creates a transaction service. 22 | type Service interface { 23 | // ExecMode returns the current execution mode. 24 | ExecMode(ctx context.Context) ExecMode 25 | } 26 | -------------------------------------------------------------------------------- /internal/transaction/transaction.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | type ( 4 | // Msg uses structural types to define the interface for a message. 5 | Msg = interface { 6 | Reset() 7 | String() string 8 | ProtoMessage() 9 | } 10 | Identity = []byte 11 | ) 12 | 13 | // GenericMsg defines a generic version of a Msg. 14 | // The GenericMsg refers to the non pointer version of Msg, 15 | // and is required to allow its instantiations in generic contexts. 16 | type GenericMsg[T any] interface { 17 | *T 18 | Msg 19 | } 20 | 21 | // Codec defines the TX codec, which converts a TX from bytes to its concrete representation. 22 | type Codec[T Tx] interface { 23 | // Decode decodes the tx bytes into a DecodedTx, containing 24 | // both concrete and bytes representation of the tx. 25 | Decode([]byte) (T, error) 26 | // DecodeJSON decodes the tx JSON bytes into a DecodedTx 27 | DecodeJSON([]byte) (T, error) 28 | } 29 | 30 | // Tx defines the interface for a transaction. 31 | // All custom transactions must implement this interface. 32 | type Tx interface { 33 | // Hash returns the unique identifier for the Tx. 34 | Hash() [32]byte 35 | // GetMessages returns the list of state transitions of the Tx. 36 | GetMessages() ([]Msg, error) 37 | // GetSenders returns the tx state transition sender. 38 | GetSenders() ([]Identity, error) // TODO reduce this to a single identity if accepted 39 | // GetGasLimit returns the gas limit of the tx. Must return math.MaxUint64 for infinite gas 40 | // txs. 41 | GetGasLimit() (uint64, error) 42 | // Bytes returns the encoded version of this tx. Note: this is ideally cached 43 | // from the first instance of the decoding of the tx. 44 | Bytes() []byte 45 | } 46 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | 6 | "cosmossdk.io/log" 7 | svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" 8 | _ "github.com/joho/godotenv/autoload" 9 | 10 | "github.com/sonr-io/snrd/app" 11 | "github.com/sonr-io/snrd/cmd" 12 | ) 13 | 14 | func main() { 15 | rootCmd := cmd.NewRootCmd() 16 | if err := svrcmd.Execute(rootCmd, "", app.DefaultNodeHome); err != nil { 17 | log.NewLogger(rootCmd.OutOrStderr()).Error("failure when running app", "err", err) 18 | os.Exit(1) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /proto/README.md: -------------------------------------------------------------------------------- 1 | # Sonr Protobuf 2 | 3 | ## Overview 4 | 5 | This directory contains the protobuf definitions for the Sonr blockchain. 6 | 7 | ## Directory Structure 8 | 9 | ### `did` 10 | 11 | The `did` directory contains the protobuf definitions for the DID module. 12 | 13 | ### `dwn` 14 | 15 | The `dwn` directory contains the protobuf definitions for the Vault module. 16 | 17 | ### `svc` 18 | 19 | The `service` directory contains the protobuf definitions for the Service module. 20 | -------------------------------------------------------------------------------- /proto/buf.gen.gogo.yaml: -------------------------------------------------------------------------------- 1 | version: v1 2 | plugins: 3 | - name: gocosmos 4 | out: .. 5 | opt: plugins=grpc,Mgoogle/protobuf/any.proto=github.com/cosmos/cosmos-sdk/codec/types,Mcosmos/orm/v1/orm.proto=cosmossdk.io/orm 6 | - name: grpc-gateway 7 | out: .. 8 | opt: logtostderr=true,allow_colon_final_segments=true 9 | -------------------------------------------------------------------------------- /proto/buf.gen.pulsar.yaml: -------------------------------------------------------------------------------- 1 | version: v1 2 | managed: 3 | enabled: true 4 | go_package_prefix: 5 | default: github.com/sonr-io/snrd/api 6 | except: 7 | - buf.build/googleapis/googleapis 8 | - buf.build/cosmos/gogo-proto 9 | - buf.build/cosmos/cosmos-proto 10 | override: 11 | buf.build/cosmos/cosmos-sdk: cosmossdk.io/api # required to import the Cosmos SDK api module for the orm 12 | plugins: 13 | - name: go-pulsar 14 | out: .. 15 | opt: paths=source_relative 16 | - name: go-grpc 17 | out: .. 18 | opt: paths=source_relative 19 | - name: go-cosmos-orm 20 | out: .. 21 | opt: paths=source_relative 22 | -------------------------------------------------------------------------------- /proto/buf.lock: -------------------------------------------------------------------------------- 1 | # Generated by buf. DO NOT EDIT. 2 | version: v1 3 | deps: 4 | - remote: buf.build 5 | owner: cosmos 6 | repository: cosmos-proto 7 | commit: 04467658e59e44bbb22fe568206e1f70 8 | digest: shake256:73a640bd60e0c523b0f8237ff34eab67c45a38b64bbbde1d80224819d272dbf316ac183526bd245f994af6608b025f5130483d0133c5edd385531326b5990466 9 | - remote: buf.build 10 | owner: cosmos 11 | repository: cosmos-sdk 12 | commit: 05419252bcc241ea8023acf1ed4cadc5 13 | digest: shake256:1e54a48c19a8b59d35e0a7efa76402939f515f2d8005df099856f24c37c20a52800308f025abb8cffcd014d437b49707388aaca4865d9d063d8f25d5d4eb77d5 14 | - remote: buf.build 15 | owner: cosmos 16 | repository: gogo-proto 17 | commit: 88ef6483f90f478fb938c37dde52ece3 18 | digest: shake256:89c45df2aa11e0cff97b0d695436713db3d993d76792e9f8dc1ae90e6ab9a9bec55503d48ceedd6b86069ab07d3041b32001b2bfe0227fa725dd515ff381e5ba 19 | - remote: buf.build 20 | owner: googleapis 21 | repository: googleapis 22 | commit: c0913f24652a4cfc95f77d97443a5005 23 | digest: shake256:0ef3248c6235d420fe61f373154adcde6b94e3297f82472b1d8d8c3747240b61b4a10405e2a6f8ac1c98816ac6e690ea7871024aa5ae0e035cd540214667ceed 24 | - remote: buf.build 25 | owner: protocolbuffers 26 | repository: wellknowntypes 27 | commit: 657250e6a39648cbb169d079a60bd9ba 28 | digest: shake256:00de25001b8dd2e29d85fc4bcc3ede7aed886d76d67f5e0f7a9b320b90f871d3eb73507d50818d823a0512f3f8db77a11c043685528403e31ff3fef18323a9fb 29 | - remote: buf.build 30 | owner: tendermint 31 | repository: tendermint 32 | commit: 33ed361a90514289beabf3189e1d7665 33 | digest: shake256:038267e06294714fd883610626554b04a127b576b4e253befb4206cb72d5d3c1eeccacd4b9ec8e3fb891f7c14e1cb0f770c077d2989638995b0a61c85afedb1d 34 | -------------------------------------------------------------------------------- /proto/buf.yaml: -------------------------------------------------------------------------------- 1 | version: v1 2 | name: buf.build/onsonr/sonr 3 | deps: 4 | - buf.build/cosmos/cosmos-sdk 5 | - buf.build/cosmos/cosmos-proto 6 | - buf.build/cosmos/gogo-proto 7 | - buf.build/googleapis/googleapis 8 | breaking: 9 | use: 10 | - FILE 11 | lint: 12 | use: 13 | - DEFAULT 14 | - COMMENTS 15 | - FILE_LOWER_SNAKE_CASE 16 | except: 17 | - UNARY_RPC 18 | - COMMENT_FIELD 19 | - COMMENT_MESSAGE 20 | - COMMENT_SERVICE 21 | - COMMENT_RPC 22 | - SERVICE_SUFFIX 23 | - PACKAGE_VERSION_SUFFIX 24 | - RPC_REQUEST_STANDARD_NAME 25 | - PACKAGE_SAME_GO_PACKAGE 26 | - PACKAGE_SAME_DIRECTORY 27 | - PACKAGE_DIRECTORY_MATCH 28 | - RPC_RESPONSE_STANDARD_NAME 29 | - COMMENT_ENUM_VALUE 30 | - COMMENT_ENUM 31 | - ENUM_ZERO_VALUE_SUFFIX 32 | ignore: 33 | - PACKAGE_NO_IMPORT_CYCLE 34 | - IMPORT_USED 35 | - tendermint 36 | - amino 37 | - cosmos 38 | -------------------------------------------------------------------------------- /proto/did/module/v1/module.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package did.module.v1; 4 | 5 | import "cosmos/app/v1alpha1/module.proto"; 6 | 7 | // Module is the app config object of the module. 8 | // Learn more: https://docs.cosmos.network/main/building-modules/depinject 9 | message Module { 10 | option (cosmos.app.v1alpha1.module) = {go_import: "github.com/sonr-io/snrd"}; 11 | } 12 | -------------------------------------------------------------------------------- /proto/did/v1/genesis.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package did.v1; 3 | 4 | import "amino/amino.proto"; 5 | import "gogoproto/gogo.proto"; 6 | 7 | option go_package = "github.com/sonr-io/snrd/x/did/types"; 8 | 9 | // GenesisState defines the module genesis state 10 | message GenesisState { 11 | // Params defines all the parameters of the module. 12 | Params params = 1 [(gogoproto.nullable) = false]; 13 | } 14 | 15 | // Params defines the set of module parameters. 16 | message Params { 17 | option (amino.name) = "did/params"; 18 | option (gogoproto.equal) = true; 19 | option (gogoproto.goproto_stringer) = false; 20 | 21 | repeated Attenuation attenuations = 1; 22 | } 23 | 24 | // Attenuation defines the attenuation of a resource 25 | message Attenuation { 26 | Resource resource = 1; 27 | repeated Capability capabilities = 2; 28 | } 29 | 30 | // Capability reprensents the available capabilities of a decentralized web node 31 | message Capability { 32 | string name = 1; 33 | string parent = 2; 34 | string description = 3; 35 | repeated string resources = 4; 36 | } 37 | 38 | // Resource reprensents the available resources of a decentralized web node 39 | message Resource { 40 | string kind = 1; 41 | string template = 2; 42 | } 43 | 44 | 45 | // Document defines a DID document 46 | message Document { 47 | string id = 1; 48 | string controller = 2; // The DID of the controller 49 | repeated string authentication = 3; 50 | repeated string assertion_method = 4; 51 | repeated string capability_delegation = 5; 52 | repeated string capability_invocation = 6; 53 | repeated string service = 7; 54 | } 55 | -------------------------------------------------------------------------------- /proto/did/v1/query.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package did.v1; 3 | 4 | import "did/v1/genesis.proto"; 5 | import "google/api/annotations.proto"; 6 | 7 | option go_package = "github.com/sonr-io/snrd/x/did/types"; 8 | 9 | // Query provides defines the gRPC querier service. 10 | service Query { 11 | // Params queries all parameters of the module. 12 | rpc Params(QueryRequest) returns (QueryParamsResponse) { 13 | option (google.api.http).get = "/did/v1/params"; 14 | } 15 | 16 | // Resolve queries the DID document by its id. 17 | rpc Resolve(QueryRequest) returns (QueryResolveResponse) { 18 | option (google.api.http).get = "/did/v1/{did}"; 19 | } 20 | 21 | // Verify verifies a message with the DID document 22 | rpc Verify(QueryVerifyRequest) returns (QueryVerifyResponse) { 23 | option (google.api.http).post = "/did/v1/{did}/verify"; 24 | } 25 | } 26 | 27 | // Queryequest is the request type for the Query/Params RPC method. 28 | message QueryRequest { 29 | string did = 1; 30 | string origin = 2; 31 | string key = 3; 32 | string asset = 4; 33 | } 34 | 35 | // QueryParamsResponse is the response type for the Query/Params RPC method. 36 | message QueryParamsResponse { 37 | // params defines the parameters of the module. 38 | Params params = 1; 39 | } 40 | 41 | // QueryResolveResponse is the response type for the Query/Resolve RPC method. 42 | message QueryResolveResponse { 43 | // document is the DID document 44 | Document document = 1; 45 | } 46 | 47 | // QuerySignRequest is the request type for the Query/Sign RPC method. 48 | message QuerySignRequest { 49 | string did = 1; 50 | string origin = 2; 51 | string key = 3; 52 | string asset = 4; 53 | string message = 5; 54 | } 55 | 56 | // QuerySignResponse is the response type for the Query/Sign RPC method. 57 | message QuerySignResponse { 58 | // signature is the signature of the message 59 | string signature = 1; 60 | } 61 | 62 | // QueryVerifyRequest is the request type for the Query/Verify RPC method. 63 | message QueryVerifyRequest { 64 | string did = 1; 65 | string origin = 2; 66 | string key = 3; 67 | string asset = 4; 68 | string message = 5; 69 | string signature = 6; 70 | } 71 | 72 | // QueryVerifyResponse is the response type for the Query/Verify RPC method. 73 | message QueryVerifyResponse { 74 | // valid is the validity of the signature 75 | bool valid = 1; 76 | } 77 | -------------------------------------------------------------------------------- /proto/did/v1/state.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package did.v1; 4 | 5 | import "cosmos/orm/v1/orm.proto"; 6 | import "did/v1/genesis.proto"; 7 | 8 | option go_package = "github.com/sonr-io/snrd/x/did/types"; 9 | 10 | message Account { 11 | option (cosmos.orm.v1.table) = { 12 | id: 1 13 | primary_key: {fields: "did"} 14 | index: { 15 | id: 1 16 | fields: "controller,subject" 17 | unique: true 18 | } 19 | }; 20 | 21 | // The unique identifier of the assertion 22 | string did = 1; 23 | 24 | // The authentication of the DID 25 | string controller = 2; 26 | 27 | // Origin of the authentication 28 | string subject = 3; 29 | 30 | // string is the verification method 31 | string public_key_hex = 4; 32 | 33 | // AssertionType is the assertion type 34 | string assertion_type = 5; 35 | 36 | // Metadata of the authentication 37 | map accumulator = 6; 38 | 39 | // CreationBlock is the block number of the creation of the authentication 40 | int64 creation_block = 7; 41 | } 42 | 43 | // PublicKey represents a public key 44 | message PublicKey { 45 | option (cosmos.orm.v1.table) = { 46 | id: 2 47 | primary_key: { 48 | fields: "number" 49 | auto_increment: true 50 | } 51 | index: { 52 | id: 1 53 | fields: "sonr_address" 54 | unique: true 55 | } 56 | index: { 57 | id: 2 58 | fields: "eth_address" 59 | unique: true 60 | } 61 | index: { 62 | id: 3 63 | fields: "btc_address" 64 | unique: true 65 | } 66 | index: { 67 | id: 4 68 | fields: "did" 69 | unique: true 70 | } 71 | }; 72 | 73 | // The unique identifier of the controller 74 | uint64 number = 1; 75 | 76 | // The unique identifier of the controller 77 | string did = 2; 78 | 79 | // The DID of the controller 80 | string sonr_address = 3; 81 | 82 | // The DID of the controller 83 | string eth_address = 4; 84 | 85 | // The DID of the controller 86 | string btc_address = 5; 87 | 88 | // string is the verification method 89 | string public_key_hex = 6; 90 | 91 | // Pointer to the Keyshares 92 | string ks_val = 7; 93 | 94 | // The block number of when a user claimed the controller 95 | int64 claimed_block = 8; 96 | 97 | // CreationBlock is the block number of the creation of the controller 98 | int64 creation_block = 9; 99 | } 100 | 101 | // Verification represents a verification method 102 | message Verification { 103 | option (cosmos.orm.v1.table) = { 104 | id: 3 105 | primary_key: {fields: "did"} 106 | index: { 107 | id: 1 108 | fields: "issuer,subject" 109 | unique: true 110 | } 111 | index: { 112 | id: 2 113 | fields: "controller,did_method,issuer" 114 | unique: true 115 | } 116 | index: { 117 | id: 3 118 | fields: "verification_type,subject,issuer" 119 | unique: true 120 | } 121 | }; 122 | 123 | // The unique identifier of the verification 124 | string did = 1; 125 | 126 | // The controller of the verification 127 | string controller = 2; 128 | 129 | // The DIDNamespace of the verification 130 | string did_method = 3; 131 | 132 | // The value of the linked identifier 133 | string issuer = 4; 134 | 135 | // The subject of the verification 136 | string subject = 5; 137 | 138 | // The public key of the verification 139 | string public_key_hex = 6; 140 | 141 | // The verification method type 142 | string verification_type = 7; 143 | 144 | // Metadata of the verification 145 | map metadata = 8; 146 | 147 | // CreationBlock is the block number of the creation of the controller 148 | int64 creation_block = 9; 149 | } 150 | -------------------------------------------------------------------------------- /proto/dwn/module/v1/module.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package dwn.module.v1; 4 | 5 | import "cosmos/app/v1alpha1/module.proto"; 6 | 7 | // Module is the app config object of the module. 8 | // Learn more: https://docs.cosmos.network/main/building-modules/depinject 9 | message Module { 10 | option (cosmos.app.v1alpha1.module) = { 11 | go_import : "github.com/sonr-io/snrd" 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /proto/dwn/v1/genesis.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package dwn.v1; 3 | 4 | import "gogoproto/gogo.proto"; 5 | import "amino/amino.proto"; 6 | 7 | option go_package = "github.com/sonr-io/snrd/x/dwn/types"; 8 | 9 | // GenesisState defines the module genesis state 10 | message GenesisState { 11 | // Params defines all the parameters of the module. 12 | Params params = 1 [(gogoproto.nullable) = false]; 13 | } 14 | 15 | // Params defines the set of module parameters. 16 | message Params { 17 | option (amino.name) = "vault/params"; 18 | option (gogoproto.equal) = true; 19 | option (gogoproto.goproto_stringer) = false; 20 | 21 | // Attenuation defines the available attenuations 22 | repeated Attenuation attenuations = 1; 23 | repeated string allowed_operators = 2; 24 | } 25 | 26 | // Attenuation defines the attenuation of a resource 27 | message Attenuation { 28 | Resource resource = 1; 29 | repeated Capability capabilities = 2; 30 | } 31 | 32 | // Capability reprensents the available capabilities of a decentralized web node 33 | message Capability { 34 | string name = 1; 35 | string parent = 2; 36 | string description = 3; 37 | repeated string resources = 4; 38 | } 39 | 40 | // Resource reprensents the available resources of a decentralized web node 41 | message Resource { 42 | string kind = 1; 43 | string template = 2; 44 | } 45 | -------------------------------------------------------------------------------- /proto/dwn/v1/query.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package dwn.v1; 3 | 4 | import "google/api/annotations.proto"; 5 | import "dwn/v1/genesis.proto"; 6 | 7 | option go_package = "github.com/sonr-io/snrd/x/dwn/types"; 8 | 9 | // ╭─────────────────────────────────────────────────────────╮ 10 | // │ RPC Query Service │ 11 | // ╰─────────────────────────────────────────────────────────╯ 12 | 13 | // Query provides defines the gRPC querier service. 14 | service Query { 15 | // Params queries all parameters of the module. 16 | rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { 17 | option (google.api.http).get = "/vault/v1/params"; 18 | } 19 | } 20 | 21 | // ╭──────────────────────────────────────────────────────────╮ 22 | // │ RPC Query Messages │ 23 | // ╰──────────────────────────────────────────────────────────╯ 24 | 25 | // QueryParamsRequest is the request type for the Query/Params RPC method. 26 | message QueryParamsRequest {} 27 | 28 | // QueryParamsResponse is the response type for the Query/Params RPC method. 29 | message QueryParamsResponse { 30 | // params defines the parameters of the module. 31 | Params params = 1; 32 | } 33 | -------------------------------------------------------------------------------- /proto/dwn/v1/state.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package dwn.v1; 3 | 4 | import "cosmos/orm/v1/orm.proto"; 5 | 6 | option go_package = "github.com/sonr-io/snrd/x/dwn/types"; 7 | 8 | // https://github.com/cosmos/cosmos-sdk/blob/main/orm/README.md 9 | 10 | message Credential { 11 | option (cosmos.orm.v1.table) = { 12 | id: 1; 13 | primary_key: { fields: "id" } 14 | }; 15 | 16 | bytes id = 1; // The credential ID as a byte array 17 | string kind = 2; // The credential type (e.g. "public-key") 18 | repeated string transports = 3; // Optional transport hints (usb, nfc, ble, internal) 19 | bytes public_key = 4; // The credential's public key 20 | string attestation_type = 5; // The attestation type used (e.g. "none", "indirect", etc) 21 | uint64 created_at = 6; // Timestamp of when the credential was created 22 | } 23 | 24 | message Profile { 25 | option (cosmos.orm.v1.table) = { 26 | id: 2; 27 | primary_key: { fields: "account" } 28 | index: { id: 1 fields: "amount" } 29 | }; 30 | 31 | bytes account = 1; 32 | uint64 amount = 2; 33 | } 34 | -------------------------------------------------------------------------------- /proto/dwn/v1/tx.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package dwn.v1; 3 | 4 | import "cosmos/msg/v1/msg.proto"; 5 | import "dwn/v1/genesis.proto"; 6 | import "gogoproto/gogo.proto"; 7 | import "cosmos_proto/cosmos.proto"; 8 | 9 | option go_package = "github.com/sonr-io/snrd/x/dwn/types"; 10 | 11 | // Msg defines the Msg service. 12 | service Msg { 13 | option (cosmos.msg.v1.service) = true; 14 | // UpdateParams defines a governance operation for updating the parameters. 15 | // 16 | // Since: cosmos-sdk 0.47 17 | rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); 18 | 19 | 20 | // Spawn spawns a new Vault 21 | rpc Initialize(MsgInitialize) returns (MsgInitializeResponse); 22 | } 23 | 24 | // MsgUpdateParams is the Msg/UpdateParams request type. 25 | // 26 | // Since: cosmos-sdk 0.47 27 | message MsgUpdateParams { 28 | option (cosmos.msg.v1.signer) = "authority"; 29 | 30 | // authority is the address of the governance account. 31 | string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; 32 | 33 | // params defines the parameters to update. 34 | // 35 | // NOTE: All parameters must be supplied. 36 | Params params = 2 [(gogoproto.nullable) = false]; 37 | } 38 | 39 | // MsgUpdateParamsResponse defines the response structure for executing a 40 | // MsgUpdateParams message. 41 | // 42 | // Since: cosmos-sdk 0.47 43 | message MsgUpdateParamsResponse {} 44 | 45 | // MsgSpawn spawns a New Vault with Unclaimed State. This is a one-time 46 | // operation that must be performed interacting with the Vault. 47 | // 48 | // Since: cosmos-sdk 0.47 49 | message MsgInitialize { 50 | option (cosmos.msg.v1.signer) = "authority"; 51 | 52 | // authority is the address of the governance account. 53 | string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; 54 | 55 | // params defines the parameters to update. 56 | // 57 | // NOTE: All parameters must be supplied. 58 | Params params = 2 [(gogoproto.nullable) = false]; 59 | } 60 | 61 | // MsgSpawnResponse defines the response structure for executing a 62 | // MsgSpawn message. 63 | // 64 | // Since: cosmos-sdk 0.47 65 | message MsgInitializeResponse {} 66 | -------------------------------------------------------------------------------- /proto/svc/module/v1/module.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package svc.module.v1; 4 | 5 | import "cosmos/app/v1alpha1/module.proto"; 6 | 7 | // Module is the app config object of the module. 8 | // Learn more: https://docs.cosmos.network/main/building-modules/depinject 9 | message Module { 10 | option (cosmos.app.v1alpha1.module) = { 11 | go_import : "github.com/sonr-io/snrd" 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /proto/svc/v1/genesis.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package svc.v1; 3 | 4 | import "gogoproto/gogo.proto"; 5 | import "amino/amino.proto"; 6 | 7 | option go_package = "github.com/sonr-io/snrd/x/svc/types"; 8 | 9 | // GenesisState defines the module genesis state 10 | message GenesisState { 11 | // Params defines all the parameters of the module. 12 | Params params = 1 [ (gogoproto.nullable) = false ]; 13 | } 14 | 15 | // Params defines the set of module parameters. 16 | message Params { 17 | option (amino.name) = "service/params"; 18 | option (gogoproto.equal) = true; 19 | option (gogoproto.goproto_stringer) = false; 20 | 21 | repeated Attenuation attenuations = 1; 22 | } 23 | 24 | // Attenuation defines the attenuation of a resource 25 | message Attenuation { 26 | Resource resource = 1; 27 | repeated Capability capabilities = 2; 28 | } 29 | 30 | // Capability reprensents the available capabilities of a decentralized web node 31 | message Capability { 32 | string name = 1; 33 | string parent = 2; 34 | string description = 3; 35 | repeated string resources = 4; 36 | } 37 | 38 | // Resource reprensents the available resources of a decentralized web node 39 | message Resource { 40 | string kind = 1; 41 | string template = 2; 42 | } 43 | 44 | // Service defines a Decentralized Service on the Sonr Blockchain 45 | message Service { 46 | string id = 1; 47 | string authority = 2; 48 | repeated string origins = 3; 49 | string name = 4; 50 | string description = 5; 51 | repeated Attenuation attenuations = 6; 52 | repeated string tags = 7; 53 | int64 expiry_height = 8; 54 | } 55 | -------------------------------------------------------------------------------- /proto/svc/v1/query.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package svc.v1; 3 | 4 | import "google/api/annotations.proto"; 5 | import "svc/v1/genesis.proto"; 6 | 7 | option go_package = "github.com/sonr-io/snrd/x/svc/types"; 8 | 9 | // Query provides defines the gRPC querier service. 10 | service Query { 11 | // Params queries all parameters of the module. 12 | rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { 13 | option (google.api.http).get = "/svc/v1/params"; 14 | } 15 | 16 | // OriginExists queries if a given origin exists. 17 | rpc OriginExists(QueryOriginExistsRequest) returns (QueryOriginExistsResponse) { 18 | option (google.api.http).get = "/svc/v1/origins/{origin}"; 19 | } 20 | 21 | // ResolveOrigin queries the domain of a given service and returns its record with capabilities. 22 | rpc ResolveOrigin(QueryResolveOriginRequest) returns (QueryResolveOriginResponse) { 23 | option (google.api.http).get = "/svc/v1/origins/{origin}/record"; 24 | } 25 | } 26 | 27 | // QueryParamsRequest is the request type for the Query/Params RPC method. 28 | message QueryParamsRequest {} 29 | 30 | // QueryParamsResponse is the response type for the Query/Params RPC method. 31 | message QueryParamsResponse { 32 | // params defines the parameters of the module. 33 | Params params = 1; 34 | } 35 | 36 | // QueryOriginExistsRequest is the request type for the Query/OriginExists RPC method. 37 | message QueryOriginExistsRequest { 38 | // origin is the origin to query. 39 | string origin = 1; 40 | } 41 | 42 | // QueryOriginExistsResponse is the response type for the Query/OriginExists RPC method. 43 | message QueryOriginExistsResponse { 44 | // exists is the boolean value representing whether the origin exists. 45 | bool exists = 1; 46 | } 47 | 48 | // QueryResolveOriginRequest is the request type for the Query/ResolveOrigin RPC method. 49 | message QueryResolveOriginRequest { 50 | // origin is the origin to query. 51 | string origin = 1; 52 | } 53 | 54 | // QueryResolveOriginResponse is the response type for the Query/ResolveOrigin RPC method. 55 | message QueryResolveOriginResponse { 56 | // record is the record of the origin. 57 | Service record = 1; 58 | } 59 | -------------------------------------------------------------------------------- /proto/svc/v1/state.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package svc.v1; 3 | 4 | import "cosmos/orm/v1/orm.proto"; 5 | 6 | option go_package = "github.com/sonr-io/snrd/x/svc/types"; 7 | 8 | 9 | // https://github.com/cosmos/cosmos-sdk/blob/main/orm/README.md 10 | 11 | message Domain { 12 | option (cosmos.orm.v1.table) = { 13 | id: 1 14 | primary_key: { 15 | fields: "id" 16 | auto_increment: true 17 | } 18 | index: { 19 | id: 1 20 | fields: "origin" 21 | unique: true 22 | } 23 | }; 24 | 25 | uint64 id = 1; 26 | string origin = 2; 27 | string name = 3; 28 | string description = 4; 29 | string category = 5; 30 | string icon = 6; 31 | repeated string tags = 7; 32 | } 33 | 34 | // Metadata represents a DID alias 35 | message Metadata { 36 | option (cosmos.orm.v1.table) = { 37 | id: 2 38 | primary_key: {fields: "id"} 39 | index: { 40 | id: 1 41 | fields: "subject,origin" 42 | unique: true 43 | } 44 | }; 45 | 46 | // The unique identifier of the alias 47 | string id = 1; 48 | 49 | // The alias of the DID 50 | string subject = 2; 51 | 52 | // Origin of the alias 53 | string origin = 3; 54 | 55 | // Controller of the alias 56 | string controller = 4; 57 | } 58 | -------------------------------------------------------------------------------- /proto/svc/v1/tx.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package svc.v1; 3 | 4 | import "cosmos/msg/v1/msg.proto"; 5 | import "svc/v1/genesis.proto"; 6 | import "gogoproto/gogo.proto"; 7 | import "cosmos_proto/cosmos.proto"; 8 | 9 | option go_package = "github.com/sonr-io/snrd/x/svc/types"; 10 | 11 | // Msg defines the Msg service. 12 | service Msg { 13 | option (cosmos.msg.v1.service) = true; 14 | 15 | // UpdateParams defines a governance operation for updating the parameters. 16 | // 17 | // Since: cosmos-sdk 0.47 18 | rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); 19 | 20 | // RegisterService initializes a Service with a given permission scope and 21 | // URI. The domain must have a valid TXT record containing the public key. 22 | rpc RegisterService(MsgRegisterService) returns (MsgRegisterServiceResponse); 23 | } 24 | 25 | // MsgUpdateParams is the Msg/UpdateParams request type. 26 | // 27 | // Since: cosmos-sdk 0.47 28 | message MsgUpdateParams { 29 | option (cosmos.msg.v1.signer) = "authority"; 30 | 31 | // authority is the address of the governance account. 32 | string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; 33 | 34 | // params defines the parameters to update. 35 | // 36 | // NOTE: All parameters must be supplied. 37 | Params params = 2 [(gogoproto.nullable) = false]; 38 | } 39 | 40 | // MsgUpdateParamsResponse defines the response structure for executing a 41 | // MsgUpdateParams message. 42 | // 43 | // Since: cosmos-sdk 0.47 44 | message MsgUpdateParamsResponse {} 45 | 46 | // MsgRegisterService is the message type for the RegisterService RPC. 47 | message MsgRegisterService { 48 | option (cosmos.msg.v1.signer) = "controller"; 49 | 50 | // authority is the address of the governance account. 51 | string controller = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; 52 | 53 | // origin is the origin of the request in wildcard form. Requires valid TXT 54 | // record in DNS. 55 | Service service = 2; 56 | } 57 | 58 | // MsgRegisterServiceResponse is the response type for the RegisterService RPC. 59 | message MsgRegisterServiceResponse { 60 | bool success = 1; 61 | string did = 2; 62 | } 63 | -------------------------------------------------------------------------------- /scripts/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | # Function to detect OS and architecture 6 | detect_platform() { 7 | OS=$(uname -s) 8 | ARCH=$(uname -m) 9 | 10 | # Normalize architecture names 11 | case "${ARCH}" in 12 | x86_64) ARCH="amd64" ;; 13 | aarch64 | arm64) ARCH="arm64" ;; 14 | esac 15 | } 16 | 17 | # Function to get latest release version 18 | get_latest_version() { 19 | LATEST_VERSION=$(curl -s https://api.github.com/repos/sonr-io/snrd/releases/latest | grep "tag_name" | cut -d '"' -f 4) 20 | LATEST_VERSION=${LATEST_VERSION#v} # Remove 'v' prefix 21 | } 22 | 23 | # Function to install binaries to current directory 24 | install_tar() { 25 | local OS_NAME=$1 26 | echo "Installing Sonr for ${OS_NAME} (${ARCH})..." 27 | DOWNLOAD_URL="https://github.com/sonr-io/snrd/releases/download/v${LATEST_VERSION}/sonr_${LATEST_VERSION}_${OS_NAME}_${ARCH}.tar.gz" 28 | 29 | # Download and extract 30 | echo "Downloading Sonr..." 31 | curl -L "${DOWNLOAD_URL}" -o sonr.tar.gz 32 | tar -xzf sonr.tar.gz 33 | rm sonr.tar.gz 34 | 35 | chmod +x sonrd hway 36 | 37 | echo "Binaries 'sonrd' and 'hway' have been extracted to the current directory" 38 | echo 39 | echo "To make them available system-wide, you can move them to /usr/local/bin with:" 40 | echo "sudo mv sonrd hway /usr/local/bin/" 41 | echo 42 | echo "Or move them to your personal bin directory with:" 43 | echo "mkdir -p ~/.local/bin" 44 | echo "mv sonrd hway ~/.local/bin/" 45 | echo "Then add ~/.local/bin to your PATH if it's not already there" 46 | } 47 | 48 | # Function to install on Debian/Ubuntu 49 | install_debian() { 50 | echo "Installing Sonr for Debian/Ubuntu (${ARCH})..." 51 | SONRD_URL="https://github.com/sonr-io/snrd/releases/download/v${LATEST_VERSION}/sonrd_${LATEST_VERSION}_${ARCH}.deb" 52 | HWAY_URL="https://github.com/sonr-io/snrd/releases/download/v${LATEST_VERSION}/hway_${LATEST_VERSION}_${ARCH}.deb" 53 | 54 | # Download packages 55 | TMP_DIR=$(mktemp -d) 56 | curl -L "${SONRD_URL}" -o "${TMP_DIR}/sonrd.deb" 57 | curl -L "${HWAY_URL}" -o "${TMP_DIR}/hway.deb" 58 | 59 | # Install packages 60 | sudo dpkg -i "${TMP_DIR}/sonrd.deb" 61 | sudo dpkg -i "${TMP_DIR}/hway.deb" 62 | 63 | # Cleanup 64 | rm -rf "${TMP_DIR}" 65 | 66 | echo "Sonr has been installed system-wide" 67 | } 68 | 69 | main() { 70 | detect_platform 71 | get_latest_version 72 | 73 | case "${OS}" in 74 | Darwin) 75 | install_tar "Darwin" 76 | ;; 77 | Linux) 78 | if [[ -f /etc/debian_version ]]; then 79 | install_debian 80 | else 81 | install_tar "Linux" 82 | fi 83 | ;; 84 | *) 85 | echo "Unsupported operating system: ${OS}" 86 | exit 1 87 | ;; 88 | esac 89 | } 90 | 91 | main 92 | -------------------------------------------------------------------------------- /scripts/json_to_pkl.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | SOURCE=$1 6 | OUTPUT=$2 7 | 8 | ROOT_DIR=$(git rev-parse --show-toplevel) 9 | cd $ROOT_DIR 10 | 11 | mkdir -p $OUTPUT 12 | pkl eval package://pkg.pkl-lang.org/pkl-pantry/org.json_schema.contrib@1.0.0#/generate.pkl -m . -p source="$SOURCE" -p output="$OUTPUT" 13 | -------------------------------------------------------------------------------- /scripts/protocgen.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | GO_MOD_PACKAGE="github.com/sonr-io/snrd" 6 | ROOT_DIR=$(git rev-parse --show-toplevel) 7 | 8 | echo "Generating gogo proto code" 9 | cd proto 10 | proto_dirs=$(find . -path -prune -o -name '*.proto' -print0 | xargs -0 -n1 dirname | sort | uniq) 11 | for dir in $proto_dirs; do 12 | for file in $(find "${dir}" -maxdepth 1 -name '*.proto'); do 13 | # this regex checks if a proto file has its go_package set to github.com/strangelove-ventures/poa/... 14 | # gogo proto files SHOULD ONLY be generated if this is false 15 | # we don't want gogo proto to run for proto files which are natively built for google.golang.org/protobuf 16 | if grep -q "option go_package" "$file" && grep -H -o -c "option go_package.*$GO_MOD_PACKAGE/api" "$file" | grep -q ':0$'; then 17 | buf generate --template buf.gen.gogo.yaml $file 18 | fi 19 | done 20 | done 21 | 22 | echo "Generating pulsar proto code" 23 | buf generate --template buf.gen.pulsar.yaml 24 | 25 | cd .. 26 | 27 | cp -r $GO_MOD_PACKAGE/* ./ 28 | rm -rf github.com 29 | 30 | # Copy files over for dep injection 31 | rm -rf api && mkdir api 32 | custom_modules=$(find . -name 'module' -type d -not -path "./proto/*" -not -path "./.cache/*") 33 | 34 | # get the 1 up directory (so ./cosmos/mint/module becomes ./cosmos/mint) 35 | # remove the relative path starter from base namespaces. so ./cosmos/mint becomes cosmos/mint 36 | base_namespace=$(echo $custom_modules | sed -e 's|/module||g' | sed -e 's|\./||g') 37 | 38 | # echo "Base namespace: $base_namespace" 39 | for module in $base_namespace; do 40 | echo " [+] Moving: ./$module to ./api/$module" 41 | 42 | mkdir -p api/$module 43 | 44 | mv $module/* ./api/$module/ 45 | 46 | # # incorrect reference to the module for coins 47 | find api/$module -type f -name '*.go' -exec sed -i -e 's|types "github.com/cosmos/cosmos-sdk/types"|types "cosmossdk.io/api/cosmos/base/v1beta1"|g' {} \; 48 | find api/$module -type f -name '*.go' -exec sed -i -e 's|types1 "github.com/cosmos/cosmos-sdk/x/bank/types"|types1 "cosmossdk.io/api/cosmos/bank/v1beta1"|g' {} \; 49 | 50 | rm -rf $module 51 | done 52 | -------------------------------------------------------------------------------- /scripts/validate_tag.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e # Exit on any error 4 | 5 | # Function to compare version strings 6 | version_gt() { 7 | test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1" 8 | } 9 | 10 | # Install commitizen if not present 11 | if ! command -v cz &> /dev/null; then 12 | echo "Installing commitizen..." 13 | pip install --user commitizen 14 | fi 15 | 16 | # Get all tags and sort them by version 17 | echo "Fetching all tags..." 18 | git fetch --tags --force 19 | TAGS=$(git tag -l "v*" | sort -V) 20 | LATEST_TAG=$(echo "$TAGS" | tail -n1) 21 | 22 | if [ -z "$LATEST_TAG" ]; then 23 | echo "No tags found" 24 | exit 1 25 | fi 26 | 27 | echo "Latest tag: $LATEST_TAG" 28 | 29 | # Run commitizen to determine next version 30 | echo "Running commitizen bump --dry-run..." 31 | NEXT_VERSION=$(cz bump --dry-run --increment=patch 2>&1 | grep "tag to create: v" | cut -d "v" -f2) 32 | 33 | if [ -z "$NEXT_VERSION" ]; then 34 | echo "Failed to determine next version" 35 | exit 1 36 | fi 37 | 38 | echo "Next version determined by commitizen: v$NEXT_VERSION" 39 | 40 | # Check if the next version already exists 41 | if echo "$TAGS" | grep -q "v$NEXT_VERSION"; then 42 | echo "ERROR: Version v$NEXT_VERSION already exists!" 43 | exit 1 44 | fi 45 | 46 | # Verify the next version is actually greater than the latest 47 | if ! version_gt "$NEXT_VERSION" "${LATEST_TAG#v}"; then 48 | echo "ERROR: Next version v$NEXT_VERSION is not greater than current version $LATEST_TAG" 49 | exit 1 50 | fi 51 | 52 | echo "✅ Version v$NEXT_VERSION is valid and does not exist yet" 53 | exit 0 54 | -------------------------------------------------------------------------------- /x/did/autocli.go: -------------------------------------------------------------------------------- 1 | package module 2 | 3 | import ( 4 | autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" 5 | 6 | modulev1 "github.com/sonr-io/snrd/api/did/v1" 7 | ) 8 | 9 | // AutoCLIOptions implements the autocli.HasAutoCLIConfig interface. 10 | func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { 11 | return &autocliv1.ModuleOptions{ 12 | Query: &autocliv1.ServiceCommandDescriptor{ 13 | Service: modulev1.Query_ServiceDesc.ServiceName, 14 | RpcCommandOptions: []*autocliv1.RpcCommandOptions{ 15 | { 16 | RpcMethod: "Params", 17 | Use: "params", 18 | Short: "Query the current consensus parameters", 19 | }, 20 | }, 21 | }, 22 | Tx: &autocliv1.ServiceCommandDescriptor{ 23 | Service: modulev1.Msg_ServiceDesc.ServiceName, 24 | RpcCommandOptions: []*autocliv1.RpcCommandOptions{ 25 | { 26 | RpcMethod: "UpdateParams", 27 | Skip: true, // set to true if authority gated 28 | }, 29 | }, 30 | }, 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /x/did/depinject.go: -------------------------------------------------------------------------------- 1 | package module 2 | 3 | import ( 4 | "os" 5 | 6 | "cosmossdk.io/core/address" 7 | "cosmossdk.io/core/appmodule" 8 | "cosmossdk.io/core/store" 9 | "cosmossdk.io/depinject" 10 | "cosmossdk.io/log" 11 | nftkeeper "cosmossdk.io/x/nft/keeper" 12 | "github.com/cosmos/cosmos-sdk/codec" 13 | authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" 14 | authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" 15 | govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" 16 | slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" 17 | stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" 18 | 19 | modulev1 "github.com/sonr-io/snrd/api/did/module/v1" 20 | "github.com/sonr-io/snrd/x/did/keeper" 21 | ) 22 | 23 | var _ appmodule.AppModule = AppModule{} 24 | 25 | // IsOnePerModuleType implements the depinject.OnePerModuleType interface. 26 | func (am AppModule) IsOnePerModuleType() {} 27 | 28 | // IsAppModule implements the appmodule.AppModule interface. 29 | func (am AppModule) IsAppModule() {} 30 | 31 | func init() { 32 | appmodule.Register( 33 | &modulev1.Module{}, 34 | appmodule.Provide(ProvideModule), 35 | ) 36 | } 37 | 38 | type ModuleInputs struct { 39 | depinject.In 40 | 41 | Cdc codec.Codec 42 | StoreService store.KVStoreService 43 | AddressCodec address.Codec 44 | 45 | AccountKeeper authkeeper.AccountKeeper 46 | NFTKeeper nftkeeper.Keeper 47 | StakingKeeper stakingkeeper.Keeper 48 | SlashingKeeper slashingkeeper.Keeper 49 | } 50 | 51 | type ModuleOutputs struct { 52 | depinject.Out 53 | 54 | Module appmodule.AppModule 55 | Keeper keeper.Keeper 56 | } 57 | 58 | func ProvideModule(in ModuleInputs) ModuleOutputs { 59 | govAddr := authtypes.NewModuleAddress(govtypes.ModuleName).String() 60 | 61 | k := keeper.NewKeeper(in.Cdc, in.StoreService, log.NewLogger(os.Stderr), govAddr, in.AccountKeeper, in.NFTKeeper, &in.StakingKeeper) 62 | m := NewAppModule(in.Cdc, k, in.NFTKeeper) 63 | 64 | return ModuleOutputs{Module: m, Keeper: k, Out: depinject.Out{}} 65 | } 66 | -------------------------------------------------------------------------------- /x/did/keeper/genesis.go: -------------------------------------------------------------------------------- 1 | package keeper 2 | 3 | import ( 4 | "context" 5 | 6 | "cosmossdk.io/log" 7 | sdk "github.com/cosmos/cosmos-sdk/types" 8 | 9 | "github.com/sonr-io/snrd/x/did/types" 10 | ) 11 | 12 | // func (k Keeper) ResolveController(ctx sdk.Context, did string) (controller.ControllerI, error) { 13 | // ct, err := k.OrmDB.ControllerTable().GetByDid(ctx, did) 14 | // if err != nil { 15 | // return nil, err 16 | // } 17 | // c, err := controller.LoadFromTableEntry(ctx, ct) 18 | // if err != nil { 19 | // return nil, err 20 | // } 21 | // return c, nil 22 | // } 23 | // 24 | // Logger returns the logger 25 | func (k Keeper) Logger() log.Logger { 26 | return k.logger 27 | } 28 | 29 | // InitGenesis initializes the module's state from a genesis state. 30 | func (k *Keeper) InitGenesis(ctx context.Context, data *types.GenesisState) error { 31 | // this line is used by starport scaffolding # genesis/module/init 32 | if err := data.Params.Validate(); err != nil { 33 | return err 34 | } 35 | return k.Params.Set(ctx, data.Params) 36 | } 37 | 38 | // ExportGenesis exports the module's state to a genesis state. 39 | func (k *Keeper) ExportGenesis(ctx context.Context) *types.GenesisState { 40 | params, err := k.Params.Get(ctx) 41 | if err != nil { 42 | panic(err) 43 | } 44 | 45 | // this line is used by starport scaffolding # genesis/module/export 46 | return &types.GenesisState{ 47 | Params: params, 48 | } 49 | } 50 | 51 | // CurrentSchema returns the current schema 52 | func (k Keeper) CurrentParams(ctx sdk.Context) (*types.Params, error) { 53 | p, err := k.Params.Get(ctx) 54 | if err != nil { 55 | return nil, err 56 | } 57 | return &p, nil 58 | } 59 | -------------------------------------------------------------------------------- /x/did/keeper/genesis_test.go: -------------------------------------------------------------------------------- 1 | package keeper_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | 8 | "github.com/sonr-io/snrd/x/did/types" 9 | ) 10 | 11 | func TestGenesis(t *testing.T) { 12 | f := SetupTest(t) 13 | 14 | genesisState := &types.GenesisState{ 15 | Params: types.DefaultParams(), 16 | 17 | // this line is used by starport scaffolding # genesis/test/state 18 | } 19 | 20 | err := f.k.InitGenesis(f.ctx, genesisState) 21 | require.NoError(t, err) 22 | 23 | got := f.k.ExportGenesis(f.ctx) 24 | require.NotNil(t, got) 25 | 26 | // this line is used by starport scaffolding # genesis/test/assert 27 | } 28 | -------------------------------------------------------------------------------- /x/did/keeper/keeper.go: -------------------------------------------------------------------------------- 1 | package keeper 2 | 3 | import ( 4 | "cosmossdk.io/collections" 5 | storetypes "cosmossdk.io/core/store" 6 | "cosmossdk.io/log" 7 | "cosmossdk.io/orm/model/ormdb" 8 | nftkeeper "cosmossdk.io/x/nft/keeper" 9 | "github.com/cosmos/cosmos-sdk/codec" 10 | authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" 11 | authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" 12 | govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" 13 | stakkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" 14 | 15 | apiv1 "github.com/sonr-io/snrd/api/did/v1" 16 | "github.com/sonr-io/snrd/x/did/types" 17 | ) 18 | 19 | // Keeper defines the middleware keeper. 20 | type Keeper struct { 21 | cdc codec.BinaryCodec 22 | 23 | logger log.Logger 24 | 25 | // state management 26 | OrmDB apiv1.StateStore 27 | Params collections.Item[types.Params] 28 | Schema collections.Schema 29 | 30 | AccountKeeper authkeeper.AccountKeeper 31 | NftKeeper nftkeeper.Keeper 32 | StakingKeeper *stakkeeper.Keeper 33 | 34 | authority string 35 | } 36 | 37 | // NewKeeper creates a new poa Keeper instance 38 | func NewKeeper( 39 | cdc codec.BinaryCodec, 40 | storeService storetypes.KVStoreService, 41 | logger log.Logger, 42 | authority string, 43 | accKeeper authkeeper.AccountKeeper, 44 | nftKeeper nftkeeper.Keeper, 45 | stkKeeper *stakkeeper.Keeper, 46 | ) Keeper { 47 | logger = logger.With(log.ModuleKey, "x/"+types.ModuleName) 48 | sb := collections.NewSchemaBuilder(storeService) 49 | if authority == "" { 50 | authority = authtypes.NewModuleAddress(govtypes.ModuleName).String() 51 | } 52 | db, err := ormdb.NewModuleDB( 53 | &types.ORMModuleSchema, 54 | ormdb.ModuleDBOptions{KVStoreService: storeService}, 55 | ) 56 | if err != nil { 57 | panic(err) 58 | } 59 | store, err := apiv1.NewStateStore(db) 60 | if err != nil { 61 | panic(err) 62 | } 63 | 64 | // Initialize IPFS client 65 | k := Keeper{ 66 | cdc: cdc, 67 | logger: logger, 68 | Params: collections.NewItem( 69 | sb, 70 | types.ParamsKey, 71 | "params", 72 | codec.CollValue[types.Params](cdc), 73 | ), 74 | authority: authority, 75 | OrmDB: store, 76 | AccountKeeper: accKeeper, 77 | NftKeeper: nftKeeper, 78 | StakingKeeper: stkKeeper, 79 | } 80 | schema, err := sb.Build() 81 | if err != nil { 82 | panic(err) 83 | } 84 | 85 | k.Schema = schema 86 | return k 87 | } 88 | -------------------------------------------------------------------------------- /x/did/keeper/querier.go: -------------------------------------------------------------------------------- 1 | package keeper 2 | 3 | import ( 4 | "context" 5 | 6 | sdk "github.com/cosmos/cosmos-sdk/types" 7 | 8 | "github.com/sonr-io/snrd/x/did/types" 9 | ) 10 | 11 | var _ types.QueryServer = Querier{} 12 | 13 | type Querier struct { 14 | Keeper 15 | } 16 | 17 | func NewQuerier(keeper Keeper) Querier { 18 | return Querier{Keeper: keeper} 19 | } 20 | 21 | // Params returns the total set of did parameters. 22 | func (k Querier) Params(goCtx context.Context, req *types.QueryRequest) (*types.QueryParamsResponse, error) { 23 | ctx := sdk.UnwrapSDKContext(goCtx) 24 | p, err := k.CurrentParams(ctx) 25 | if err != nil { 26 | return nil, err 27 | } 28 | return &types.QueryParamsResponse{Params: p}, nil 29 | } 30 | 31 | // Resolve implements types.QueryServer. 32 | func (k Querier) Resolve(goCtx context.Context, req *types.QueryRequest) (*types.QueryResolveResponse, error) { 33 | return &types.QueryResolveResponse{}, nil 34 | } 35 | 36 | // Sign implements types.QueryServer. 37 | func (k Querier) Sign(goCtx context.Context, req *types.QuerySignRequest) (*types.QuerySignResponse, error) { 38 | // ctx := sdk.UnwrapSDKContext(goCtx) 39 | return &types.QuerySignResponse{}, nil 40 | } 41 | 42 | // Verify implements types.QueryServer. 43 | func (k Querier) Verify(goCtx context.Context, req *types.QueryVerifyRequest) (*types.QueryVerifyResponse, error) { 44 | // ctx := sdk.UnwrapSDKContext(goCtx) 45 | return &types.QueryVerifyResponse{}, nil 46 | } 47 | -------------------------------------------------------------------------------- /x/did/keeper/rpc.go: -------------------------------------------------------------------------------- 1 | package keeper 2 | 3 | import ( 4 | "context" 5 | 6 | "cosmossdk.io/errors" 7 | govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" 8 | 9 | "github.com/sonr-io/snrd/x/did/types" 10 | ) 11 | 12 | type msgServer struct { 13 | k Keeper 14 | } 15 | 16 | var _ types.MsgServer = msgServer{} 17 | 18 | // NewMsgServerImpl returns an implementation of the module MsgServer interface. 19 | func NewMsgServerImpl(keeper Keeper) types.MsgServer { 20 | return &msgServer{k: keeper} 21 | } 22 | 23 | // UpdateParams updates the x/did module parameters. 24 | func (ms msgServer) UpdateParams(ctx context.Context, msg *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { 25 | if ms.k.authority != msg.Authority { 26 | return nil, errors.Wrapf( 27 | govtypes.ErrInvalidSigner, 28 | "invalid authority; expected %s, got %s", 29 | ms.k.authority, 30 | msg.Authority, 31 | ) 32 | } 33 | return nil, ms.k.Params.Set(ctx, msg.Params) 34 | } 35 | 36 | // ExecuteTx implements types.MsgServer. 37 | func (ms msgServer) ExecuteTx(ctx context.Context, msg *types.MsgExecuteTx) (*types.MsgExecuteTxResponse, error) { 38 | // ctx := sdk.UnwrapSDKContext(goCtx) 39 | return &types.MsgExecuteTxResponse{}, nil 40 | } 41 | 42 | // LinkAssertion implements types.MsgServer. 43 | func (ms msgServer) LinkAssertion(ctx context.Context, msg *types.MsgLinkAssertion) (*types.MsgLinkAssertionResponse, error) { 44 | // ctx := sdk.UnwrapSDKContext(goCtx) 45 | return &types.MsgLinkAssertionResponse{}, nil 46 | } 47 | 48 | // LinkAuthentication implements types.MsgServer. 49 | func (ms msgServer) LinkAuthentication(ctx context.Context, msg *types.MsgLinkAuthentication) (*types.MsgLinkAuthenticationResponse, error) { 50 | // ctx := sdk.UnwrapSDKContext(goCtx) 51 | return &types.MsgLinkAuthenticationResponse{}, nil 52 | } 53 | 54 | // UnlinkAssertion implements types.MsgServer. 55 | func (ms msgServer) UnlinkAssertion(ctx context.Context, msg *types.MsgUnlinkAssertion) (*types.MsgUnlinkAssertionResponse, error) { 56 | // ctx := sdk.UnwrapSDKContext(goCtx) 57 | return &types.MsgUnlinkAssertionResponse{}, nil 58 | } 59 | 60 | // UnlinkAuthentication implements types.MsgServer. 61 | func (ms msgServer) UnlinkAuthentication(ctx context.Context, msg *types.MsgUnlinkAuthentication) (*types.MsgUnlinkAuthenticationResponse, error) { 62 | // ctx := sdk.UnwrapSDKContext(goCtx) 63 | return &types.MsgUnlinkAuthenticationResponse{}, nil 64 | } 65 | -------------------------------------------------------------------------------- /x/did/module.go: -------------------------------------------------------------------------------- 1 | package module 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | 7 | "github.com/grpc-ecosystem/grpc-gateway/runtime" 8 | 9 | abci "github.com/cometbft/cometbft/abci/types" 10 | 11 | "cosmossdk.io/client/v2/autocli" 12 | errorsmod "cosmossdk.io/errors" 13 | nftkeeper "cosmossdk.io/x/nft/keeper" 14 | 15 | "github.com/cosmos/cosmos-sdk/client" 16 | "github.com/cosmos/cosmos-sdk/codec" 17 | codectypes "github.com/cosmos/cosmos-sdk/codec/types" 18 | sdk "github.com/cosmos/cosmos-sdk/types" 19 | "github.com/cosmos/cosmos-sdk/types/module" 20 | 21 | "github.com/sonr-io/snrd/x/did/keeper" 22 | "github.com/sonr-io/snrd/x/did/types" 23 | // this line is used by starport scaffolding # 1 24 | ) 25 | 26 | const ( 27 | ConsensusVersion = 1 28 | 29 | // this line is used by starport scaffolding # simapp/module/const 30 | ) 31 | 32 | var ( 33 | _ module.AppModuleBasic = AppModuleBasic{} 34 | _ module.AppModuleGenesis = AppModule{} 35 | _ module.AppModule = AppModule{} 36 | _ autocli.HasAutoCLIConfig = AppModule{} 37 | ) 38 | 39 | // AppModuleBasic defines the basic application module used by the wasm module. 40 | type AppModuleBasic struct { 41 | cdc codec.Codec 42 | } 43 | 44 | type AppModule struct { 45 | AppModuleBasic 46 | 47 | keeper keeper.Keeper 48 | nftKeeper nftkeeper.Keeper 49 | } 50 | 51 | // NewAppModule constructor 52 | func NewAppModule( 53 | cdc codec.Codec, 54 | keeper keeper.Keeper, 55 | nftKeeper nftkeeper.Keeper, 56 | ) *AppModule { 57 | return &AppModule{ 58 | AppModuleBasic: AppModuleBasic{cdc: cdc}, 59 | keeper: keeper, 60 | nftKeeper: nftKeeper, 61 | } 62 | } 63 | 64 | func (a AppModuleBasic) Name() string { 65 | return types.ModuleName 66 | } 67 | 68 | func (a AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { 69 | return cdc.MustMarshalJSON(&types.GenesisState{ 70 | Params: types.DefaultParams(), 71 | }) 72 | } 73 | 74 | func (a AppModuleBasic) ValidateGenesis(marshaler codec.JSONCodec, _ client.TxEncodingConfig, message json.RawMessage) error { 75 | var data types.GenesisState 76 | err := marshaler.UnmarshalJSON(message, &data) 77 | if err != nil { 78 | return err 79 | } 80 | if err := data.Params.Validate(); err != nil { 81 | return errorsmod.Wrap(err, "params") 82 | } 83 | return nil 84 | } 85 | 86 | func (a AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { 87 | err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) 88 | if err != nil { 89 | panic(err) 90 | } 91 | } 92 | 93 | func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { 94 | types.RegisterLegacyAminoCodec(cdc) 95 | } 96 | 97 | func (a AppModuleBasic) RegisterInterfaces(r codectypes.InterfaceRegistry) { 98 | types.RegisterInterfaces(r) 99 | } 100 | 101 | func (a AppModule) InitGenesis(ctx sdk.Context, marshaler codec.JSONCodec, message json.RawMessage) []abci.ValidatorUpdate { 102 | didGenesisState := types.DefaultGenesis() 103 | if err := a.keeper.Params.Set(ctx, didGenesisState.Params); err != nil { 104 | panic(err) 105 | } 106 | // nftGenesisState := nft.DefaultGenesisState() 107 | // if err := types.DefaultNFTClasses(nftGenesisState); err != nil { 108 | // panic(err) 109 | // } 110 | // a.nftKeeper.InitGenesis(ctx, nftGenesisState) 111 | return nil 112 | } 113 | 114 | func (a AppModule) ExportGenesis(ctx sdk.Context, marshaler codec.JSONCodec) json.RawMessage { 115 | genState := a.keeper.ExportGenesis(ctx) 116 | return marshaler.MustMarshalJSON(genState) 117 | } 118 | 119 | func (a AppModule) RegisterInvariants(_ sdk.InvariantRegistry) { 120 | } 121 | 122 | func (a AppModule) QuerierRoute() string { 123 | return types.QuerierRoute 124 | } 125 | 126 | func (a AppModule) RegisterServices(cfg module.Configurator) { 127 | types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(a.keeper)) 128 | types.RegisterQueryServer(cfg.QueryServer(), keeper.NewQuerier(a.keeper)) 129 | } 130 | 131 | // ConsensusVersion is a sequence number for state-breaking change of the 132 | // module. It should be incremented on each consensus-breaking change 133 | // introduced by the module. To avoid wrong/empty versions, the initial version 134 | // should be set to 1. 135 | func (a AppModule) ConsensusVersion() uint64 { 136 | return ConsensusVersion 137 | } 138 | -------------------------------------------------------------------------------- /x/did/types/address.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/cosmos/cosmos-sdk/types/bech32" 5 | ) 6 | 7 | // ComputeSonrAddr computes the Sonr address from a public key 8 | func ComputeSonrAddr(pk []byte) (string, error) { 9 | sonrAddr, err := bech32.ConvertAndEncode("idx", pk) 10 | if err != nil { 11 | return "", err 12 | } 13 | return sonrAddr, nil 14 | } 15 | 16 | // ComputeBitcoinAddr computes the Bitcoin address from a public key 17 | func ComputeBitcoinAddr(pk []byte) (string, error) { 18 | btcAddr, err := bech32.ConvertAndEncode("bc", pk) 19 | if err != nil { 20 | return "", err 21 | } 22 | return btcAddr, nil 23 | } 24 | 25 | // 26 | // // ComputeEthereumAddr computes the Ethereum address from a public key 27 | // func ComputeEthereumAddr(pk *ecdsa.PublicKey) string { 28 | // // Generate Ethereum address 29 | // address := ethcrypto.PubkeyToAddress(*pk) 30 | // 31 | // // Apply ERC-55 checksum encoding 32 | // addr := address.Hex() 33 | // addr = strings.ToLower(addr) 34 | // addr = strings.TrimPrefix(addr, "0x") 35 | // hash := sha3.NewLegacyKeccak256() 36 | // hash.Write([]byte(addr)) 37 | // hashBytes := hash.Sum(nil) 38 | // 39 | // result := "0x" 40 | // for i, c := range addr { 41 | // if c >= '0' && c <= '9' { 42 | // result += string(c) 43 | // } else { 44 | // if hashBytes[i/2]>>(4-i%2*4)&0xf >= 8 { 45 | // result += strings.ToUpper(string(c)) 46 | // } else { 47 | // result += string(c) 48 | // } 49 | // } 50 | // } 51 | // return result 52 | // } 53 | -------------------------------------------------------------------------------- /x/did/types/codec.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/cosmos/cosmos-sdk/codec" 5 | "github.com/cosmos/cosmos-sdk/codec/types" 6 | cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" 7 | cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" 8 | sdk "github.com/cosmos/cosmos-sdk/types" 9 | "github.com/cosmos/cosmos-sdk/types/msgservice" 10 | ) 11 | 12 | var ( 13 | amino = codec.NewLegacyAmino() 14 | AminoCdc = codec.NewAminoCodec(amino) 15 | ) 16 | 17 | func init() { 18 | RegisterLegacyAminoCodec(amino) 19 | cryptocodec.RegisterCrypto(amino) 20 | sdk.RegisterLegacyAminoCodec(amino) 21 | } 22 | 23 | // RegisterLegacyAminoCodec registers concrete types on the LegacyAmino codec 24 | func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { 25 | cdc.RegisterConcrete(&MsgUpdateParams{}, ModuleName+"/MsgUpdateParams", nil) 26 | } 27 | 28 | func RegisterInterfaces(registry types.InterfaceRegistry) { 29 | registry.RegisterImplementations( 30 | (*cryptotypes.PubKey)(nil), 31 | // &PubKey{}, 32 | ) 33 | 34 | registry.RegisterImplementations( 35 | (*sdk.Msg)(nil), 36 | &MsgUpdateParams{}, 37 | ) 38 | msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) 39 | } 40 | -------------------------------------------------------------------------------- /x/did/types/errors.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import sdkerrors "cosmossdk.io/errors" 4 | 5 | var ( 6 | ErrInvalidGenesisState = sdkerrors.Register(ModuleName, 100, "invalid genesis state") 7 | ErrInvalidETHAddressFormat = sdkerrors.Register(ModuleName, 200, "invalid ETH address format") 8 | ErrInvalidBTCAddressFormat = sdkerrors.Register(ModuleName, 201, "invalid BTC address format") 9 | ErrInvalidIDXAddressFormat = sdkerrors.Register(ModuleName, 202, "invalid IDX address format") 10 | ) 11 | -------------------------------------------------------------------------------- /x/did/types/format.go: -------------------------------------------------------------------------------- 1 | package types 2 | -------------------------------------------------------------------------------- /x/did/types/genesis.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | ormv1alpha1 "cosmossdk.io/api/cosmos/orm/v1alpha1" 5 | "cosmossdk.io/collections" 6 | ) 7 | 8 | // ParamsKey saves the current module params. 9 | var ParamsKey = collections.NewPrefix(0) 10 | 11 | const ( 12 | ModuleName = "did" 13 | 14 | StoreKey = ModuleName 15 | 16 | QuerierRoute = ModuleName 17 | ) 18 | 19 | var ORMModuleSchema = ormv1alpha1.ModuleSchemaDescriptor{ 20 | SchemaFile: []*ormv1alpha1.ModuleSchemaDescriptor_FileEntry{ 21 | {Id: 1, ProtoFileName: "did/v1/state.proto"}, 22 | }, 23 | Prefix: []byte{0}, 24 | } 25 | 26 | // this line is used by starport scaffolding # genesis/types/import 27 | 28 | // DefaultIndex is the default global index 29 | const DefaultIndex uint64 = 1 30 | 31 | // DefaultGenesis returns the default genesis state 32 | func DefaultGenesis() *GenesisState { 33 | return &GenesisState{ 34 | // this line is used by starport scaffolding # genesis/types/default 35 | Params: DefaultParams(), 36 | } 37 | } 38 | 39 | // Validate performs basic genesis state validation returning an error upon any 40 | // failure. 41 | func (gs GenesisState) Validate() error { 42 | // this line is used by starport scaffolding # genesis/types/validate 43 | 44 | return gs.Params.Validate() 45 | } 46 | 47 | // Equal checks if two Attenuation are equal 48 | func (a *Attenuation) Equal(that *Attenuation) bool { 49 | if that == nil { 50 | return false 51 | } 52 | if a.Resource != nil { 53 | if that.Resource == nil { 54 | return false 55 | } 56 | if !a.Resource.Equal(that.Resource) { 57 | return false 58 | } 59 | } 60 | if len(a.Capabilities) != len(that.Capabilities) { 61 | return false 62 | } 63 | for i := range a.Capabilities { 64 | if !a.Capabilities[i].Equal(that.Capabilities[i]) { 65 | return false 66 | } 67 | } 68 | return true 69 | } 70 | 71 | // Equal checks if two Capability are equal 72 | func (c *Capability) Equal(that *Capability) bool { 73 | if that == nil { 74 | return false 75 | } 76 | if c.Name != that.Name { 77 | return false 78 | } 79 | if c.Parent != that.Parent { 80 | return false 81 | } 82 | // TODO: check description 83 | if len(c.Resources) != len(that.Resources) { 84 | return false 85 | } 86 | for i := range c.Resources { 87 | if c.Resources[i] != that.Resources[i] { 88 | return false 89 | } 90 | } 91 | return true 92 | } 93 | 94 | // Equal checks if two Resource are equal 95 | func (r *Resource) Equal(that *Resource) bool { 96 | if that == nil { 97 | return false 98 | } 99 | if r.Kind != that.Kind { 100 | return false 101 | } 102 | if r.Template != that.Template { 103 | return false 104 | } 105 | return true 106 | } 107 | -------------------------------------------------------------------------------- /x/did/types/genesis_test.go: -------------------------------------------------------------------------------- 1 | package types_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/sonr-io/snrd/x/did/types" 7 | 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func TestGenesisState_Validate(t *testing.T) { 12 | tests := []struct { 13 | desc string 14 | genState *types.GenesisState 15 | valid bool 16 | }{ 17 | { 18 | desc: "default is valid", 19 | genState: types.DefaultGenesis(), 20 | valid: true, 21 | }, 22 | // this line is used by starport scaffolding # types/genesis/testcase 23 | } 24 | for _, tc := range tests { 25 | t.Run(tc.desc, func(t *testing.T) { 26 | err := tc.genState.Validate() 27 | if tc.valid { 28 | require.NoError(t, err) 29 | } else { 30 | require.Error(t, err) 31 | } 32 | }) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /x/did/types/msgs.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "cosmossdk.io/errors" 5 | sdk "github.com/cosmos/cosmos-sdk/types" 6 | ) 7 | 8 | var _ sdk.Msg = &MsgUpdateParams{} 9 | 10 | // ╭───────────────────────────────────────────────────────────╮ 11 | // │ MsgUpdateParams type definition │ 12 | // ╰───────────────────────────────────────────────────────────╯ 13 | 14 | // NewMsgUpdateParams creates new instance of MsgUpdateParams 15 | func NewMsgUpdateParams( 16 | sender sdk.Address, 17 | someValue bool, 18 | ) *MsgUpdateParams { 19 | return &MsgUpdateParams{ 20 | Authority: sender.String(), 21 | Params: DefaultParams(), 22 | } 23 | } 24 | 25 | // Route returns the name of the module 26 | func (msg MsgUpdateParams) Route() string { return ModuleName } 27 | 28 | // Type returns the the action 29 | func (msg MsgUpdateParams) Type() string { return "update_params" } 30 | 31 | // GetSignBytes implements the LegacyMsg interface. 32 | func (msg MsgUpdateParams) GetSignBytes() []byte { 33 | return sdk.MustSortJSON(AminoCdc.MustMarshalJSON(&msg)) 34 | } 35 | 36 | // GetSigners returns the expected signers for a MsgUpdateParams message. 37 | func (msg *MsgUpdateParams) GetSigners() []sdk.AccAddress { 38 | addr, _ := sdk.AccAddressFromBech32(msg.Authority) 39 | return []sdk.AccAddress{addr} 40 | } 41 | 42 | // ValidateBasic does a sanity check on the provided data. 43 | func (msg *MsgUpdateParams) Validate() error { 44 | if _, err := sdk.AccAddressFromBech32(msg.Authority); err != nil { 45 | return errors.Wrap(err, "invalid authority address") 46 | } 47 | 48 | return msg.Params.Validate() 49 | } 50 | -------------------------------------------------------------------------------- /x/did/types/params.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "encoding/json" 5 | ) 6 | 7 | // DefaultParams returns default module parameters. 8 | func DefaultParams() Params { 9 | return Params{} 10 | } 11 | 12 | // Stringer method for Params. 13 | func (p Params) String() string { 14 | bz, err := json.Marshal(p) 15 | if err != nil { 16 | panic(err) 17 | } 18 | 19 | return string(bz) 20 | } 21 | 22 | // Validate does the sanity check on the params. 23 | func (p Params) Validate() error { 24 | // TODO: 25 | return nil 26 | } 27 | -------------------------------------------------------------------------------- /x/did/types/pubkey.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "strings" 7 | 8 | sdk "github.com/cosmos/cosmos-sdk/crypto/types" 9 | "google.golang.org/protobuf/proto" 10 | ) 11 | 12 | type PubKeyI interface { 13 | GetRole() string 14 | GetKeyType() string 15 | // GetRawKey() *commonv1.RawKey 16 | // GetJwk() *commonv1.JSONWebKey 17 | } 18 | 19 | type PubKeyG[T any] interface { 20 | *T 21 | PublicKey 22 | } 23 | 24 | type pubKeyImpl struct { 25 | decode func(b []byte) (PublicKey, error) 26 | validate func(key PublicKey) error 27 | } 28 | 29 | // func WithSecp256K1PubKey() Option { 30 | // return WithPubKeyWithValidationFunc(func(pt *secp256k1.PubKey) error { 31 | // _, err := dcrd_secp256k1.ParsePubKey(pt.Key) 32 | // return err 33 | // }) 34 | // } 35 | // 36 | // func WithPubKey[T any, PT PubKeyG[T]]() Option { 37 | // return WithPubKeyWithValidationFunc[T, PT](func(_ PT) error { 38 | // return nil 39 | // }) 40 | // } 41 | // 42 | // func WithPubKeyWithValidationFunc[T any, PT PubKeyG[T]](validateFn func(PT) error) Option { 43 | // pkImpl := pubKeyImpl{ 44 | // decode: func(b []byte) (PublicKey, error) { 45 | // key := PT(new(T)) 46 | // err := gogoproto.Unmarshal(b, key) 47 | // if err != nil { 48 | // return nil, err 49 | // } 50 | // return key, nil 51 | // }, 52 | // validate: func(k PublicKey) error { 53 | // concrete, ok := k.(PT) 54 | // if !ok { 55 | // return fmt.Errorf( 56 | // "invalid pubkey type passed for validation, wanted: %T, got: %T", 57 | // concrete, 58 | // k, 59 | // ) 60 | // } 61 | // return validateFn(concrete) 62 | // }, 63 | // } 64 | // return func(a *Account) { 65 | // a.supportedPubKeys[gogoproto.MessageName(PT(new(T)))] = pkImpl 66 | // } 67 | // } 68 | func nameFromTypeURL(url string) string { 69 | name := url 70 | if i := strings.LastIndexByte(url, '/'); i >= 0 { 71 | name = name[i+len("/"):] 72 | } 73 | return name 74 | } 75 | 76 | // CustomPubKey represents a custom secp256k1 public key. 77 | type CustomPubKey struct { 78 | proto.Message 79 | 80 | Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` 81 | } 82 | 83 | // NewCustomPubKeyFromRawBytes creates a new CustomPubKey from raw bytes. 84 | func NewCustomPubKeyFromRawBytes(key []byte) (*CustomPubKey, error) { 85 | // Validate the key length and format 86 | if len(key) != 33 { 87 | return nil, fmt.Errorf("invalid key length; expected 33 bytes, got %d", len(key)) 88 | } 89 | if key[0] != 0x02 && key[0] != 0x03 { 90 | return nil, fmt.Errorf("invalid key format; expected 0x02 or 0x03 as the first byte, got 0x%02x", key[0]) 91 | } 92 | 93 | return &CustomPubKey{Key: key}, nil 94 | } 95 | 96 | // Bytes returns the byte representation of the public key. 97 | func (pk *CustomPubKey) Bytes() []byte { 98 | return pk.Key 99 | } 100 | 101 | // Equals checks if two public keys are equal. 102 | func (pk *CustomPubKey) Equals(other sdk.PubKey) bool { 103 | return bytes.EqualFold(pk.Bytes(), other.Bytes()) 104 | } 105 | 106 | // Type returns the type of the public key. 107 | func (pk *CustomPubKey) Type() string { 108 | return "custom-secp256k1" 109 | } 110 | 111 | // Marshal implements the proto.Message interface. 112 | func (pk *CustomPubKey) Marshal() ([]byte, error) { 113 | return proto.Marshal(pk) 114 | } 115 | 116 | // Unmarshal implements the proto.Message interface. 117 | func (pk *CustomPubKey) Unmarshal(data []byte) error { 118 | return proto.Unmarshal(data, pk) 119 | } 120 | 121 | // Address returns the address derived from the public key. 122 | func (pk *CustomPubKey) Address() []byte { 123 | // Implement address derivation logic here 124 | // For simplicity, this example uses a placeholder 125 | return []byte("derived-address") 126 | } 127 | 128 | // VerifySignature verifies a signature using the public key. 129 | func (pk *CustomPubKey) VerifySignature(msg []byte, sig []byte) bool { 130 | // Implement signature verification logic here 131 | // For simplicity, this example uses a placeholder 132 | return true 133 | } 134 | -------------------------------------------------------------------------------- /x/did/types/signer.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "context" 5 | 6 | signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1" 7 | "cosmossdk.io/x/tx/signing" 8 | "github.com/cosmos/cosmos-sdk/types/tx" 9 | ) 10 | 11 | type directHandler struct{} 12 | 13 | func (s directHandler) Mode() signingv1beta1.SignMode { 14 | return signingv1beta1.SignMode_SIGN_MODE_DIRECT_AUX 15 | } 16 | 17 | func (s directHandler) GetSignBytes( 18 | _ context.Context, 19 | signerData signing.SignerData, 20 | txData signing.TxData, 21 | ) ([]byte, error) { 22 | txDoc := tx.SignDoc{ 23 | BodyBytes: txData.BodyBytes, 24 | AuthInfoBytes: txData.AuthInfoBytes, 25 | ChainId: signerData.ChainID, 26 | AccountNumber: signerData.AccountNumber, 27 | } 28 | return txDoc.Marshal() 29 | } 30 | -------------------------------------------------------------------------------- /x/dwn/autocli.go: -------------------------------------------------------------------------------- 1 | package module 2 | 3 | import ( 4 | autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" 5 | modulev1 "github.com/sonr-io/snrd/api/dwn/v1" 6 | ) 7 | 8 | // AutoCLIOptions implements the autocli.HasAutoCLIConfig interface. 9 | func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { 10 | return &autocliv1.ModuleOptions{ 11 | Query: &autocliv1.ServiceCommandDescriptor{ 12 | Service: modulev1.Query_ServiceDesc.ServiceName, 13 | RpcCommandOptions: []*autocliv1.RpcCommandOptions{ 14 | { 15 | RpcMethod: "Params", 16 | Use: "params", 17 | Short: "Query the current consensus parameters", 18 | }, 19 | }, 20 | }, 21 | Tx: &autocliv1.ServiceCommandDescriptor{ 22 | Service: modulev1.Msg_ServiceDesc.ServiceName, 23 | RpcCommandOptions: []*autocliv1.RpcCommandOptions{ 24 | { 25 | RpcMethod: "UpdateParams", 26 | Skip: false, // set to true if authority gated 27 | }, 28 | }, 29 | }, 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /x/dwn/client/cli/query.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | 6 | "github.com/cosmos/cosmos-sdk/client" 7 | "github.com/cosmos/cosmos-sdk/client/flags" 8 | 9 | "github.com/sonr-io/snrd/x/dwn/types" 10 | ) 11 | 12 | // !NOTE: Must enable in module.go (disabled in favor of autocli.go) 13 | 14 | func GetQueryCmd() *cobra.Command { 15 | queryCmd := &cobra.Command{ 16 | Use: types.ModuleName, 17 | Short: "Querying commands for " + types.ModuleName, 18 | DisableFlagParsing: true, 19 | SuggestionsMinimumDistance: 2, 20 | RunE: client.ValidateCmd, 21 | } 22 | queryCmd.AddCommand( 23 | GetCmdParams(), 24 | ) 25 | return queryCmd 26 | } 27 | 28 | func GetCmdParams() *cobra.Command { 29 | cmd := &cobra.Command{ 30 | Use: "params", 31 | Short: "Show all module params", 32 | Args: cobra.ExactArgs(0), 33 | RunE: func(cmd *cobra.Command, args []string) error { 34 | clientCtx, err := client.GetClientQueryContext(cmd) 35 | if err != nil { 36 | return err 37 | } 38 | 39 | queryClient := types.NewQueryClient(clientCtx) 40 | res, err := queryClient.Params(cmd.Context(), &types.QueryParamsRequest{}) 41 | if err != nil { 42 | return err 43 | } 44 | 45 | return clientCtx.PrintProto(res) 46 | }, 47 | } 48 | flags.AddQueryFlagsToCmd(cmd) 49 | return cmd 50 | } 51 | -------------------------------------------------------------------------------- /x/dwn/client/cli/tx.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | 6 | "github.com/cosmos/cosmos-sdk/client" 7 | "github.com/cosmos/cosmos-sdk/client/flags" 8 | "github.com/cosmos/cosmos-sdk/client/tx" 9 | 10 | "github.com/sonr-io/snrd/x/dwn/types" 11 | ) 12 | 13 | // !NOTE: Must enable in module.go (disabled in favor of autocli.go) 14 | 15 | // NewTxCmd returns a root CLI command handler for certain modules 16 | // transaction commands. 17 | func NewTxCmd() *cobra.Command { 18 | txCmd := &cobra.Command{ 19 | Use: types.ModuleName, 20 | Short: types.ModuleName + " subcommands.", 21 | DisableFlagParsing: true, 22 | SuggestionsMinimumDistance: 2, 23 | RunE: client.ValidateCmd, 24 | } 25 | 26 | txCmd.AddCommand( 27 | MsgUpdateParams(), 28 | ) 29 | return txCmd 30 | } 31 | 32 | // Returns a CLI command handler for registering a 33 | // contract for the module. 34 | func MsgUpdateParams() *cobra.Command { 35 | cmd := &cobra.Command{ 36 | Use: "update-params [some-value]", 37 | Short: "Update the params (must be submitted from the authority)", 38 | Args: cobra.ExactArgs(1), 39 | RunE: func(cmd *cobra.Command, args []string) error { 40 | cliCtx, err := client.GetClientTxContext(cmd) 41 | if err != nil { 42 | return err 43 | } 44 | 45 | senderAddress := cliCtx.GetFromAddress() 46 | 47 | msg := &types.MsgUpdateParams{ 48 | Authority: senderAddress.String(), 49 | Params: types.Params{}, 50 | } 51 | 52 | if err := msg.Validate(); err != nil { 53 | return err 54 | } 55 | 56 | return tx.GenerateOrBroadcastTxCLI(cliCtx, cmd.Flags(), msg) 57 | }, 58 | } 59 | 60 | flags.AddTxFlagsToCmd(cmd) 61 | return cmd 62 | } 63 | -------------------------------------------------------------------------------- /x/dwn/depinject.go: -------------------------------------------------------------------------------- 1 | package module 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/cosmos/cosmos-sdk/codec" 7 | authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" 8 | slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" 9 | 10 | govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" 11 | stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" 12 | 13 | "cosmossdk.io/core/address" 14 | "cosmossdk.io/core/appmodule" 15 | "cosmossdk.io/core/store" 16 | "cosmossdk.io/depinject" 17 | "cosmossdk.io/log" 18 | 19 | modulev1 "github.com/sonr-io/snrd/api/dwn/module/v1" 20 | "github.com/sonr-io/snrd/x/dwn/keeper" 21 | ) 22 | 23 | var _ appmodule.AppModule = AppModule{} 24 | 25 | // IsOnePerModuleType implements the depinject.OnePerModuleType interface. 26 | func (am AppModule) IsOnePerModuleType() {} 27 | 28 | // IsAppModule implements the appmodule.AppModule interface. 29 | func (am AppModule) IsAppModule() {} 30 | 31 | func init() { 32 | appmodule.Register( 33 | &modulev1.Module{}, 34 | appmodule.Provide(ProvideModule), 35 | ) 36 | } 37 | 38 | type ModuleInputs struct { 39 | depinject.In 40 | 41 | Cdc codec.Codec 42 | StoreService store.KVStoreService 43 | AddressCodec address.Codec 44 | 45 | StakingKeeper stakingkeeper.Keeper 46 | SlashingKeeper slashingkeeper.Keeper 47 | } 48 | 49 | type ModuleOutputs struct { 50 | depinject.Out 51 | 52 | Module appmodule.AppModule 53 | Keeper keeper.Keeper 54 | } 55 | 56 | func ProvideModule(in ModuleInputs) ModuleOutputs { 57 | govAddr := authtypes.NewModuleAddress(govtypes.ModuleName).String() 58 | 59 | k := keeper.NewKeeper(in.Cdc, in.StoreService, log.NewLogger(os.Stderr), govAddr) 60 | m := NewAppModule(in.Cdc, k) 61 | 62 | return ModuleOutputs{Module: m, Keeper: k, Out: depinject.Out{}} 63 | } 64 | -------------------------------------------------------------------------------- /x/dwn/keeper/genesis_test.go: -------------------------------------------------------------------------------- 1 | package keeper_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/sonr-io/snrd/x/dwn/types" 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestGenesis(t *testing.T) { 11 | f := SetupTest(t) 12 | 13 | genesisState := &types.GenesisState{ 14 | Params: types.DefaultParams(), 15 | } 16 | 17 | f.k.InitGenesis(f.ctx, genesisState) 18 | 19 | got := f.k.ExportGenesis(f.ctx) 20 | require.NotNil(t, got) 21 | 22 | } 23 | -------------------------------------------------------------------------------- /x/dwn/keeper/keeper.go: -------------------------------------------------------------------------------- 1 | package keeper 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/cosmos/cosmos-sdk/codec" 7 | 8 | authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" 9 | govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" 10 | 11 | "cosmossdk.io/collections" 12 | storetypes "cosmossdk.io/core/store" 13 | "cosmossdk.io/log" 14 | "cosmossdk.io/orm/model/ormdb" 15 | 16 | apiv1 "github.com/sonr-io/snrd/api/dwn/v1" 17 | "github.com/sonr-io/snrd/x/dwn/types" 18 | ) 19 | 20 | type Keeper struct { 21 | cdc codec.BinaryCodec 22 | 23 | logger log.Logger 24 | 25 | // state management 26 | Schema collections.Schema 27 | Params collections.Item[types.Params] 28 | OrmDB apiv1.StateStore 29 | 30 | authority string 31 | } 32 | 33 | // NewKeeper creates a new Keeper instance 34 | func NewKeeper( 35 | cdc codec.BinaryCodec, 36 | storeService storetypes.KVStoreService, 37 | logger log.Logger, 38 | authority string, 39 | ) Keeper { 40 | logger = logger.With(log.ModuleKey, "x/"+types.ModuleName) 41 | 42 | sb := collections.NewSchemaBuilder(storeService) 43 | 44 | if authority == "" { 45 | authority = authtypes.NewModuleAddress(govtypes.ModuleName).String() 46 | } 47 | 48 | db, err := ormdb.NewModuleDB(&types.ORMModuleSchema, ormdb.ModuleDBOptions{KVStoreService: storeService}) 49 | if err != nil { 50 | panic(err) 51 | } 52 | 53 | store, err := apiv1.NewStateStore(db) 54 | if err != nil { 55 | panic(err) 56 | } 57 | 58 | k := Keeper{ 59 | cdc: cdc, 60 | logger: logger, 61 | 62 | Params: collections.NewItem(sb, types.ParamsKey, "params", codec.CollValue[types.Params](cdc)), 63 | OrmDB: store, 64 | 65 | authority: authority, 66 | } 67 | 68 | schema, err := sb.Build() 69 | if err != nil { 70 | panic(err) 71 | } 72 | 73 | k.Schema = schema 74 | 75 | return k 76 | } 77 | 78 | func (k Keeper) Logger() log.Logger { 79 | return k.logger 80 | } 81 | 82 | // InitGenesis initializes the module's state from a genesis state. 83 | func (k *Keeper) InitGenesis(ctx context.Context, data *types.GenesisState) error { 84 | if err := data.Params.Validate(); err != nil { 85 | return err 86 | } 87 | 88 | return k.Params.Set(ctx, data.Params) 89 | } 90 | 91 | // ExportGenesis exports the module's state to a genesis state. 92 | func (k *Keeper) ExportGenesis(ctx context.Context) *types.GenesisState { 93 | params, err := k.Params.Get(ctx) 94 | if err != nil { 95 | panic(err) 96 | } 97 | 98 | return &types.GenesisState{ 99 | Params: params, 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /x/dwn/keeper/keeper_test.go: -------------------------------------------------------------------------------- 1 | package keeper_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/suite" 7 | 8 | "cosmossdk.io/log" 9 | storetypes "cosmossdk.io/store/types" 10 | 11 | cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" 12 | "github.com/cosmos/cosmos-sdk/runtime" 13 | "github.com/cosmos/cosmos-sdk/testutil/integration" 14 | simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" 15 | sdk "github.com/cosmos/cosmos-sdk/types" 16 | moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" 17 | authcodec "github.com/cosmos/cosmos-sdk/x/auth/codec" 18 | authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" 19 | authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" 20 | bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" 21 | banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" 22 | govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" 23 | mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper" 24 | minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" 25 | stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" 26 | stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" 27 | 28 | module "github.com/sonr-io/snrd/x/dwn" 29 | "github.com/sonr-io/snrd/x/dwn/keeper" 30 | "github.com/sonr-io/snrd/x/dwn/types" 31 | ) 32 | 33 | var maccPerms = map[string][]string{ 34 | authtypes.FeeCollectorName: nil, 35 | stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking}, 36 | stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking}, 37 | minttypes.ModuleName: {authtypes.Minter}, 38 | govtypes.ModuleName: {authtypes.Burner}, 39 | } 40 | 41 | type testFixture struct { 42 | suite.Suite 43 | 44 | ctx sdk.Context 45 | k keeper.Keeper 46 | msgServer types.MsgServer 47 | queryServer types.QueryServer 48 | appModule *module.AppModule 49 | 50 | accountkeeper authkeeper.AccountKeeper 51 | bankkeeper bankkeeper.BaseKeeper 52 | stakingKeeper *stakingkeeper.Keeper 53 | mintkeeper mintkeeper.Keeper 54 | 55 | addrs []sdk.AccAddress 56 | govModAddr string 57 | } 58 | 59 | func SetupTest(t *testing.T) *testFixture { 60 | t.Helper() 61 | f := new(testFixture) 62 | 63 | // Base setup 64 | logger := log.NewTestLogger(t) 65 | encCfg := moduletestutil.MakeTestEncodingConfig() 66 | 67 | f.govModAddr = authtypes.NewModuleAddress(govtypes.ModuleName).String() 68 | f.addrs = simtestutil.CreateIncrementalAccounts(3) 69 | 70 | keys := storetypes.NewKVStoreKeys(authtypes.ModuleName, banktypes.ModuleName, stakingtypes.ModuleName, minttypes.ModuleName, types.ModuleName) 71 | f.ctx = sdk.NewContext(integration.CreateMultiStore(keys, logger), cmtproto.Header{}, false, logger) 72 | 73 | // Register SDK modules. 74 | registerBaseSDKModules(logger, f, encCfg, keys) 75 | 76 | // Setup Keeper. 77 | f.k = keeper.NewKeeper(encCfg.Codec, runtime.NewKVStoreService(keys[types.ModuleName]), logger, f.govModAddr) 78 | f.msgServer = keeper.NewMsgServerImpl(f.k) 79 | f.queryServer = keeper.NewQuerier(f.k) 80 | f.appModule = module.NewAppModule(encCfg.Codec, f.k) 81 | 82 | return f 83 | } 84 | 85 | func registerModuleInterfaces(encCfg moduletestutil.TestEncodingConfig) { 86 | authtypes.RegisterInterfaces(encCfg.InterfaceRegistry) 87 | stakingtypes.RegisterInterfaces(encCfg.InterfaceRegistry) 88 | banktypes.RegisterInterfaces(encCfg.InterfaceRegistry) 89 | minttypes.RegisterInterfaces(encCfg.InterfaceRegistry) 90 | 91 | types.RegisterInterfaces(encCfg.InterfaceRegistry) 92 | } 93 | 94 | func registerBaseSDKModules( 95 | logger log.Logger, 96 | f *testFixture, 97 | encCfg moduletestutil.TestEncodingConfig, 98 | keys map[string]*storetypes.KVStoreKey, 99 | ) { 100 | registerModuleInterfaces(encCfg) 101 | 102 | // Auth Keeper. 103 | f.accountkeeper = authkeeper.NewAccountKeeper( 104 | encCfg.Codec, runtime.NewKVStoreService(keys[authtypes.StoreKey]), 105 | authtypes.ProtoBaseAccount, 106 | maccPerms, 107 | authcodec.NewBech32Codec(sdk.Bech32MainPrefix), sdk.Bech32MainPrefix, 108 | f.govModAddr, 109 | ) 110 | 111 | // Bank Keeper. 112 | f.bankkeeper = bankkeeper.NewBaseKeeper( 113 | encCfg.Codec, runtime.NewKVStoreService(keys[banktypes.StoreKey]), 114 | f.accountkeeper, 115 | nil, 116 | f.govModAddr, logger, 117 | ) 118 | 119 | // Staking Keeper. 120 | f.stakingKeeper = stakingkeeper.NewKeeper( 121 | encCfg.Codec, runtime.NewKVStoreService(keys[stakingtypes.StoreKey]), 122 | f.accountkeeper, f.bankkeeper, f.govModAddr, 123 | authcodec.NewBech32Codec(sdk.Bech32PrefixValAddr), 124 | authcodec.NewBech32Codec(sdk.Bech32PrefixConsAddr), 125 | ) 126 | 127 | // Mint Keeper. 128 | f.mintkeeper = mintkeeper.NewKeeper( 129 | encCfg.Codec, runtime.NewKVStoreService(keys[minttypes.StoreKey]), 130 | f.stakingKeeper, f.accountkeeper, f.bankkeeper, 131 | authtypes.FeeCollectorName, f.govModAddr, 132 | ) 133 | } 134 | -------------------------------------------------------------------------------- /x/dwn/keeper/msg_server.go: -------------------------------------------------------------------------------- 1 | package keeper 2 | 3 | import ( 4 | "context" 5 | 6 | govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" 7 | 8 | "cosmossdk.io/errors" 9 | "github.com/sonr-io/snrd/x/dwn/types" 10 | ) 11 | 12 | type msgServer struct { 13 | k Keeper 14 | } 15 | 16 | var _ types.MsgServer = msgServer{} 17 | 18 | // NewMsgServerImpl returns an implementation of the module MsgServer interface. 19 | func NewMsgServerImpl(keeper Keeper) types.MsgServer { 20 | return &msgServer{k: keeper} 21 | } 22 | 23 | func (ms msgServer) UpdateParams(ctx context.Context, msg *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { 24 | if ms.k.authority != msg.Authority { 25 | return nil, errors.Wrapf(govtypes.ErrInvalidSigner, "invalid authority; expected %s, got %s", ms.k.authority, msg.Authority) 26 | } 27 | 28 | return nil, ms.k.Params.Set(ctx, msg.Params) 29 | } 30 | 31 | // Initialize implements types.MsgServer. 32 | func (ms msgServer) Initialize(ctx context.Context, msg *types.MsgInitialize) (*types.MsgInitializeResponse, error) { 33 | // ctx := sdk.UnwrapSDKContext(goCtx) 34 | return &types.MsgInitializeResponse{}, nil 35 | } 36 | -------------------------------------------------------------------------------- /x/dwn/keeper/msg_server_test.go: -------------------------------------------------------------------------------- 1 | package keeper_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | 8 | "github.com/sonr-io/snrd/x/dwn/types" 9 | ) 10 | 11 | func TestParams(t *testing.T) { 12 | f := SetupTest(t) 13 | require := require.New(t) 14 | 15 | testCases := []struct { 16 | name string 17 | request *types.MsgUpdateParams 18 | err bool 19 | }{ 20 | { 21 | name: "fail; invalid authority", 22 | request: &types.MsgUpdateParams{ 23 | Authority: f.addrs[0].String(), 24 | Params: types.DefaultParams(), 25 | }, 26 | err: true, 27 | }, 28 | { 29 | name: "success", 30 | request: &types.MsgUpdateParams{ 31 | Authority: f.govModAddr, 32 | Params: types.DefaultParams(), 33 | }, 34 | err: false, 35 | }, 36 | } 37 | 38 | for _, tc := range testCases { 39 | tc := tc 40 | t.Run(tc.name, func(t *testing.T) { 41 | _, err := f.msgServer.UpdateParams(f.ctx, tc.request) 42 | 43 | if tc.err { 44 | require.Error(err) 45 | } else { 46 | require.NoError(err) 47 | 48 | r, err := f.queryServer.Params(f.ctx, &types.QueryParamsRequest{}) 49 | require.NoError(err) 50 | 51 | require.EqualValues(&tc.request.Params, r.Params) 52 | } 53 | 54 | }) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /x/dwn/keeper/query_server.go: -------------------------------------------------------------------------------- 1 | package keeper 2 | 3 | import ( 4 | "context" 5 | 6 | sdk "github.com/cosmos/cosmos-sdk/types" 7 | 8 | "github.com/sonr-io/snrd/x/dwn/types" 9 | ) 10 | 11 | var _ types.QueryServer = Querier{} 12 | 13 | type Querier struct { 14 | Keeper 15 | } 16 | 17 | func NewQuerier(keeper Keeper) Querier { 18 | return Querier{Keeper: keeper} 19 | } 20 | 21 | func (k Querier) Params(c context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { 22 | ctx := sdk.UnwrapSDKContext(c) 23 | 24 | p, err := k.Keeper.Params.Get(ctx) 25 | if err != nil { 26 | return nil, err 27 | } 28 | 29 | return &types.QueryParamsResponse{Params: &p}, nil 30 | } 31 | -------------------------------------------------------------------------------- /x/dwn/module.go: -------------------------------------------------------------------------------- 1 | package module 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | 7 | "github.com/gorilla/mux" 8 | "github.com/grpc-ecosystem/grpc-gateway/runtime" 9 | 10 | abci "github.com/cometbft/cometbft/abci/types" 11 | 12 | "cosmossdk.io/client/v2/autocli" 13 | errorsmod "cosmossdk.io/errors" 14 | 15 | "github.com/cosmos/cosmos-sdk/client" 16 | "github.com/cosmos/cosmos-sdk/codec" 17 | codectypes "github.com/cosmos/cosmos-sdk/codec/types" 18 | sdk "github.com/cosmos/cosmos-sdk/types" 19 | "github.com/cosmos/cosmos-sdk/types/module" 20 | 21 | "github.com/sonr-io/snrd/x/dwn/keeper" 22 | "github.com/sonr-io/snrd/x/dwn/types" 23 | ) 24 | 25 | const ( 26 | // ConsensusVersion defines the current x/dwn module consensus version. 27 | ConsensusVersion = 1 28 | ) 29 | 30 | var ( 31 | _ module.AppModuleBasic = AppModuleBasic{} 32 | _ module.AppModuleGenesis = AppModule{} 33 | _ module.AppModule = AppModule{} 34 | 35 | _ autocli.HasAutoCLIConfig = AppModule{} 36 | ) 37 | 38 | // AppModuleBasic defines the basic application module used by the wasm module. 39 | type AppModuleBasic struct { 40 | cdc codec.Codec 41 | } 42 | 43 | type AppModule struct { 44 | AppModuleBasic 45 | 46 | keeper keeper.Keeper 47 | } 48 | 49 | // NewAppModule constructor 50 | func NewAppModule( 51 | cdc codec.Codec, 52 | keeper keeper.Keeper, 53 | ) *AppModule { 54 | return &AppModule{ 55 | AppModuleBasic: AppModuleBasic{cdc: cdc}, 56 | keeper: keeper, 57 | } 58 | } 59 | 60 | func (a AppModuleBasic) Name() string { 61 | return types.ModuleName 62 | } 63 | 64 | func (a AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { 65 | return cdc.MustMarshalJSON(&types.GenesisState{ 66 | Params: types.DefaultParams(), 67 | }) 68 | } 69 | 70 | func (a AppModuleBasic) ValidateGenesis(marshaler codec.JSONCodec, _ client.TxEncodingConfig, message json.RawMessage) error { 71 | var data types.GenesisState 72 | err := marshaler.UnmarshalJSON(message, &data) 73 | if err != nil { 74 | return err 75 | } 76 | if err := data.Params.Validate(); err != nil { 77 | return errorsmod.Wrap(err, "params") 78 | } 79 | return nil 80 | } 81 | 82 | func (a AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) { 83 | } 84 | 85 | func (a AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { 86 | err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) 87 | if err != nil { 88 | // same behavior as in cosmos-sdk 89 | panic(err) 90 | } 91 | } 92 | 93 | // Disable in favor of autocli.go. If you wish to use these, it will override AutoCLI methods. 94 | /* 95 | func (a AppModuleBasic) GetTxCmd() *cobra.Command { 96 | return cli.NewTxCmd() 97 | } 98 | 99 | func (a AppModuleBasic) GetQueryCmd() *cobra.Command { 100 | return cli.GetQueryCmd() 101 | } 102 | */ 103 | 104 | func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { 105 | types.RegisterLegacyAminoCodec(cdc) 106 | } 107 | 108 | func (a AppModuleBasic) RegisterInterfaces(r codectypes.InterfaceRegistry) { 109 | types.RegisterInterfaces(r) 110 | } 111 | 112 | func (a AppModule) InitGenesis(ctx sdk.Context, marshaler codec.JSONCodec, message json.RawMessage) []abci.ValidatorUpdate { 113 | var genesisState types.GenesisState 114 | marshaler.MustUnmarshalJSON(message, &genesisState) 115 | 116 | if err := a.keeper.Params.Set(ctx, genesisState.Params); err != nil { 117 | panic(err) 118 | } 119 | 120 | return nil 121 | } 122 | 123 | func (a AppModule) ExportGenesis(ctx sdk.Context, marshaler codec.JSONCodec) json.RawMessage { 124 | genState := a.keeper.ExportGenesis(ctx) 125 | return marshaler.MustMarshalJSON(genState) 126 | } 127 | 128 | func (a AppModule) RegisterInvariants(_ sdk.InvariantRegistry) { 129 | } 130 | 131 | func (a AppModule) QuerierRoute() string { 132 | return types.QuerierRoute 133 | } 134 | 135 | func (a AppModule) RegisterServices(cfg module.Configurator) { 136 | types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(a.keeper)) 137 | types.RegisterQueryServer(cfg.QueryServer(), keeper.NewQuerier(a.keeper)) 138 | } 139 | 140 | // ConsensusVersion is a sequence number for state-breaking change of the 141 | // module. It should be incremented on each consensus-breaking change 142 | // introduced by the module. To avoid wrong/empty versions, the initial version 143 | // should be set to 1. 144 | func (a AppModule) ConsensusVersion() uint64 { 145 | return ConsensusVersion 146 | } 147 | -------------------------------------------------------------------------------- /x/dwn/types/attns.go: -------------------------------------------------------------------------------- 1 | package types 2 | -------------------------------------------------------------------------------- /x/dwn/types/codec.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/cosmos/cosmos-sdk/codec" 5 | "github.com/cosmos/cosmos-sdk/codec/types" 6 | cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" 7 | sdk "github.com/cosmos/cosmos-sdk/types" 8 | "github.com/cosmos/cosmos-sdk/types/msgservice" 9 | ) 10 | 11 | var ( 12 | amino = codec.NewLegacyAmino() 13 | AminoCdc = codec.NewAminoCodec(amino) 14 | ) 15 | 16 | func init() { 17 | RegisterLegacyAminoCodec(amino) 18 | cryptocodec.RegisterCrypto(amino) 19 | sdk.RegisterLegacyAminoCodec(amino) 20 | } 21 | 22 | // RegisterLegacyAminoCodec registers concrete types on the LegacyAmino codec 23 | func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { 24 | cdc.RegisterConcrete(&MsgUpdateParams{}, ModuleName+"/MsgUpdateParams", nil) 25 | } 26 | 27 | func RegisterInterfaces(registry types.InterfaceRegistry) { 28 | 29 | registry.RegisterImplementations( 30 | (*sdk.Msg)(nil), 31 | &MsgUpdateParams{}, 32 | ) 33 | 34 | msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) 35 | } 36 | -------------------------------------------------------------------------------- /x/dwn/types/embed/codec.go: -------------------------------------------------------------------------------- 1 | package embed 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/ipfs/boxo/files" 7 | motr "github.com/onsonr/motr/pkg/config" 8 | ) 9 | 10 | const SchemaVersion = 1 11 | const ( 12 | AppManifestFileName = "app.webmanifest" 13 | DWNConfigFileName = "dwn.json" 14 | IndexHTMLFileName = "index.html" 15 | MainJSFileName = "main.js" 16 | ServiceWorkerFileName = "sw.js" 17 | ) 18 | 19 | // spawnVaultDirectory creates a new directory with the default files 20 | func NewVaultFS(cfg *motr.Config) (files.Directory, error) { 21 | manifestBz, err := NewWebManifest() 22 | if err != nil { 23 | return nil, err 24 | } 25 | cnfBz, err := json.Marshal(cfg) 26 | if err != nil { 27 | return nil, err 28 | } 29 | return files.NewMapDirectory(map[string]files.Node{ 30 | AppManifestFileName: files.NewBytesFile(manifestBz), 31 | DWNConfigFileName: files.NewBytesFile(cnfBz), 32 | IndexHTMLFileName: files.NewBytesFile(IndexHTML), 33 | MainJSFileName: files.NewBytesFile(MainJS), 34 | ServiceWorkerFileName: files.NewBytesFile(WorkerJS), 35 | }), nil 36 | } 37 | 38 | // NewVaultConfig returns the default vault config 39 | func NewVaultConfig(addr string, ucanCID string) *motr.Config { 40 | return &motr.Config{ 41 | MotrToken: ucanCID, 42 | MotrAddress: addr, 43 | IpfsGatewayUrl: "http://localhost:80", 44 | SonrApiUrl: "http://localhost:1317", 45 | SonrRpcUrl: "http://localhost:26657", 46 | SonrChainId: "sonr-testnet-1", 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /x/dwn/types/embed/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Sonr DWN 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 27 | 28 | 29 | 47 | 48 | 51 | 52 |
53 | You are currently offline. Some features may be limited. 54 |
55 | 56 | 57 | 64 | 65 |
68 |
75 | Loading... 76 |
77 |
78 | 79 | 80 | 87 | 88 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /x/dwn/types/embed/utils.go: -------------------------------------------------------------------------------- 1 | package embed 2 | 3 | import ( 4 | _ "embed" 5 | "reflect" 6 | "strings" 7 | ) 8 | 9 | //go:embed index.html 10 | var IndexHTML []byte 11 | 12 | //go:embed main.js 13 | var MainJS []byte 14 | 15 | //go:embed sw.js 16 | var WorkerJS []byte 17 | 18 | func getSchema(structType interface{}) string { 19 | t := reflect.TypeOf(structType) 20 | if t.Kind() == reflect.Ptr { 21 | t = t.Elem() 22 | } 23 | 24 | if t.Kind() != reflect.Struct { 25 | return "" 26 | } 27 | 28 | var fields []string 29 | for i := 0; i < t.NumField(); i++ { 30 | field := t.Field(i) 31 | fieldName := toCamelCase(field.Name) 32 | fields = append(fields, fieldName) 33 | } 34 | 35 | // Add "++" at the beginning, separated by a comma 36 | return "++, " + strings.Join(fields, ", ") 37 | } 38 | 39 | func toCamelCase(s string) string { 40 | if s == "" { 41 | return s 42 | } 43 | if len(s) == 1 { 44 | return strings.ToLower(s) 45 | } 46 | return strings.ToLower(s[:1]) + s[1:] 47 | } 48 | -------------------------------------------------------------------------------- /x/dwn/types/embed/webworker.go: -------------------------------------------------------------------------------- 1 | package embed 2 | 3 | import "encoding/json" 4 | 5 | func NewWebManifest() ([]byte, error) { 6 | return json.Marshal(baseWebManifest) 7 | } 8 | 9 | var baseWebManifest = WebManifest{ 10 | Name: "Sonr Vault", 11 | ShortName: "Sonr.ID", 12 | StartURL: "/index.html", 13 | Display: "standalone", 14 | DisplayOverride: []string{ 15 | "fullscreen", 16 | "minimal-ui", 17 | }, 18 | Icons: []IconDefinition{ 19 | { 20 | Src: "/icons/icon-192x192.png", 21 | Sizes: "192x192", 22 | Type: "image/png", 23 | }, 24 | }, 25 | ServiceWorker: ServiceWorker{ 26 | Scope: "/", 27 | Src: "/sw.js", 28 | UseCache: true, 29 | }, 30 | ProtocolHandlers: []ProtocolHandler{ 31 | { 32 | Scheme: "did.sonr", 33 | URL: "/resolve/sonr/%s", 34 | }, 35 | { 36 | Scheme: "did.eth", 37 | URL: "/resolve/eth/%s", 38 | }, 39 | { 40 | Scheme: "did.btc", 41 | URL: "/resolve/btc/%s", 42 | }, 43 | { 44 | Scheme: "did.usdc", 45 | URL: "/resolve/usdc/%s", 46 | }, 47 | { 48 | Scheme: "did.ipfs", 49 | URL: "/resolve/ipfs/%s", 50 | }, 51 | }, 52 | } 53 | 54 | type WebManifest struct { 55 | // Required fields 56 | Name string `json:"name"` // Full name of the application 57 | ShortName string `json:"short_name"` // Short version of the name 58 | 59 | // Display and appearance 60 | Description string `json:"description,omitempty"` // Purpose and features of the application 61 | Display string `json:"display,omitempty"` // Preferred display mode: fullscreen, standalone, minimal-ui, browser 62 | DisplayOverride []string `json:"display_override,omitempty"` 63 | ThemeColor string `json:"theme_color,omitempty"` // Default theme color for the application 64 | BackgroundColor string `json:"background_color,omitempty"` // Background color during launch 65 | Orientation string `json:"orientation,omitempty"` // Default orientation: any, natural, landscape, portrait 66 | 67 | // URLs and scope 68 | StartURL string `json:"start_url"` // Starting URL when launching 69 | Scope string `json:"scope,omitempty"` // Navigation scope of the web application 70 | ServiceWorker ServiceWorker `json:"service_worker,omitempty"` 71 | 72 | // Icons 73 | Icons []IconDefinition `json:"icons,omitempty"` 74 | 75 | // Optional features 76 | RelatedApplications []RelatedApplication `json:"related_applications,omitempty"` 77 | PreferRelatedApplications bool `json:"prefer_related_applications,omitempty"` 78 | Shortcuts []Shortcut `json:"shortcuts,omitempty"` 79 | 80 | // Experimental features (uncomment if needed) 81 | FileHandlers []FileHandler `json:"file_handlers,omitempty"` 82 | ProtocolHandlers []ProtocolHandler `json:"protocol_handlers,omitempty"` 83 | } 84 | 85 | type FileHandler struct { 86 | Action string `json:"action"` 87 | Accept map[string][]string `json:"accept"` 88 | } 89 | 90 | type LaunchHandler struct { 91 | Action string `json:"action"` 92 | } 93 | 94 | type IconDefinition struct { 95 | Src string `json:"src"` 96 | Sizes string `json:"sizes"` 97 | Type string `json:"type,omitempty"` 98 | Purpose string `json:"purpose,omitempty"` 99 | } 100 | 101 | type ProtocolHandler struct { 102 | Scheme string `json:"scheme"` 103 | URL string `json:"url"` 104 | } 105 | 106 | type RelatedApplication struct { 107 | Platform string `json:"platform"` 108 | URL string `json:"url,omitempty"` 109 | ID string `json:"id,omitempty"` 110 | } 111 | 112 | type Shortcut struct { 113 | Name string `json:"name"` 114 | ShortName string `json:"short_name,omitempty"` 115 | Description string `json:"description,omitempty"` 116 | URL string `json:"url"` 117 | Icons []IconDefinition `json:"icons,omitempty"` 118 | } 119 | 120 | type ServiceWorker struct { 121 | Scope string `json:"scope"` 122 | Src string `json:"src"` 123 | UseCache bool `json:"use_cache"` 124 | } 125 | -------------------------------------------------------------------------------- /x/dwn/types/genesis.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // Capability hierarchy for smart account operations 4 | // ---------------------------------------------- 5 | // OWNER 6 | // 7 | // └─ OPERATOR 8 | // ├─ EXECUTE 9 | // ├─ PROPOSE 10 | // └─ SIGN 11 | // └─ SET_POLICY 12 | // └─ SET_THRESHOLD 13 | // └─ RECOVER 14 | // └─ SOCIAL 15 | // 16 | // DefaultIndex is the default global index 17 | const DefaultIndex uint64 = 1 18 | 19 | // DefaultGenesis returns the default genesis state 20 | func DefaultGenesis() *GenesisState { 21 | return &GenesisState{ 22 | // this line is used by starport scaffolding # genesis/types/default 23 | Params: DefaultParams(), 24 | } 25 | } 26 | 27 | // Validate performs basic genesis state validation returning an error upon any 28 | // failure. 29 | func (gs GenesisState) Validate() error { 30 | // this line is used by starport scaffolding # genesis/types/validate 31 | 32 | return gs.Params.Validate() 33 | } 34 | 35 | // Equal checks if two Attenuation are equal 36 | func (a *Attenuation) Equal(that *Attenuation) bool { 37 | if that == nil { 38 | return false 39 | } 40 | if a.Resource != nil { 41 | if that.Resource == nil { 42 | return false 43 | } 44 | if !a.Resource.Equal(that.Resource) { 45 | return false 46 | } 47 | } 48 | if len(a.Capabilities) != len(that.Capabilities) { 49 | return false 50 | } 51 | for i := range a.Capabilities { 52 | if !a.Capabilities[i].Equal(that.Capabilities[i]) { 53 | return false 54 | } 55 | } 56 | return true 57 | } 58 | 59 | // Equal checks if two Capability are equal 60 | func (c *Capability) Equal(that *Capability) bool { 61 | if that == nil { 62 | return false 63 | } 64 | if c.Name != that.Name { 65 | return false 66 | } 67 | if c.Parent != that.Parent { 68 | return false 69 | } 70 | // TODO: check description 71 | if len(c.Resources) != len(that.Resources) { 72 | return false 73 | } 74 | for i := range c.Resources { 75 | if c.Resources[i] != that.Resources[i] { 76 | return false 77 | } 78 | } 79 | return true 80 | } 81 | 82 | // Equal checks if two Resource are equal 83 | func (r *Resource) Equal(that *Resource) bool { 84 | if that == nil { 85 | return false 86 | } 87 | if r.Kind != that.Kind { 88 | return false 89 | } 90 | if r.Template != that.Template { 91 | return false 92 | } 93 | return true 94 | } 95 | -------------------------------------------------------------------------------- /x/dwn/types/genesis_test.go: -------------------------------------------------------------------------------- 1 | package types_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/sonr-io/snrd/x/dwn/types" 7 | 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func TestGenesisState_Validate(t *testing.T) { 12 | tests := []struct { 13 | desc string 14 | genState *types.GenesisState 15 | valid bool 16 | }{ 17 | { 18 | desc: "default is valid", 19 | genState: types.DefaultGenesis(), 20 | valid: true, 21 | }, 22 | { 23 | desc: "valid genesis state", 24 | genState: &types.GenesisState{}, 25 | valid: true, 26 | }, 27 | } 28 | for _, tc := range tests { 29 | t.Run(tc.desc, func(t *testing.T) { 30 | err := tc.genState.Validate() 31 | if tc.valid { 32 | require.NoError(t, err) 33 | } else { 34 | require.Error(t, err) 35 | } 36 | }) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /x/dwn/types/keys.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "cosmossdk.io/collections" 5 | 6 | ormv1alpha1 "cosmossdk.io/api/cosmos/orm/v1alpha1" 7 | ) 8 | 9 | var ( 10 | // ParamsKey saves the current module params. 11 | ParamsKey = collections.NewPrefix(0) 12 | ) 13 | 14 | const ( 15 | ModuleName = "dwn" 16 | 17 | StoreKey = ModuleName 18 | 19 | QuerierRoute = ModuleName 20 | ) 21 | 22 | var ORMModuleSchema = ormv1alpha1.ModuleSchemaDescriptor{ 23 | SchemaFile: []*ormv1alpha1.ModuleSchemaDescriptor_FileEntry{ 24 | {Id: 1, ProtoFileName: "dwn/v1/state.proto"}, 25 | }, 26 | Prefix: []byte{0}, 27 | } 28 | -------------------------------------------------------------------------------- /x/dwn/types/msgs.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "cosmossdk.io/errors" 5 | sdk "github.com/cosmos/cosmos-sdk/types" 6 | ) 7 | 8 | var _ sdk.Msg = &MsgUpdateParams{} 9 | 10 | // ╭───────────────────────────────────────────────────────────╮ 11 | // │ MsgUpdateParams type definition │ 12 | // ╰───────────────────────────────────────────────────────────╯ 13 | 14 | // NewMsgUpdateParams creates new instance of MsgUpdateParams 15 | func NewMsgUpdateParams( 16 | sender sdk.Address, 17 | someValue bool, 18 | ) *MsgUpdateParams { 19 | return &MsgUpdateParams{ 20 | Authority: sender.String(), 21 | Params: Params{}, 22 | } 23 | } 24 | 25 | // Route returns the name of the module 26 | func (msg MsgUpdateParams) Route() string { return ModuleName } 27 | 28 | // Type returns the the action 29 | func (msg MsgUpdateParams) Type() string { return "update_params" } 30 | 31 | // GetSignBytes implements the LegacyMsg interface. 32 | func (msg MsgUpdateParams) GetSignBytes() []byte { 33 | return sdk.MustSortJSON(AminoCdc.MustMarshalJSON(&msg)) 34 | } 35 | 36 | // GetSigners returns the expected signers for a MsgUpdateParams message. 37 | func (msg *MsgUpdateParams) GetSigners() []sdk.AccAddress { 38 | addr, _ := sdk.AccAddressFromBech32(msg.Authority) 39 | return []sdk.AccAddress{addr} 40 | } 41 | 42 | // ValidateBasic does a sanity check on the provided data. 43 | func (msg *MsgUpdateParams) Validate() error { 44 | if _, err := sdk.AccAddressFromBech32(msg.Authority); err != nil { 45 | return errors.Wrap(err, "invalid authority address") 46 | } 47 | 48 | return msg.Params.Validate() 49 | } 50 | -------------------------------------------------------------------------------- /x/dwn/types/params.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "encoding/json" 5 | ) 6 | 7 | // DefaultParams returns default module parameters. 8 | func DefaultParams() Params { 9 | return Params{ 10 | AllowedOperators: []string{ // TODO: 11 | "localhost", 12 | "didao.xyz", 13 | "sonr.id", 14 | }, 15 | } 16 | } 17 | 18 | // Stringer method for Params. 19 | func (p Params) String() string { 20 | bz, err := json.Marshal(p) 21 | if err != nil { 22 | panic(err) 23 | } 24 | 25 | return string(bz) 26 | } 27 | 28 | // Validate does the sanity check on the params. 29 | func (p Params) Validate() error { 30 | // TODO: 31 | return nil 32 | } 33 | -------------------------------------------------------------------------------- /x/svc/README.md: -------------------------------------------------------------------------------- 1 | # `x/svc` 2 | 3 | The svc module is responsible for managing the registration and authorization of services within the Sonr ecosystem. It provides a secure and verifiable mechanism for registering and authorizing services using Decentralized Identifiers (DIDs) and now incorporates UCAN (User Controlled Authorization Networks) for enhanced authorization capabilities. 4 | 5 | ## Concepts 6 | 7 | - **Service**: A decentralized svc on the Sonr Blockchain with properties such as ID, authority, origin, name, description, category, tags, and expiry height. 8 | - **Profile**: Represents a DID alias with properties like ID, subject, origin, and controller. 9 | - **Metadata**: Contains information about a svc, including name, description, category, icon, and tags. 10 | - **UCAN Authorization**: The module utilizes UCANs for a decentralized and user-centric authorization mechanism. 11 | 12 | ### Dependencies 13 | 14 | - [x/did](https://github.com/sonr-io/snrd/tree/master/x/did) 15 | - [x/group](https://github.com/sonr-io/snrd/tree/master/x/group) 16 | - [x/nft](https://github.com/sonr-io/snrd/tree/master/x/nft) 17 | 18 | ## State 19 | 20 | The module uses the following state structures: 21 | 22 | ### Metadata 23 | 24 | Stores information about services: 25 | 26 | - Primary key: `id` (auto-increment) 27 | - Unique index: `origin` 28 | - Fields: id, origin, name, description, category, icon (URI), tags 29 | 30 | ### Profile 31 | 32 | Stores DID alias information: 33 | 34 | - Primary key: `id` 35 | - Unique index: `subject,origin` 36 | - Fields: id, subject, origin, controller 37 | 38 | ## Messages 39 | 40 | ### MsgUpdateParams 41 | 42 | Updates the module parameters, including UCAN-related parameters. Can only be executed by the governance account. 43 | 44 | ### MsgRegisterService 45 | 46 | Registers a new svc on the blockchain. Requires a valid TXT record in DNS for the origin and may be subject to UCAN authorization checks. 47 | 48 | ## Params 49 | 50 | The module has the following parameters: 51 | 52 | - `categories`: List of allowed svc categories 53 | - `types`: List of allowed svc types 54 | - `UcanPermissions`: Specifies the required UCAN permissions for various actions within the module, such as registering a service. 55 | 56 | ## Query 57 | 58 | The module provides the following query: 59 | 60 | ### Params 61 | 62 | Retrieves all parameters of the module, including UCAN-related parameters. 63 | 64 | ## Client 65 | 66 | ### gRPC 67 | 68 | The module provides a gRPC Query svc with the following RPC: 69 | 70 | - `Params`: Get all parameters of the module, including UCAN-related parameters. 71 | 72 | ### CLI 73 | 74 | (TODO: Add CLI commands for interacting with the module) 75 | 76 | ## Events 77 | 78 | (TODO: List and describe event tags used by the module, including those related to UCAN authorization) 79 | 80 | ## UCAN Authorization 81 | 82 | This module utilizes UCAN (User Controlled Authorization Networks) to provide a decentralized and user-centric authorization mechanism. UCANs are self-contained authorization tokens that allow users to delegate specific capabilities to other entities without relying on a central authority. 83 | 84 | ### UCAN Integration 85 | 86 | - The module parameters include a `UcanPermissions` field that defines the default UCAN permissions required for actions within the module. 87 | - Message handlers in the `MsgServer` perform UCAN authorization checks by: 88 | - Retrieving the UCAN permissions from the context (injected by a middleware). 89 | - Retrieving the required UCAN permissions from the module parameters. 90 | - Verifying that the provided UCAN permissions satisfy the required permissions. 91 | - A dedicated middleware is responsible for: 92 | - Parsing incoming requests for UCAN tokens. 93 | - Verifying UCAN token signatures and validity. 94 | - Extracting UCAN permissions. 95 | - Injecting UCAN permissions into the context. 96 | - UCAN verification logic involves: 97 | - Checking UCAN token signatures against the issuer's public key (resolved via the `x/did` module). 98 | - Validating token expiration and other constraints. 99 | - Parsing token capabilities and extracting relevant permissions. 100 | 101 | ## Future Improvements 102 | 103 | - Implement svc discovery mechanisms 104 | - Add support for svc reputation and rating systems 105 | - Enhance svc metadata with more detailed information 106 | - Implement svc update and deactivation functionality 107 | 108 | ## Tests 109 | 110 | (TODO: Add acceptance tests for the module) 111 | 112 | ## Appendix 113 | 114 | This module is part of the Sonr blockchain project and interacts with other modules such as DID and NFT modules to provide a comprehensive decentralized svc ecosystem. 115 | -------------------------------------------------------------------------------- /x/svc/autocli.go: -------------------------------------------------------------------------------- 1 | package module 2 | 3 | import ( 4 | autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" 5 | modulev1 "github.com/sonr-io/snrd/api/svc/v1" 6 | ) 7 | 8 | // AutoCLIOptions implements the autocli.HasAutoCLIConfig interface. 9 | func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { 10 | return &autocliv1.ModuleOptions{ 11 | Query: &autocliv1.ServiceCommandDescriptor{ 12 | Service: modulev1.Query_ServiceDesc.ServiceName, 13 | RpcCommandOptions: []*autocliv1.RpcCommandOptions{ 14 | { 15 | RpcMethod: "Params", 16 | Use: "params", 17 | Short: "Query the current consensus parameters", 18 | }, 19 | }, 20 | }, 21 | Tx: &autocliv1.ServiceCommandDescriptor{ 22 | Service: modulev1.Msg_ServiceDesc.ServiceName, 23 | RpcCommandOptions: []*autocliv1.RpcCommandOptions{ 24 | { 25 | RpcMethod: "UpdateParams", 26 | Skip: false, // set to true if authority gated 27 | }, 28 | }, 29 | }, 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /x/svc/client/cli/query.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | 6 | "github.com/cosmos/cosmos-sdk/client" 7 | "github.com/cosmos/cosmos-sdk/client/flags" 8 | 9 | "github.com/sonr-io/snrd/x/svc/types" 10 | ) 11 | 12 | // !NOTE: Must enable in module.go (disabled in favor of autocli.go) 13 | 14 | func GetQueryCmd() *cobra.Command { 15 | queryCmd := &cobra.Command{ 16 | Use: types.ModuleName, 17 | Short: "Querying commands for " + types.ModuleName, 18 | DisableFlagParsing: true, 19 | SuggestionsMinimumDistance: 2, 20 | RunE: client.ValidateCmd, 21 | } 22 | queryCmd.AddCommand( 23 | GetCmdParams(), 24 | ) 25 | return queryCmd 26 | } 27 | 28 | func GetCmdParams() *cobra.Command { 29 | cmd := &cobra.Command{ 30 | Use: "params", 31 | Short: "Show all module params", 32 | Args: cobra.ExactArgs(0), 33 | RunE: func(cmd *cobra.Command, args []string) error { 34 | clientCtx, err := client.GetClientQueryContext(cmd) 35 | if err != nil { 36 | return err 37 | } 38 | 39 | queryClient := types.NewQueryClient(clientCtx) 40 | res, err := queryClient.Params(cmd.Context(), &types.QueryParamsRequest{}) 41 | if err != nil { 42 | return err 43 | } 44 | 45 | return clientCtx.PrintProto(res) 46 | }, 47 | } 48 | flags.AddQueryFlagsToCmd(cmd) 49 | return cmd 50 | } 51 | -------------------------------------------------------------------------------- /x/svc/client/cli/tx.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | 6 | "github.com/cosmos/cosmos-sdk/client" 7 | "github.com/cosmos/cosmos-sdk/client/flags" 8 | "github.com/cosmos/cosmos-sdk/client/tx" 9 | 10 | "github.com/sonr-io/snrd/x/svc/types" 11 | ) 12 | 13 | // !NOTE: Must enable in module.go (disabled in favor of autocli.go) 14 | 15 | // NewTxCmd returns a root CLI command handler for certain modules 16 | // transaction commands. 17 | func NewTxCmd() *cobra.Command { 18 | txCmd := &cobra.Command{ 19 | Use: types.ModuleName, 20 | Short: types.ModuleName + " subcommands.", 21 | DisableFlagParsing: true, 22 | SuggestionsMinimumDistance: 2, 23 | RunE: client.ValidateCmd, 24 | } 25 | 26 | txCmd.AddCommand( 27 | MsgUpdateParams(), 28 | ) 29 | return txCmd 30 | } 31 | 32 | // Returns a CLI command handler for registering a 33 | // contract for the module. 34 | func MsgUpdateParams() *cobra.Command { 35 | cmd := &cobra.Command{ 36 | Use: "update-params [some-value]", 37 | Short: "Update the params (must be submitted from the authority)", 38 | Args: cobra.ExactArgs(1), 39 | RunE: func(cmd *cobra.Command, args []string) error { 40 | cliCtx, err := client.GetClientTxContext(cmd) 41 | if err != nil { 42 | return err 43 | } 44 | 45 | senderAddress := cliCtx.GetFromAddress() 46 | 47 | msg := &types.MsgUpdateParams{ 48 | Authority: senderAddress.String(), 49 | Params: types.Params{}, 50 | } 51 | 52 | if err := msg.Validate(); err != nil { 53 | return err 54 | } 55 | 56 | return tx.GenerateOrBroadcastTxCLI(cliCtx, cmd.Flags(), msg) 57 | }, 58 | } 59 | 60 | flags.AddTxFlagsToCmd(cmd) 61 | return cmd 62 | } 63 | -------------------------------------------------------------------------------- /x/svc/depinject.go: -------------------------------------------------------------------------------- 1 | package module 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/cosmos/cosmos-sdk/codec" 7 | authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" 8 | slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" 9 | 10 | govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" 11 | stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" 12 | 13 | "cosmossdk.io/core/address" 14 | "cosmossdk.io/core/appmodule" 15 | "cosmossdk.io/core/store" 16 | "cosmossdk.io/depinject" 17 | "cosmossdk.io/log" 18 | 19 | modulev1 "github.com/sonr-io/snrd/api/svc/module/v1" 20 | "github.com/sonr-io/snrd/x/svc/keeper" 21 | ) 22 | 23 | var _ appmodule.AppModule = AppModule{} 24 | 25 | // IsOnePerModuleType implements the depinject.OnePerModuleType interface. 26 | func (am AppModule) IsOnePerModuleType() {} 27 | 28 | // IsAppModule implements the appmodule.AppModule interface. 29 | func (am AppModule) IsAppModule() {} 30 | 31 | func init() { 32 | appmodule.Register( 33 | &modulev1.Module{}, 34 | appmodule.Provide(ProvideModule), 35 | ) 36 | } 37 | 38 | type ModuleInputs struct { 39 | depinject.In 40 | 41 | Cdc codec.Codec 42 | StoreService store.KVStoreService 43 | AddressCodec address.Codec 44 | 45 | StakingKeeper stakingkeeper.Keeper 46 | SlashingKeeper slashingkeeper.Keeper 47 | } 48 | 49 | type ModuleOutputs struct { 50 | depinject.Out 51 | 52 | Module appmodule.AppModule 53 | Keeper keeper.Keeper 54 | } 55 | 56 | func ProvideModule(in ModuleInputs) ModuleOutputs { 57 | govAddr := authtypes.NewModuleAddress(govtypes.ModuleName).String() 58 | 59 | k := keeper.NewKeeper(in.Cdc, in.StoreService, log.NewLogger(os.Stderr), govAddr) 60 | m := NewAppModule(in.Cdc, k) 61 | 62 | return ModuleOutputs{Module: m, Keeper: k, Out: depinject.Out{}} 63 | } 64 | -------------------------------------------------------------------------------- /x/svc/keeper/genesis_test.go: -------------------------------------------------------------------------------- 1 | package keeper_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/sonr-io/snrd/x/svc/types" 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestGenesis(t *testing.T) { 11 | f := SetupTest(t) 12 | 13 | genesisState := &types.GenesisState{ 14 | Params: types.DefaultParams(), 15 | } 16 | 17 | f.k.InitGenesis(f.ctx, genesisState) 18 | 19 | got := f.k.ExportGenesis(f.ctx) 20 | require.NotNil(t, got) 21 | 22 | } 23 | -------------------------------------------------------------------------------- /x/svc/keeper/keeper.go: -------------------------------------------------------------------------------- 1 | package keeper 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/cosmos/cosmos-sdk/codec" 7 | 8 | authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" 9 | govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" 10 | 11 | "cosmossdk.io/collections" 12 | storetypes "cosmossdk.io/core/store" 13 | "cosmossdk.io/log" 14 | "cosmossdk.io/orm/model/ormdb" 15 | 16 | apiv1 "github.com/sonr-io/snrd/api/svc/v1" 17 | "github.com/sonr-io/snrd/x/svc/types" 18 | ) 19 | 20 | type Keeper struct { 21 | cdc codec.BinaryCodec 22 | 23 | logger log.Logger 24 | 25 | // state management 26 | Schema collections.Schema 27 | Params collections.Item[types.Params] 28 | OrmDB apiv1.StateStore 29 | 30 | authority string 31 | } 32 | 33 | // NewKeeper creates a new Keeper instance 34 | func NewKeeper( 35 | cdc codec.BinaryCodec, 36 | storeService storetypes.KVStoreService, 37 | logger log.Logger, 38 | authority string, 39 | ) Keeper { 40 | logger = logger.With(log.ModuleKey, "x/"+types.ModuleName) 41 | 42 | sb := collections.NewSchemaBuilder(storeService) 43 | 44 | if authority == "" { 45 | authority = authtypes.NewModuleAddress(govtypes.ModuleName).String() 46 | } 47 | 48 | db, err := ormdb.NewModuleDB(&types.ORMModuleSchema, ormdb.ModuleDBOptions{KVStoreService: storeService}) 49 | if err != nil { 50 | panic(err) 51 | } 52 | 53 | store, err := apiv1.NewStateStore(db) 54 | if err != nil { 55 | panic(err) 56 | } 57 | 58 | k := Keeper{ 59 | cdc: cdc, 60 | logger: logger, 61 | 62 | Params: collections.NewItem(sb, types.ParamsKey, "params", codec.CollValue[types.Params](cdc)), 63 | OrmDB: store, 64 | 65 | authority: authority, 66 | } 67 | 68 | schema, err := sb.Build() 69 | if err != nil { 70 | panic(err) 71 | } 72 | 73 | k.Schema = schema 74 | 75 | return k 76 | } 77 | 78 | func (k Keeper) Logger() log.Logger { 79 | return k.logger 80 | } 81 | 82 | // InitGenesis initializes the module's state from a genesis state. 83 | func (k *Keeper) InitGenesis(ctx context.Context, data *types.GenesisState) error { 84 | 85 | if err := data.Params.Validate(); err != nil { 86 | return err 87 | } 88 | 89 | return k.Params.Set(ctx, data.Params) 90 | } 91 | 92 | // ExportGenesis exports the module's state to a genesis state. 93 | func (k *Keeper) ExportGenesis(ctx context.Context) *types.GenesisState { 94 | params, err := k.Params.Get(ctx) 95 | if err != nil { 96 | panic(err) 97 | } 98 | 99 | return &types.GenesisState{ 100 | Params: params, 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /x/svc/keeper/msg_server.go: -------------------------------------------------------------------------------- 1 | package keeper 2 | 3 | import ( 4 | "context" 5 | 6 | govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" 7 | 8 | "cosmossdk.io/errors" 9 | "github.com/sonr-io/snrd/x/svc/types" 10 | ) 11 | 12 | type msgServer struct { 13 | k Keeper 14 | } 15 | 16 | var _ types.MsgServer = msgServer{} 17 | 18 | // NewMsgServerImpl returns an implementation of the module MsgServer interface. 19 | func NewMsgServerImpl(keeper Keeper) types.MsgServer { 20 | return &msgServer{k: keeper} 21 | } 22 | 23 | func (ms msgServer) UpdateParams(ctx context.Context, msg *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { 24 | if ms.k.authority != msg.Authority { 25 | return nil, errors.Wrapf(govtypes.ErrInvalidSigner, "invalid authority; expected %s, got %s", ms.k.authority, msg.Authority) 26 | } 27 | 28 | return nil, ms.k.Params.Set(ctx, msg.Params) 29 | } 30 | 31 | // RegisterService implements types.MsgServer. 32 | func (ms msgServer) RegisterService(ctx context.Context, msg *types.MsgRegisterService) (*types.MsgRegisterServiceResponse, error) { 33 | // ctx := sdk.UnwrapSDKContext(goCtx) 34 | panic("RegisterService is unimplemented") 35 | return &types.MsgRegisterServiceResponse{}, nil 36 | } 37 | -------------------------------------------------------------------------------- /x/svc/keeper/msg_server_test.go: -------------------------------------------------------------------------------- 1 | package keeper_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | 8 | "github.com/sonr-io/snrd/x/svc/types" 9 | ) 10 | 11 | func TestParams(t *testing.T) { 12 | f := SetupTest(t) 13 | require := require.New(t) 14 | 15 | testCases := []struct { 16 | name string 17 | request *types.MsgUpdateParams 18 | err bool 19 | }{ 20 | { 21 | name: "fail; invalid authority", 22 | request: &types.MsgUpdateParams{ 23 | Authority: f.addrs[0].String(), 24 | Params: types.DefaultParams(), 25 | }, 26 | err: true, 27 | }, 28 | { 29 | name: "success", 30 | request: &types.MsgUpdateParams{ 31 | Authority: f.govModAddr, 32 | Params: types.DefaultParams(), 33 | }, 34 | err: false, 35 | }, 36 | } 37 | 38 | for _, tc := range testCases { 39 | tc := tc 40 | t.Run(tc.name, func(t *testing.T) { 41 | _, err := f.msgServer.UpdateParams(f.ctx, tc.request) 42 | 43 | if tc.err { 44 | require.Error(err) 45 | } else { 46 | require.NoError(err) 47 | 48 | r, err := f.queryServer.Params(f.ctx, &types.QueryParamsRequest{}) 49 | require.NoError(err) 50 | 51 | require.EqualValues(&tc.request.Params, r.Params) 52 | } 53 | 54 | }) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /x/svc/keeper/query_server.go: -------------------------------------------------------------------------------- 1 | package keeper 2 | 3 | import ( 4 | "context" 5 | 6 | sdk "github.com/cosmos/cosmos-sdk/types" 7 | 8 | "github.com/sonr-io/snrd/x/svc/types" 9 | ) 10 | 11 | var _ types.QueryServer = Querier{} 12 | 13 | type Querier struct { 14 | Keeper 15 | } 16 | 17 | func NewQuerier(keeper Keeper) Querier { 18 | return Querier{Keeper: keeper} 19 | } 20 | 21 | func (k Querier) Params(c context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { 22 | ctx := sdk.UnwrapSDKContext(c) 23 | 24 | p, err := k.Keeper.Params.Get(ctx) 25 | if err != nil { 26 | return nil, err 27 | } 28 | 29 | return &types.QueryParamsResponse{Params: &p}, nil 30 | } 31 | 32 | // OriginExists implements types.QueryServer. 33 | func (k Querier) OriginExists(goCtx context.Context, req *types.QueryOriginExistsRequest) (*types.QueryOriginExistsResponse, error) { 34 | // ctx := sdk.UnwrapSDKContext(goCtx) 35 | return &types.QueryOriginExistsResponse{}, nil 36 | } 37 | 38 | // ResolveOrigin implements types.QueryServer. 39 | func (k Querier) ResolveOrigin(goCtx context.Context, req *types.QueryResolveOriginRequest) (*types.QueryResolveOriginResponse, error) { 40 | // ctx := sdk.UnwrapSDKContext(goCtx) 41 | return &types.QueryResolveOriginResponse{}, nil 42 | } 43 | -------------------------------------------------------------------------------- /x/svc/module.go: -------------------------------------------------------------------------------- 1 | package module 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | 7 | "github.com/gorilla/mux" 8 | "github.com/grpc-ecosystem/grpc-gateway/runtime" 9 | 10 | abci "github.com/cometbft/cometbft/abci/types" 11 | 12 | "cosmossdk.io/client/v2/autocli" 13 | errorsmod "cosmossdk.io/errors" 14 | 15 | "github.com/cosmos/cosmos-sdk/client" 16 | "github.com/cosmos/cosmos-sdk/codec" 17 | codectypes "github.com/cosmos/cosmos-sdk/codec/types" 18 | sdk "github.com/cosmos/cosmos-sdk/types" 19 | "github.com/cosmos/cosmos-sdk/types/module" 20 | 21 | "github.com/sonr-io/snrd/x/svc/keeper" 22 | "github.com/sonr-io/snrd/x/svc/types" 23 | ) 24 | 25 | const ( 26 | // ConsensusVersion defines the current x/svc module consensus version. 27 | ConsensusVersion = 1 28 | ) 29 | 30 | var ( 31 | _ module.AppModuleBasic = AppModuleBasic{} 32 | _ module.AppModuleGenesis = AppModule{} 33 | _ module.AppModule = AppModule{} 34 | 35 | _ autocli.HasAutoCLIConfig = AppModule{} 36 | ) 37 | 38 | // AppModuleBasic defines the basic application module used by the wasm module. 39 | type AppModuleBasic struct { 40 | cdc codec.Codec 41 | } 42 | 43 | type AppModule struct { 44 | AppModuleBasic 45 | 46 | keeper keeper.Keeper 47 | } 48 | 49 | // NewAppModule constructor 50 | func NewAppModule( 51 | cdc codec.Codec, 52 | keeper keeper.Keeper, 53 | ) *AppModule { 54 | return &AppModule{ 55 | AppModuleBasic: AppModuleBasic{cdc: cdc}, 56 | keeper: keeper, 57 | } 58 | } 59 | 60 | func (a AppModuleBasic) Name() string { 61 | return types.ModuleName 62 | } 63 | 64 | func (a AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { 65 | return cdc.MustMarshalJSON(&types.GenesisState{ 66 | Params: types.DefaultParams(), 67 | }) 68 | } 69 | 70 | func (a AppModuleBasic) ValidateGenesis(marshaler codec.JSONCodec, _ client.TxEncodingConfig, message json.RawMessage) error { 71 | var data types.GenesisState 72 | err := marshaler.UnmarshalJSON(message, &data) 73 | if err != nil { 74 | return err 75 | } 76 | if err := data.Params.Validate(); err != nil { 77 | return errorsmod.Wrap(err, "params") 78 | } 79 | return nil 80 | } 81 | 82 | func (a AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) { 83 | } 84 | 85 | func (a AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { 86 | err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) 87 | if err != nil { 88 | // same behavior as in cosmos-sdk 89 | panic(err) 90 | } 91 | } 92 | 93 | // Disable in favor of autocli.go. If you wish to use these, it will override AutoCLI methods. 94 | /* 95 | func (a AppModuleBasic) GetTxCmd() *cobra.Command { 96 | return cli.NewTxCmd() 97 | } 98 | 99 | func (a AppModuleBasic) GetQueryCmd() *cobra.Command { 100 | return cli.GetQueryCmd() 101 | } 102 | */ 103 | 104 | func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { 105 | types.RegisterLegacyAminoCodec(cdc) 106 | } 107 | 108 | func (a AppModuleBasic) RegisterInterfaces(r codectypes.InterfaceRegistry) { 109 | types.RegisterInterfaces(r) 110 | } 111 | 112 | func (a AppModule) InitGenesis(ctx sdk.Context, marshaler codec.JSONCodec, message json.RawMessage) []abci.ValidatorUpdate { 113 | var genesisState types.GenesisState 114 | marshaler.MustUnmarshalJSON(message, &genesisState) 115 | 116 | if err := a.keeper.Params.Set(ctx, genesisState.Params); err != nil { 117 | panic(err) 118 | } 119 | 120 | return nil 121 | } 122 | 123 | func (a AppModule) ExportGenesis(ctx sdk.Context, marshaler codec.JSONCodec) json.RawMessage { 124 | genState := a.keeper.ExportGenesis(ctx) 125 | return marshaler.MustMarshalJSON(genState) 126 | } 127 | 128 | func (a AppModule) RegisterInvariants(_ sdk.InvariantRegistry) { 129 | } 130 | 131 | func (a AppModule) QuerierRoute() string { 132 | return types.QuerierRoute 133 | } 134 | 135 | func (a AppModule) RegisterServices(cfg module.Configurator) { 136 | types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(a.keeper)) 137 | types.RegisterQueryServer(cfg.QueryServer(), keeper.NewQuerier(a.keeper)) 138 | } 139 | 140 | // ConsensusVersion is a sequence number for state-breaking change of the 141 | // module. It should be incremented on each consensus-breaking change 142 | // introduced by the module. To avoid wrong/empty versions, the initial version 143 | // should be set to 1. 144 | func (a AppModule) ConsensusVersion() uint64 { 145 | return ConsensusVersion 146 | } 147 | -------------------------------------------------------------------------------- /x/svc/types/codec.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/cosmos/cosmos-sdk/codec" 5 | "github.com/cosmos/cosmos-sdk/codec/types" 6 | cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" 7 | sdk "github.com/cosmos/cosmos-sdk/types" 8 | "github.com/cosmos/cosmos-sdk/types/msgservice" 9 | ) 10 | 11 | var ( 12 | amino = codec.NewLegacyAmino() 13 | AminoCdc = codec.NewAminoCodec(amino) 14 | ) 15 | 16 | func init() { 17 | RegisterLegacyAminoCodec(amino) 18 | cryptocodec.RegisterCrypto(amino) 19 | sdk.RegisterLegacyAminoCodec(amino) 20 | } 21 | 22 | // RegisterLegacyAminoCodec registers concrete types on the LegacyAmino codec 23 | func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { 24 | cdc.RegisterConcrete(&MsgUpdateParams{}, ModuleName+"/MsgUpdateParams", nil) 25 | } 26 | 27 | func RegisterInterfaces(registry types.InterfaceRegistry) { 28 | 29 | registry.RegisterImplementations( 30 | (*sdk.Msg)(nil), 31 | &MsgUpdateParams{}, 32 | ) 33 | 34 | msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) 35 | } 36 | -------------------------------------------------------------------------------- /x/svc/types/genesis.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // DefaultIndex is the default global index 4 | const DefaultIndex uint64 = 1 5 | 6 | // DefaultGenesis returns the default genesis state 7 | func DefaultGenesis() *GenesisState { 8 | return &GenesisState{ 9 | Params: DefaultParams(), 10 | } 11 | } 12 | 13 | // Validate performs basic genesis state validation returning an error upon any 14 | // failure. 15 | func (gs GenesisState) Validate() error { 16 | return gs.Params.Validate() 17 | } 18 | 19 | // Equal checks if two Attenuation are equal 20 | func (a *Attenuation) Equal(that *Attenuation) bool { 21 | if that == nil { 22 | return false 23 | } 24 | if a.Resource != nil { 25 | if that.Resource == nil { 26 | return false 27 | } 28 | if !a.Resource.Equal(that.Resource) { 29 | return false 30 | } 31 | } 32 | if len(a.Capabilities) != len(that.Capabilities) { 33 | return false 34 | } 35 | for i := range a.Capabilities { 36 | if !a.Capabilities[i].Equal(that.Capabilities[i]) { 37 | return false 38 | } 39 | } 40 | return true 41 | } 42 | 43 | // Equal checks if two Capability are equal 44 | func (c *Capability) Equal(that *Capability) bool { 45 | if that == nil { 46 | return false 47 | } 48 | if c.Name != that.Name { 49 | return false 50 | } 51 | if c.Parent != that.Parent { 52 | return false 53 | } 54 | // TODO: check description 55 | if len(c.Resources) != len(that.Resources) { 56 | return false 57 | } 58 | for i := range c.Resources { 59 | if c.Resources[i] != that.Resources[i] { 60 | return false 61 | } 62 | } 63 | return true 64 | } 65 | 66 | // Equal checks if two Resource are equal 67 | func (r *Resource) Equal(that *Resource) bool { 68 | if that == nil { 69 | return false 70 | } 71 | if r.Kind != that.Kind { 72 | return false 73 | } 74 | if r.Template != that.Template { 75 | return false 76 | } 77 | return true 78 | } 79 | -------------------------------------------------------------------------------- /x/svc/types/genesis_test.go: -------------------------------------------------------------------------------- 1 | package types_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/sonr-io/snrd/x/svc/types" 7 | 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func TestGenesisState_Validate(t *testing.T) { 12 | tests := []struct { 13 | desc string 14 | genState *types.GenesisState 15 | valid bool 16 | }{ 17 | { 18 | desc: "default is valid", 19 | genState: types.DefaultGenesis(), 20 | valid: true, 21 | }, 22 | { 23 | desc: "valid genesis state", 24 | genState: &types.GenesisState{}, 25 | valid: true, 26 | }, 27 | } 28 | for _, tc := range tests { 29 | t.Run(tc.desc, func(t *testing.T) { 30 | err := tc.genState.Validate() 31 | if tc.valid { 32 | require.NoError(t, err) 33 | } else { 34 | require.Error(t, err) 35 | } 36 | }) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /x/svc/types/keys.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "cosmossdk.io/collections" 5 | 6 | ormv1alpha1 "cosmossdk.io/api/cosmos/orm/v1alpha1" 7 | ) 8 | 9 | var ( 10 | // ParamsKey saves the current module params. 11 | ParamsKey = collections.NewPrefix(0) 12 | ) 13 | 14 | const ( 15 | ModuleName = "svc" 16 | 17 | StoreKey = ModuleName 18 | 19 | QuerierRoute = ModuleName 20 | ) 21 | 22 | var ORMModuleSchema = ormv1alpha1.ModuleSchemaDescriptor{ 23 | SchemaFile: []*ormv1alpha1.ModuleSchemaDescriptor_FileEntry{ 24 | {Id: 1, ProtoFileName: "svc/v1/state.proto"}, 25 | }, 26 | Prefix: []byte{0}, 27 | } 28 | -------------------------------------------------------------------------------- /x/svc/types/msgs.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "cosmossdk.io/errors" 5 | sdk "github.com/cosmos/cosmos-sdk/types" 6 | ) 7 | 8 | var _ sdk.Msg = &MsgUpdateParams{} 9 | 10 | // ╭───────────────────────────────────────────────────────────╮ 11 | // │ MsgUpdateParams type definition │ 12 | // ╰───────────────────────────────────────────────────────────╯ 13 | 14 | // NewMsgUpdateParams creates new instance of MsgUpdateParams 15 | func NewMsgUpdateParams( 16 | sender sdk.Address, 17 | someValue bool, 18 | ) *MsgUpdateParams { 19 | return &MsgUpdateParams{ 20 | Authority: sender.String(), 21 | Params: Params{ 22 | // SomeValue: someValue, 23 | }, 24 | } 25 | } 26 | 27 | // Route returns the name of the module 28 | func (msg MsgUpdateParams) Route() string { return ModuleName } 29 | 30 | // Type returns the the action 31 | func (msg MsgUpdateParams) Type() string { return "update_params" } 32 | 33 | // GetSignBytes implements the LegacyMsg interface. 34 | func (msg MsgUpdateParams) GetSignBytes() []byte { 35 | return sdk.MustSortJSON(AminoCdc.MustMarshalJSON(&msg)) 36 | } 37 | 38 | // GetSigners returns the expected signers for a MsgUpdateParams message. 39 | func (msg *MsgUpdateParams) GetSigners() []sdk.AccAddress { 40 | addr, _ := sdk.AccAddressFromBech32(msg.Authority) 41 | return []sdk.AccAddress{addr} 42 | } 43 | 44 | // Validate does a sanity check on the provided data. 45 | func (msg *MsgUpdateParams) Validate() error { 46 | if _, err := sdk.AccAddressFromBech32(msg.Authority); err != nil { 47 | return errors.Wrap(err, "invalid authority address") 48 | } 49 | return msg.Params.Validate() 50 | } 51 | 52 | // ╭───────────────────────────────────────────────────────────╮ 53 | // │ Registration Components │ 54 | // ╰───────────────────────────────────────────────────────────╯ 55 | -------------------------------------------------------------------------------- /x/svc/types/params.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "encoding/json" 5 | ) 6 | 7 | // DefaultParams returns default module parameters. 8 | func DefaultParams() Params { 9 | // TODO: 10 | return Params{} 11 | } 12 | 13 | // Stringer method for Params. 14 | func (p Params) String() string { 15 | bz, err := json.Marshal(p) 16 | if err != nil { 17 | panic(err) 18 | } 19 | 20 | return string(bz) 21 | } 22 | 23 | // Validate does the sanity check on the params. 24 | func (p Params) Validate() error { 25 | // TODO: 26 | return nil 27 | } 28 | 29 | // DefaultAttenuations returns the default Attenuation 30 | --------------------------------------------------------------------------------