├── .editorconfig ├── .eslintignore ├── .gitattributes ├── .github └── workflows │ ├── build.yaml │ ├── prod-tests.yaml │ └── s3-action.yaml ├── .gitignore ├── .prettierrc.yaml ├── .vscode └── settings.json ├── .yarnrc ├── .yarnrc.yml ├── LICENSE ├── README.md ├── babel.config.js ├── lerna.json ├── package.json ├── packages └── create-hyperweb-app │ ├── .babelrc.js │ ├── .editorconfig │ ├── .eslintignore │ ├── .eslintrc.js │ ├── .gitignore │ ├── .npmignore │ ├── .npmrc │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── src │ ├── cli.ts │ ├── constants.ts │ ├── create-hyperweb-app.ts │ ├── git-cca-template.ts │ ├── git-question-template.ts │ ├── index.ts │ ├── prompt.ts │ └── utils.ts │ └── tsconfig.json ├── templates ├── chain-admin │ ├── .eslintrc.json │ ├── .gitignore │ ├── .yarnrc.yml │ ├── CHANGELOG.md │ ├── CREDITS.txt │ ├── README.md │ ├── components │ │ ├── asset-list │ │ │ ├── AssetListSection.tsx │ │ │ ├── AssetsOverview.tsx │ │ │ ├── DropdownTransferModal.tsx │ │ │ ├── RowTransferModal.tsx │ │ │ ├── index.ts │ │ │ └── types.tsx │ │ ├── common │ │ │ ├── Button.tsx │ │ │ ├── Drawer.tsx │ │ │ ├── Footer.tsx │ │ │ ├── Header │ │ │ │ ├── AddressButton.tsx │ │ │ │ ├── ChainDropdown.tsx │ │ │ │ ├── Header.tsx │ │ │ │ └── index.ts │ │ │ ├── Layout.tsx │ │ │ ├── Provider.tsx │ │ │ ├── Radio │ │ │ │ ├── Radio.module.css │ │ │ │ ├── Radio.tsx │ │ │ │ ├── RadioGroup.tsx │ │ │ │ └── index.ts │ │ │ ├── Sidebar │ │ │ │ ├── NavItems.tsx │ │ │ │ ├── Sidebar.tsx │ │ │ │ ├── SidebarContent.tsx │ │ │ │ └── index.ts │ │ │ ├── Stepper.tsx │ │ │ ├── Table.tsx │ │ │ ├── Wallet │ │ │ │ ├── Connected.tsx │ │ │ │ ├── Connecting.tsx │ │ │ │ ├── RingLoader │ │ │ │ │ ├── RingLoader.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── ring.module.css │ │ │ │ ├── SelectWallet.tsx │ │ │ │ ├── WalletConnect.tsx │ │ │ │ └── index.ts │ │ │ └── index.tsx │ │ ├── contract │ │ │ ├── common │ │ │ │ ├── AttachFundsRadio.tsx │ │ │ │ ├── BackButton.tsx │ │ │ │ ├── ComboboxField.tsx │ │ │ │ ├── ContractAddressField.tsx │ │ │ │ ├── ContractIndexField.tsx │ │ │ │ ├── InputField.tsx │ │ │ │ ├── JsonEditor.tsx │ │ │ │ ├── JsonInput.tsx │ │ │ │ ├── SelectAssetContent.tsx │ │ │ │ ├── SelectAssetItem.tsx │ │ │ │ └── index.ts │ │ │ ├── deploy │ │ │ │ ├── CodeIdField.tsx │ │ │ │ ├── CreateFromCodeId.tsx │ │ │ │ ├── CreateFromUpload.tsx │ │ │ │ ├── DeployFromJS.tsx │ │ │ │ ├── DeployJsContract.tsx │ │ │ │ ├── FileUploader.tsx │ │ │ │ ├── InstantiateContract.tsx │ │ │ │ ├── InstantiatePermissionRadio.tsx │ │ │ │ ├── TxSuccessDisplay.tsx │ │ │ │ ├── UploadContract.tsx │ │ │ │ └── index.ts │ │ │ ├── execute │ │ │ │ ├── ExecuteJsContract.tsx │ │ │ │ ├── ExecuteTab.tsx │ │ │ │ ├── ExecuteWasmContract.tsx │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ ├── my-contracts │ │ │ │ ├── EmptyState.tsx │ │ │ │ ├── MyContractsTab.tsx │ │ │ │ ├── MyContractsTable.tsx │ │ │ │ ├── PopoverSelect.tsx │ │ │ │ └── index.ts │ │ │ └── query │ │ │ │ ├── QueryJsContract.tsx │ │ │ │ ├── QueryTab.tsx │ │ │ │ ├── QueryWasmContract.tsx │ │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── staking │ │ │ ├── AllValidators.tsx │ │ │ ├── AllValidatorsList.tsx │ │ │ ├── DelegateModal.tsx │ │ │ ├── MyValidators.tsx │ │ │ ├── MyValidatorsList.tsx │ │ │ ├── Overview.tsx │ │ │ ├── RedelegateModal.tsx │ │ │ ├── SelectValidatorModal.tsx │ │ │ ├── StakingSection.tsx │ │ │ ├── UndelegateModal.tsx │ │ │ ├── ValidatorInfoModal.tsx │ │ │ └── index.ts │ │ └── voting │ │ │ ├── Proposal.tsx │ │ │ ├── Voting.tsx │ │ │ └── index.ts │ ├── config │ │ ├── breakpoints.ts │ │ ├── chains.ts │ │ ├── hyperweb.ts │ │ ├── index.ts │ │ ├── products.ts │ │ ├── theme.ts │ │ └── wallets.ts │ ├── contexts │ │ ├── chain.ts │ │ └── index.ts │ ├── declaration.d.ts │ ├── hooks │ │ ├── asset-list │ │ │ ├── index.ts │ │ │ ├── useAssets.ts │ │ │ ├── useBalance.ts │ │ │ ├── useChainAssetsPrices.ts │ │ │ ├── useChainUtils.ts │ │ │ └── useTotalAssets.ts │ │ ├── common │ │ │ ├── index.ts │ │ │ ├── useAddHyperwebChain.ts │ │ │ ├── useCopyToClipboard.ts │ │ │ ├── useCustomSigningClient.ts │ │ │ ├── useDetectBreakpoints.ts │ │ │ ├── useDisclosure.ts │ │ │ ├── useIsHyperwebChain.ts │ │ │ ├── useMediaQuery.ts │ │ │ ├── useOutsideClick.ts │ │ │ ├── useRpcEndpoint.ts │ │ │ ├── useSigningClient.ts │ │ │ ├── useStarshipChains.ts │ │ │ ├── useToast.tsx │ │ │ └── useToastHandlers.ts │ │ ├── contract │ │ │ ├── index.ts │ │ │ ├── useCodeDetails.ts │ │ │ ├── useContractInfo.ts │ │ │ ├── useExecuteContractTx.tsx │ │ │ ├── useHandleTx.tsx │ │ │ ├── useInstantiateTx.tsx │ │ │ ├── useJsContractInfo.ts │ │ │ ├── useJsdQueryClient.ts │ │ │ ├── useMyContracts.ts │ │ │ ├── useQueryContract.ts │ │ │ ├── useQueryJsContract.ts │ │ │ └── useStoreCodeTx.tsx │ │ ├── index.ts │ │ ├── staking │ │ │ ├── index.ts │ │ │ ├── useAssetsPrices.ts │ │ │ ├── useStakingData.ts │ │ │ └── useValidatorLogos.ts │ │ └── voting │ │ │ ├── index.ts │ │ │ ├── useModal.ts │ │ │ ├── useVoting.ts │ │ │ └── useVotingData.ts │ ├── next.config.js │ ├── package.json │ ├── pages │ │ ├── _app.tsx │ │ ├── asset-list.tsx │ │ ├── contract.tsx │ │ ├── disclaimer.tsx │ │ ├── docs.tsx │ │ ├── faucet.tsx │ │ ├── governance.tsx │ │ ├── index.tsx │ │ └── staking.tsx │ ├── public │ │ ├── images │ │ │ ├── chains-dark.png │ │ │ ├── chains.png │ │ │ ├── contract-file-dark.svg │ │ │ ├── contract-file.svg │ │ │ ├── empty.svg │ │ │ ├── favicon.ico │ │ │ ├── upload-dark.svg │ │ │ └── upload.svg │ │ └── logos │ │ │ ├── hyperweb-logo-dark.svg │ │ │ ├── hyperweb-logo-sm.svg │ │ │ └── hyperweb-logo.svg │ ├── starship │ │ ├── configs │ │ │ └── config.yaml │ │ ├── index.ts │ │ └── types.ts │ ├── styles │ │ ├── comp.module.css │ │ ├── globals.css │ │ ├── layout.module.css │ │ └── utils.module.css │ ├── tsconfig.json │ ├── utils │ │ ├── asset-list │ │ │ ├── format.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── common.ts │ │ ├── contract.ts │ │ ├── faucet.ts │ │ ├── index.ts │ │ ├── staking │ │ │ ├── index.ts │ │ │ ├── logos.ts │ │ │ ├── math.ts │ │ │ └── staking.ts │ │ └── voting.ts │ └── yarn.lock └── hyperweb │ ├── .eslintrc.json │ ├── .github │ └── workflows │ │ ├── build.yaml │ │ ├── e2e-docker-tests.yaml │ │ └── e2e-tests.yaml │ ├── .gitignore │ ├── .prettierrc.json │ ├── .questions.json │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── __tests__ │ ├── setup.test.ts │ └── simpleState.test.ts │ ├── configs │ ├── ci.yaml │ └── local.yaml │ ├── dist │ └── contracts │ │ ├── simpleState.js │ │ └── simpleState.js.map │ ├── docs │ └── WRITING_FIRST_CONTRACT.md │ ├── jest.config.js │ ├── package.json │ ├── scripts │ ├── build.ts │ └── configs.ts │ ├── src │ └── simple-state │ │ └── index.ts │ ├── test-utils │ └── sleep.ts │ ├── tsconfig.esm.json │ ├── tsconfig.json │ ├── ui │ ├── .eslintrc.json │ ├── components │ │ ├── common │ │ │ ├── Footer.tsx │ │ │ ├── Header.tsx │ │ │ ├── Layout.tsx │ │ │ └── index.ts │ │ ├── index.ts │ │ └── wallet │ │ │ ├── Astronaut.tsx │ │ │ ├── Chain.tsx │ │ │ ├── Connect.tsx │ │ │ ├── User.tsx │ │ │ ├── Wallet.tsx │ │ │ ├── Warning.tsx │ │ │ └── index.ts │ ├── config │ │ ├── defaults.ts │ │ ├── index.ts │ │ └── projects.ts │ ├── next.config.js │ ├── pages │ │ ├── _app.tsx │ │ └── index.tsx │ ├── public │ │ └── favicon.ico │ ├── styles │ │ └── globals.css │ ├── tsconfig.json │ └── utils │ │ └── index.ts │ └── yarn.lock └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | *.json 2 | *.md 3 | *.css 4 | *.d.ts 5 | 6 | node_modules/ 7 | main/ 8 | module/ 9 | coverage/ 10 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.js text eol=lf -------------------------------------------------------------------------------- /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: Build templates 2 | 3 | on: 4 | workflow_dispatch: 5 | pull_request: 6 | types: [opened, reopened, synchronize] 7 | 8 | jobs: 9 | setup: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout repository 13 | uses: actions/checkout@v4 14 | 15 | - name: Get examples from directories 16 | id: get-matrix 17 | env: 18 | DIRS: '["templates"]' # Add more dirs here if needed 19 | run: | 20 | # Get examples from each directory 21 | all_examples=$(for dir in $(echo $DIRS | jq -r '.[]'); do 22 | for example in $(ls ./$dir/); do 23 | echo "{\"example\": \"$example\", \"path\": \"$dir\"}" 24 | done 25 | done | jq -s -c '.') 26 | 27 | echo "matrix=$all_examples" >> $GITHUB_OUTPUT 28 | 29 | outputs: 30 | matrix: ${{ steps.get-matrix.outputs.matrix }} 31 | 32 | build: 33 | needs: [setup] 34 | runs-on: ubuntu-latest 35 | strategy: 36 | max-parallel: 4 37 | fail-fast: true 38 | matrix: 39 | include: ${{fromJson(needs.setup.outputs.matrix)}} 40 | env: 41 | EXAMPLE_DIR: ${{ github.workspace }}/dest/${{ matrix.example }} 42 | YARN_ENABLE_IMMUTABLE_INSTALLS: false 43 | 44 | steps: 45 | - name: Checkout repository 46 | uses: actions/checkout@v4 47 | 48 | - name: Set up Node.js 49 | uses: actions/setup-node@v4 50 | with: 51 | node-version: 20 52 | 53 | - name: Set up Yarn 54 | uses: threeal/setup-yarn-action@v2.0.0 55 | 56 | - name: Cache dependencies 57 | uses: actions/cache@v4 58 | with: 59 | path: | 60 | ${{ env.EXAMPLE_DIR }}/node_modules 61 | key: ${{ runner.os }}-modules-${{ matrix.example }}-${{ hashFiles('**/yarn.lock') }} 62 | restore-keys: | 63 | ${{ runner.os }}-modules-${{ matrix.example }}- 64 | 65 | - name: Cache NextJS 66 | uses: actions/cache@v4 67 | with: 68 | path: | 69 | ${{ env.EXAMPLE_DIR }}/.next/cache 70 | key: ${{ runner.os }}-nextjs-${{ matrix.example }}-${{ hashFiles( 71 | '${{ env.EXAMPLE_DIR }}/**/*.{js,jsx,ts,tsx}', 72 | '!${{ env.EXAMPLE_DIR }}/node_modules/**', 73 | '!${{ env.EXAMPLE_DIR }}/.next/**', 74 | '!${{ env.EXAMPLE_DIR }}/.yarn/**' 75 | ) }} 76 | restore-keys: | 77 | ${{ runner.os }}-nextjs-${{ matrix.example }}- 78 | 79 | - name: Build example 80 | run: | 81 | echo "Building example: ${{ matrix.example }} from /${{ matrix.path }}" 82 | 83 | mkdir -p ${{ env.EXAMPLE_DIR }} 84 | cp -r ./${{ matrix.path }}/${{ matrix.example }}/* ${{ env.EXAMPLE_DIR }}/ 85 | cd ${{ env.EXAMPLE_DIR }} 86 | ls -la 87 | 88 | yarn install 89 | yarn build 90 | -------------------------------------------------------------------------------- /.github/workflows/prod-tests.yaml: -------------------------------------------------------------------------------- 1 | name: Run Tests Prod 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | workflow_dispatch: 8 | 9 | jobs: 10 | run-tests: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Setup Node.js 15 | uses: actions/setup-node@v4 16 | with: 17 | node-version: 20 18 | 19 | - name: Set up Yarn 20 | uses: threeal/setup-yarn-action@v2.0.0 21 | with: 22 | cache: false 23 | 24 | - name: Install Dependencies 25 | run: | 26 | echo "YARN_ENABLE_IMMUTABLE_INSTALLS=false" >> $GITHUB_ENV 27 | npm install -g create-hyperweb-app 28 | 29 | - name: chain-admin 30 | run: | 31 | cha --template chain-admin --name chain-admin 32 | cd chain-admin 33 | yarn build 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .yarn 2 | .yarn/* 3 | .DS_Store 4 | .eslintcache 5 | *.log 6 | **/node_modules 7 | coverage 8 | packages/**/build 9 | packages/**/main 10 | packages/**/module 11 | -------------------------------------------------------------------------------- /.prettierrc.yaml: -------------------------------------------------------------------------------- 1 | # .prettierrc or .prettierrc.yaml 2 | singleQuote: true 3 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "[javascriptreact]": { 4 | "editor.formatOnSave": false 5 | }, 6 | "[javascript]": { 7 | "editor.formatOnSave": false 8 | }, 9 | "editor.codeActionsOnSave": { 10 | "source.fixAll.eslint": "explicit" 11 | }, 12 | "eslint.validate": ["javascript", "javascriptreact"], 13 | "files.exclude": { 14 | ".yarn/*": true 15 | }, 16 | "typescript.tsdk": "node_modules/typescript/lib" 17 | } 18 | -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | registry "https://registry.npmjs.org/" 6 | lastUpdateCheck 1700470015338 7 | save-exact true 8 | save-prefix false 9 | workspaces-experimental true 10 | # yarn-path ".yarn/releases/yarn-1.22.21.js" 11 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2024 Interweb, inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | babelrcRoots: 'packages/*', 3 | presets: ['@pyramation/env'], 4 | }; 5 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "lerna": "3.4.2", 3 | "useWorkspaces": true, 4 | "conventionalCommits": true, 5 | "npmClient": "yarn", 6 | "npmClientArgs": [ 7 | "--no-lockfile" 8 | ], 9 | "packages": [ 10 | "packages/*", 11 | "examples/*", 12 | "templates/*" 13 | ], 14 | "version": "independent", 15 | "registry": "https://registry.npmjs.org", 16 | "command": { 17 | "create": { 18 | "homepage": "https://github.com/hyperweb-io/create-hyperweb-app", 19 | "license": "SEE LICENSE IN LICENSE", 20 | "access": "restricted" 21 | }, 22 | "publish": { 23 | "allowBranch": "main", 24 | "message": "chore(release): publish" 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-hyperweb-app-project", 3 | "version": "0.0.1", 4 | "publishConfig": { 5 | "access": "restricted" 6 | }, 7 | "private": true, 8 | "scripts": { 9 | "build": "lerna run prepare --parallel", 10 | "buidl": "lerna run buidl --parallel", 11 | "bootstrap": "lerna bootstrap --use-workspaces", 12 | "lint": "lerna run lint", 13 | "format": "lerna run format", 14 | "test": "lerna run test --stream", 15 | "locks:update": "./scripts/update-locks.sh", 16 | "locks": "lerna run locks --stream", 17 | "locks:remove": "lerna run locks:remove --stream", 18 | "update": "yarn upgrade-interactive --latest", 19 | "clear:node_modules": "find . -name 'node_modules' -type d -prune -print | xargs rm -rf" 20 | }, 21 | "devDependencies": { 22 | "@babel/cli": "7.24.7", 23 | "@babel/core": "7.24.7", 24 | "@babel/eslint-parser": "^7.24.7", 25 | "@pyramation/babel-preset-env": "0.2.0", 26 | "babel-core": "7.0.0-bridge.0", 27 | "babel-jest": "^29.3.1", 28 | "eslint": "8.28.0", 29 | "eslint-config-prettier": "^8.5.0", 30 | "eslint-plugin-prettier": "^4.0.0", 31 | "jest": "29.3.1", 32 | "lerna": "4.0.0", 33 | "prettier": "2.8.0" 34 | }, 35 | "workspaces": [ 36 | "packages/*", 37 | "examples/*", 38 | "templates/*" 39 | ], 40 | "repository": { 41 | "type": "git", 42 | "url": "https://github.com/hyperweb-io/create-hyperweb-app" 43 | }, 44 | "packageManager": "yarn@4.1.0" 45 | } 46 | -------------------------------------------------------------------------------- /packages/create-hyperweb-app/.babelrc.js: -------------------------------------------------------------------------------- 1 | const useESModules = !!process.env.MODULE; 2 | 3 | module.exports = (api) => { 4 | api.cache(() => process.env.MODULE); 5 | return { 6 | plugins: [ 7 | ['@babel/transform-runtime', { useESModules }], 8 | '@babel/proposal-object-rest-spread', 9 | '@babel/proposal-class-properties', 10 | '@babel/proposal-export-default-from' 11 | ], 12 | presets: useESModules ? ['@babel/typescript'] : ['@babel/typescript', '@babel/env'] 13 | }; 14 | }; 15 | -------------------------------------------------------------------------------- /packages/create-hyperweb-app/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /packages/create-hyperweb-app/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | main/ 4 | module/ 5 | coverage/ -------------------------------------------------------------------------------- /packages/create-hyperweb-app/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: ['prettier'], 3 | extends: ['eslint:recommended', 'prettier'], 4 | parser: '@babel/eslint-parser', 5 | parserOptions: { 6 | ecmaVersion: 11, 7 | requireConfigFile: false, 8 | sourceType: 'module', 9 | ecmaFeatures: { 10 | jsx: true 11 | } 12 | }, 13 | env: { 14 | es6: true, 15 | browser: true, 16 | node: true, 17 | jest: true 18 | }, 19 | rules: { 20 | 'no-debugger': 2, 21 | 'no-alert': 2, 22 | 'no-await-in-loop': 0, 23 | 'no-prototype-builtins': 0, 24 | 'no-return-assign': ['error', 'except-parens'], 25 | 'no-restricted-syntax': [ 26 | 2, 27 | 'ForInStatement', 28 | 'LabeledStatement', 29 | 'WithStatement' 30 | ], 31 | 'no-unused-vars': [ 32 | 0, 33 | { 34 | ignoreSiblings: true, 35 | argsIgnorePattern: 'React|res|next|^_' 36 | } 37 | ], 38 | 'prefer-const': [ 39 | 'error', 40 | { 41 | destructuring: 'all' 42 | } 43 | ], 44 | 'no-unused-expressions': [ 45 | 2, 46 | { 47 | allowTaggedTemplates: true 48 | } 49 | ], 50 | 'no-console': 1, 51 | 'comma-dangle': 2, 52 | 'jsx-quotes': [2, 'prefer-double'], 53 | 'linebreak-style': ['error', 'unix'], 54 | quotes: [ 55 | 2, 56 | 'single', 57 | { 58 | avoidEscape: true, 59 | allowTemplateLiterals: true 60 | } 61 | ], 62 | 'prettier/prettier': [ 63 | 'error', 64 | { 65 | trailingComma: 'none', 66 | singleQuote: true, 67 | printWidth: 80 68 | } 69 | ] 70 | } 71 | }; 72 | -------------------------------------------------------------------------------- /packages/create-hyperweb-app/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # dist 12 | dist 13 | main 14 | module 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Compiled binary addons (http://nodejs.org/api/addons.html) 26 | build/Release 27 | 28 | # Dependency directories 29 | node_modules 30 | jspm_packages 31 | 32 | # Optional npm cache directory 33 | .npm 34 | 35 | # Optional REPL history 36 | .node_repl_history 37 | 38 | # Editors 39 | .idea 40 | 41 | # Lib 42 | lib 43 | 44 | # npm package lock 45 | package-lock.json 46 | yarn.lock 47 | 48 | # others 49 | .DS_Store -------------------------------------------------------------------------------- /packages/create-hyperweb-app/.npmignore: -------------------------------------------------------------------------------- 1 | *.log 2 | npm-debug.log* 3 | 4 | # Coverage directory used by tools like istanbul 5 | coverage 6 | .nyc_output 7 | 8 | # Dependency directories 9 | node_modules 10 | 11 | # npm package lock 12 | package-lock.json 13 | yarn.lock 14 | 15 | # project files 16 | __fixtures__ 17 | __tests__ 18 | .babelrc 19 | .babelrc.js 20 | .editorconfig 21 | .eslintignore 22 | .eslintrc 23 | .eslintrc.js 24 | .gitignore 25 | .travis.yml 26 | .vscode 27 | CHANGELOG.md 28 | examples 29 | jest.config.js 30 | package.json 31 | src 32 | test -------------------------------------------------------------------------------- /packages/create-hyperweb-app/.npmrc: -------------------------------------------------------------------------------- 1 | scripts-prepend-node-path=true -------------------------------------------------------------------------------- /packages/create-hyperweb-app/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [0.0.8](https://github.com/hyperweb-io/create-hyperweb-app/compare/create-hyperweb-app@0.0.6...create-hyperweb-app@0.0.8) (2024-10-24) 7 | 8 | **Note:** Version bump only for package create-hyperweb-app 9 | 10 | 11 | 12 | 13 | 14 | ## [0.0.7](https://github.com/hyperweb-io/create-hyperweb-app/compare/create-hyperweb-app@0.0.6...create-hyperweb-app@0.0.7) (2024-10-21) 15 | 16 | **Note:** Version bump only for package create-hyperweb-app 17 | 18 | 19 | 20 | 21 | 22 | ## [0.0.6](https://github.com/hyperweb-io/create-hyperweb-app/compare/create-hyperweb-app@0.0.5...create-hyperweb-app@0.0.6) (2024-10-04) 23 | 24 | **Note:** Version bump only for package create-hyperweb-app 25 | 26 | 27 | 28 | 29 | 30 | ## [0.0.5](https://github.com/hyperweb-io/create-hyperweb-app/compare/create-hyperweb-app@0.0.4...create-hyperweb-app@0.0.5) (2024-10-04) 31 | 32 | **Note:** Version bump only for package create-hyperweb-app 33 | 34 | 35 | 36 | 37 | 38 | ## [0.0.4](https://github.com/hyperweb-io/create-hyperweb-app/compare/create-hyperweb-app@0.0.3...create-hyperweb-app@0.0.4) (2024-10-04) 39 | 40 | **Note:** Version bump only for package create-hyperweb-app 41 | 42 | 43 | 44 | 45 | 46 | ## 0.0.3 (2024-10-04) 47 | 48 | **Note:** Version bump only for package create-hyperweb-app 49 | -------------------------------------------------------------------------------- /packages/create-hyperweb-app/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2024 Interweb, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/create-hyperweb-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-hyperweb-app", 3 | "version": "0.0.8", 4 | "description": "Set up a Hyperweb app by running one command ⚛️", 5 | "author": "Dan Lynch ", 6 | "homepage": "https://github.com/hyperweb-io/create-hyperweb-app#readme", 7 | "license": "SEE LICENSE IN LICENSE", 8 | "main": "dist/index.js", 9 | "typings": "dist/index.d.ts", 10 | "bin": { 11 | "cha": "dist/create-hyperweb-app.js", 12 | "create-hyperweb-app": "dist/create-hyperweb-app.js" 13 | }, 14 | "directories": { 15 | "lib": "src", 16 | "test": "__tests__" 17 | }, 18 | "files": [ 19 | "dist" 20 | ], 21 | "scripts": { 22 | "build:dist": "yarn tsc -p tsconfig.json --outDir dist --module commonjs || true", 23 | "build:chmod": "chmod +x ./dist/create-hyperweb-app.js", 24 | "build": "npm run build:dist && npm run build:chmod", 25 | "prepare": "npm run build", 26 | "dev": "node ./dist/create-hyperweb-app", 27 | "lint": "eslint .", 28 | "format": "eslint --fix .", 29 | "test": "jest", 30 | "test:watch": "jest --watch", 31 | "test:debug": "node --inspect node_modules/.bin/jest --runInBand" 32 | }, 33 | "publishConfig": { 34 | "access": "public" 35 | }, 36 | "repository": { 37 | "type": "git", 38 | "url": "https://github.com/hyperweb-io/create-hyperweb-app" 39 | }, 40 | "keywords": [ 41 | "interchain", 42 | "cosmology", 43 | "create-hyperweb-app", 44 | "cosmos-kit" 45 | ], 46 | "bugs": { 47 | "url": "https://github.com/hyperweb-io/create-hyperweb-app/issues" 48 | }, 49 | "devDependencies": { 50 | "@types/jest": "^29.2.2", 51 | "case": "1.6.3", 52 | "eslint": "8.28.0", 53 | "eslint-config-prettier": "^8.5.0", 54 | "eslint-plugin-prettier": "^4.0.0", 55 | "glob": "8.0.3", 56 | "jest": "^29.3.1", 57 | "jest-in-case": "^1.0.2", 58 | "prettier": "^2.1.2", 59 | "ts-jest": "^29.0.3", 60 | "typescript": "^5.1.6" 61 | }, 62 | "dependencies": { 63 | "ansi-colors": "4.1.3", 64 | "dargs": "7.0.0", 65 | "fuzzy": "0.1.3", 66 | "inquirerer": "0.1.3", 67 | "minimist": "1.2.7", 68 | "mkdirp": "1.0.4", 69 | "semver": "^7.6.0", 70 | "shelljs": "0.8.5" 71 | }, 72 | "gitHead": "8cacfd657ec77cadabe58e80b8cc8adfa9704f83" 73 | } 74 | -------------------------------------------------------------------------------- /packages/create-hyperweb-app/src/cli.ts: -------------------------------------------------------------------------------- 1 | import { CHA_URL } from "./constants"; 2 | import { createGitApp } from "./git-cca-template"; 3 | export const cli = async (argv, version) => { 4 | const repo = argv.repo ?? CHA_URL; 5 | const createApp = createGitApp(repo, version); 6 | await createApp(argv); 7 | }; -------------------------------------------------------------------------------- /packages/create-hyperweb-app/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const CHA_URL = 'https://github.com/hyperweb-io/create-hyperweb-app.git'; -------------------------------------------------------------------------------- /packages/create-hyperweb-app/src/create-hyperweb-app.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import pkg from '../package.json'; 3 | import { cli } from './cli'; 4 | import * as shell from 'shelljs'; 5 | 6 | var argv = require('minimist')(process.argv.slice(2), { 7 | alias: { 8 | b: 'fromBranch', 9 | e: 'example', 10 | t: 'template', 11 | n: 'name' 12 | } 13 | }); 14 | 15 | (async () => { 16 | if (argv._.includes('version') 17 | || (argv.hasOwnProperty('version') && argv.version) 18 | || (argv.hasOwnProperty('v') && argv.v) 19 | ) { 20 | console.log(pkg.version) 21 | } else if (argv._.includes('upgrade') 22 | || (argv.hasOwnProperty('upgrade') && argv.upgrade) 23 | ) { 24 | shell.exec(`npm install -g create-hyperweb-app@latest`); 25 | } else { 26 | await cli(argv, pkg.version); 27 | } 28 | })(); 29 | -------------------------------------------------------------------------------- /packages/create-hyperweb-app/src/index.ts: -------------------------------------------------------------------------------- 1 | // noop 2 | 3 | export * from './git-cca-template'; -------------------------------------------------------------------------------- /packages/create-hyperweb-app/src/prompt.ts: -------------------------------------------------------------------------------- 1 | import { filter } from 'fuzzy'; 2 | import { prompt as inquirerer } from 'inquirerer'; 3 | 4 | export const getFuzzySearch = (list) => { 5 | return (answers, input) => { 6 | input = input || ''; 7 | return new Promise(function (resolve) { 8 | setTimeout(function () { 9 | const fuzzyResult = filter(input, list); 10 | resolve( 11 | fuzzyResult.map(function (el) { 12 | return el.original; 13 | }) 14 | ); 15 | }, 25); 16 | }); 17 | }; 18 | }; 19 | 20 | export const getFuzzySearchNames = (nameValueItemList) => { 21 | const list = nameValueItemList.map(({ name, value }) => name); 22 | return (answers, input) => { 23 | input = input || ''; 24 | return new Promise(function (resolve) { 25 | setTimeout(function () { 26 | const fuzzyResult = filter(input, list); 27 | resolve( 28 | fuzzyResult.map(function (el) { 29 | return nameValueItemList.find( 30 | ({ name, value }) => el.original == name 31 | ); 32 | }) 33 | ); 34 | }, 25); 35 | }); 36 | }; 37 | }; 38 | const transform = (questions) => { 39 | return questions.map((q) => { 40 | if (q.type === 'fuzzy') { 41 | const choices = q.choices; 42 | delete q.choices; 43 | return { 44 | ...q, 45 | type: 'autocomplete', 46 | source: getFuzzySearch(choices) 47 | }; 48 | } else if (q.type === 'fuzzy:objects') { 49 | const choices = q.choices; 50 | delete q.choices; 51 | return { 52 | ...q, 53 | type: 'autocomplete', 54 | source: getFuzzySearchNames(choices) 55 | }; 56 | } else { 57 | return q; 58 | } 59 | }); 60 | }; 61 | 62 | export const prompt = async (questions = [], argv = {}) => { 63 | questions = transform(questions); 64 | return await inquirerer(questions, argv); 65 | }; 66 | -------------------------------------------------------------------------------- /packages/create-hyperweb-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "rootDir": "src", 5 | "skipLibCheck": true, 6 | "emitDeclarationOnly": false, 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "target": "es2022", 10 | "module": "es2022", 11 | "lib": [ 12 | "es2022", 13 | "DOM" 14 | ], 15 | "sourceMap": true, 16 | "isolatedModules": true, 17 | "allowJs": true, 18 | "downlevelIteration": true, 19 | "moduleResolution": "node", 20 | "resolveJsonModule": true 21 | }, 22 | "include": [ 23 | "src/**/*" 24 | ], 25 | "exclude": [ 26 | "node_modules" 27 | ] 28 | } -------------------------------------------------------------------------------- /templates/chain-admin/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals", 3 | "rules": { 4 | "react-hooks/exhaustive-deps": "off" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /templates/chain-admin/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /templates/chain-admin/.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | -------------------------------------------------------------------------------- /templates/chain-admin/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | -------------------------------------------------------------------------------- /templates/chain-admin/CREDITS.txt: -------------------------------------------------------------------------------- 1 | CREDITS 2 | ------- 3 | The CosmWasm dashboard of this project was inspired by the design of https://github.com/alleslabs/celatone-frontend 4 | No code from the original project was used in this project. 5 | -------------------------------------------------------------------------------- /templates/chain-admin/components/asset-list/AssetListSection.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Text, Box } from '@interchain-ui/react'; 3 | import { useChain } from '@interchain-kit/react'; 4 | 5 | import AssetsOverview from './AssetsOverview'; 6 | import { useAssets } from '@/hooks'; 7 | 8 | interface AssetListSectionProps { 9 | chainName: string; 10 | children?: React.ReactNode; 11 | } 12 | 13 | export const AssetListSection = ({ chainName }: AssetListSectionProps) => { 14 | const { address } = useChain(chainName); 15 | const { data, isLoading, refetch } = useAssets(chainName); 16 | 17 | if (!address) { 18 | return ( 19 | 20 | 25 | My assets 26 | 27 | 28 | 37 | 38 | Connect the wallet to see the assets 39 | 40 | 41 | 42 | ); 43 | } 44 | 45 | return ( 46 | 47 | 54 | 55 | ); 56 | }; 57 | -------------------------------------------------------------------------------- /templates/chain-admin/components/asset-list/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types'; 2 | export * from './AssetListSection'; 3 | -------------------------------------------------------------------------------- /templates/chain-admin/components/asset-list/types.tsx: -------------------------------------------------------------------------------- 1 | import { AvailableItem } from '@interchain-ui/react'; 2 | 3 | export type Unpacked = T extends (infer U)[] ? U : T; 4 | 5 | export type PrettyAsset = { 6 | logoUrl: string | undefined; 7 | symbol: string; 8 | prettyChainName: string; 9 | displayAmount: string; 10 | dollarValue: string; 11 | amount: string; 12 | denom: string; 13 | }; 14 | 15 | export type Token = { 16 | price: number; 17 | denom: string; 18 | symbol: string; 19 | liquidity: number; 20 | volume_24h: number; 21 | volume_24h_change: number; 22 | name: string; 23 | price_24h_change: number; 24 | price_7d_change: number; 25 | exponent: number; 26 | display: string; 27 | }; 28 | 29 | export type PriceHash = { 30 | [key: string]: number; 31 | }; 32 | 33 | export const Transfer = { 34 | Deposit: 'Deposit', 35 | Withdraw: 'Withdraw', 36 | } as const; 37 | 38 | export type TransferValues = typeof Transfer[keyof typeof Transfer]; 39 | 40 | export type TransferInfo = { 41 | type: TransferValues; 42 | sourceChainName: string; 43 | destChainName: string; 44 | token: AvailableItem; 45 | }; 46 | 47 | export type AssetOption = { 48 | value: string; 49 | icon: { png: string | undefined }; 50 | }; 51 | 52 | export type PrettyAssetOption = PrettyAsset & AssetOption; 53 | -------------------------------------------------------------------------------- /templates/chain-admin/components/common/Drawer.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode, useEffect, useRef } from 'react'; 2 | import { Box } from '@interchain-ui/react'; 3 | import { useOutsideClick } from '@/hooks'; 4 | 5 | type DrawerProps = { 6 | isOpen: boolean; 7 | onClose: () => void; 8 | children: ReactNode; 9 | direction?: 'top' | 'bottom' | 'left' | 'right'; 10 | }; 11 | 12 | export const Drawer = ({ 13 | isOpen, 14 | onClose, 15 | children, 16 | direction = 'left', 17 | }: DrawerProps) => { 18 | const contentRef = useRef(null); 19 | 20 | useOutsideClick({ 21 | ref: contentRef, 22 | handler: onClose, 23 | shouldListen: isOpen, 24 | }); 25 | 26 | useEffect(() => { 27 | if (isOpen) { 28 | const scrollbarWidth = 29 | window.innerWidth - document.documentElement.clientWidth; 30 | document.body.style.overflow = 'hidden'; 31 | document.body.style.paddingRight = `${scrollbarWidth}px`; 32 | } 33 | 34 | return () => { 35 | document.body.style.overflow = ''; 36 | document.body.style.paddingRight = ''; 37 | }; 38 | }, [isOpen]); 39 | 40 | const getTransform = () => { 41 | switch (direction) { 42 | case 'top': 43 | return `translateY(${isOpen ? '0%' : '-100%'})`; 44 | case 'bottom': 45 | return `translateY(${isOpen ? '0%' : '100%'})`; 46 | case 'right': 47 | return `translateX(${isOpen ? '0%' : '100%'})`; 48 | default: 49 | return `translateX(${isOpen ? '0%' : '-100%'})`; 50 | } 51 | }; 52 | 53 | return ( 54 | 69 | 84 | {children} 85 | 86 | 87 | ); 88 | }; 89 | -------------------------------------------------------------------------------- /templates/chain-admin/components/common/Footer.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link'; 2 | import { FaXTwitter } from 'react-icons/fa6'; 3 | import { Box, Icon, Text } from '@interchain-ui/react'; 4 | 5 | import { useDetectBreakpoints } from '@/hooks'; 6 | 7 | export const Footer = () => { 8 | const { isMobile } = useDetectBreakpoints(); 9 | 10 | return ( 11 | 12 | {isMobile && ( 13 | 14 | 15 | 16 | )} 17 | 23 | 24 | © {new Date().getFullYear()} Hyperweb 25 | 26 | {isMobile ? : } 27 | 28 | 29 | Terms of Service 30 | 31 | 32 | 33 | 34 | ); 35 | }; 36 | 37 | const TextDivider = () => { 38 | return ( 39 | 40 | | 41 | 42 | ); 43 | }; 44 | 45 | const socialLinks = [ 46 | { 47 | icon: , 48 | href: 'https://github.com/hyperweb-io', 49 | }, 50 | { 51 | icon: , 52 | href: 'https://discord.com/invite/xh3ZwHj2qQ', 53 | }, 54 | { 55 | icon: ( 56 | 57 | 58 | 59 | ), 60 | href: 'https://x.com/Hyperweb_', 61 | }, 62 | { 63 | icon: , 64 | href: 'https://www.youtube.com/channel/UCA9jzRlnUJRxec8S5Lt7Vcw', 65 | }, 66 | ]; 67 | 68 | const SocialLinks = () => { 69 | return ( 70 | 71 | {socialLinks.map(({ icon, href }) => ( 72 | 73 | {icon} 74 | 75 | ))} 76 | 77 | ); 78 | }; 79 | -------------------------------------------------------------------------------- /templates/chain-admin/components/common/Header/AddressButton.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Popover, 3 | PopoverContent, 4 | PopoverTrigger, 5 | useColorModeValue, 6 | } from '@interchain-ui/react'; 7 | import { useChain } from '@interchain-kit/react'; 8 | import { MdOutlineAccountBalanceWallet } from 'react-icons/md'; 9 | 10 | import { Button, WalletConnect } from '@/components'; 11 | import { darkColors, lightColors } from '@/config'; 12 | import { useChainStore } from '@/contexts'; 13 | import { useCopyToClipboard, useDetectBreakpoints } from '@/hooks'; 14 | import { shortenAddress } from '@/utils'; 15 | 16 | export const AddressButton = () => { 17 | const { selectedChain } = useChainStore(); 18 | const { address } = useChain(selectedChain); 19 | const { isCopied, copyToClipboard } = useCopyToClipboard(); 20 | const { isDesktop } = useDetectBreakpoints(); 21 | 22 | const arrowBgColor = useColorModeValue( 23 | lightColors?.background as string, 24 | darkColors?.background as string 25 | ); 26 | 27 | if (!isDesktop) { 28 | return ( 29 | 36 | 37 | 62 | ); 63 | }; 64 | -------------------------------------------------------------------------------- /templates/chain-admin/components/common/Header/ChainDropdown.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image'; 2 | import { useState } from 'react'; 3 | import { useChain, useWalletManager } from '@interchain-kit/react'; 4 | import { Box, Combobox, Skeleton, Stack, Text } from '@interchain-ui/react'; 5 | 6 | import { useStarshipChains, useDetectBreakpoints } from '@/hooks'; 7 | import { chainStore, useChainStore } from '@/contexts'; 8 | 9 | export const ChainDropdown = () => { 10 | const { selectedChain } = useChainStore(); 11 | const { chain } = useChain(selectedChain); 12 | const [input, setInput] = useState(chain.prettyName ?? ''); 13 | const { data: starshipChains } = useStarshipChains(); 14 | const { getChainLogoUrl } = useWalletManager(); 15 | 16 | const { isMobile } = useDetectBreakpoints(); 17 | 18 | return ( 19 | { 21 | setInput(input); 22 | }} 23 | selectedKey={selectedChain} 24 | onSelectionChange={(key) => { 25 | const chainName = key as string | null; 26 | if (chainName) { 27 | chainStore.setSelectedChain(chainName); 28 | } 29 | }} 30 | inputAddonStart={ 31 | 32 | {input === chain.prettyName ? ( 33 | {chain.prettyName 42 | ) : ( 43 | 44 | )} 45 | 46 | } 47 | styleProps={{ 48 | width: isMobile ? '130px' : '260px', 49 | }} 50 | > 51 | {(starshipChains?.v2.chains ?? []).map((c) => ( 52 | 53 | 58 | {c.prettyName 67 | 68 | {c.prettyName} 69 | 70 | 71 | 72 | ))} 73 | 74 | ); 75 | }; 76 | -------------------------------------------------------------------------------- /templates/chain-admin/components/common/Header/Header.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link'; 2 | import Image from 'next/image'; 3 | import { Box, useColorModeValue, useTheme } from '@interchain-ui/react'; 4 | import { RxHamburgerMenu } from 'react-icons/rx'; 5 | 6 | import { ChainDropdown } from './ChainDropdown'; 7 | import { Button } from '../Button'; 8 | import { useDetectBreakpoints, useAddHyperwebChain } from '@/hooks'; 9 | import { AddressButton } from './AddressButton'; 10 | 11 | interface HeaderProps { 12 | onOpenSidebar: () => void; 13 | } 14 | 15 | export const Header = ({ onOpenSidebar }: HeaderProps) => { 16 | const { theme, setTheme } = useTheme(); 17 | const { isDesktop, isMobile } = useDetectBreakpoints(); 18 | const { isHyperwebAdded } = useAddHyperwebChain(); 19 | 20 | const brandLogo = useColorModeValue( 21 | '/logos/hyperweb-logo.svg', 22 | '/logos/hyperweb-logo-dark.svg' 23 | ); 24 | 25 | const brandLogoSm = '/logos/hyperweb-logo-sm.svg'; 26 | 27 | return ( 28 | 34 | {!isDesktop && ( 35 | 36 | your logo 43 | 44 | )} 45 | 46 | {isHyperwebAdded && } 47 | {isHyperwebAdded && } 48 | 70 | 71 | ); 72 | }; 73 | -------------------------------------------------------------------------------- /templates/chain-admin/components/contract/common/index.ts: -------------------------------------------------------------------------------- 1 | export * from './InputField'; 2 | export * from './JsonEditor'; 3 | export * from './JsonInput'; 4 | export * from './ComboboxField'; 5 | export * from './ContractAddressField'; 6 | export * from './ContractIndexField'; 7 | export * from './AttachFundsRadio'; 8 | export * from './BackButton'; 9 | -------------------------------------------------------------------------------- /templates/chain-admin/components/contract/deploy/CreateFromCodeId.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@interchain-ui/react'; 2 | 3 | import { BackButton } from '../common'; 4 | import { InstantiateContract } from './InstantiateContract'; 5 | import { useDetectBreakpoints } from '@/hooks'; 6 | 7 | type CreateFromCodeIdProps = { 8 | onBack: () => void; 9 | switchTab: (addressValue: string, tabId: number) => void; 10 | }; 11 | 12 | export const CreateFromCodeId = ({ 13 | onBack, 14 | switchTab, 15 | }: CreateFromCodeIdProps) => { 16 | const { isTablet } = useDetectBreakpoints(); 17 | 18 | return ( 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | ); 28 | }; 29 | -------------------------------------------------------------------------------- /templates/chain-admin/components/contract/deploy/CreateFromUpload.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import { Box } from '@interchain-ui/react'; 3 | 4 | import { UploadContract } from './UploadContract'; 5 | import { BackButton } from '../common'; 6 | import { Stepper } from '../../common'; 7 | import { InstantiateContract } from './InstantiateContract'; 8 | import { useDetectBreakpoints } from '@/hooks'; 9 | 10 | type CreateFromUploadProps = { 11 | onBack: () => void; 12 | switchTab: (addressValue: string, tabId: number) => void; 13 | }; 14 | 15 | enum Step { 16 | Upload = 'Upload', 17 | Instantiate = 'Instantiate', 18 | } 19 | 20 | const steps = [Step.Upload, Step.Instantiate]; 21 | 22 | export const CreateFromUpload = ({ 23 | onBack, 24 | switchTab, 25 | }: CreateFromUploadProps) => { 26 | const [activeStepName, setActiveStepName] = useState(Step.Upload); 27 | const [completed, setCompleted] = useState(false); 28 | const [codeId, setCodeId] = useState(); 29 | 30 | const nextStep = () => { 31 | const currentIndex = steps.indexOf(activeStepName); 32 | if (currentIndex < steps.length - 1) { 33 | setActiveStepName(steps[currentIndex + 1]); 34 | } else { 35 | setCompleted(true); 36 | } 37 | }; 38 | 39 | const { isTablet } = useDetectBreakpoints(); 40 | 41 | return ( 42 | 43 | 52 | 53 | 54 | 55 | 60 | 61 | 62 | { 65 | setCodeId(codeId); 66 | nextStep(); 67 | }} 68 | /> 69 | { 75 | setCompleted(false); 76 | setActiveStepName(Step.Upload); 77 | }} 78 | onViewMyContracts={onBack} 79 | /> 80 | 81 | 82 | ); 83 | }; 84 | -------------------------------------------------------------------------------- /templates/chain-admin/components/contract/deploy/DeployFromJS.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@interchain-ui/react'; 2 | 3 | import { BackButton } from '../common'; 4 | import { useDetectBreakpoints } from '@/hooks'; 5 | import { DeployJsContract } from './DeployJsContract'; 6 | 7 | type DeployFromJSProps = { 8 | onBack: () => void; 9 | switchTab: (addressValue: string, tabId: number) => void; 10 | }; 11 | 12 | export const DeployFromJS = ({ onBack, switchTab }: DeployFromJSProps) => { 13 | const { isTablet } = useDetectBreakpoints(); 14 | 15 | return ( 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | ); 25 | }; 26 | -------------------------------------------------------------------------------- /templates/chain-admin/components/contract/deploy/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CreateFromUpload'; 2 | export * from './CreateFromCodeId'; 3 | export * from './DeployFromJS'; 4 | -------------------------------------------------------------------------------- /templates/chain-admin/components/contract/execute/ExecuteTab.tsx: -------------------------------------------------------------------------------- 1 | import { useIsHyperwebChain } from '@/hooks'; 2 | import { ExecuteJsContract } from './ExecuteJsContract'; 3 | import { ExecuteWasmContract } from './ExecuteWasmContract'; 4 | 5 | export type ExecuteTabProps = { 6 | show: boolean; 7 | addressValue: string; 8 | onAddressInput: (input: string) => void; 9 | }; 10 | 11 | export const ExecuteTab = ({ 12 | show, 13 | addressValue, 14 | onAddressInput, 15 | }: ExecuteTabProps) => { 16 | const isHyperwebChain = useIsHyperwebChain(); 17 | 18 | return isHyperwebChain ? ( 19 | 24 | ) : ( 25 | 30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /templates/chain-admin/components/contract/execute/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ExecuteTab'; 2 | -------------------------------------------------------------------------------- /templates/chain-admin/components/contract/index.ts: -------------------------------------------------------------------------------- 1 | export * from './query'; 2 | export * from './execute'; 3 | export * from './my-contracts'; 4 | -------------------------------------------------------------------------------- /templates/chain-admin/components/contract/my-contracts/EmptyState.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image'; 2 | import { Box, Text } from '@interchain-ui/react'; 3 | 4 | export const EmptyState = ({ text }: { text: string }) => ( 5 | 12 | empty 13 | 14 | {text} 15 | 16 | 17 | ); 18 | -------------------------------------------------------------------------------- /templates/chain-admin/components/contract/my-contracts/MyContractsTab.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import { Box } from '@interchain-ui/react'; 3 | 4 | import { Button } from '../../common'; 5 | import { PopoverSelect } from './PopoverSelect'; 6 | import { MyContractsTable } from './MyContractsTable'; 7 | import { useIsHyperwebChain } from '@/hooks'; 8 | import { DeployFromJS, CreateFromUpload, CreateFromCodeId } from '../deploy'; 9 | 10 | const ContentViews = { 11 | MY_CONTRACTS: 'my_contracts', 12 | CREATE_FROM_UPLOAD: 'create_from_upload', 13 | CREATE_FROM_CODE_ID: 'create_from_code_id', 14 | DEPLOY_FROM_JS: 'deploy_from_js', 15 | } as const; 16 | 17 | type ContentView = typeof ContentViews[keyof typeof ContentViews]; 18 | 19 | const contractCreationOptions = [ 20 | { label: 'From Upload', value: ContentViews.CREATE_FROM_UPLOAD }, 21 | { label: 'From Code ID', value: ContentViews.CREATE_FROM_CODE_ID }, 22 | ]; 23 | 24 | type MyContractsTabProps = { 25 | show: boolean; 26 | switchTab: (addressValue: string, tabId: number) => void; 27 | }; 28 | 29 | export const MyContractsTab = ({ show, switchTab }: MyContractsTabProps) => { 30 | const [contentView, setContentView] = useState( 31 | ContentViews.MY_CONTRACTS 32 | ); 33 | 34 | const isHyperwebChain = useIsHyperwebChain(); 35 | 36 | return ( 37 | 38 | setContentView(ContentViews.DEPLOY_FROM_JS)} 47 | > 48 | Deploy Contract 49 | 50 | ) : ( 51 | Create Contract} 53 | options={contractCreationOptions} 54 | onOptionClick={(value) => setContentView(value as ContentView)} 55 | popoverWidth="152px" 56 | /> 57 | ) 58 | } 59 | /> 60 | {contentView === ContentViews.CREATE_FROM_UPLOAD && ( 61 | setContentView(ContentViews.MY_CONTRACTS)} 64 | /> 65 | )} 66 | {contentView === ContentViews.CREATE_FROM_CODE_ID && ( 67 | setContentView(ContentViews.MY_CONTRACTS)} 70 | /> 71 | )} 72 | {contentView === ContentViews.DEPLOY_FROM_JS && ( 73 | setContentView(ContentViews.MY_CONTRACTS)} 76 | /> 77 | )} 78 | 79 | ); 80 | }; 81 | -------------------------------------------------------------------------------- /templates/chain-admin/components/contract/my-contracts/PopoverSelect.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import { 3 | Box, 4 | Popover, 5 | PopoverContent, 6 | PopoverTrigger, 7 | Text, 8 | useColorModeValue, 9 | useTheme, 10 | } from '@interchain-ui/react'; 11 | 12 | import { useDetectBreakpoints } from '@/hooks'; 13 | 14 | type Option = { 15 | label: string; 16 | value: string; 17 | }; 18 | 19 | type PopoverSelectProps = { 20 | trigger: React.ReactNode; 21 | options: Option[]; 22 | onOptionClick: (value: string) => void; 23 | popoverWidth?: string; 24 | }; 25 | 26 | export const PopoverSelect = ({ 27 | trigger, 28 | options, 29 | onOptionClick, 30 | popoverWidth = '100%', 31 | }: PopoverSelectProps) => { 32 | const [isPopoverOpen, setIsPopoverOpen] = useState(false); 33 | 34 | const { theme } = useTheme(); 35 | const { isMobile } = useDetectBreakpoints(); 36 | 37 | return ( 38 | 45 | {trigger} 46 | 47 | 60 | {options.map((p) => ( 61 | { 64 | onOptionClick(p.value); 65 | setIsPopoverOpen(false); 66 | }} 67 | > 68 | {p.label} 69 | 70 | ))} 71 | 72 | 73 | 74 | ); 75 | }; 76 | 77 | const CustomOption = ({ 78 | children, 79 | onClick, 80 | }: { 81 | children: React.ReactNode; 82 | onClick: () => void; 83 | }) => { 84 | return ( 85 | 99 | 108 | {children} 109 | 110 | 111 | ); 112 | }; 113 | -------------------------------------------------------------------------------- /templates/chain-admin/components/contract/my-contracts/index.ts: -------------------------------------------------------------------------------- 1 | export * from './MyContractsTab'; 2 | -------------------------------------------------------------------------------- /templates/chain-admin/components/contract/query/QueryTab.tsx: -------------------------------------------------------------------------------- 1 | import { useIsHyperwebChain } from '@/hooks'; 2 | import { QueryWasmContract } from './QueryWasmContract'; 3 | import { QueryJsContract } from './QueryJsContract'; 4 | 5 | export type QueryTabProps = { 6 | show: boolean; 7 | addressValue: string; 8 | onAddressInput: (input: string) => void; 9 | }; 10 | 11 | export const QueryTab = ({ 12 | show, 13 | addressValue, 14 | onAddressInput, 15 | }: QueryTabProps) => { 16 | const isHyperwebChain = useIsHyperwebChain(); 17 | 18 | return isHyperwebChain ? ( 19 | 24 | ) : ( 25 | 30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /templates/chain-admin/components/contract/query/index.ts: -------------------------------------------------------------------------------- 1 | export * from './QueryTab'; 2 | -------------------------------------------------------------------------------- /templates/chain-admin/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './common'; 2 | export * from './staking'; 3 | export * from './voting'; 4 | export * from './asset-list'; 5 | export * from './contract'; 6 | -------------------------------------------------------------------------------- /templates/chain-admin/components/staking/AllValidators.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import { Text } from '@interchain-ui/react'; 3 | 4 | import { DelegateModal } from './DelegateModal'; 5 | import AllValidatorsList from './AllValidatorsList'; 6 | import { Prices, useDisclosure } from '@/hooks'; 7 | import { type ExtendedValidator as Validator } from '@/utils'; 8 | 9 | export const AllValidators = ({ 10 | validators, 11 | balance, 12 | updateData, 13 | unbondingDays, 14 | chainName, 15 | logos, 16 | prices, 17 | }: { 18 | validators: Validator[]; 19 | balance: string; 20 | updateData: () => void; 21 | unbondingDays: string; 22 | chainName: string; 23 | logos: { 24 | [key: string]: string; 25 | }; 26 | prices: Prices; 27 | }) => { 28 | const delegateModalControl = useDisclosure(); 29 | const [selectedValidator, setSelectedValidator] = useState(); 30 | 31 | return ( 32 | <> 33 | 39 | All Validators 40 | 41 | 42 | 49 | 50 | {selectedValidator && ( 51 | 62 | )} 63 | 64 | ); 65 | }; 66 | -------------------------------------------------------------------------------- /templates/chain-admin/components/staking/MyValidatorsList.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Dispatch, SetStateAction } from 'react'; 3 | import { 4 | Button, 5 | ValidatorList, 6 | ValidatorNameCell, 7 | ValidatorTokenAmountCell, 8 | } from '@interchain-ui/react'; 9 | import { useChain } from '@interchain-kit/react'; 10 | 11 | import { getNativeAsset } from '@/utils'; 12 | import { type ExtendedValidator as Validator } from '@/utils'; 13 | 14 | const MyValidatorsList = ({ 15 | myValidators, 16 | openModal, 17 | chainName, 18 | logos, 19 | setSelectedValidator, 20 | }: { 21 | myValidators: Validator[]; 22 | chainName: string; 23 | openModal: () => void; 24 | setSelectedValidator: Dispatch>; 25 | logos: { 26 | [key: string]: string; 27 | }; 28 | }) => { 29 | const { assetList } = useChain(chainName); 30 | const coin = getNativeAsset(assetList); 31 | 32 | return ( 33 | ( 41 | 45 | ), 46 | }, 47 | { 48 | id: 'amount-staked', 49 | label: 'Amount Staked', 50 | width: '196px', 51 | align: 'right', 52 | render: (validator: Validator) => ( 53 | 57 | ), 58 | }, 59 | { 60 | id: 'claimable-rewards', 61 | label: 'Claimable Rewards', 62 | width: '196px', 63 | align: 'right', 64 | render: (validator: Validator) => ( 65 | 69 | ), 70 | }, 71 | { 72 | id: 'action', 73 | width: '196px', 74 | align: 'right', 75 | render: (validator) => ( 76 | 88 | ), 89 | }, 90 | ]} 91 | data={myValidators} 92 | tableProps={{ 93 | width: '$full', 94 | }} 95 | /> 96 | ); 97 | }; 98 | 99 | export default React.memo(MyValidatorsList); 100 | -------------------------------------------------------------------------------- /templates/chain-admin/components/staking/StakingSection.tsx: -------------------------------------------------------------------------------- 1 | import { useChain } from '@interchain-kit/react'; 2 | import { Box, Spinner, Text } from '@interchain-ui/react'; 3 | 4 | import Overview from './Overview'; 5 | import { MyValidators } from './MyValidators'; 6 | import { AllValidators } from './AllValidators'; 7 | import { useStakingData, useValidatorLogos } from '@/hooks'; 8 | 9 | export const StakingSection = ({ chainName }: { chainName: string }) => { 10 | const { address } = useChain(chainName); 11 | const { data, isLoading, refetch } = useStakingData(chainName); 12 | const { data: logos, isLoading: isFetchingLogos } = useValidatorLogos( 13 | chainName, 14 | data?.allValidators || [] 15 | ); 16 | 17 | return ( 18 | 19 | {!address ? ( 20 | 26 | 27 | Please connect your wallet 28 | 29 | 30 | ) : isLoading || isFetchingLogos || !data ? ( 31 | 37 | 38 | 39 | ) : ( 40 | <> 41 | 49 | 50 | {data.myValidators.length > 0 && ( 51 | 61 | )} 62 | 63 | 72 | 73 | )} 74 | 75 | ); 76 | }; 77 | -------------------------------------------------------------------------------- /templates/chain-admin/components/staking/ValidatorInfoModal.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | BasicModal, 3 | Box, 4 | Button, 5 | StakingDelegate, 6 | Text, 7 | } from '@interchain-ui/react'; 8 | import { useChain } from '@interchain-kit/react'; 9 | 10 | import { UseDisclosureReturn } from '@/hooks'; 11 | import { 12 | getNativeAsset, 13 | formatValidatorMetaInfo, 14 | type ExtendedValidator as Validator, 15 | } from '@/utils'; 16 | 17 | export const ValidatorInfoModal = ({ 18 | chainName, 19 | logoUrl, 20 | handleClick, 21 | modalControl, 22 | selectedValidator, 23 | }: { 24 | chainName: string; 25 | modalControl: UseDisclosureReturn; 26 | selectedValidator: Validator; 27 | handleClick: { 28 | openDelegateModal: () => void; 29 | openUndelegateModal: () => void; 30 | openSelectValidatorModal: () => void; 31 | }; 32 | logoUrl: string; 33 | }) => { 34 | const { assetList } = useChain(chainName); 35 | const coin = getNativeAsset(assetList); 36 | 37 | const { isOpen, onClose } = modalControl; 38 | const { openDelegateModal, openSelectValidatorModal, openUndelegateModal } = 39 | handleClick; 40 | 41 | return ( 42 | 43 | 44 | {selectedValidator.description} 53 | ) 54 | } 55 | delegationItems={[ 56 | { 57 | label: 'Your Delegation', 58 | tokenAmount: selectedValidator.delegation, 59 | tokenName: coin.symbol, 60 | }, 61 | ]} 62 | footer={ 63 | 64 | 73 | 82 | 91 | 92 | } 93 | /> 94 | 95 | 96 | ); 97 | }; 98 | -------------------------------------------------------------------------------- /templates/chain-admin/components/staking/index.ts: -------------------------------------------------------------------------------- 1 | export * from './StakingSection'; 2 | -------------------------------------------------------------------------------- /templates/chain-admin/components/voting/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Voting'; 2 | export * from './Proposal'; -------------------------------------------------------------------------------- /templates/chain-admin/config/breakpoints.ts: -------------------------------------------------------------------------------- 1 | export const breakpoints = { 2 | mobile: 480, 3 | tablet: 768, 4 | desktop: 1200, 5 | }; 6 | -------------------------------------------------------------------------------- /templates/chain-admin/config/chains.ts: -------------------------------------------------------------------------------- 1 | export const HYPERWEB_CHAIN_NAME = 'hyperweb'; 2 | -------------------------------------------------------------------------------- /templates/chain-admin/config/hyperweb.ts: -------------------------------------------------------------------------------- 1 | export const DEFAULT_HYPERWEB_TOKEN_PRICE = 1; 2 | -------------------------------------------------------------------------------- /templates/chain-admin/config/index.ts: -------------------------------------------------------------------------------- 1 | export * from './chains'; 2 | export * from './theme'; 3 | export * from './wallets'; 4 | export * from './products'; 5 | export * from './breakpoints'; 6 | export * from './hyperweb'; 7 | -------------------------------------------------------------------------------- /templates/chain-admin/config/products.ts: -------------------------------------------------------------------------------- 1 | export type ProductCategory = 'cosmos-sdk' | 'frontend' | 'testing'; 2 | 3 | export type Product = { 4 | name: string; 5 | description: string; 6 | link: string; 7 | category: ProductCategory; 8 | }; 9 | 10 | export const products: Product[] = [ 11 | { 12 | name: 'Interchain Kit', 13 | description: 14 | 'A wallet adapter for react with mobile WalletConnect support for the Cosmos ecosystem.', 15 | link: 'https://hyperweb.io/stack/interchain-kit', 16 | category: 'frontend', 17 | }, 18 | { 19 | name: 'InterchainJS', 20 | description: 'A single, universal signing interface for any network', 21 | link: 'https://hyperweb.io/stack/interchainjs', 22 | category: 'frontend', 23 | }, 24 | { 25 | name: 'Telescope', 26 | description: 27 | 'A TypeScript Transpiler for Cosmos Protobufs to generate libraries for Cosmos blockchains.', 28 | link: 'https://hyperweb.io/stack/telescope', 29 | category: 'cosmos-sdk', 30 | }, 31 | { 32 | name: 'Interchain UI', 33 | description: 34 | 'A simple, modular and cross-framework component library for Cosmos ecosystem.', 35 | link: 'https://hyperweb.io/stack/interchain-ui', 36 | category: 'frontend', 37 | }, 38 | { 39 | name: 'Chain Registry', 40 | description: 41 | 'Get chain and asset list information from the npm package for the Official Cosmos chain registry.', 42 | link: 'https://hyperweb.io/stack/chain-registry', 43 | category: 'frontend', 44 | }, 45 | { 46 | name: 'Starship', 47 | description: 48 | 'Starship makes it easy to build a universal interchain development environment in k8s.', 49 | link: 'https://hyperweb.io/stack/starship', 50 | category: 'testing', 51 | }, 52 | { 53 | name: 'Videos', 54 | description: 55 | 'How-to videos from the official Cosmology website, with learning resources for building in Cosmos.', 56 | link: 'https://cosmology.zone/learn', 57 | category: 'frontend', 58 | }, 59 | { 60 | name: 'Next.js', 61 | description: 'A React Framework supports hybrid static & server rendering.', 62 | link: 'https://nextjs.org/', 63 | category: 'frontend', 64 | }, 65 | ]; 66 | -------------------------------------------------------------------------------- /templates/chain-admin/config/theme.ts: -------------------------------------------------------------------------------- 1 | import { ThemeDef, ThemeVariant } from '@interchain-ui/react'; 2 | 3 | export const CustomTheme: Record = { 4 | light: 'custom-light', 5 | dark: 'custom-dark', 6 | }; 7 | 8 | export const lightColors: ThemeDef['vars']['colors'] = { 9 | purple900: '#322F3C', 10 | purple600: '#7310FF', 11 | purple400: '#AB6FFF', 12 | purple200: '#E5D4FB', 13 | purple100: '#F9F4FF', 14 | purple50: '#FCFAFF', 15 | blackAlpha600: '#2C3137', 16 | blackAlpha500: '#6D7987', 17 | blackAlpha400: '#697584', 18 | blackAlpha300: '#DDE2E9', 19 | blackAlpha200: '#D5DDE9', 20 | blackAlpha100: '#F6F8FE', 21 | blackAlpha50: '#FBFBFB', 22 | gray100: '#EFF2F4', 23 | white: '#FFFFFF', 24 | background: '#FFFFFF', 25 | green600: '#38A169', 26 | green400: '#63C892', 27 | green200: '#A9E8C7', 28 | orange600: '#ED8936', 29 | orange400: '#EBB07F', 30 | orange200: '#F5D1B4', 31 | red600: '#E65858', 32 | red400: '#E18080', 33 | red200: '#F1C4C4', 34 | blue100: '#F4FCFF', 35 | blue200: '#C6E7FF', 36 | blue300: '#AEDEFF', 37 | blue400: '#68C7FF', 38 | blue500: '#35B4FF', 39 | blue600: '#01A1FF', 40 | blue700: '#0068A6', 41 | blue800: '#194F8F', 42 | blue900: '#002D4D', 43 | }; 44 | 45 | export const darkColors: ThemeDef['vars']['colors'] = { 46 | purple900: '#322F3C', 47 | purple600: '#9042FE', 48 | purple400: '#AB6FFF', 49 | purple200: '#4D198F', 50 | purple100: '#14004D', 51 | purple50: '#FCFAFF', 52 | blackAlpha600: '#FFFFFF', 53 | blackAlpha500: '#9EACBD', 54 | blackAlpha400: '#807C86', 55 | blackAlpha300: '#46424D', 56 | blackAlpha200: '#443F4B', 57 | blackAlpha100: '#29262F', 58 | blackAlpha50: '#1D2328', 59 | gray100: '#EFF2F4', 60 | white: '#FFFFFF', 61 | background: '#232A31', 62 | green600: '#38A169', 63 | green400: '#63C892', 64 | green200: '#A9E8C7', 65 | orange600: '#ED8936', 66 | orange400: '#EBB07F', 67 | orange200: '#F5D1B4', 68 | red600: '#E65858', 69 | red400: '#E18080', 70 | red200: '#F1C4C4', 71 | blue100: '#F4FCFF', 72 | blue200: '#C6E7FF', 73 | blue300: '#AEDEFF', 74 | blue400: '#68C7FF', 75 | blue500: '#35B4FF', 76 | blue600: '#01A1FF', 77 | blue700: '#0068A6', 78 | blue800: '#194F8F', 79 | blue900: '#002D4D', 80 | }; 81 | 82 | export const lightTheme: ThemeDef = { 83 | name: CustomTheme.light, 84 | vars: { 85 | colors: lightColors, 86 | }, 87 | }; 88 | 89 | export const darkTheme: ThemeDef = { 90 | name: CustomTheme.dark, 91 | vars: { 92 | colors: darkColors, 93 | }, 94 | }; 95 | -------------------------------------------------------------------------------- /templates/chain-admin/config/wallets.ts: -------------------------------------------------------------------------------- 1 | import { keplrExtensionInfo } from '@interchain-kit/keplr-extension'; 2 | import { keplrWallet } from '@interchain-kit/keplr-extension'; 3 | import { leapWallet } from '@interchain-kit/leap-extension'; 4 | 5 | export const keplrWalletName = keplrExtensionInfo.name; 6 | export const wallets = [keplrWallet, leapWallet]; 7 | -------------------------------------------------------------------------------- /templates/chain-admin/contexts/chain.ts: -------------------------------------------------------------------------------- 1 | import { create } from 'zustand'; 2 | import { HYPERWEB_CHAIN_NAME } from '@/config'; 3 | 4 | interface ChainStore { 5 | selectedChain: string; 6 | isHyperwebAdded: boolean; 7 | } 8 | 9 | export const useChainStore = create()(() => ({ 10 | selectedChain: HYPERWEB_CHAIN_NAME, 11 | isHyperwebAdded: false, 12 | })); 13 | 14 | export const chainStore = { 15 | setSelectedChain: (chainName: string) => { 16 | useChainStore.setState({ selectedChain: chainName }); 17 | }, 18 | setIsHyperwebAdded: (isAdded: boolean) => { 19 | useChainStore.setState({ isHyperwebAdded: isAdded }); 20 | }, 21 | }; 22 | -------------------------------------------------------------------------------- /templates/chain-admin/contexts/index.ts: -------------------------------------------------------------------------------- 1 | export * from './chain'; 2 | -------------------------------------------------------------------------------- /templates/chain-admin/declaration.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.yaml' { 2 | const content: unknown; 3 | export default content; 4 | } 5 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/asset-list/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useChainUtils'; 2 | export * from './useChainAssetsPrices'; 3 | export * from './useAssets'; 4 | export * from './useTotalAssets'; 5 | export * from './useBalance'; 6 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/asset-list/useBalance.ts: -------------------------------------------------------------------------------- 1 | import { useChain } from '@interchain-kit/react'; 2 | import { defaultContext } from '@tanstack/react-query'; 3 | import { useGetBalance } from '@interchainjs/react/cosmos/bank/v1beta1/query.rpc.react'; 4 | 5 | import { useRpcEndpoint } from '../common'; 6 | 7 | export const useBalance = ( 8 | chainName: string, 9 | enabled: boolean = true, 10 | displayDenom?: string 11 | ) => { 12 | const { address, assetList } = useChain(chainName); 13 | 14 | let denom = assetList?.assets[0].base!; 15 | for (const asset of assetList?.assets || []) { 16 | if (asset.display.toLowerCase() === displayDenom?.toLowerCase()) { 17 | denom = asset.base; 18 | break; 19 | } 20 | } 21 | 22 | const { data: rpcEndpoint, isFetching } = useRpcEndpoint(chainName); 23 | 24 | const isReady = !!address && !!rpcEndpoint; 25 | 26 | const balanceQuery = useGetBalance({ 27 | request: { 28 | denom, 29 | address: address || '', 30 | }, 31 | options: { 32 | enabled: isReady && enabled, 33 | select: ({ balance }) => balance, 34 | context: defaultContext, 35 | }, 36 | clientResolver: rpcEndpoint, 37 | customizedQueryKey: ['balance', address, denom], 38 | }); 39 | 40 | return { 41 | balance: balanceQuery.data, 42 | isLoading: isFetching || balanceQuery.isFetching, 43 | }; 44 | }; 45 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/asset-list/useChainAssetsPrices.ts: -------------------------------------------------------------------------------- 1 | import { Asset } from '@chain-registry/types'; 2 | import { useQuery } from '@tanstack/react-query'; 3 | import { useChainUtils } from './useChainUtils'; 4 | import { DEFAULT_HYPERWEB_TOKEN_PRICE } from '@/config'; 5 | 6 | type CoinGeckoId = string; 7 | type CoinGeckoUSD = { usd: number }; 8 | type CoinGeckoUSDResponse = Record; 9 | 10 | const getAssetsWithGeckoIds = (assets: Asset[]) => { 11 | return assets.filter((asset) => !!asset?.coingecko_id); 12 | }; 13 | 14 | const getGeckoIds = (assets: Asset[]) => { 15 | return assets.map((asset) => asset.coingecko_id) as string[]; 16 | }; 17 | 18 | const formatPrices = ( 19 | prices: CoinGeckoUSDResponse, 20 | assets: Asset[] 21 | ): Record => { 22 | return Object.entries(prices).reduce((priceHash, cur) => { 23 | const denom = assets.find((asset) => asset.coingecko_id === cur[0])!.base; 24 | return { ...priceHash, [denom]: cur[1].usd }; 25 | }, {}); 26 | }; 27 | 28 | const handleError = (resp: Response) => { 29 | if (!resp.ok) throw Error(resp.statusText); 30 | return resp; 31 | }; 32 | 33 | const fetchPrices = async ( 34 | geckoIds: string[] 35 | ): Promise => { 36 | const url = `https://api.coingecko.com/api/v3/simple/price?ids=${geckoIds.join()}&vs_currencies=usd`; 37 | 38 | return fetch(url) 39 | .then(handleError) 40 | .then((res) => res.json()); 41 | }; 42 | 43 | export const useChainAssetsPrices = (chainName: string) => { 44 | const { allAssets, isStarshipChain } = useChainUtils(chainName); 45 | const assetsWithGeckoIds = getAssetsWithGeckoIds(allAssets); 46 | const geckoIds = getGeckoIds(assetsWithGeckoIds); 47 | 48 | return useQuery({ 49 | queryKey: ['useChainAssetsPrices', chainName], 50 | queryFn: () => fetchPrices(geckoIds), 51 | select: (data) => ({ 52 | ...formatPrices(data, assetsWithGeckoIds), 53 | ...(isStarshipChain 54 | ? { [allAssets[0].base]: DEFAULT_HYPERWEB_TOKEN_PRICE } 55 | : {}), 56 | }), 57 | staleTime: Infinity, 58 | }); 59 | }; 60 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/common/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useToast'; 2 | export * from './useDisclosure'; 3 | export * from './useCopyToClipboard'; 4 | export * from './useOutsideClick'; 5 | export * from './useMediaQuery'; 6 | export * from './useDetectBreakpoints'; 7 | export * from './useStarshipChains'; 8 | export * from './useIsHyperwebChain'; 9 | export * from './useAddHyperwebChain'; 10 | export * from './useRpcEndpoint'; 11 | export * from './useSigningClient'; 12 | export * from './useToastHandlers'; 13 | export * from './useCustomSigningClient'; 14 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/common/useAddHyperwebChain.ts: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react'; 2 | import { useWalletManager } from '@interchain-kit/react'; 3 | 4 | import { useStarshipChains } from './useStarshipChains'; 5 | import { chainStore, useChainStore } from '@/contexts'; 6 | import { StarshipChains } from './useStarshipChains'; 7 | 8 | export const useAddHyperwebChain = () => { 9 | const { isHyperwebAdded } = useChainStore(); 10 | const { data, refetch } = useStarshipChains(); 11 | const { v2: starshipData } = data ?? {}; 12 | const { addChains } = useWalletManager(); 13 | 14 | useEffect(() => { 15 | if (starshipData && !isHyperwebAdded) { 16 | addHyperwebChain(starshipData); 17 | } 18 | }, [starshipData, isHyperwebAdded]); 19 | 20 | const refetchAndAddChain = () => { 21 | refetch().then(({ data }) => { 22 | addHyperwebChain(data?.v2); 23 | }); 24 | }; 25 | 26 | const addHyperwebChain = (data: StarshipChains['v2'] | null | undefined) => { 27 | if (!data) return; 28 | addChains(data.chains, data.assets); 29 | chainStore.setSelectedChain(data.chains[0].chainName); 30 | chainStore.setIsHyperwebAdded(true); 31 | }; 32 | 33 | return { 34 | addHyperwebChain, 35 | refetchAndAddChain, 36 | isHyperwebAdded, 37 | }; 38 | }; 39 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/common/useCopyToClipboard.ts: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import { toast } from '@interchain-ui/react'; 3 | 4 | export const useCopyToClipboard = () => { 5 | const [isCopied, setIsCopied] = useState(false); 6 | 7 | const copyToClipboard = async (text: string) => { 8 | try { 9 | await navigator.clipboard.writeText(text); 10 | setIsCopied(true); 11 | setTimeout(() => setIsCopied(false), 1000); 12 | } catch (err) { 13 | toast.error('Failed to copy text. Please try again.'); 14 | } 15 | }; 16 | 17 | return { isCopied, copyToClipboard }; 18 | }; 19 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/common/useCustomSigningClient.ts: -------------------------------------------------------------------------------- 1 | import { SigningClient } from '@interchainjs/cosmos/signing-client'; 2 | import { 3 | DirectGenericOfflineSigner, 4 | AminoGenericOfflineSigner, 5 | } from '@interchainjs/cosmos/types/wallet'; 6 | import { useQuery } from '@tanstack/react-query'; 7 | import { useChain } from '@interchain-kit/react'; 8 | 9 | import { useChainStore } from '@/contexts'; 10 | 11 | import { useRpcEndpoint } from './useRpcEndpoint'; 12 | 13 | export const useCustomSigningClient = ({ 14 | signerType = 'direct', 15 | }: { 16 | signerType?: 'direct' | 'amino'; 17 | } = {}) => { 18 | const { selectedChain } = useChainStore(); 19 | const { chain } = useChain(selectedChain); 20 | const { data: rpcEndpoint } = useRpcEndpoint(selectedChain); 21 | 22 | const chainId = chain.chainId || ''; 23 | const signerAmino = new AminoGenericOfflineSigner( 24 | (window as any).keplr.getOfflineSignerOnlyAmino(chainId) 25 | ); 26 | const signerDirect = new DirectGenericOfflineSigner( 27 | (window as any).keplr.getOfflineSigner(chainId) 28 | ); 29 | 30 | return useQuery({ 31 | queryKey: ['useCustomSigningClient', signerType, chainId], 32 | queryFn: async () => { 33 | const client = await SigningClient.connectWithSigner( 34 | rpcEndpoint!, 35 | signerType === 'amino' ? signerAmino : signerDirect, 36 | { 37 | broadcast: { 38 | checkTx: true, 39 | deliverTx: true, 40 | }, 41 | } 42 | ); 43 | return client; 44 | }, 45 | enabled: !!rpcEndpoint && !!chainId, 46 | }); 47 | }; 48 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/common/useDetectBreakpoints.ts: -------------------------------------------------------------------------------- 1 | import { breakpoints } from '@/config'; 2 | import { useMediaQuery } from './useMediaQuery'; 3 | 4 | export const useDetectBreakpoints = () => { 5 | const { mobile, tablet, desktop } = breakpoints; 6 | 7 | const isSmMobile = useMediaQuery(`(max-width: ${mobile - 1}px)`); 8 | const isMobile = useMediaQuery(`(max-width: ${tablet - 1}px)`); 9 | const isTablet = useMediaQuery(`(max-width: ${desktop - 1}px)`); 10 | const isDesktop = useMediaQuery(`(min-width: ${desktop}px)`); 11 | 12 | return { isSmMobile, isMobile, isTablet, isDesktop }; 13 | }; 14 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/common/useDisclosure.ts: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | 3 | export const useDisclosure = (initialState = false) => { 4 | const [isOpen, setIsOpen] = useState(initialState); 5 | 6 | const onClose = () => setIsOpen(false); 7 | const onOpen = () => setIsOpen(true); 8 | const onToggle = () => setIsOpen((prev) => !prev); 9 | 10 | return { 11 | isOpen, 12 | onClose, 13 | onOpen, 14 | onToggle, 15 | }; 16 | }; 17 | 18 | export type UseDisclosureReturn = ReturnType; 19 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/common/useIsHyperwebChain.ts: -------------------------------------------------------------------------------- 1 | import { useChainStore } from '@/contexts'; 2 | import { useStarshipChains } from './useStarshipChains'; 3 | 4 | export const useIsHyperwebChain = () => { 5 | const { selectedChain } = useChainStore(); 6 | const { data: starshipData } = useStarshipChains(); 7 | 8 | return starshipData?.v2.chains[0].chainName === selectedChain; 9 | }; 10 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/common/useMediaQuery.ts: -------------------------------------------------------------------------------- 1 | import { useState, useCallback, useEffect } from 'react'; 2 | 3 | export const useMediaQuery = (mediaQuery: string) => { 4 | const [targetReached, setTargetReached] = useState(false); 5 | 6 | const updateTarget = useCallback((e: MediaQueryListEvent) => { 7 | if (e.matches) { 8 | setTargetReached(true); 9 | } else { 10 | setTargetReached(false); 11 | } 12 | }, []); 13 | 14 | useEffect(() => { 15 | const media = window.matchMedia(mediaQuery); 16 | media.addEventListener('change', updateTarget); 17 | 18 | // Check on mount (callback is not called until a change occurs) 19 | if (media.matches) { 20 | setTargetReached(true); 21 | } 22 | 23 | return () => media.removeEventListener('change', updateTarget); 24 | }, []); 25 | 26 | return targetReached; 27 | }; 28 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/common/useOutsideClick.ts: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react'; 2 | 3 | interface UseOutsideClickProps { 4 | ref: React.RefObject; 5 | handler: () => void; 6 | shouldListen?: boolean; 7 | } 8 | 9 | export const useOutsideClick = ({ ref, handler, shouldListen = true }: UseOutsideClickProps) => { 10 | const handleClick = (event: MouseEvent) => { 11 | if (ref.current && !ref.current.contains(event.target as Node)) { 12 | handler(); 13 | } 14 | }; 15 | 16 | useEffect(() => { 17 | if (shouldListen) { 18 | document.addEventListener('mousedown', handleClick); 19 | } else { 20 | document.removeEventListener('mousedown', handleClick); 21 | } 22 | 23 | return () => { 24 | document.removeEventListener('mousedown', handleClick); 25 | }; 26 | }, [ref, handler, shouldListen]); 27 | }; 28 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/common/useRpcEndpoint.ts: -------------------------------------------------------------------------------- 1 | import { useChain } from '@interchain-kit/react'; 2 | import { useQuery } from '@tanstack/react-query'; 3 | 4 | export const useRpcEndpoint = (chainName: string) => { 5 | const { getRpcEndpoint } = useChain(chainName); 6 | 7 | return useQuery({ 8 | queryKey: ['rpcEndpoint', chainName], 9 | queryFn: async () => { 10 | return await getRpcEndpoint(); 11 | }, 12 | staleTime: Infinity, 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/common/useSigningClient.ts: -------------------------------------------------------------------------------- 1 | import { useChain } from '@interchain-kit/react'; 2 | import { useQuery } from '@tanstack/react-query'; 3 | 4 | export const useSigningClient = (chainName: string) => { 5 | const { getSigningClient, address } = useChain(chainName); 6 | 7 | return useQuery({ 8 | queryKey: ['signingClient', chainName], 9 | queryFn: async () => { 10 | return await getSigningClient(); 11 | }, 12 | enabled: !!address, 13 | staleTime: Infinity, 14 | }); 15 | }; 16 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/common/useStarshipChains.ts: -------------------------------------------------------------------------------- 1 | import { useQuery } from '@tanstack/react-query'; 2 | import { AssetList, Chain } from '@chain-registry/types'; 3 | import { 4 | Chain as ChainV2, 5 | AssetList as AssetListV2, 6 | } from '@chain-registry/v2-types'; 7 | 8 | import { StarshipConfig } from '@/starship'; 9 | import { convertKeysToCamelCase } from '@/utils'; 10 | import config from '@/starship/configs/config.yaml'; 11 | 12 | export type StarshipChains = { 13 | v1: { 14 | chains: Chain[]; 15 | assets: AssetList[]; 16 | }; 17 | v2: { 18 | chains: ChainV2[]; 19 | assets: AssetListV2[]; 20 | }; 21 | }; 22 | 23 | export const useStarshipChains = () => { 24 | const { registry } = config as StarshipConfig; 25 | const baseUrl = `http://localhost:${registry.ports.rest}`; 26 | 27 | return useQuery({ 28 | queryKey: ['starship-chains'], 29 | queryFn: async (): Promise => { 30 | try { 31 | const { chains = [] } = 32 | (await fetcher<{ chains: Chain[] }>(`${baseUrl}/chains`)) ?? {}; 33 | 34 | const assets = (await Promise.all( 35 | chains.map((chain) => 36 | fetcher(`${baseUrl}/chains/${chain.chain_id}/assets`) 37 | ) 38 | ).then((assetLists) => assetLists.filter(Boolean))) as AssetList[]; 39 | 40 | return chains.length > 0 && assets.length > 0 41 | ? { 42 | v1: { 43 | chains, 44 | assets, 45 | }, 46 | v2: { 47 | chains: convertKeysToCamelCase(chains) as ChainV2[], 48 | assets: convertKeysToCamelCase(assets) as AssetListV2[], 49 | }, 50 | } 51 | : null; 52 | } catch (error) { 53 | console.error(error); 54 | return null; 55 | } 56 | }, 57 | staleTime: Infinity, 58 | cacheTime: Infinity, 59 | refetchOnMount: false, 60 | refetchOnReconnect: false, 61 | }); 62 | }; 63 | 64 | const fetcher = async (url: string): Promise => { 65 | try { 66 | const response = await fetch(url); 67 | const data = await response.json(); 68 | return data; 69 | } catch (error) { 70 | console.error(error); 71 | return null; 72 | } 73 | }; 74 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/common/useToast.tsx: -------------------------------------------------------------------------------- 1 | import { toast, Text, ToastType, Spinner } from '@interchain-ui/react'; 2 | 3 | export type CustomToast = { 4 | type: ToastType; 5 | title: string; 6 | duration?: number; 7 | description?: string | JSX.Element; 8 | }; 9 | 10 | const ToastTitle = ({ title }: { title: string }) => { 11 | return ( 12 | 13 | {title} 14 | 15 | ); 16 | }; 17 | 18 | export const useToast = () => { 19 | const customToast = ({ 20 | type, 21 | title, 22 | description, 23 | duration = 5000, 24 | }: CustomToast) => { 25 | return toast.custom(type, , { 26 | duration, 27 | description, 28 | icon: type === 'loading' ? : undefined, 29 | }); 30 | }; 31 | 32 | customToast.close = toast.dismiss; 33 | 34 | return { toast: customToast }; 35 | }; 36 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/common/useToastHandlers.ts: -------------------------------------------------------------------------------- 1 | import { useToast } from './useToast'; 2 | 3 | enum TxStatus { 4 | Failed = 'Transaction Failed', 5 | Successful = 'Transaction Successful', 6 | Broadcasting = 'Transaction Broadcasting', 7 | } 8 | 9 | export function useToastHandlers() { 10 | const { toast } = useToast(); 11 | 12 | return { 13 | onMutate: () => { 14 | const id = toast({ 15 | title: TxStatus.Broadcasting, 16 | description: 'Waiting for transaction to be included in the block', 17 | type: 'loading', 18 | duration: 999999, 19 | }); 20 | return { toastId: id }; 21 | }, 22 | onSuccess: (_data: unknown, _variables: unknown, context: any) => { 23 | toast.close(context?.toastId); 24 | 25 | toast({ 26 | title: TxStatus.Successful, 27 | type: 'success', 28 | description: 'Your transaction has been successfully completed', 29 | }); 30 | }, 31 | onError: (error: unknown, _variables: unknown, context: any) => { 32 | toast.close(context?.toastId); 33 | 34 | toast({ 35 | title: TxStatus.Failed, 36 | description: 37 | error instanceof Error 38 | ? error.message 39 | : 'An unexpected error occurred', 40 | type: 'error', 41 | duration: 10000, 42 | }); 43 | }, 44 | }; 45 | } 46 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/contract/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useContractInfo'; 2 | export * from './useQueryContract'; 3 | export * from './useExecuteContractTx'; 4 | export * from './useStoreCodeTx'; 5 | export * from './useInstantiateTx'; 6 | export * from './useMyContracts'; 7 | export * from './useCodeDetails'; 8 | export * from './useJsContractInfo'; 9 | export * from './useQueryJsContract'; 10 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/contract/useCodeDetails.ts: -------------------------------------------------------------------------------- 1 | import { useQuery } from '@tanstack/react-query'; 2 | import { createGetCode } from '@interchainjs/react/cosmwasm/wasm/v1/query.rpc.func'; 3 | 4 | import { prettyCodeInfo } from '@/utils'; 5 | import { useChainStore } from '@/contexts'; 6 | import { useRpcEndpoint } from '../common'; 7 | 8 | export const useCodeDetails = (codeId: number, enabled: boolean = true) => { 9 | const { selectedChain } = useChainStore(); 10 | const { data: rpcEndpoint } = useRpcEndpoint(selectedChain); 11 | 12 | return useQuery({ 13 | queryKey: ['useCodeDetails', codeId], 14 | queryFn: async () => { 15 | const getCode = createGetCode(rpcEndpoint); 16 | try { 17 | const { codeInfo } = await getCode({ 18 | codeId: BigInt(codeId), 19 | }); 20 | return codeInfo && prettyCodeInfo(codeInfo); 21 | } catch (error) { 22 | console.error(error); 23 | return null; 24 | } 25 | }, 26 | enabled: !!rpcEndpoint && enabled, 27 | retry: false, 28 | cacheTime: 0, 29 | refetchOnMount: false, 30 | refetchOnReconnect: false, 31 | refetchOnWindowFocus: false, 32 | }); 33 | }; 34 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/contract/useContractInfo.ts: -------------------------------------------------------------------------------- 1 | import { defaultContext } from '@tanstack/react-query'; 2 | import { useGetContractInfo } from '@interchainjs/react/cosmwasm/wasm/v1/query.rpc.react'; 3 | 4 | import { useChainStore } from '@/contexts'; 5 | import { useRpcEndpoint } from '../common'; 6 | 7 | export const useContractInfo = ({ 8 | contractAddress, 9 | enabled = true, 10 | }: { 11 | contractAddress: string; 12 | enabled?: boolean; 13 | }) => { 14 | const { selectedChain } = useChainStore(); 15 | const { data: rpcEndpoint } = useRpcEndpoint(selectedChain); 16 | 17 | return useGetContractInfo({ 18 | request: { 19 | address: contractAddress, 20 | }, 21 | options: { 22 | enabled: !!contractAddress && !!rpcEndpoint && enabled, 23 | context: defaultContext, 24 | }, 25 | clientResolver: rpcEndpoint, 26 | }); 27 | }; 28 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/contract/useExecuteContractTx.tsx: -------------------------------------------------------------------------------- 1 | import { useChain } from '@interchain-kit/react'; 2 | import { getSigningJsdClient, jsd } from 'hyperwebjs'; 3 | import { createExecuteContract } from '@interchainjs/react/cosmwasm/wasm/v1/tx.rpc.func'; 4 | import { Coin, StdFee } from '@interchainjs/react/types'; 5 | 6 | import { toUint8Array } from '@/utils'; 7 | 8 | import { useHandleTx } from './useHandleTx'; 9 | import { useCustomSigningClient, useRpcEndpoint } from '../common'; 10 | 11 | interface ExecuteTxParams { 12 | address: string; 13 | contractAddress: string; 14 | fee: StdFee; 15 | msg: object; 16 | funds: Coin[]; 17 | onTxSucceed?: () => void; 18 | onTxFailed?: () => void; 19 | } 20 | 21 | interface ExecuteJsdTxParams { 22 | address: string; 23 | contractIndex: string; 24 | fnName: string; 25 | arg: string; 26 | onTxSucceed?: () => void; 27 | onTxFailed?: () => void; 28 | } 29 | 30 | export const useExecuteContractTx = (chainName: string) => { 31 | const { data: signingClient } = useCustomSigningClient(); 32 | const { data: rpcEndpoint } = useRpcEndpoint(chainName); 33 | const { chain, wallet } = useChain(chainName); 34 | const handleTx = useHandleTx(chainName); 35 | 36 | const executeTx = async ({ 37 | address, 38 | contractAddress, 39 | fee, 40 | funds, 41 | msg, 42 | onTxFailed = () => {}, 43 | onTxSucceed = () => {}, 44 | }: ExecuteTxParams) => { 45 | await handleTx({ 46 | txFunction: async () => { 47 | const executeContract = createExecuteContract(signingClient); 48 | const res = await executeContract( 49 | address, 50 | { 51 | sender: address, 52 | contract: contractAddress, 53 | msg: toUint8Array(msg), 54 | funds, 55 | }, 56 | fee, 57 | '' 58 | ); 59 | return res; 60 | }, 61 | onTxSucceed, 62 | onTxFailed, 63 | }); 64 | }; 65 | 66 | const executeJsdTx = async ({ 67 | address, 68 | contractIndex, 69 | fnName, 70 | arg, 71 | onTxFailed = () => {}, 72 | onTxSucceed = () => {}, 73 | }: ExecuteJsdTxParams) => { 74 | const msg = jsd.jsd.MessageComposer.fromPartial.eval({ 75 | creator: address, 76 | index: BigInt(contractIndex), 77 | fnName, 78 | arg, 79 | }); 80 | 81 | const fee = { amount: [], gas: '550000' }; 82 | 83 | await handleTx({ 84 | txFunction: async () => { 85 | const signingClient = await getSigningJsdClient({ 86 | rpcEndpoint: rpcEndpoint!, 87 | signer: wallet.getOfflineSignerDirect(chain.chainId ?? ''), 88 | }); 89 | 90 | return signingClient.signAndBroadcast(address, [msg], fee); 91 | }, 92 | onTxSucceed, 93 | onTxFailed, 94 | }); 95 | }; 96 | 97 | return { executeTx, executeJsdTx }; 98 | }; 99 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/contract/useHandleTx.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link'; 2 | import { useState, useCallback } from 'react'; 3 | import { Box, Text, Icon } from '@interchain-ui/react'; 4 | import { useChain } from '@interchain-kit/react'; 5 | 6 | import { useToast } from '../common'; 7 | import { getExplorerLink } from '@/utils'; 8 | 9 | interface HandleTxParams { 10 | txFunction: () => Promise; 11 | successMessage?: string; 12 | onTxSucceed?: (result: T) => void; 13 | onTxFailed?: () => void; 14 | } 15 | 16 | export const useHandleTx = (chainName: string) => { 17 | const { toast } = useToast(); 18 | const { chain } = useChain(chainName); 19 | const [toastId, setToastId] = useState(); 20 | 21 | return useCallback( 22 | async ({ 23 | txFunction, 24 | successMessage = 'Transaction Successful', 25 | onTxSucceed = () => {}, 26 | onTxFailed = () => {}, 27 | }: HandleTxParams) => { 28 | const toastId = toast({ 29 | title: 'Sending Transaction', 30 | type: 'loading', 31 | duration: 999999, 32 | }); 33 | 34 | setToastId(toastId); 35 | 36 | try { 37 | const result: any = await txFunction(); 38 | if (result.code !== 0) { 39 | throw new Error(result.rawLog); 40 | } 41 | onTxSucceed(result); 42 | toast.close(toastId); 43 | 44 | const explorerLink = getExplorerLink(chain, result?.transactionHash); 45 | 46 | toast({ 47 | title: successMessage, 48 | type: 'success', 49 | description: explorerLink ? ( 50 | 51 | 52 | View tx details 53 | 54 | 55 | 56 | ) : undefined, 57 | }); 58 | } catch (e: any) { 59 | console.error(e); 60 | onTxFailed(); 61 | toast.close(toastId); 62 | toast({ 63 | title: 'Transaction Failed', 64 | type: 'error', 65 | description: ( 66 | 67 | {e.message} 68 | 69 | ), 70 | duration: 10000, 71 | }); 72 | } 73 | }, 74 | [toast, toastId] 75 | ); 76 | }; 77 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/contract/useInstantiateTx.tsx: -------------------------------------------------------------------------------- 1 | import { DeliverTxResponse, getSigningJsdClient, jsd } from 'hyperwebjs'; 2 | import { createInstantiateContract } from '@interchainjs/react/cosmwasm/wasm/v1/tx.rpc.func'; 3 | import { Coin, StdFee } from '@interchainjs/react/types'; 4 | import { useChain } from '@interchain-kit/react'; 5 | 6 | import { toUint8Array } from '@/utils'; 7 | 8 | import { useHandleTx } from './useHandleTx'; 9 | import { useCustomSigningClient, useRpcEndpoint } from '../common'; 10 | 11 | interface InstantiateTxParams { 12 | address: string; 13 | codeId: number; 14 | initMsg: object; 15 | label: string; 16 | admin: string; 17 | funds: Coin[]; 18 | onTxSucceed?: (txInfo: DeliverTxResponse) => void; 19 | onTxFailed?: () => void; 20 | } 21 | 22 | interface InstantiateJsdTxParams { 23 | address: string; 24 | code: string; 25 | onTxSucceed?: (txInfo: DeliverTxResponse) => void; 26 | onTxFailed?: () => void; 27 | } 28 | 29 | export const useInstantiateTx = (chainName: string) => { 30 | const { data: signingClient } = useCustomSigningClient(); 31 | const { data: rpcEndpoint } = useRpcEndpoint(chainName); 32 | const { chain, wallet } = useChain(chainName); 33 | const handleTx = useHandleTx(chainName); 34 | 35 | const instantiateTx = async ({ 36 | address, 37 | codeId, 38 | initMsg, 39 | label, 40 | admin, 41 | funds, 42 | onTxSucceed, 43 | onTxFailed, 44 | }: InstantiateTxParams) => { 45 | const fee: StdFee = { amount: [], gas: '300000' }; 46 | 47 | await handleTx({ 48 | txFunction: async () => { 49 | const instantiateContract = createInstantiateContract(signingClient); 50 | const res = await instantiateContract( 51 | address, 52 | { 53 | sender: address, 54 | codeId: BigInt(codeId), 55 | admin, 56 | funds, 57 | label, 58 | msg: toUint8Array(initMsg), 59 | }, 60 | fee, 61 | '' 62 | ); 63 | return res; 64 | }, 65 | successMessage: 'Instantiate Success', 66 | onTxSucceed, 67 | onTxFailed, 68 | }); 69 | }; 70 | 71 | const instantiateJsdTx = async ({ 72 | address, 73 | code, 74 | onTxSucceed, 75 | onTxFailed, 76 | }: InstantiateJsdTxParams) => { 77 | const fee: StdFee = { amount: [], gas: '550000' }; 78 | 79 | await handleTx({ 80 | txFunction: async () => { 81 | const signingClient = await getSigningJsdClient({ 82 | rpcEndpoint: rpcEndpoint!, 83 | signer: wallet.getOfflineSignerDirect(chain.chainId ?? ''), 84 | }); 85 | 86 | const msg = jsd.jsd.MessageComposer.fromPartial.instantiate({ 87 | creator: address, 88 | code, 89 | }); 90 | 91 | return signingClient.signAndBroadcast( 92 | address, 93 | [msg], 94 | fee 95 | ) as Promise; 96 | }, 97 | successMessage: 'Deploy Success', 98 | onTxSucceed, 99 | onTxFailed, 100 | }); 101 | }; 102 | 103 | return { instantiateTx, instantiateJsdTx }; 104 | }; 105 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/contract/useJsContractInfo.ts: -------------------------------------------------------------------------------- 1 | import { useQuery } from '@tanstack/react-query'; 2 | import { useJsdQueryClient } from './useJsdQueryClient'; 3 | 4 | export const useJsContractInfo = ({ 5 | contractIndex, 6 | enabled = true, 7 | }: { 8 | contractIndex: string; 9 | enabled?: boolean; 10 | }) => { 11 | const { data: jsdQueryClient } = useJsdQueryClient(); 12 | 13 | return useQuery({ 14 | queryKey: ['useJsContractInfo', contractIndex], 15 | queryFn: async () => { 16 | if (!jsdQueryClient) return null; 17 | 18 | const response = await jsdQueryClient.jsd.jsd.contracts({ 19 | index: BigInt(contractIndex), 20 | }); 21 | 22 | return response; 23 | }, 24 | enabled: !!contractIndex && enabled, 25 | }); 26 | }; 27 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/contract/useJsdQueryClient.ts: -------------------------------------------------------------------------------- 1 | import { useChain } from '@interchain-kit/react'; 2 | import { useQuery } from '@tanstack/react-query'; 3 | import { jsd } from 'hyperwebjs'; 4 | 5 | import { useChainStore } from '@/contexts'; 6 | import { useIsHyperwebChain } from '../common'; 7 | 8 | export type JsdQueryClient = NonNullable< 9 | Awaited['data']> 10 | >; 11 | 12 | export const useJsdQueryClient = () => { 13 | const { selectedChain } = useChainStore(); 14 | const { getRpcEndpoint } = useChain(selectedChain); 15 | const isHyperwebChain = useIsHyperwebChain(); 16 | 17 | return useQuery({ 18 | queryKey: ['jsdQueryClient', isHyperwebChain], 19 | queryFn: async () => { 20 | const rpcEndpoint = await getRpcEndpoint(); 21 | const client = await jsd.ClientFactory.createRPCQueryClient({ 22 | rpcEndpoint, 23 | }); 24 | return client; 25 | }, 26 | enabled: isHyperwebChain, 27 | staleTime: Infinity, 28 | cacheTime: Infinity, 29 | refetchOnMount: false, 30 | refetchOnReconnect: false, 31 | refetchOnWindowFocus: false, 32 | }); 33 | }; 34 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/contract/useQueryContract.ts: -------------------------------------------------------------------------------- 1 | import { useQuery } from '@tanstack/react-query'; 2 | import { createGetSmartContractState } from '@interchainjs/react/cosmwasm/wasm/v1/query.rpc.func'; 3 | 4 | import { useChainStore } from '@/contexts'; 5 | import { fromUint8Array, toUint8Array } from '@/utils'; 6 | 7 | import { useRpcEndpoint } from '../common'; 8 | 9 | export const useQueryContract = ({ 10 | contractAddress, 11 | queryMsg, 12 | enabled = true, 13 | }: { 14 | contractAddress: string; 15 | queryMsg: string; 16 | enabled?: boolean; 17 | }) => { 18 | const { selectedChain } = useChainStore(); 19 | const { data: rpcEndpoint } = useRpcEndpoint(selectedChain); 20 | 21 | return useQuery({ 22 | queryKey: ['useQueryContract', contractAddress, queryMsg], 23 | queryFn: () => { 24 | const parsedQueryMsg = queryMsg ? JSON.parse(queryMsg) : null; 25 | const getSmartContractState = createGetSmartContractState(rpcEndpoint); 26 | return getSmartContractState({ 27 | address: contractAddress, 28 | queryData: parsedQueryMsg 29 | ? toUint8Array(parsedQueryMsg) 30 | : new Uint8Array(), 31 | }); 32 | }, 33 | select: ({ data }) => fromUint8Array(data), 34 | enabled: !!rpcEndpoint && !!contractAddress && !!queryMsg && enabled, 35 | }); 36 | }; 37 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/contract/useQueryJsContract.ts: -------------------------------------------------------------------------------- 1 | import { useQuery } from '@tanstack/react-query'; 2 | import { useJsdQueryClient } from './useJsdQueryClient'; 3 | 4 | export const useQueryJsContract = ({ 5 | contractIndex, 6 | fnName, 7 | arg, 8 | enabled = true, 9 | }: { 10 | contractIndex: string; 11 | fnName: string; 12 | arg: string; 13 | enabled?: boolean; 14 | }) => { 15 | const { data: jsdQueryClient } = useJsdQueryClient(); 16 | 17 | return useQuery({ 18 | queryKey: ['useQueryJsContract', contractIndex, fnName, arg], 19 | queryFn: async () => { 20 | if (!jsdQueryClient) return null; 21 | const response = await jsdQueryClient.jsd.jsd.eval({ 22 | index: BigInt(contractIndex), 23 | fnName, 24 | arg, 25 | }); 26 | return response; 27 | }, 28 | enabled: !!jsdQueryClient && !!contractIndex && !!fnName && enabled, 29 | }); 30 | }; 31 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './common'; 2 | export * from './staking'; 3 | export * from './voting'; 4 | export * from './asset-list'; 5 | export * from './contract'; 6 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/staking/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useStakingData'; 2 | export * from './useAssetsPrices'; 3 | export * from './useValidatorLogos'; 4 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/staking/useAssetsPrices.ts: -------------------------------------------------------------------------------- 1 | import { assets } from 'chain-registry'; 2 | import { useQuery } from '@tanstack/react-query'; 3 | import { AssetList } from '@chain-registry/types'; 4 | import { useChainStore } from '@/contexts'; 5 | import { useStarshipChains } from '../common'; 6 | import { DEFAULT_HYPERWEB_TOKEN_PRICE } from '@/config'; 7 | 8 | type CoinGeckoId = string; 9 | type CoinGeckoUSD = { usd: number }; 10 | type CoinGeckoUSDResponse = Record; 11 | export type Prices = Record; 12 | 13 | const handleError = (resp: Response) => { 14 | if (!resp.ok) throw Error(resp.statusText); 15 | return resp; 16 | }; 17 | 18 | const getGeckoIdsFromAssets = (assets: AssetList[]) => { 19 | return assets 20 | .map((asset) => asset.assets[0].coingecko_id) 21 | .filter(Boolean) as string[]; 22 | }; 23 | 24 | const formatPrices = ( 25 | prices: CoinGeckoUSDResponse, 26 | assets: AssetList[] 27 | ): Prices => { 28 | return Object.entries(prices).reduce((priceHash, cur) => { 29 | const assetList = assets.find( 30 | (asset) => asset.assets[0].coingecko_id === cur[0] 31 | )!; 32 | const denom = assetList.assets[0].base; 33 | return { ...priceHash, [denom]: cur[1].usd }; 34 | }, {}); 35 | }; 36 | 37 | const fetchPrices = async ( 38 | geckoIds: string[] 39 | ): Promise => { 40 | const url = `https://api.coingecko.com/api/v3/simple/price?ids=${geckoIds.join()}&vs_currencies=usd`; 41 | 42 | return fetch(url) 43 | .then(handleError) 44 | .then((res) => res.json()); 45 | }; 46 | 47 | export const useAssetsPrices = () => { 48 | const geckoIds = getGeckoIdsFromAssets(assets); 49 | 50 | const { selectedChain } = useChainStore(); 51 | const { data: starshipData } = useStarshipChains(); 52 | const { chains: starshipChains = [], assets: starshipAssets = [] } = 53 | starshipData?.v1 ?? {}; 54 | 55 | const isStarshipChain = starshipChains.some( 56 | (chain) => chain.chain_name === selectedChain 57 | ); 58 | 59 | return useQuery({ 60 | queryKey: ['useAssetsPrices'], 61 | queryFn: () => fetchPrices(geckoIds), 62 | select: (data) => ({ 63 | ...formatPrices(data, assets), 64 | ...(isStarshipChain 65 | ? { [starshipAssets[0].assets[0].base]: DEFAULT_HYPERWEB_TOKEN_PRICE } 66 | : {}), 67 | }), 68 | staleTime: Infinity, 69 | }); 70 | }; 71 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/staking/useValidatorLogos.ts: -------------------------------------------------------------------------------- 1 | import { ExtendedValidator, getLogoUrls } from '@/utils'; 2 | import { useQuery } from '@tanstack/react-query'; 3 | 4 | export const useValidatorLogos = ( 5 | chainName: string, 6 | validators: ExtendedValidator[] 7 | ) => { 8 | return useQuery({ 9 | queryKey: ['validatorLogos', chainName, validators.length], 10 | queryFn: () => getLogoUrls(validators, chainName), 11 | staleTime: Infinity, 12 | }); 13 | }; 14 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/voting/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useModal'; 2 | export * from './useVoting'; 3 | export * from './useVotingData'; 4 | -------------------------------------------------------------------------------- /templates/chain-admin/hooks/voting/useModal.ts: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | 3 | export function useModal(title = '') { 4 | const [modal, setModal] = useState({ open: false, title }); 5 | 6 | const open = () => setModal(modal => ({ ...modal, open: true })); 7 | const close = () => setModal(modal => ({ ...modal, open: false })); 8 | const toggle = () => setModal(modal => ({ ...modal, open: !modal.open })); 9 | 10 | const setTitle = (title: string) => setModal(modal => ({ ...modal, title })); 11 | 12 | return { modal, open, close, toggle, setTitle } 13 | } -------------------------------------------------------------------------------- /templates/chain-admin/hooks/voting/useVoting.ts: -------------------------------------------------------------------------------- 1 | import { useChain } from '@interchain-kit/react'; 2 | import { Proposal } from '@interchainjs/react/cosmos/gov/v1/gov'; 3 | import { useVote } from '@interchainjs/react/cosmos/gov/v1beta1/tx.rpc.react'; 4 | import { MsgVote } from '@interchainjs/react/cosmos/gov/v1beta1/tx'; 5 | import { defaultContext } from '@tanstack/react-query'; 6 | import { StdFee } from '@interchainjs/react/types'; 7 | 8 | import { getNativeAsset } from '@/utils'; 9 | import { useSigningClient, useToastHandlers } from '../common'; 10 | 11 | export type useVotingOptions = { 12 | chainName: string; 13 | proposal: Proposal; 14 | }; 15 | 16 | export type onVoteOptions = { 17 | option: number; 18 | success?: () => void; 19 | error?: () => void; 20 | }; 21 | 22 | export function useVoting({ chainName, proposal }: useVotingOptions) { 23 | const { address, assetList } = useChain(chainName); 24 | const toastHandlers = useToastHandlers(); 25 | const { data: signingClient } = useSigningClient(chainName); 26 | const { mutate: vote, isLoading: isVoting } = useVote({ 27 | clientResolver: signingClient, 28 | options: { 29 | context: defaultContext, 30 | ...toastHandlers, 31 | }, 32 | }); 33 | 34 | const coin = getNativeAsset(assetList); 35 | 36 | async function onVote({ 37 | option, 38 | success = () => {}, 39 | error = () => {}, 40 | }: onVoteOptions) { 41 | if (!address || !option) return; 42 | 43 | const msg = MsgVote.fromPartial({ 44 | option, 45 | voter: address, 46 | proposalId: proposal.id, 47 | }); 48 | 49 | const fee: StdFee = { 50 | amount: [ 51 | { 52 | denom: coin.base, 53 | amount: '0', 54 | }, 55 | ], 56 | gas: '100000', 57 | }; 58 | 59 | vote( 60 | { 61 | signerAddress: address, 62 | message: msg, 63 | fee, 64 | memo: 'Vote', 65 | }, 66 | { 67 | onSuccess: () => { 68 | success(); 69 | }, 70 | onError: (err) => { 71 | error(); 72 | console.error(err); 73 | }, 74 | } 75 | ); 76 | } 77 | 78 | return { isVoting, onVote }; 79 | } 80 | -------------------------------------------------------------------------------- /templates/chain-admin/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | 3 | module.exports = { 4 | reactStrictMode: true, 5 | swcMinify: true, 6 | webpack: (config) => { 7 | config.module.rules.push({ 8 | test: /\.yaml$/, 9 | use: 'yaml-loader', 10 | }); 11 | 12 | return config; 13 | }, 14 | images: { 15 | remotePatterns: [ 16 | { 17 | hostname: 'raw.githubusercontent.com', 18 | }, 19 | { 20 | hostname: 'gist.githubusercontent.com', 21 | }, 22 | ], 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /templates/chain-admin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chain-admin", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint", 10 | "locks:remove": "rm -f yarn.lock", 11 | "locks:create": "generate-lockfile --lockfile ../../yarn.lock --package package.json --write yarn.lock --force", 12 | "locks": "npm run locks:remove && npm run locks:create", 13 | "starship": "starship --config starship/configs/config.yaml" 14 | }, 15 | "resolutions": { 16 | "react": "18.2.0", 17 | "react-dom": "18.2.0", 18 | "@types/react": "18.0.25", 19 | "@types/react-dom": "18.0.9" 20 | }, 21 | "dependencies": { 22 | "@chain-registry/assets": "1.63.5", 23 | "@interchain-kit/core": "^0.2.1", 24 | "@interchain-kit/keplr-extension": "^0.2.1", 25 | "@interchain-kit/leap-extension": "^0.2.1", 26 | "@interchain-kit/react": "^0.2.1", 27 | "@interchain-ui/react": "1.23.31", 28 | "@interchain-ui/react-no-ssr": "0.1.2", 29 | "@interchainjs/cosmos": "^1.9.12", 30 | "@interchainjs/react": "^1.9.12", 31 | "@tanstack/react-query": "4.32.0", 32 | "ace-builds": "1.35.0", 33 | "bignumber.js": "9.1.2", 34 | "chain-registry": "1.62.3", 35 | "dayjs": "1.11.11", 36 | "hyperwebjs": "^0.0.5", 37 | "interchain-kit": "^0.2.1", 38 | "next": "^13", 39 | "node-gzip": "^1.1.2", 40 | "react": "18.2.0", 41 | "react-ace": "11.0.1", 42 | "react-dom": "18.2.0", 43 | "react-dropzone": "^14.2.3", 44 | "react-icons": "5.2.1", 45 | "react-markdown": "9.0.1", 46 | "zustand": "4.5.2" 47 | }, 48 | "devDependencies": { 49 | "@chain-registry/types": "0.44.3", 50 | "@starship-ci/cli": "^2.10.2", 51 | "@tanstack/react-query-devtools": "4.32.0", 52 | "@types/node": "18.11.9", 53 | "@types/node-gzip": "^1", 54 | "@types/react": "18.0.25", 55 | "@types/react-dom": "18.0.9", 56 | "eslint": "8.28.0", 57 | "eslint-config-next": "13.0.5", 58 | "generate-lockfile": "0.0.12", 59 | "starshipjs": "^2.4.1", 60 | "typescript": "4.9.3", 61 | "yaml-loader": "^0.8.1" 62 | }, 63 | "packageManager": "yarn@4.3.0" 64 | } 65 | -------------------------------------------------------------------------------- /templates/chain-admin/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import '../styles/globals.css'; 2 | import '@interchain-ui/react/styles'; 3 | 4 | import type { AppProps } from 'next/app'; 5 | import { ChainProvider } from '@interchain-kit/react'; 6 | import { chains, assetLists } from '@chain-registry/v2'; 7 | import { QueryClientProvider, QueryClient } from '@tanstack/react-query'; 8 | import { Box, Toaster, useTheme } from '@interchain-ui/react'; 9 | // import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; 10 | 11 | import { CustomThemeProvider, Layout } from '@/components'; 12 | import { wallets } from '@/config'; 13 | 14 | const queryClient = new QueryClient({ 15 | defaultOptions: { 16 | queries: { 17 | retry: 2, 18 | refetchOnMount: false, 19 | refetchOnWindowFocus: false, 20 | }, 21 | }, 22 | }); 23 | 24 | function CreateCosmosApp({ Component, pageProps }: AppProps) { 25 | const { themeClass } = useTheme(); 26 | 27 | return ( 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | {/* */} 38 | 39 | 40 | 41 | ); 42 | } 43 | 44 | export default CreateCosmosApp; 45 | -------------------------------------------------------------------------------- /templates/chain-admin/pages/asset-list.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNoSSR } from '@interchain-ui/react-no-ssr'; 2 | import { AssetListSection } from '@/components'; 3 | import { useChainStore } from '@/contexts'; 4 | 5 | export default function AssetListPage() { 6 | const { selectedChain } = useChainStore(); 7 | 8 | return ( 9 | 10 | 11 | 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /templates/chain-admin/pages/governance.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNoSSR } from '@interchain-ui/react-no-ssr'; 2 | import { Voting } from '@/components'; 3 | import { useChainStore } from '@/contexts'; 4 | 5 | export default function GovernancePage() { 6 | const { selectedChain } = useChainStore(); 7 | 8 | return ( 9 | 10 | 11 | 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /templates/chain-admin/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image'; 2 | import { Box, Text, useColorModeValue } from '@interchain-ui/react'; 3 | import { useChain } from '@interchain-kit/react'; 4 | 5 | import { Button } from '@/components'; 6 | import { useChainStore } from '@/contexts'; 7 | import { useDetectBreakpoints, useAddHyperwebChain } from '@/hooks'; 8 | 9 | export default function Home() { 10 | const { isMobile } = useDetectBreakpoints(); 11 | const { isHyperwebAdded } = useAddHyperwebChain(); 12 | 13 | const chainsImageSrc = useColorModeValue( 14 | '/images/chains.png', 15 | '/images/chains-dark.png' 16 | ); 17 | 18 | return ( 19 | <> 20 | 26 | Create Hyperweb App 27 | 28 | 34 | Welcome to Interchain Kit +{' '} 35 | Next.js 36 | 37 | {isHyperwebAdded && } 38 | 43 | chains 54 | 55 | 56 | ); 57 | } 58 | 59 | const HighlightText = ({ children }: { children: string }) => { 60 | return ( 61 | 62 | {children} 63 | 64 | ); 65 | }; 66 | 67 | const ConnectButton = () => { 68 | const { selectedChain } = useChainStore(); 69 | const { connect, address, openView } = useChain(selectedChain); 70 | 71 | return ( 72 | 80 | ); 81 | }; 82 | -------------------------------------------------------------------------------- /templates/chain-admin/pages/staking.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNoSSR } from '@interchain-ui/react-no-ssr'; 2 | import { useChainStore } from '@/contexts'; 3 | import { StakingSection } from '@/components'; 4 | 5 | export default function StakingPage() { 6 | const { selectedChain } = useChainStore(); 7 | 8 | return ( 9 | 10 | 11 | 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /templates/chain-admin/public/images/chains-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperweb-io/create-hyperweb-app/6c533cbf785fe78829709e605ffafeac8d9c9886/templates/chain-admin/public/images/chains-dark.png -------------------------------------------------------------------------------- /templates/chain-admin/public/images/chains.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperweb-io/create-hyperweb-app/6c533cbf785fe78829709e605ffafeac8d9c9886/templates/chain-admin/public/images/chains.png -------------------------------------------------------------------------------- /templates/chain-admin/public/images/contract-file-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /templates/chain-admin/public/images/contract-file.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /templates/chain-admin/public/images/empty.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /templates/chain-admin/public/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperweb-io/create-hyperweb-app/6c533cbf785fe78829709e605ffafeac8d9c9886/templates/chain-admin/public/images/favicon.ico -------------------------------------------------------------------------------- /templates/chain-admin/public/logos/hyperweb-logo-sm.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /templates/chain-admin/starship/configs/config.yaml: -------------------------------------------------------------------------------- 1 | name: starship-devnet 2 | version: 0.2.19 3 | 4 | chains: 5 | - id: hyperweb-1 6 | name: hyperweb 7 | numValidators: 1 8 | image: ghcr.io/cosmology-tech/jsd:0.1.1 9 | coins: 100000000000000uhyper,100000000000000uhypweb,100000000000000uatom,100000000000000uusdc 10 | ports: 11 | rest: 1317 12 | rpc: 26657 13 | faucet: 8000 14 | exposer: 8001 15 | faucet: 16 | enabled: true 17 | type: starship 18 | 19 | registry: 20 | enabled: true 21 | ports: 22 | rest: 8081 23 | 24 | explorer: 25 | enabled: false 26 | ports: 27 | rest: 8080 28 | 29 | images: 30 | imagePullPolicy: Always 31 | -------------------------------------------------------------------------------- /templates/chain-admin/starship/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types'; 2 | -------------------------------------------------------------------------------- /templates/chain-admin/starship/types.ts: -------------------------------------------------------------------------------- 1 | export interface StarshipConfig { 2 | registry: { 3 | ports: { 4 | rest: number; 5 | }; 6 | }; 7 | chains: Array<{ 8 | id: string; 9 | name: string; 10 | ports: { 11 | rpc: number; 12 | rest: number; 13 | faucet: number; 14 | }; 15 | }>; 16 | relayers: Array<{ 17 | chains: [string, string]; 18 | }>; 19 | } 20 | -------------------------------------------------------------------------------- /templates/chain-admin/styles/comp.module.css: -------------------------------------------------------------------------------- 1 | .tabs { 2 | width: 100%; 3 | } 4 | 5 | .tabs ul { 6 | max-width: 600px; 7 | min-width: auto; 8 | margin: 0 auto; 9 | } 10 | 11 | .input-pl { 12 | padding-left: 36px; 13 | } 14 | 15 | .input-pr { 16 | padding-right: 66px; 17 | } 18 | -------------------------------------------------------------------------------- /templates/chain-admin/styles/globals.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | padding: 0; 4 | margin: 0; 5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 7 | } 8 | 9 | a { 10 | color: inherit; 11 | text-decoration: none; 12 | } 13 | 14 | * { 15 | box-sizing: border-box; 16 | } 17 | -------------------------------------------------------------------------------- /templates/chain-admin/styles/layout.module.css: -------------------------------------------------------------------------------- 1 | .layout { 2 | padding-left: calc(100vw - 100%); /* prevent scrollbar layout shift */ 3 | } 4 | -------------------------------------------------------------------------------- /templates/chain-admin/styles/utils.module.css: -------------------------------------------------------------------------------- 1 | .threeLineClamp { 2 | display: -webkit-box; 3 | line-clamp: 3; 4 | -webkit-line-clamp: 3; 5 | -webkit-box-orient: vertical; 6 | overflow: hidden; 7 | text-overflow: ellipsis; 8 | white-space: normal; 9 | } 10 | -------------------------------------------------------------------------------- /templates/chain-admin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "baseUrl": ".", 18 | "paths": { 19 | "@/*": ["*"] 20 | } 21 | }, 22 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 23 | "exclude": ["node_modules"] 24 | } 25 | -------------------------------------------------------------------------------- /templates/chain-admin/utils/asset-list/format.ts: -------------------------------------------------------------------------------- 1 | import BigNumber from 'bignumber.js'; 2 | import { PrettyAsset } from '@/components'; 3 | import { AvailableItem } from '@interchain-ui/react'; 4 | 5 | export const truncDecimals = ( 6 | val: string | number | undefined, 7 | decimals: number 8 | ) => { 9 | return new BigNumber(val || 0).decimalPlaces(decimals).toString(); 10 | }; 11 | 12 | export const formatDollarValue = (dollarValue: string, amount: string) => { 13 | return new BigNumber(dollarValue).gt(0.01) 14 | ? '$' + truncDecimals(dollarValue, 2) 15 | : new BigNumber(amount).gt(0) 16 | ? '< $0.01' 17 | : '$0'; 18 | }; 19 | 20 | export const prettyAssetToTransferItem = (from: PrettyAsset): AvailableItem => { 21 | return { 22 | imgSrc: from.logoUrl ?? '', 23 | symbol: from.symbol, 24 | name: from.prettyChainName, 25 | denom: from.denom, 26 | available: new BigNumber(from.displayAmount).toNumber(), 27 | priceDisplayAmount: new BigNumber( 28 | truncDecimals(from.dollarValue, 2) 29 | ).toNumber(), 30 | }; 31 | }; 32 | -------------------------------------------------------------------------------- /templates/chain-admin/utils/asset-list/index.ts: -------------------------------------------------------------------------------- 1 | export * from './format'; 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /templates/chain-admin/utils/asset-list/types.ts: -------------------------------------------------------------------------------- 1 | import { AssetDenomUnit } from '@chain-registry/types'; 2 | 3 | export type CoinDenom = AssetDenomUnit['denom']; 4 | 5 | export type Exponent = AssetDenomUnit['exponent']; 6 | 7 | export type CoinSymbol = string; 8 | 9 | export interface PriceHash { 10 | [key: CoinDenom]: number; 11 | } 12 | 13 | export type CoinGeckoToken = string; 14 | 15 | export interface CoinGeckoUSD { 16 | usd: number; 17 | } 18 | 19 | export type CoinGeckoUSDResponse = Record; 20 | 21 | export interface CoinValue { 22 | amount: string; 23 | denom: CoinDenom; 24 | displayAmount: string; 25 | value: string; 26 | symbol: CoinSymbol; 27 | } 28 | -------------------------------------------------------------------------------- /templates/chain-admin/utils/common.ts: -------------------------------------------------------------------------------- 1 | import { Wallet } from '@interchain-kit/core'; 2 | import { Asset, AssetList, Chain } from '@chain-registry/v2-types'; 3 | import BigNumber from 'bignumber.js'; 4 | 5 | export const getNativeAsset = (assets: AssetList) => { 6 | return assets.assets[0] as Asset; 7 | }; 8 | 9 | export const getExponentFromAsset = (asset: Asset) => { 10 | const unit = asset.denomUnits.find((unit) => unit.denom === asset.display); 11 | return unit?.exponent ?? 6; 12 | }; 13 | 14 | export const shortenAddress = (address: string, partLength = 6) => { 15 | return `${address.slice(0, partLength)}...${address.slice(-partLength)}`; 16 | }; 17 | 18 | export const getWalletLogo = (wallet?: Wallet) => { 19 | if (!wallet?.logo) return ''; 20 | 21 | return typeof wallet.logo === 'string' 22 | ? wallet.logo 23 | : wallet.logo.major || wallet.logo.minor; 24 | }; 25 | 26 | function toCamelCase(key: string) { 27 | return ( 28 | key 29 | // First, remove all leading non-alphabet characters except $ 30 | .replace(/^[^a-zA-Z$]+/, '') 31 | // Convert what follows a separator into upper case 32 | .replace(/[-_\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : '')) 33 | // Ensure the first character of the result is always lowercase 34 | .replace(/^./, (c) => c.toLowerCase()) 35 | ); 36 | } 37 | 38 | export function convertKeysToCamelCase(obj: any): any { 39 | if (typeof obj !== 'object' || obj === null) { 40 | return obj; 41 | } 42 | 43 | if (Array.isArray(obj)) { 44 | return obj.map((item) => convertKeysToCamelCase(item)); 45 | } 46 | 47 | return Object.keys(obj).reduce((result, key) => { 48 | const camelKey = toCamelCase(key); 49 | const value = convertKeysToCamelCase(obj[key]); 50 | result[camelKey as keyof typeof result] = value; 51 | return result; 52 | }, {} as Record); 53 | } 54 | 55 | export const convertGasToTokenAmount = ( 56 | gasAmount: string, 57 | chain: Chain, 58 | exponent: number 59 | ) => { 60 | const gasPrice = chain.fees?.feeTokens[0].averageGasPrice ?? 0.025; 61 | return BigNumber(gasAmount).shiftedBy(-exponent).multipliedBy(gasPrice); 62 | }; 63 | -------------------------------------------------------------------------------- /templates/chain-admin/utils/faucet.ts: -------------------------------------------------------------------------------- 1 | import { fromBech32 } from '@interchainjs/encoding'; 2 | 3 | export const creditFromFaucet = async ( 4 | address: string, 5 | denom: string, 6 | port: number 7 | ) => { 8 | const faucetEndpoint = `http://localhost:${port}/credit`; 9 | 10 | await fetch(faucetEndpoint, { 11 | method: 'POST', 12 | body: JSON.stringify({ 13 | address, 14 | denom, 15 | }), 16 | headers: { 17 | 'Content-type': 'application/json', 18 | }, 19 | }); 20 | }; 21 | 22 | export const validateChainAddress = (address: string, bech32Prefix: string) => { 23 | if (!address.startsWith(bech32Prefix)) { 24 | return `Invalid prefix (expected "${bech32Prefix}")`; 25 | } 26 | 27 | try { 28 | fromBech32(address); 29 | } catch (e) { 30 | return 'Invalid address'; 31 | } 32 | 33 | return null; 34 | }; 35 | -------------------------------------------------------------------------------- /templates/chain-admin/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './common'; 2 | export * from './staking'; 3 | export * from './voting'; 4 | export * from './asset-list'; 5 | export * from './contract'; 6 | export * from './faucet'; 7 | -------------------------------------------------------------------------------- /templates/chain-admin/utils/staking/index.ts: -------------------------------------------------------------------------------- 1 | export * from './math'; 2 | export * from './logos'; 3 | export * from './staking'; 4 | -------------------------------------------------------------------------------- /templates/chain-admin/utils/staking/math.ts: -------------------------------------------------------------------------------- 1 | import { Prices } from '@/hooks'; 2 | import BigNumber from 'bignumber.js'; 3 | 4 | export const isGreaterThanZero = (val: number | string | undefined) => { 5 | return new BigNumber(val || 0).gt(0); 6 | }; 7 | 8 | export const shiftDigits = ( 9 | num: string | number, 10 | places: number, 11 | decimalPlaces?: number 12 | ) => { 13 | return new BigNumber(num) 14 | .shiftedBy(places) 15 | .decimalPlaces(decimalPlaces || 6) 16 | .toString(); 17 | }; 18 | 19 | export const toNumber = (val: string, decimals: number = 6) => { 20 | return new BigNumber(val).decimalPlaces(decimals).toNumber(); 21 | }; 22 | 23 | export const sum = (...args: string[]) => { 24 | return args 25 | .reduce( 26 | (prev, cur) => prev.plus(new BigNumber(cur).isNaN() ? 0 : cur), 27 | new BigNumber(0) 28 | ) 29 | .toString(); 30 | }; 31 | 32 | export const calcDollarValue = ( 33 | denom: string, 34 | amount: string | number, 35 | prices: Prices 36 | ) => { 37 | return new BigNumber(prices?.[denom] || 0) 38 | .times(amount) 39 | .decimalPlaces(2) 40 | .toNumber(); 41 | }; 42 | 43 | export const toBaseAmount = (num: string | number, places: number) => { 44 | return new BigNumber(num) 45 | .shiftedBy(places) 46 | .integerValue(BigNumber.ROUND_DOWN) 47 | .toString(); 48 | }; 49 | -------------------------------------------------------------------------------- /templates/chain-admin/utils/voting.ts: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs'; 2 | import BigNumber from 'bignumber.js'; 3 | import { Chain } from '@chain-registry/types'; 4 | import { 5 | Proposal, 6 | ProposalStatus, 7 | } from '@interchainjs/react/cosmos/gov/v1beta1/gov'; 8 | 9 | export function getChainLogo(chain: Chain) { 10 | return chain.logo_URIs?.svg || chain.logo_URIs?.png || chain.logo_URIs?.jpeg; 11 | } 12 | 13 | export function formatDate(date?: Date) { 14 | if (!date) return null; 15 | return dayjs(date).format('YYYY-MM-DD HH:mm:ss'); 16 | } 17 | 18 | export function paginate(limit: bigint, reverse: boolean = false) { 19 | return { 20 | limit, 21 | reverse, 22 | key: new Uint8Array(), 23 | offset: 0n, 24 | countTotal: true, 25 | }; 26 | } 27 | 28 | export function percent(num: number | string = 0, total: number, decimals = 2) { 29 | return total 30 | ? new BigNumber(num) 31 | .dividedBy(total) 32 | .multipliedBy(100) 33 | .decimalPlaces(decimals) 34 | .toNumber() 35 | : 0; 36 | } 37 | 38 | export const exponentiate = (num: number | string | undefined, exp: number) => { 39 | if (!num) return 0; 40 | return new BigNumber(num) 41 | .multipliedBy(new BigNumber(10).exponentiatedBy(exp)) 42 | .toNumber(); 43 | }; 44 | 45 | export function decodeUint8Array(value?: Uint8Array) { 46 | return value ? new TextDecoder('utf-8').decode(value) : ''; 47 | } 48 | 49 | export function getTitle(value?: Uint8Array) { 50 | return decodeUint8Array(value) 51 | .slice(0, 250) 52 | .match(/[A-Z][A-Za-z].*(?=\u0012)/)?.[0]; 53 | } 54 | 55 | export function parseQuorum(value?: Uint8Array) { 56 | const quorum = decodeUint8Array(value); 57 | return new BigNumber(quorum).shiftedBy(-quorum.length).toNumber(); 58 | } 59 | 60 | export function processProposals(proposals: Proposal[]) { 61 | const sorted = proposals.sort( 62 | (a, b) => Number(b.proposalId) - Number(a.proposalId) 63 | ); 64 | 65 | proposals.forEach((proposal) => { 66 | // @ts-ignore 67 | if (!proposal.content?.title && proposal.content?.value) { 68 | // @ts-ignore 69 | proposal.content.title = getTitle(proposal.content?.value); 70 | } 71 | }); 72 | 73 | return sorted 74 | .filter( 75 | ({ status }) => status === ProposalStatus.PROPOSAL_STATUS_VOTING_PERIOD 76 | ) 77 | .concat( 78 | sorted.filter( 79 | ({ status }) => status !== ProposalStatus.PROPOSAL_STATUS_VOTING_PERIOD 80 | ) 81 | ); 82 | } 83 | -------------------------------------------------------------------------------- /templates/hyperweb/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true, 5 | "node": true, 6 | "jest": true 7 | }, 8 | "extends": [ 9 | "eslint:recommended", 10 | "plugin:@typescript-eslint/recommended", 11 | "prettier" 12 | ], 13 | "overrides": [], 14 | "parser": "@typescript-eslint/parser", 15 | "parserOptions": { 16 | "ecmaVersion": "latest", 17 | "sourceType": "module" 18 | }, 19 | "plugins": ["@typescript-eslint", "simple-import-sort", "unused-imports"], 20 | "rules": { 21 | "simple-import-sort/imports": 1, 22 | "simple-import-sort/exports": 1, 23 | "unused-imports/no-unused-imports": 1, 24 | "@typescript-eslint/no-unused-vars": [ 25 | 1, 26 | { 27 | "argsIgnorePattern": "React|res|next|^_" 28 | } 29 | ], 30 | "@typescript-eslint/no-explicit-any": 0, 31 | "@typescript-eslint/no-var-requires": 0, 32 | "no-console": 0, 33 | "@typescript-eslint/ban-ts-comment": 0, 34 | "prefer-const": 0, 35 | "no-case-declarations": 0, 36 | "no-implicit-globals": 0, 37 | "@typescript-eslint/no-unsafe-declaration-merging": 0 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /templates/hyperweb/.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | workflow_dispatch: 11 | 12 | jobs: 13 | e2e-tests: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Checkout Repository 📝 18 | uses: actions/checkout@v4 19 | 20 | - name: Setup Node.js 21 | uses: actions/setup-node@v4 22 | with: 23 | node-version: "20.x" 24 | cache: "yarn" 25 | 26 | - name: Install Dependencies 27 | run: yarn install --frozen-lockfile 28 | 29 | - name: Build contracts 30 | run: yarn build 31 | -------------------------------------------------------------------------------- /templates/hyperweb/.github/workflows/e2e-docker-tests.yaml: -------------------------------------------------------------------------------- 1 | name: Run E2E Docker Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | workflow_dispatch: 11 | 12 | jobs: 13 | e2e-tests: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Checkout Repository 📝 18 | uses: actions/checkout@v4 19 | 20 | - name: Setup Node.js 21 | uses: actions/setup-node@v4 22 | with: 23 | node-version: "20.x" 24 | cache: "yarn" 25 | 26 | - name: Install Dependencies 27 | run: yarn install --frozen-lockfile 28 | 29 | - name: Build contracts 30 | run: yarn build 31 | 32 | - name: Run docker infra 33 | run: | 34 | yarn run docker 35 | sleep 5 36 | 37 | - name: Run E2E Tests 38 | run: yarn test 39 | -------------------------------------------------------------------------------- /templates/hyperweb/.github/workflows/e2e-tests.yaml: -------------------------------------------------------------------------------- 1 | name: Run E2E Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | workflow_dispatch: 11 | 12 | jobs: 13 | e2e-tests: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Checkout Repository 📝 18 | uses: actions/checkout@v4 19 | 20 | - name: Setup Node.js 21 | uses: actions/setup-node@v4 22 | with: 23 | node-version: "20.x" 24 | cache: "yarn" 25 | 26 | - name: Install Dependencies 27 | run: yarn install --frozen-lockfile 28 | 29 | - name: Build contracts 30 | run: yarn build 31 | 32 | - name: Set Up Starship Infrastructure 33 | id: starship-infra 34 | uses: cosmology-tech/starship-action@0.5.9 35 | with: 36 | config: configs/ci.yaml 37 | cli-version: 3.3.0 38 | 39 | - name: Run E2E Tests 40 | run: yarn test 41 | -------------------------------------------------------------------------------- /templates/hyperweb/.gitignore: -------------------------------------------------------------------------------- 1 | **/node_modules/ 2 | **/.DS_Store 3 | **/yarn-error.log 4 | lerna-debug.log 5 | 6 | **/.idea 7 | 8 | **/.next 9 | next-env.d.ts -------------------------------------------------------------------------------- /templates/hyperweb/.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "tabWidth": 2, 4 | "semi": true, 5 | "singleQuote": false 6 | } 7 | -------------------------------------------------------------------------------- /templates/hyperweb/.questions.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "__USERFULLNAME__", 4 | "message": "Enter author full name", 5 | "required": true 6 | }, 7 | { 8 | "name": "__USEREMAIL__", 9 | "message": "Enter author email", 10 | "required": true 11 | }, 12 | { 13 | "name": "__MODULENAME__", 14 | "message": "Enter the module name", 15 | "required": true 16 | }, 17 | { 18 | "name": "__MODULEDESC__", 19 | "message": "Enter the module description", 20 | "required": true 21 | }, 22 | { 23 | "name": "__REPONAME__", 24 | "message": "Enter the repository name", 25 | "required": true 26 | }, 27 | { 28 | "name": "__USERNAME__", 29 | "message": "Enter your github username", 30 | "required": true 31 | }, 32 | { 33 | "name": "__ACCESS__", 34 | "message": "Module access?", 35 | "choices": [ 36 | "public", 37 | "restricted" 38 | ], 39 | "type": "list", 40 | "required": true 41 | } 42 | ] 43 | -------------------------------------------------------------------------------- /templates/hyperweb/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [0.0.5](https://github.com/__USERNAME__/__REPONAME__/compare/hyperweb@0.0.4...hyperweb@0.0.5) (2024-10-21) 7 | 8 | **Note:** Version bump only for package hyperweb 9 | 10 | 11 | 12 | 13 | 14 | ## [0.0.4](https://github.com/__USERNAME__/__REPONAME__/compare/hyperweb@0.0.3...hyperweb@0.0.4) (2024-10-21) 15 | 16 | **Note:** Version bump only for package hyperweb 17 | 18 | 19 | 20 | 21 | 22 | ## [0.0.3](https://github.com/__USERNAME__/__REPONAME__/compare/hyperweb@0.0.2...hyperweb@0.0.3) (2024-10-04) 23 | 24 | **Note:** Version bump only for package hyperweb 25 | 26 | 27 | 28 | 29 | 30 | ## 0.0.2 (2024-10-04) 31 | 32 | **Note:** Version bump only for package hyperweb 33 | -------------------------------------------------------------------------------- /templates/hyperweb/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2025 Interweb, inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /templates/hyperweb/__tests__/setup.test.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | import path from 'path'; 3 | 4 | import { StargateClient } from '@cosmjs/stargate'; 5 | 6 | import { ConfigContext, useChain, useRegistry } from 'starshipjs'; 7 | 8 | beforeAll(async () => { 9 | const configFile = path.join(__dirname, '..', 'configs', 'local.yaml'); 10 | ConfigContext.setConfigFile(configFile); 11 | ConfigContext.setRegistry(await useRegistry(configFile)); 12 | }); 13 | 14 | describe('Test clients', () => { 15 | let client; 16 | 17 | beforeAll(async () => { 18 | const { getRpcEndpoint } = useChain('hyperweb'); 19 | client = await StargateClient.connect(await getRpcEndpoint()); 20 | }); 21 | 22 | it('check chain height', async () => { 23 | const height = await client.getHeight(); 24 | 25 | expect(height).toBeGreaterThan(0); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /templates/hyperweb/configs/ci.yaml: -------------------------------------------------------------------------------- 1 | name: starship-devnet 2 | version: 1.3.0 3 | 4 | chains1: 5 | - id: hyperweb-1 6 | name: hyperweb 7 | numValidators: 1 8 | image: ghcr.io/hyperweb-io/hyperweb:latest 9 | coins: 100000000000000uhyper,100000000000000uhypweb,100000000000000uatom,100000000000000uusdc 10 | ports: 11 | rest: 1317 12 | rpc: 26657 13 | faucet: 8000 14 | exposer: 8001 15 | resources: 16 | cpu: "0.4" 17 | memory: "400M" 18 | faucet: 19 | enabled: true 20 | type: starship 21 | concurrency: 2 22 | resources: 23 | cpu: "0.2" 24 | memory: "200M" 25 | 26 | registry: 27 | enabled: true 28 | ports: 29 | rest: 8081 30 | resources: 31 | cpu: "0.1" 32 | memory: "100M" 33 | 34 | images: 35 | imagePullPolicy: Always 36 | -------------------------------------------------------------------------------- /templates/hyperweb/configs/local.yaml: -------------------------------------------------------------------------------- 1 | name: starship-devnet 2 | version: 1.3.0 3 | 4 | chains: 5 | - id: hyperweb-1 6 | name: hyperweb 7 | numValidators: 1 8 | image: ghcr.io/hyperweb-io/hyperweb:latest 9 | coins: 100000000000000uhyper,100000000000000uhypweb,100000000000000uatom,100000000000000uusdc 10 | ports: 11 | rest: 1317 12 | rpc: 26657 13 | faucet: 8000 14 | exposer: 8001 15 | faucet: 16 | enabled: true 17 | type: starship 18 | 19 | registry: 20 | enabled: true 21 | ports: 22 | rest: 8081 23 | 24 | explorer: 25 | enabled: true 26 | ports: 27 | rest: 8080 28 | 29 | images: 30 | imagePullPolicy: Always 31 | -------------------------------------------------------------------------------- /templates/hyperweb/dist/contracts/simpleState.js: -------------------------------------------------------------------------------- 1 | // src/simple-state/index.ts 2 | var Contract = class { 3 | state; 4 | constructor() { 5 | console.log("[Contract] constructor called"); 6 | } 7 | reset() { 8 | console.log("[Contract] reset called"); 9 | this.state.value = 0; 10 | } 11 | init() { 12 | console.log("[Contract] init called"); 13 | this.state.value = 0; 14 | return this.state.value; 15 | } 16 | inc(x) { 17 | console.log("[Contract] inc called"); 18 | this.state.value += x; 19 | return this.state.value; 20 | } 21 | dec(x) { 22 | console.log("[Contract] dec called"); 23 | this.state.value -= x; 24 | } 25 | read() { 26 | console.log("[Contract] read called"); 27 | return this.state.value; 28 | } 29 | }; 30 | export { 31 | Contract as default 32 | }; 33 | //# sourceMappingURL=simpleState.js.map 34 | -------------------------------------------------------------------------------- /templates/hyperweb/dist/contracts/simpleState.js.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "sources": ["../../src/simple-state/index.ts"], 4 | "sourcesContent": ["export interface State {\n value: number;\n}\n\nexport default class Contract {\n state: State;\n\n constructor() {\n console.log(\"[Contract] constructor called\");\n }\n\n reset() {\n console.log(\"[Contract] reset called\");\n this.state.value = 0;\n }\n\n init(): number {\n console.log(\"[Contract] init called\");\n this.state.value = 0;\n return this.state.value\n }\n\n inc(x: number): number {\n console.log(\"[Contract] inc called\");\n this.state.value += x;\n return this.state.value;\n }\n\n dec(x: number) {\n console.log(\"[Contract] dec called\");\n this.state.value -= x;\n }\n\n read() {\n console.log(\"[Contract] read called\");\n return this.state.value;\n }\n}\n"], 5 | "mappings": ";AAIA,IAAqB,WAArB,MAA8B;AAAA,EAC5B;AAAA,EAEA,cAAc;AACZ,YAAQ,IAAI,+BAA+B;AAAA,EAC7C;AAAA,EAEA,QAAQ;AACN,YAAQ,IAAI,yBAAyB;AACrC,SAAK,MAAM,QAAQ;AAAA,EACrB;AAAA,EAEA,OAAe;AACb,YAAQ,IAAI,wBAAwB;AACpC,SAAK,MAAM,QAAQ;AACnB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EAEA,IAAI,GAAmB;AACrB,YAAQ,IAAI,uBAAuB;AACnC,SAAK,MAAM,SAAS;AACpB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EAEA,IAAI,GAAW;AACb,YAAQ,IAAI,uBAAuB;AACnC,SAAK,MAAM,SAAS;AAAA,EACtB;AAAA,EAEA,OAAO;AACL,YAAQ,IAAI,wBAAwB;AACpC,WAAO,KAAK,MAAM;AAAA,EACpB;AACF;", 6 | "names": [] 7 | } 8 | -------------------------------------------------------------------------------- /templates/hyperweb/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | testTimeout: 150000, 6 | transform: { 7 | "^.+\\.tsx?$": [ 8 | "ts-jest", 9 | { 10 | babelConfig: false, 11 | tsconfig: "tsconfig.json", 12 | }, 13 | ], 14 | }, 15 | transformIgnorePatterns: [`/node_modules/*`], 16 | testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", 17 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], 18 | modulePathIgnorePatterns: ["dist/*"] 19 | }; 20 | -------------------------------------------------------------------------------- /templates/hyperweb/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hyperweb", 3 | "version": "0.0.5", 4 | "author": "__USERFULLNAME__ <__USEREMAIL__>", 5 | "description": "__MODULEDESC__", 6 | "homepage": "https://github.com/__USERNAME__/__REPONAME__", 7 | "license": "SEE LICENSE IN LICENSE", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/__USERNAME__/__REPONAME__" 11 | }, 12 | "bugs": { 13 | "url": "https://github.com/__USERNAME__/__REPONAME__/issues" 14 | }, 15 | "publishConfig": { 16 | "access": "__ACCESS__", 17 | "directory": "dist" 18 | }, 19 | "scripts": { 20 | "dev": "next dev ./ui", 21 | "start": "next start ./ui", 22 | "lint": "next lint ./ui", 23 | "build:ui": "next build ./ui", 24 | "clean": "rimraf dist/contracts/**", 25 | "build": "ts-node scripts/build.ts", 26 | "test": "jest --verbose --bail", 27 | "test:debug": "jest --runInBand --verbose --bail", 28 | "docker": "npm run docker:stop && npm run docker:run", 29 | "docker:run": "docker run -d --name hyperweb-plus -p 26657:26657 -p 1317:1317 -p 8000:8000 -p 8001:8001 -p 8081:8081 ghcr.io/hyperweb-io/hyperweb-plus:latest", 30 | "docker:exec": "docker exec -it hyperweb-plus /bin/bash", 31 | "docker:stop": "docker stop hyperweb-plus || true && docker rm hyperweb-plus || true", 32 | "starship": "starship --config configs/local.yaml", 33 | "starship:ci": "starship --config configs/ci.yaml" 34 | }, 35 | "resolutions": { 36 | "react": "18.2.0", 37 | "react-dom": "18.2.0", 38 | "@types/react": "18.0.25", 39 | "@types/react-dom": "18.0.9" 40 | }, 41 | "dependencies": { 42 | "@chain-registry/types": "^0.50.18", 43 | "@interchain-kit/core": "0.0.1-beta.62", 44 | "@interchain-kit/keplr-extension": "0.0.1-beta.62", 45 | "@interchain-kit/leap-extension": "0.0.1-beta.62", 46 | "@interchain-kit/react": "0.0.1-beta.62", 47 | "@interchain-ui/react": "1.26.1", 48 | "@interchain-ui/react-no-ssr": "^0.1.6", 49 | "interchain-kit": "0.0.1-beta.62", 50 | "next": "^13", 51 | "react": "18.2.0", 52 | "react-dom": "18.2.0", 53 | "react-icons": "4.6.0" 54 | }, 55 | "devDependencies": { 56 | "@hyperweb/build": "^1.0.1", 57 | "@interchainjs/cosmos": "^1.9.12", 58 | "@starship-ci/cli": "^3.3.0", 59 | "@types/jest": "^29.5.11", 60 | "@types/node": "^22.7.4", 61 | "@types/react": "18.2.0", 62 | "@types/react-dom": "18.2.0", 63 | "@typescript-eslint/eslint-plugin": "^6.18.1", 64 | "@typescript-eslint/parser": "^6.18.1", 65 | "eslint": "^8.56.0", 66 | "eslint-config-next": "13.0.5", 67 | "eslint-config-prettier": "^9.1.0", 68 | "eslint-plugin-simple-import-sort": "^10.0.0", 69 | "eslint-plugin-unused-imports": "^3.0.0", 70 | "generate-lockfile": "0.0.12", 71 | "hyperwebjs": "1.1.1", 72 | "jest": "^29.6.2", 73 | "prettier": "^3.0.2", 74 | "rimraf": "4.4.1", 75 | "starshipjs": "^3.3.0", 76 | "ts-jest": "^29.1.1", 77 | "ts-node": "^10.9.2", 78 | "typescript": "^5.1.6" 79 | }, 80 | "keywords": [], 81 | "packageManager": "yarn@4.3.0", 82 | "gitHead": "d7557df95ccbe65022679a20d52e2f3bfc8af6f5" 83 | } 84 | -------------------------------------------------------------------------------- /templates/hyperweb/scripts/build.ts: -------------------------------------------------------------------------------- 1 | import { HyperwebBuild, HyperwebBuildOptions } from "@hyperweb/build"; 2 | import { join } from "path"; 3 | 4 | import { configs, type BuildConfig } from "./configs"; 5 | 6 | const rootDir = join(__dirname, "/../"); 7 | 8 | async function buildInterweb(config: BuildConfig): Promise { 9 | const { entryFile, outFile, externalPackages } = config; 10 | 11 | const options: Partial = { 12 | entryPoints: [join(rootDir, entryFile)], 13 | outfile: join(rootDir, outFile), 14 | external: externalPackages, 15 | }; 16 | 17 | try { 18 | await HyperwebBuild.build(options); 19 | console.log(`Build completed successfully! Output: ${options.outfile}`); 20 | } catch (error) { 21 | console.error("Build failed:", error); 22 | throw error; 23 | } 24 | } 25 | 26 | async function main() { 27 | for (const config of configs) { 28 | try { 29 | await buildInterweb(config); 30 | } catch (error) { 31 | console.error(`Build failed for ${config.entryFile}:`, error); 32 | } 33 | } 34 | } 35 | 36 | main().catch(console.error); 37 | -------------------------------------------------------------------------------- /templates/hyperweb/scripts/configs.ts: -------------------------------------------------------------------------------- 1 | export interface BuildConfig { 2 | entryFile: string; 3 | outFile: string; 4 | externalPackages: string[]; 5 | } 6 | 7 | export const configs: BuildConfig[] = [ 8 | { 9 | entryFile: "src/simple-state/index.ts", 10 | outFile: "dist/contracts/simpleState.js", 11 | externalPackages: ["otherpackage", "~somepackage"], 12 | }, 13 | ]; 14 | -------------------------------------------------------------------------------- /templates/hyperweb/src/simple-state/index.ts: -------------------------------------------------------------------------------- 1 | export interface State { 2 | value: number; 3 | } 4 | 5 | export default class Contract { 6 | state: State; 7 | 8 | constructor() { 9 | console.log("[Contract] constructor called"); 10 | } 11 | 12 | reset() { 13 | console.log("[Contract] reset called"); 14 | this.state.value = 0; 15 | } 16 | 17 | init(): number { 18 | console.log("[Contract] init called"); 19 | this.state.value = 0; 20 | return this.state.value 21 | } 22 | 23 | inc(x: number): number { 24 | console.log("[Contract] inc called"); 25 | this.state.value += x; 26 | return this.state.value; 27 | } 28 | 29 | dec(x: number) { 30 | console.log("[Contract] dec called"); 31 | this.state.value -= x; 32 | } 33 | 34 | read() { 35 | console.log("[Contract] read called"); 36 | return this.state.value; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /templates/hyperweb/test-utils/sleep.ts: -------------------------------------------------------------------------------- 1 | export function sleep(time: number) { 2 | return new Promise((resolve) => setTimeout(resolve, time)); 3 | } 4 | -------------------------------------------------------------------------------- /templates/hyperweb/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist/esm", 5 | "module": "es2022", 6 | "rootDir": "src/", 7 | "declaration": false 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /templates/hyperweb/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "dist", 4 | "rootDir": "src/", 5 | "target": "es2022", 6 | "module": "commonjs", 7 | "esModuleInterop": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "strict": true, 10 | "strictNullChecks": false, 11 | "skipLibCheck": true, 12 | "sourceMap": true, 13 | "declaration": true, 14 | "resolveJsonModule": true, 15 | "moduleResolution": "node" 16 | }, 17 | "include": ["src/**/*"], 18 | "exclude": ["dist", "node_modules", "**/*.spec.*", "**/*.test.*"] 19 | } 20 | -------------------------------------------------------------------------------- /templates/hyperweb/ui/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /templates/hyperweb/ui/components/common/Header.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Box, 3 | Button, 4 | Icon, 5 | Link, 6 | Text, 7 | useColorModeValue, 8 | useTheme, 9 | } from "@interchain-ui/react"; 10 | 11 | const stacks = ["Interchain Kit", "Next.js", "InterchainJS"]; 12 | 13 | export function Header() { 14 | const { theme, setTheme } = useTheme(); 15 | 16 | const toggleColorMode = () => { 17 | setTheme(theme === "light" ? "dark" : "light"); 18 | }; 19 | 20 | return ( 21 | <> 22 | 23 | 33 | 34 | 35 | 36 | 44 | Create Hyperweb App 45 | 46 | 47 | 51 | Welcome to  52 | 53 | 58 | {stacks.join(" + ")} 59 | 60 | 61 | 62 | 63 | ); 64 | } 65 | -------------------------------------------------------------------------------- /templates/hyperweb/ui/components/common/Layout.tsx: -------------------------------------------------------------------------------- 1 | import Head from "next/head"; 2 | import { Container } from "@interchain-ui/react"; 3 | import { Header } from "./Header"; 4 | import { Footer } from "./Footer"; 5 | 6 | export function Layout({ children }: { children: React.ReactNode }) { 7 | return ( 8 | 9 | 10 | Create Hyperweb App 11 | 12 | 13 | 14 |
15 | {children} 16 |