├── README.md ├── cli ├── rest │ ├── node │ │ ├── requests.go │ │ └── routes.go │ ├── plan │ │ ├── requests.go │ │ └── routes.go │ ├── deposit │ │ ├── requests.go │ │ ├── routes.go │ │ └── handlers.go │ ├── service │ │ ├── requests.go │ │ ├── responses.go │ │ └── routes.go │ ├── provider │ │ ├── requests.go │ │ └── routes.go │ ├── bank │ │ ├── routes.go │ │ ├── requests.go │ │ └── handlers.go │ ├── account │ │ ├── routes.go │ │ └── handlers.go │ ├── distribution │ │ ├── routes.go │ │ └── requests.go │ ├── config │ │ ├── routes.go │ │ └── requests.go │ ├── session │ │ ├── requests.go │ │ └── routes.go │ ├── gov │ │ ├── routes.go │ │ └── requests.go │ ├── keys │ │ ├── requests.go │ │ └── routes.go │ ├── staking │ │ └── routes.go │ └── subscription │ │ ├── routes.go │ │ └── requests.go ├── .gitignore ├── services │ └── wireguard │ │ ├── types │ │ ├── vars.go │ │ ├── ip.go │ │ └── key.go │ │ ├── wireguard_windows.go │ │ ├── wireguard_darwin.go │ │ └── wireguard_linux.go ├── cmd │ └── flags.go ├── types │ ├── flags.go │ ├── errors.go │ ├── keys.go │ ├── rest.go │ └── service.go ├── utils │ ├── errors.go │ ├── rand.go │ ├── freeport.go │ └── rest.go ├── middlewares │ ├── headers.go │ ├── log.go │ └── auth.go ├── x │ ├── common │ │ ├── bandwidth.go │ │ ├── deposit.go │ │ └── key.go │ ├── gov │ │ └── vote.go │ ├── subscription │ │ ├── quota.go │ │ └── subscription.go │ ├── provider │ │ └── provider.go │ ├── auth │ │ └── account.go │ ├── node │ │ └── node.go │ ├── plan │ │ └── plan.go │ ├── staking │ │ └── delegation.go │ └── session │ │ └── session.go ├── Makefile ├── go.mod ├── lite │ └── tx.go ├── .golangci.yml └── context │ └── context.go ├── electron ├── icon.png ├── icon.ico ├── icon.icns ├── preload.js ├── channels.js ├── globals.js ├── entitlements.mac.plist ├── api.js └── index.js ├── .eslintignore ├── .env ├── public ├── robots.txt ├── favicon.ico ├── assets │ ├── 192x192.png │ └── 512x512.png ├── manifest.json └── index.html ├── src ├── assets │ ├── Loader.gif │ ├── Success.svg │ ├── Checkbox.svg │ ├── Failure.svg │ └── Collapse.svg ├── containers │ ├── common │ │ ├── _validation.js │ │ ├── Snackbar.js │ │ ├── SidebarOnboard.js │ │ └── SidebarDashboard.js │ ├── Wallet │ │ ├── WithdrawRewards │ │ │ ├── Modal │ │ │ │ ├── _validation.js │ │ │ │ ├── FromAddress.js │ │ │ │ ├── FromName.js │ │ │ │ ├── Memo.js │ │ │ │ └── Withdraw.js │ │ │ ├── _validation.js │ │ │ └── Withdraw.js │ │ ├── Validators │ │ │ ├── ModalUnbond │ │ │ │ ├── _validation.js │ │ │ │ ├── FromAddress.js │ │ │ │ ├── FromName.js │ │ │ │ └── Memo.js │ │ │ ├── ModalDelegate │ │ │ │ ├── _validation.js │ │ │ │ ├── ToAddress.js │ │ │ │ ├── ToName.js │ │ │ │ └── Memo.js │ │ │ ├── ModalRedelegate │ │ │ │ ├── _validation.js │ │ │ │ ├── FromAddress.js │ │ │ │ ├── FromName.js │ │ │ │ ├── Memo.js │ │ │ │ └── ToAddress.js │ │ │ ├── Row │ │ │ │ ├── Unbond.js │ │ │ │ ├── Delegate.js │ │ │ │ ├── Redelegate.js │ │ │ │ └── Avatar.js │ │ │ └── Status.js │ │ ├── Proposals │ │ │ ├── Modal │ │ │ │ ├── _validation.js │ │ │ │ └── Memo.js │ │ │ ├── Row │ │ │ │ ├── Type.js │ │ │ │ ├── Percentage.js │ │ │ │ ├── DepositEnd.js │ │ │ │ ├── IntialDeposit.js │ │ │ │ ├── SubmitTIme.js │ │ │ │ ├── TotalDeposit.js │ │ │ │ ├── VotingEnd.js │ │ │ │ ├── VotingStart.js │ │ │ │ ├── Title.js │ │ │ │ ├── ButtonYes.js │ │ │ │ ├── ButtonNoWithVeto.js │ │ │ │ ├── ButtonNo.js │ │ │ │ ├── ButtonAbstain.js │ │ │ │ └── Description.js │ │ │ └── index.js │ │ ├── Receive │ │ │ ├── QRCode.js │ │ │ ├── AddressCopy.js │ │ │ ├── Address.js │ │ │ └── index.js │ │ ├── Keys │ │ │ ├── ModalList │ │ │ │ ├── Row │ │ │ │ │ └── Delete │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── Submit.js │ │ │ │ ├── Create.js │ │ │ │ └── index.js │ │ │ ├── Manage.js │ │ │ └── Settings.js │ │ └── Send │ │ │ ├── _validation.js │ │ │ ├── Modal │ │ │ ├── To.js │ │ │ ├── Amount.js │ │ │ ├── Memo.js │ │ │ └── Send.js │ │ │ ├── To.js │ │ │ └── Send.js │ ├── KeyInfo │ │ ├── _validation.js │ │ ├── AddressCopy.js │ │ ├── Address.js │ │ ├── Mnemonic.js │ │ ├── PublicKeyCopy.js │ │ ├── PublicKey.js │ │ ├── MnemonicDownload.js │ │ ├── Continue.js │ │ └── Note.js │ ├── CreateKey │ │ ├── _validation.js │ │ ├── Mnemonic.js │ │ └── Name.js │ ├── Splash │ │ ├── Status.js │ │ └── ProgressBar.js │ └── Configuration │ │ ├── _validation.js │ │ ├── ChainID.js │ │ ├── Gas.js │ │ ├── GasPrices.js │ │ └── RPCAddress.js ├── constants │ ├── splash.js │ ├── snackbar.js │ ├── globals.js │ ├── coingecko.js │ ├── account.js │ ├── proposals.js │ ├── delegations.js │ ├── common.js │ ├── validators.js │ └── configuration.js ├── pages │ ├── KeyInfo │ │ └── index.js │ ├── Splash │ │ ├── index.js │ │ └── index.css │ ├── CreateKey │ │ ├── index.js │ │ └── index.css │ ├── Configuration │ │ ├── index.js │ │ └── index.css │ └── Wallet │ │ ├── index.js │ │ ├── OnboardSidebar.css │ │ └── DashboardSidebar.css ├── components │ ├── Dropdown │ │ └── index.js │ ├── Label │ │ ├── index.css │ │ └── index.js │ ├── Snackbar │ │ ├── index.css │ │ └── index.js │ ├── TextArea │ │ ├── index.css │ │ └── index.js │ ├── Loader │ │ ├── index.css │ │ └── index.js │ ├── NumberInputField │ │ └── index.css │ ├── SocialIcons │ │ ├── index.css │ │ └── index.js │ ├── Tooltip │ │ ├── index.css │ │ └── Tooltip.js │ ├── Image │ │ ├── index.css │ │ └── index.js │ ├── SelectField │ │ └── index.css │ ├── Copy │ │ ├── index.css │ │ └── index.js │ ├── ProgressBar │ │ ├── index.css │ │ └── index.js │ ├── TextInputField │ │ └── index.css │ ├── TextBox │ │ ├── index.js │ │ └── index.css │ ├── Icon.js │ ├── Checkbox │ │ └── index.js │ ├── ChipButton │ │ ├── index.js │ │ └── index.css │ ├── Switch │ │ └── index.js │ ├── Visible │ │ └── index.js │ ├── Button │ │ ├── index.js │ │ └── index.css │ └── Table │ │ ├── index.css │ │ └── index.js ├── utils │ ├── validator.js │ ├── bignumber.js │ ├── string.js │ ├── manager.js │ ├── bech32.js │ └── amount.js ├── actions │ ├── transactions │ │ ├── index.js │ │ └── info.js │ ├── splash.js │ ├── snackbar.js │ ├── coingecko.js │ └── proposals.js ├── services │ └── axios.js ├── reducers │ ├── transactions │ │ └── index.js │ ├── configuration │ │ ├── get.js │ │ ├── put.js │ │ └── index.js │ ├── splash.js │ ├── index.js │ ├── proposals.js │ ├── delegations.js │ ├── coingecko.js │ ├── keys │ │ └── delete.js │ ├── snackbar.js │ └── account.js ├── routes.js ├── index.js └── App.js ├── .env.development ├── .gitignore └── .github ├── workflows └── lint.yml └── ISSUE_TEMPLATE ├── feature_request.md └── bug_report.md /README.md: -------------------------------------------------------------------------------- 1 | # Sentinel Desktop Client 2 | -------------------------------------------------------------------------------- /cli/rest/node/requests.go: -------------------------------------------------------------------------------- 1 | package node 2 | -------------------------------------------------------------------------------- /cli/rest/plan/requests.go: -------------------------------------------------------------------------------- 1 | package plan 2 | -------------------------------------------------------------------------------- /cli/rest/deposit/requests.go: -------------------------------------------------------------------------------- 1 | package deposit 2 | -------------------------------------------------------------------------------- /cli/rest/service/requests.go: -------------------------------------------------------------------------------- 1 | package service 2 | -------------------------------------------------------------------------------- /electron/icon.png: -------------------------------------------------------------------------------- 1 | ../build/assets/512x512.png -------------------------------------------------------------------------------- /cli/rest/provider/requests.go: -------------------------------------------------------------------------------- 1 | package provider 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /bin 2 | /build 3 | /cli 4 | /dist 5 | /build.js 6 | -------------------------------------------------------------------------------- /cli/.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /bin 3 | /doc 4 | doc.go* 5 | .DS_Store* -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | GENERATE_SOURCEMAP=false 2 | REACT_APP_VERSION=$npm_package_version 3 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /electron/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sentinel-official/desktop-client/HEAD/electron/icon.ico -------------------------------------------------------------------------------- /cli/services/wireguard/types/vars.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | const ( 4 | DefaultInterface = "wg99" 5 | ) 6 | -------------------------------------------------------------------------------- /electron/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sentinel-official/desktop-client/HEAD/electron/icon.icns -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sentinel-official/desktop-client/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/assets/Loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sentinel-official/desktop-client/HEAD/src/assets/Loader.gif -------------------------------------------------------------------------------- /public/assets/192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sentinel-official/desktop-client/HEAD/public/assets/192x192.png -------------------------------------------------------------------------------- /public/assets/512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sentinel-official/desktop-client/HEAD/public/assets/512x512.png -------------------------------------------------------------------------------- /src/containers/common/_validation.js: -------------------------------------------------------------------------------- 1 | export const ValidateMemo = (value) => { 2 | return new Error(''); 3 | }; 4 | -------------------------------------------------------------------------------- /src/constants/splash.js: -------------------------------------------------------------------------------- 1 | export const SPLASH_TIMEOUT = 1000; 2 | export const SPLASH_STATUS_SET = 'SPLASH_STATUS_SET'; 3 | -------------------------------------------------------------------------------- /.env.development: -------------------------------------------------------------------------------- 1 | BROWSER=none 2 | FAST_REFRESH=true 3 | REACT_APP_LISTEN_URL=http://127.0.0.1:26667 4 | REACT_APP_TOKEN= 5 | -------------------------------------------------------------------------------- /src/constants/snackbar.js: -------------------------------------------------------------------------------- 1 | export const SNACKBAR_SHOW = 'SNACKBAR_SHOW'; 2 | export const SNACKBAR_HIDE = 'SNACKBAR_HIDE'; 3 | -------------------------------------------------------------------------------- /src/pages/KeyInfo/index.js: -------------------------------------------------------------------------------- 1 | import './index.css'; 2 | import Page from '../../containers/KeyInfo'; 3 | 4 | export default Page; 5 | -------------------------------------------------------------------------------- /src/pages/Splash/index.js: -------------------------------------------------------------------------------- 1 | import './index.css'; 2 | import Page from '../../containers/Splash'; 3 | 4 | export default Page; 5 | -------------------------------------------------------------------------------- /src/pages/CreateKey/index.js: -------------------------------------------------------------------------------- 1 | import './index.css'; 2 | import Page from '../../containers/CreateKey'; 3 | 4 | export default Page; 5 | -------------------------------------------------------------------------------- /src/components/Dropdown/index.js: -------------------------------------------------------------------------------- 1 | import './index.css'; 2 | import { Dropdown } from 'react-bootstrap'; 3 | 4 | export default Dropdown; 5 | -------------------------------------------------------------------------------- /src/containers/Wallet/WithdrawRewards/Modal/_validation.js: -------------------------------------------------------------------------------- 1 | export const ValidateMemo = (value) => { 2 | return new Error(''); 3 | }; 4 | -------------------------------------------------------------------------------- /src/pages/Configuration/index.js: -------------------------------------------------------------------------------- 1 | import './index.css'; 2 | import Page from '../../containers/Configuration'; 3 | 4 | export default Page; 5 | -------------------------------------------------------------------------------- /src/utils/validator.js: -------------------------------------------------------------------------------- 1 | export const isActive = (item) => { 2 | return item.jailed === false && item.status === 'BOND_STATUS_BONDED'; 3 | }; 4 | -------------------------------------------------------------------------------- /src/components/Label/index.css: -------------------------------------------------------------------------------- 1 | label { 2 | font-weight: 500; 3 | font-size: 16px; 4 | text-transform: uppercase; 5 | color: #8EA1C8; 6 | } 7 | -------------------------------------------------------------------------------- /electron/preload.js: -------------------------------------------------------------------------------- 1 | const { contextBridge } = require('electron'); 2 | const api = require('./api'); 3 | 4 | contextBridge.exposeInMainWorld('electron', api); 5 | -------------------------------------------------------------------------------- /src/constants/globals.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | listenURL: process.env.REACT_APP_LISTEN_URL, 3 | validators: { 4 | avatars: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /src/components/Snackbar/index.css: -------------------------------------------------------------------------------- 1 | .snackbar { 2 | left: 10px; 3 | transform: translatex(10px); 4 | } 5 | 6 | .snackbar > div { 7 | background: #282525; 8 | } 9 | -------------------------------------------------------------------------------- /src/components/TextArea/index.css: -------------------------------------------------------------------------------- 1 | .form-control, .form-control::placeholder, .form-control:focus { 2 | font-size: 16px; 3 | background: #E9F0F4; 4 | border: none; 5 | } 6 | -------------------------------------------------------------------------------- /src/actions/transactions/index.js: -------------------------------------------------------------------------------- 1 | import './delegate'; 2 | import './info'; 3 | import './redelegate'; 4 | import './send'; 5 | import './unbond'; 6 | import './vote'; 7 | import './withdraw'; 8 | -------------------------------------------------------------------------------- /src/pages/Wallet/index.js: -------------------------------------------------------------------------------- 1 | import './DashboardSidebar.css'; 2 | import './OnboardSidebar.css'; 3 | import './index.css'; 4 | import Page from '../../containers/Wallet'; 5 | 6 | export default Page; 7 | -------------------------------------------------------------------------------- /src/utils/bignumber.js: -------------------------------------------------------------------------------- 1 | import BigNumber from 'bignumber.js'; 2 | 3 | export default BigNumber.clone({ 4 | DECIMAL_PLACES: 1e9, 5 | EXPONENTIAL_AT: 1e9, 6 | POW_PRECISION: 1e9, 7 | }); 8 | -------------------------------------------------------------------------------- /src/components/Loader/index.css: -------------------------------------------------------------------------------- 1 | .loader { 2 | position: absolute; 3 | top: 50%; 4 | left: 50%; 5 | background: #109FEC; 6 | animation: .75s linear infinite spinner-grow !important; 7 | } 8 | -------------------------------------------------------------------------------- /src/components/NumberInputField/index.css: -------------------------------------------------------------------------------- 1 | .form-control, .form-control::placeholder, .form-control:focus { 2 | font-size: 16px; 3 | background: #E9F0F4; 4 | border: none; 5 | height: 45px; 6 | } 7 | -------------------------------------------------------------------------------- /src/actions/splash.js: -------------------------------------------------------------------------------- 1 | import { SPLASH_STATUS_SET } from '../constants/splash'; 2 | 3 | export const setSplashStatus = (data) => { 4 | return { 5 | type: SPLASH_STATUS_SET, 6 | data, 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /src/containers/KeyInfo/_validation.js: -------------------------------------------------------------------------------- 1 | export const ValidateMnemonicSaved = (saved) => { 2 | if (saved === false) { 3 | return new Error('Mnemonic not saved'); 4 | } 5 | 6 | return new Error(''); 7 | }; 8 | -------------------------------------------------------------------------------- /cli/cmd/flags.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | const ( 4 | flagCORSAllowedOrigins = "cors.allowed-origins" 5 | flagListenURL = "listen-url" 6 | flagTLSCrt = "tls-crt" 7 | flagTLSKey = "tls-key" 8 | ) 9 | -------------------------------------------------------------------------------- /src/components/SocialIcons/index.css: -------------------------------------------------------------------------------- 1 | .social-icons .icon { 2 | width: 20px; 3 | margin: 0 15px; 4 | } 5 | 6 | @media (max-width: 576px) { 7 | .social-icons .icon { 8 | margin: 0 10px; 9 | } 10 | } -------------------------------------------------------------------------------- /src/components/Tooltip/index.css: -------------------------------------------------------------------------------- 1 | .tooltip-section .icon { 2 | width: 16px; 3 | fill: transparent; 4 | margin-bottom: 5px; 5 | } 6 | 7 | .error-message.text-area { 8 | right: -15px; 9 | top: 65px; 10 | } -------------------------------------------------------------------------------- /electron/channels.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | MANAGER_LISTEN_URL_GET_REQUEST: 'MANAGER_LISTEN_URL_GET_REQUEST', 3 | MANAGER_START_REQUEST: 'MANAGER_START_REQUEST', 4 | MANAGER_START_RESPONSE: 'MANAGER_START_RESPONSE', 5 | }; 6 | -------------------------------------------------------------------------------- /src/containers/Wallet/Validators/ModalUnbond/_validation.js: -------------------------------------------------------------------------------- 1 | export const ValidateAmount = (value) => { 2 | if (value === 0) { 3 | return new Error('Value must be greater than 0'); 4 | } 5 | 6 | return new Error(''); 7 | }; 8 | -------------------------------------------------------------------------------- /cli/types/flags.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | ) 6 | 7 | const ( 8 | FlagHome = "home" 9 | ) 10 | 11 | var ( 12 | LineBreakCmd = &cobra.Command{Run: func(_ *cobra.Command, _ []string) {}} 13 | ) 14 | -------------------------------------------------------------------------------- /src/components/Image/index.css: -------------------------------------------------------------------------------- 1 | .moniker-image { 2 | width: 20px; 3 | height: 20px; 4 | border-radius: 50%; 5 | margin-right: 5px; 6 | margin-bottom: 2px; 7 | } 8 | 9 | .image-section { 10 | text-align: center; 11 | } -------------------------------------------------------------------------------- /src/containers/Wallet/Validators/ModalDelegate/_validation.js: -------------------------------------------------------------------------------- 1 | export const ValidateAmount = (value) => { 2 | if (value === 0) { 3 | return new Error('Value must be greater than 0'); 4 | } 5 | 6 | return new Error(''); 7 | }; 8 | -------------------------------------------------------------------------------- /src/pages/Splash/index.css: -------------------------------------------------------------------------------- 1 | .splash-container { 2 | height: 100vh; 3 | display: flex; 4 | justify-content: center; 5 | align-items: center; 6 | background: radial-gradient(50% 166.98% at 50% 50%, #142E54 0%, #142D51 100%); 7 | } 8 | -------------------------------------------------------------------------------- /cli/services/wireguard/wireguard_windows.go: -------------------------------------------------------------------------------- 1 | package wireguard 2 | 3 | func (w *WireGuard) PreUp() error { 4 | return w.cfg.WriteToFile(w.cfgDir) 5 | } 6 | 7 | func (w *WireGuard) RealInterface() (string, error) { 8 | return w.cfg.Name, nil 9 | } 10 | -------------------------------------------------------------------------------- /src/containers/Wallet/WithdrawRewards/_validation.js: -------------------------------------------------------------------------------- 1 | export const ValidateFrom = (value) => { 2 | value = value.trim(); 3 | if (value.length === 0) { 4 | return new Error('Length must be greater than 0'); 5 | } 6 | 7 | return new Error(''); 8 | }; 9 | -------------------------------------------------------------------------------- /cli/utils/errors.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "google.golang.org/grpc/codes" 5 | "google.golang.org/grpc/status" 6 | ) 7 | 8 | func IsNotFoundError(v error) error { 9 | if status.Code(v) == codes.NotFound { 10 | return nil 11 | } 12 | 13 | return v 14 | } 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bin 2 | /build 3 | /coverage 4 | /dist 5 | .DS_Store 6 | .env.development.local 7 | .env.local 8 | .env.production.local 9 | .env.test.local 10 | .eslintcache 11 | /.idea 12 | /node_modules 13 | npm-debug.log* 14 | /.pnp 15 | .pnp.js 16 | yarn-debug.log* 17 | yarn-error.log* 18 | -------------------------------------------------------------------------------- /electron/globals.js: -------------------------------------------------------------------------------- 1 | const { app } = require('electron'); 2 | 3 | const manager = null; 4 | const listenURL = app.commandLine.getSwitchValue('listen-url') || 'http://127.0.0.1:26667'; 5 | const window = null; 6 | 7 | module.exports = { 8 | listenURL, 9 | manager, 10 | window, 11 | }; 12 | -------------------------------------------------------------------------------- /cli/utils/rand.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "crypto/rand" 5 | "encoding/hex" 6 | ) 7 | 8 | func RandomStringHex(length int64) string { 9 | bytes := make([]byte, length) 10 | if _, err := rand.Read(bytes); err != nil { 11 | panic(err) 12 | } 13 | 14 | return hex.EncodeToString(bytes) 15 | } 16 | -------------------------------------------------------------------------------- /src/constants/coingecko.js: -------------------------------------------------------------------------------- 1 | export const COINGECKO_GET_IN_PROGRESS = 'COINGECKO_GET_IN_PROGRESS'; 2 | export const COINGECKO_GET_SUCCESS = 'COINGECKO_GET_SUCCESS'; 3 | export const COINGECKO_GET_ERROR = 'COINGECKO_GET_ERROR'; 4 | 5 | export const COINGECKO_GET_URL = 'https://api.coingecko.com/api/v3/coins/sentinel-group'; 6 | -------------------------------------------------------------------------------- /electron/entitlements.mac.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.cs.allow-unsigned-executable-memory 6 | 7 | 8 | -------------------------------------------------------------------------------- /cli/middlewares/headers.go: -------------------------------------------------------------------------------- 1 | package middlewares 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | func AddHeaders(next http.Handler) http.Handler { 8 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 9 | w.Header().Add("Content-Type", "application/json") 10 | next.ServeHTTP(w, r) 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /src/containers/CreateKey/_validation.js: -------------------------------------------------------------------------------- 1 | export const ValidateMnemonic = (value) => { 2 | return new Error(''); 3 | }; 4 | 5 | export const ValidateName = (value) => { 6 | value = value.trim(); 7 | if (value.length === 0) { 8 | return new Error('Length must be greater than 0'); 9 | } 10 | 11 | return new Error(''); 12 | }; 13 | -------------------------------------------------------------------------------- /cli/rest/bank/routes.go: -------------------------------------------------------------------------------- 1 | package bank 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/gorilla/mux" 7 | 8 | "github.com/sentinel-official/desktop-client/cli/context" 9 | ) 10 | 11 | func RegisterRoutes(r *mux.Router, ctx *context.Context) { 12 | r.Name("Send"). 13 | Methods(http.MethodPost).Path("/bank/send"). 14 | HandlerFunc(HandlerSend(ctx)) 15 | } 16 | -------------------------------------------------------------------------------- /cli/rest/service/responses.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/sentinel-official/desktop-client/cli/x/common" 5 | ) 6 | 7 | type ResponseStatus struct { 8 | Bandwidth common.Bandwidth `json:"bandwidth"` 9 | From string `json:"from"` 10 | ID uint64 `json:"id"` 11 | To string `json:"to"` 12 | } 13 | -------------------------------------------------------------------------------- /cli/types/errors.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type Error struct { 4 | Code int `json:"code"` 5 | Message string `json:"message"` 6 | Module string `json:"module,omitempty"` 7 | } 8 | 9 | func NewError(module string, code int, message string) *Error { 10 | return &Error{ 11 | Code: code, 12 | Message: message, 13 | Module: module, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/actions/snackbar.js: -------------------------------------------------------------------------------- 1 | import { SNACKBAR_HIDE, SNACKBAR_SHOW } from '../constants/snackbar'; 2 | 3 | export const hideSnackbar = (data) => { 4 | return { 5 | type: SNACKBAR_HIDE, 6 | data, 7 | }; 8 | }; 9 | 10 | export const showSnackbar = (data) => { 11 | return { 12 | type: SNACKBAR_SHOW, 13 | data, 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /src/containers/Wallet/Proposals/Modal/_validation.js: -------------------------------------------------------------------------------- 1 | export const ValidateMemo = (value) => { 2 | return new Error(''); 3 | }; 4 | 5 | export const ValidatePassword = (value) => { 6 | value = value.trim(); 7 | if (value.length === 0) { 8 | return new Error('Length must be greater than 0'); 9 | } 10 | 11 | return new Error(''); 12 | }; 13 | -------------------------------------------------------------------------------- /src/utils/string.js: -------------------------------------------------------------------------------- 1 | import { HTTPSURLRegex } from '../constants/common'; 2 | 3 | export const capitalizeFirstLetter = (value) => { 4 | value = value.toString(); 5 | return value.charAt(0).toUpperCase() + value.slice(1); 6 | }; 7 | 8 | export const addHTTPSURLScheme = (value) => { 9 | return HTTPSURLRegex.test(value) ? value : `https://${value}`; 10 | }; 11 | -------------------------------------------------------------------------------- /src/components/Loader/index.js: -------------------------------------------------------------------------------- 1 | import './index.css'; 2 | import { Spinner as BootstrapSpinner } from 'react-bootstrap'; 3 | import React from 'react'; 4 | 5 | const Spinner = () => { 6 | return ( 7 | 11 | ); 12 | }; 13 | 14 | export default React.memo(Spinner); 15 | -------------------------------------------------------------------------------- /cli/rest/account/routes.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/gorilla/mux" 7 | 8 | "github.com/sentinel-official/desktop-client/cli/context" 9 | ) 10 | 11 | func RegisterRoutes(r *mux.Router, ctx *context.Context) { 12 | r.Name("GetAccount"). 13 | Methods(http.MethodGet).Path("/accounts/{address}"). 14 | HandlerFunc(HandlerGetAccount(ctx)) 15 | } 16 | -------------------------------------------------------------------------------- /cli/rest/deposit/routes.go: -------------------------------------------------------------------------------- 1 | package deposit 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/gorilla/mux" 7 | 8 | "github.com/sentinel-official/desktop-client/cli/context" 9 | ) 10 | 11 | func RegisterRoutes(r *mux.Router, ctx *context.Context) { 12 | r.Name("GetDeposit"). 13 | Methods(http.MethodGet).Path("/accounts/{address}/deposits"). 14 | HandlerFunc(HandlerGetDeposits(ctx)) 15 | } 16 | -------------------------------------------------------------------------------- /src/containers/Wallet/Receive/QRCode.js: -------------------------------------------------------------------------------- 1 | import * as PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | import ReactQRCode from 'qrcode.react'; 4 | 5 | const QRCode = ({ 6 | value, 7 | }) => { 8 | return ( 9 | 10 | ); 11 | }; 12 | 13 | QRCode.propTypes = { 14 | value: PropTypes.string.isRequired, 15 | }; 16 | 17 | export default QRCode; 18 | -------------------------------------------------------------------------------- /src/components/SelectField/index.css: -------------------------------------------------------------------------------- 1 | .validators-select .MuiSelect-select:focus { 2 | background-color: transparent; 3 | } 4 | 5 | .validators-select:before { 6 | border: 0 solid !important; 7 | } 8 | 9 | .validators-select:hover:not(.Mui-disabled):before { 10 | border: 0 solid !important; 11 | } 12 | 13 | .validators-select:after { 14 | border-bottom: 2px solid #109FEC !important; 15 | } 16 | -------------------------------------------------------------------------------- /src/constants/account.js: -------------------------------------------------------------------------------- 1 | import { managerBaseURL } from './common'; 2 | 3 | export const ACCOUNT_GET_IN_PROGRESS = 'ACCOUNT_GET_IN_PROGRESS'; 4 | export const ACCOUNT_GET_SUCCESS = 'ACCOUNT_GET_SUCCESS'; 5 | export const ACCOUNT_GET_ERROR = 'ACCOUNT_GET_ERROR'; 6 | 7 | export const accountGetURL = (address) => { 8 | const baseURL = managerBaseURL(); 9 | return `${baseURL}/accounts/${address}`; 10 | }; 11 | -------------------------------------------------------------------------------- /src/constants/proposals.js: -------------------------------------------------------------------------------- 1 | import { managerBaseURL } from './common'; 2 | 3 | export const PROPOSALS_GET_IN_PROGRESS = 'PROPOSALS_GET_IN_PROGRESS'; 4 | export const PROPOSALS_GET_SUCCESS = 'PROPOSALS_GET_SUCCESS'; 5 | export const PROPOSALS_GET_ERROR = 'PROPOSALS_GET_ERROR'; 6 | 7 | export const proposalsGetURL = () => { 8 | const baseURL = managerBaseURL(); 9 | return `${baseURL}/accounts`; 10 | }; 11 | -------------------------------------------------------------------------------- /src/actions/transactions/info.js: -------------------------------------------------------------------------------- 1 | import { TX_INFO_MODAL_HIDE, TX_INFO_MODAL_SHOW } from '../../constants/transactions'; 2 | 3 | export const setTxInfoModalShow = (data) => { 4 | return { 5 | type: TX_INFO_MODAL_SHOW, 6 | data, 7 | }; 8 | }; 9 | 10 | export const setTxInfoModalHide = (data) => { 11 | return { 12 | type: TX_INFO_MODAL_HIDE, 13 | data, 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /cli/rest/distribution/routes.go: -------------------------------------------------------------------------------- 1 | package distribution 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/gorilla/mux" 7 | 8 | "github.com/sentinel-official/desktop-client/cli/context" 9 | ) 10 | 11 | func RegisterRoutes(r *mux.Router, ctx *context.Context) { 12 | r.Name("WithdrawRewards"). 13 | Methods(http.MethodPost).Path("/delegators/{address}/rewards"). 14 | HandlerFunc(HandlerWithdrawRewards(ctx)) 15 | } 16 | -------------------------------------------------------------------------------- /cli/types/keys.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | ) 7 | 8 | var ( 9 | Version = "" 10 | DefaultListenURL = "http://127.0.0.1:26667" 11 | DefaultHomeDirectory = func() string { 12 | home, err := os.UserHomeDir() 13 | if err != nil { 14 | panic(err) 15 | } 16 | 17 | return filepath.Join(home, ".sentinel", "client") 18 | }() 19 | Denom = "udvpn" 20 | ) 21 | -------------------------------------------------------------------------------- /cli/x/common/bandwidth.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | hubtypes "github.com/sentinel-official/hub/types" 5 | ) 6 | 7 | type Bandwidth struct { 8 | Upload int64 `json:"upload"` 9 | Download int64 `json:"download"` 10 | } 11 | 12 | func NewBandwidthFromRaw(item hubtypes.Bandwidth) Bandwidth { 13 | return Bandwidth{ 14 | Upload: item.Upload.Int64(), 15 | Download: item.Download.Int64(), 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/components/Copy/index.css: -------------------------------------------------------------------------------- 1 | .copy-section { 2 | padding: 4px; 3 | cursor: pointer; 4 | background: #DEE9EF; 5 | display: flex; 6 | align-items: center; 7 | justify-content: center; 8 | border-radius: 50%; 9 | left: 0; 10 | right: 0; 11 | bottom: 0; 12 | top: 0; 13 | width: 26px; 14 | height: 26px; 15 | } 16 | 17 | .copy-section .icon { 18 | width: 14px; 19 | } 20 | -------------------------------------------------------------------------------- /src/containers/Wallet/Receive/AddressCopy.js: -------------------------------------------------------------------------------- 1 | import * as PropTypes from 'prop-types'; 2 | import Copy from '../../../components/Copy'; 3 | import React from 'react'; 4 | 5 | const AddressCopy = ({ 6 | text, 7 | }) => { 8 | return ( 9 | 10 | ); 11 | }; 12 | 13 | AddressCopy.propTypes = { 14 | text: PropTypes.string.isRequired, 15 | }; 16 | 17 | export default AddressCopy; 18 | -------------------------------------------------------------------------------- /src/components/ProgressBar/index.css: -------------------------------------------------------------------------------- 1 | .bar-container { 2 | position: absolute; 3 | bottom: 5px; 4 | width: 100%; 5 | } 6 | 7 | .bar-container span { 8 | display: none !important; 9 | } 10 | 11 | .bar-container > div > div > div { 12 | background-color: #129EED !important; 13 | border: 3px solid #153F6A; 14 | box-sizing: border-box; 15 | box-shadow: 0 -2px 14px rgba(18, 158, 237, 0.3); 16 | } 17 | -------------------------------------------------------------------------------- /src/containers/Wallet/Proposals/Row/Type.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TextBox from '../../../../components/TextBox'; 3 | 4 | const Type = () => { 5 | return ( 6 |
7 | 11 |
12 | 13 | ); 14 | }; 15 | 16 | export default Type; 17 | -------------------------------------------------------------------------------- /src/containers/Wallet/Proposals/Row/Percentage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TextBox from '../../../../components/TextBox'; 3 | 4 | const Percentage = () => { 5 | return ( 6 |
7 | 11 |
12 | 13 | ); 14 | }; 15 | 16 | export default Percentage; 17 | -------------------------------------------------------------------------------- /src/services/axios.js: -------------------------------------------------------------------------------- 1 | import Axios from 'axios'; 2 | 3 | const axios = Axios.create({}); 4 | 5 | export const withInterceptors = (token) => { 6 | axios.interceptors.request.use((config) => { 7 | config.headers = { 8 | Authorization: token, 9 | }; 10 | 11 | return config; 12 | }, (error) => { 13 | return Promise.reject(error); 14 | }); 15 | }; 16 | 17 | export default axios; 18 | -------------------------------------------------------------------------------- /src/containers/Wallet/Proposals/Row/DepositEnd.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TextBox from '../../../../components/TextBox'; 3 | 4 | const DepositEnd = () => { 5 | return ( 6 |
7 | 11 |
12 | 13 | ); 14 | }; 15 | 16 | export default DepositEnd; 17 | -------------------------------------------------------------------------------- /src/containers/Wallet/Proposals/Row/IntialDeposit.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TextBox from '../../../../components/TextBox'; 3 | 4 | const InitialDeposit = () => { 5 | return ( 6 |
7 | 11 |
12 | 13 | ); 14 | }; 15 | 16 | export default InitialDeposit; 17 | -------------------------------------------------------------------------------- /src/containers/Wallet/Proposals/Row/SubmitTIme.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TextBox from '../../../../components/TextBox'; 3 | 4 | const SubmitTime = () => { 5 | return ( 6 |
7 | 11 |
12 | 13 | ); 14 | }; 15 | 16 | export default SubmitTime; 17 | -------------------------------------------------------------------------------- /src/containers/Wallet/Proposals/Row/TotalDeposit.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TextBox from '../../../../components/TextBox'; 3 | 4 | const TotalDeposit = () => { 5 | return ( 6 |
7 | 11 |
12 | 13 | ); 14 | }; 15 | 16 | export default TotalDeposit; 17 | -------------------------------------------------------------------------------- /src/containers/Wallet/Proposals/Row/VotingEnd.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TextBox from '../../../../components/TextBox'; 3 | 4 | const VotingEnd = () => { 5 | return ( 6 |
7 | 11 |
12 | 13 | ); 14 | }; 15 | 16 | export default VotingEnd; 17 | -------------------------------------------------------------------------------- /src/containers/Wallet/Proposals/Row/VotingStart.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TextBox from '../../../../components/TextBox'; 3 | 4 | const VotingStart = () => { 5 | return ( 6 |
7 | 11 |
12 | 13 | ); 14 | }; 15 | 16 | export default VotingStart; 17 | -------------------------------------------------------------------------------- /src/containers/Wallet/Keys/ModalList/Row/Delete/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Submit from './Submit'; 3 | import Typography from '@material-ui/core/Typography'; 4 | 5 | const Delete = () => { 6 | return ( 7 | 11 | 12 | 13 | ); 14 | }; 15 | 16 | export default Delete; 17 | -------------------------------------------------------------------------------- /src/constants/delegations.js: -------------------------------------------------------------------------------- 1 | import { managerBaseURL } from './common'; 2 | 3 | export const DELEGATIONS_GET_IN_PROGRESS = 'DELEGATIONS_GET_IN_PROGRESS'; 4 | export const DELEGATIONS_GET_SUCCESS = 'DELEGATIONS_GET_SUCCESS'; 5 | export const DELEGATIONS_GET_ERROR = 'DELEGATIONS_GET_ERROR'; 6 | 7 | export const delegationsGetURL = (address) => { 8 | const baseURL = managerBaseURL(); 9 | return `${baseURL}/delegators/${address}/delegations`; 10 | }; 11 | -------------------------------------------------------------------------------- /cli/utils/freeport.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "net" 5 | ) 6 | 7 | func GetFreeUDPPort() (uint16, error) { 8 | addr, err := net.ResolveUDPAddr("udp", "0.0.0.0:0") 9 | if err != nil { 10 | return 0, err 11 | } 12 | 13 | conn, err := net.ListenUDP("udp", addr) 14 | if err != nil { 15 | return 0, err 16 | } 17 | 18 | defer func() { 19 | _ = conn.Close() 20 | }() 21 | 22 | return uint16(conn.LocalAddr().(*net.UDPAddr).Port), nil 23 | } 24 | -------------------------------------------------------------------------------- /src/components/TextInputField/index.css: -------------------------------------------------------------------------------- 1 | .form-control { 2 | padding: 0.375rem 2rem 0.375rem 0.75rem; 3 | } 4 | 5 | .form-control, .form-control::placeholder, .form-control:focus { 6 | font-size: 16px; 7 | background: #E9F0F4; 8 | border: none; 9 | color: #8B99B5; 10 | height: 45px; 11 | box-shadow: none; 12 | } 13 | 14 | textarea.form-control, textarea.form-control::placeholder, textarea.form-control:focus { 15 | height: auto; 16 | } -------------------------------------------------------------------------------- /src/containers/Wallet/Proposals/Row/Title.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TextBox from '../../../../components/TextBox'; 3 | 4 | const Title = () => { 5 | return ( 6 |
7 | 11 |
12 | 13 | ); 14 | }; 15 | 16 | export default Title; 17 | -------------------------------------------------------------------------------- /src/containers/common/Snackbar.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux'; 2 | import { hideSnackbar } from '../../actions/snackbar'; 3 | import Snackbar from '../../components/Snackbar'; 4 | 5 | const stateToProps = (state) => { 6 | return { 7 | open: state.snackbar.open, 8 | message: state.snackbar.message, 9 | }; 10 | }; 11 | 12 | const actionsToProps = { 13 | onClose: hideSnackbar, 14 | }; 15 | 16 | export default connect(stateToProps, actionsToProps)(Snackbar); 17 | -------------------------------------------------------------------------------- /src/reducers/transactions/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import delegate from './delegate'; 3 | import info from './info'; 4 | import redelegate from './redelegate'; 5 | import send from './send'; 6 | import unbond from './unbond'; 7 | import vote from './vote'; 8 | import withdraw from './withdraw'; 9 | 10 | export default combineReducers({ 11 | info, 12 | delegate, 13 | redelegate, 14 | send, 15 | unbond, 16 | vote, 17 | withdraw, 18 | }); 19 | -------------------------------------------------------------------------------- /cli/rest/config/routes.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/gorilla/mux" 7 | 8 | "github.com/sentinel-official/desktop-client/cli/context" 9 | ) 10 | 11 | func RegisterRoutes(r *mux.Router, ctx *context.Context) { 12 | r.Name("GetConfig"). 13 | Methods(http.MethodGet).Path("/config"). 14 | HandlerFunc(HandlerGetConfig(ctx)) 15 | r.Name("UpdateConfig"). 16 | Methods(http.MethodPut).Path("/config"). 17 | HandlerFunc(HandlerUpdateConfig(ctx)) 18 | } 19 | -------------------------------------------------------------------------------- /src/components/Label/index.js: -------------------------------------------------------------------------------- 1 | import './index.css'; 2 | import * as PropTypes from 'prop-types'; 3 | import React from 'react'; 4 | 5 | const Label = ({ 6 | className, 7 | label, 8 | }) => { 9 | return ( 10 | 13 | ); 14 | }; 15 | 16 | Label.propTypes = { 17 | className: PropTypes.string.isRequired, 18 | label: PropTypes.string.isRequired, 19 | }; 20 | 21 | export default React.memo(Label); 22 | -------------------------------------------------------------------------------- /src/components/TextBox/index.js: -------------------------------------------------------------------------------- 1 | import './index.css'; 2 | import * as PropTypes from 'prop-types'; 3 | import React from 'react'; 4 | 5 | const TextBox = ({ 6 | className, 7 | value, 8 | }) => { 9 | return ( 10 |

11 | {value} 12 |

13 | ); 14 | }; 15 | 16 | TextBox.propTypes = { 17 | className: PropTypes.string.isRequired, 18 | value: PropTypes.string.isRequired, 19 | }; 20 | 21 | export default React.memo(TextBox); 22 | -------------------------------------------------------------------------------- /cli/rest/provider/routes.go: -------------------------------------------------------------------------------- 1 | package provider 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/gorilla/mux" 7 | 8 | "github.com/sentinel-official/desktop-client/cli/context" 9 | ) 10 | 11 | func RegisterRoutes(r *mux.Router, ctx *context.Context) { 12 | r.Name("GetProvider"). 13 | Methods(http.MethodGet).Path("/providers/{address}"). 14 | HandlerFunc(HandlerGetProvider(ctx)) 15 | r.Name("GetProviders"). 16 | Methods(http.MethodGet).Path("/providers"). 17 | HandlerFunc(HandlerGetProviders(ctx)) 18 | } 19 | -------------------------------------------------------------------------------- /cli/rest/plan/routes.go: -------------------------------------------------------------------------------- 1 | package plan 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/gorilla/mux" 7 | 8 | "github.com/sentinel-official/desktop-client/cli/context" 9 | ) 10 | 11 | func RegisterRoutes(r *mux.Router, ctx *context.Context) { 12 | r.Name("GetPlan"). 13 | Methods(http.MethodGet).Path("/plans/{id}"). 14 | HandlerFunc(HandlerGetPlan(ctx)) 15 | r.Name("GetPlansForProvider"). 16 | Methods(http.MethodGet).Path("/providers/{address}/plans"). 17 | HandlerFunc(HandlerGetPlansForProvider(ctx)) 18 | } 19 | -------------------------------------------------------------------------------- /cli/rest/service/routes.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/gorilla/mux" 7 | 8 | "github.com/sentinel-official/desktop-client/cli/context" 9 | ) 10 | 11 | func RegisterRoutes(r *mux.Router, ctx *context.Context) { 12 | r.Name("ServiceDisconnect"). 13 | Methods(http.MethodPost).Path("/service/disconnect"). 14 | HandlerFunc(HandlerDisconnect(ctx)) 15 | r.Name("ServiceStatus"). 16 | Methods(http.MethodGet).Path("/service/status"). 17 | HandlerFunc(HandlerStatus(ctx)) 18 | } 19 | -------------------------------------------------------------------------------- /src/constants/common.js: -------------------------------------------------------------------------------- 1 | import globals from './globals'; 2 | 3 | export const managerBaseURL = () => { 4 | return `${globals.listenURL}/api/v1`; 5 | }; 6 | 7 | export const emptyFunc = () => ({}); 8 | 9 | export const COIN_DENOM = 'UDVPN'.toLowerCase(); 10 | export const COIN_DISPLAY_DENOM = 'DVPN'.toUpperCase(); 11 | export const COIN_DECIMALS = 6; 12 | 13 | export const numberInputInvalidKeys = ['-', '+', 'e']; 14 | export const numberInputInvalidKeyCodes = [69, 187, 189]; 15 | 16 | export const HTTPSURLRegex = /https?/; 17 | -------------------------------------------------------------------------------- /src/assets/Success.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: push 3 | jobs: 4 | build: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v2 8 | 9 | - name: Cache dependencies 10 | uses: actions/cache@v2 11 | with: 12 | path: '**/node_modules' 13 | key: ${{ runner.os }}-dependencies-${{ hashFiles('**/yarn.lock') }} 14 | 15 | - name: Install dependencies 16 | run: yarn install 17 | 18 | - name: Run ESLint 19 | run: ./node_modules/eslint/bin/eslint.js . 20 | -------------------------------------------------------------------------------- /src/containers/Wallet/Proposals/Row/ButtonYes.js: -------------------------------------------------------------------------------- 1 | import Button from '../../../../components/Button'; 2 | import React from 'react'; 3 | 4 | const ButtonYes = () => { 5 | const onClick = () => { 6 | 7 | }; 8 | 9 | return ( 10 | 18 | ); 19 | }; 20 | 21 | ChipButton.propTypes = { 22 | className: PropTypes.string.isRequired, 23 | label: PropTypes.string.isRequired, 24 | type: PropTypes.string.isRequired, 25 | onClick: PropTypes.func.isRequired, 26 | }; 27 | 28 | export default ChipButton; 29 | -------------------------------------------------------------------------------- /src/containers/Wallet/WithdrawRewards/Modal/FromAddress.js: -------------------------------------------------------------------------------- 1 | import * as PropTypes from 'prop-types'; 2 | import { connect } from 'react-redux'; 3 | import React from 'react'; 4 | import TextBox from '../../../../components/TextBox'; 5 | 6 | const FromAddress = (props) => { 7 | return ( 8 | 12 | ); 13 | }; 14 | 15 | FromAddress.propTypes = { 16 | value: PropTypes.string.isRequired, 17 | }; 18 | 19 | const stateToProps = (state) => { 20 | return { 21 | value: state.transactions.withdraw.from.value, 22 | }; 23 | }; 24 | 25 | export default connect(stateToProps)(FromAddress); 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /cli/x/common/deposit.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | deposittypes "github.com/sentinel-official/hub/x/deposit/types" 5 | ) 6 | 7 | type Deposit struct { 8 | Address string `json:"address"` 9 | Amount Coins `json:"amount"` 10 | } 11 | 12 | func NewDepositFromRaw(item *deposittypes.Deposit) Deposit { 13 | return Deposit{ 14 | Address: item.Address, 15 | Amount: NewCoinsFromRaw(item.Coins), 16 | } 17 | } 18 | 19 | type Deposits []Deposit 20 | 21 | func NewDepositsFromRaw(items deposittypes.Deposits) Deposits { 22 | deposits := make(Deposits, 0, len(items)) 23 | for i := range items { 24 | deposits = append(deposits, NewDepositFromRaw(&items[i])) 25 | } 26 | 27 | return deposits 28 | } 29 | -------------------------------------------------------------------------------- /src/containers/Wallet/Validators/ModalRedelegate/FromAddress.js: -------------------------------------------------------------------------------- 1 | import * as PropTypes from 'prop-types'; 2 | import { connect } from 'react-redux'; 3 | import React from 'react'; 4 | import TextBox from '../../../../components/TextBox'; 5 | 6 | const FromAddress = (props) => { 7 | return ( 8 | 12 | ); 13 | }; 14 | 15 | FromAddress.propTypes = { 16 | value: PropTypes.string.isRequired, 17 | }; 18 | 19 | const stateToProps = (state) => { 20 | return { 21 | value: state.transactions.redelegate.from.value, 22 | }; 23 | }; 24 | 25 | export default connect(stateToProps)(FromAddress); 26 | -------------------------------------------------------------------------------- /src/reducers/splash.js: -------------------------------------------------------------------------------- 1 | import { SPLASH_STATUS_SET } from '../constants/splash'; 2 | import { combineReducers } from 'redux'; 3 | 4 | const completed = (state = 0, { 5 | type, 6 | data, 7 | }) => { 8 | switch (type) { 9 | case SPLASH_STATUS_SET: 10 | return data.completed; 11 | default: 12 | return state; 13 | } 14 | }; 15 | 16 | const message = (state = 'PREPARING THE SENTINEL CLIENT', { 17 | type, 18 | data, 19 | }) => { 20 | switch (type) { 21 | case SPLASH_STATUS_SET: 22 | return data.message; 23 | default: 24 | return state; 25 | } 26 | }; 27 | 28 | export default combineReducers({ 29 | completed, 30 | message, 31 | }); 32 | -------------------------------------------------------------------------------- /cli/rest/keys/routes.go: -------------------------------------------------------------------------------- 1 | package keys 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/gorilla/mux" 7 | 8 | "github.com/sentinel-official/desktop-client/cli/context" 9 | ) 10 | 11 | func RegisterRoutes(r *mux.Router, ctx *context.Context) { 12 | r.Name("GetKey"). 13 | Methods(http.MethodGet).Path("/keys/{name}"). 14 | HandlerFunc(HandlerGetKey(ctx)) 15 | r.Name("GetKeys"). 16 | Methods(http.MethodGet).Path("/keys"). 17 | HandlerFunc(HandlerGetKeys(ctx)) 18 | 19 | r.Name("AddKey"). 20 | Methods(http.MethodPost).Path("/keys"). 21 | HandlerFunc(HandlerAddKey(ctx)) 22 | r.Name("DeleteKey"). 23 | Methods(http.MethodPost).Path("/keys/{name}/delete"). 24 | HandlerFunc(HandlerDeleteKey(ctx)) 25 | } 26 | -------------------------------------------------------------------------------- /cli/x/gov/vote.go: -------------------------------------------------------------------------------- 1 | package gov 2 | 3 | import ( 4 | govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" 5 | ) 6 | 7 | type Vote struct { 8 | ProposalId uint64 `json:"proposal_id"` 9 | Voter string `json:"voter"` 10 | Option string `json:"option"` 11 | } 12 | 13 | func NewVoteFromRaw(vote *govtypes.Vote) Vote { 14 | return Vote{ 15 | ProposalId: vote.ProposalId, 16 | Voter: vote.Voter, 17 | Option: vote.Option.String(), 18 | } 19 | } 20 | 21 | type Votes []Vote 22 | 23 | func NewVotesFromRaw(items govtypes.Votes) Votes { 24 | votes := make(Votes, 0, len(items)) 25 | for i := range items { 26 | votes = append(votes, NewVoteFromRaw(&items[i])) 27 | } 28 | 29 | return votes 30 | } 31 | -------------------------------------------------------------------------------- /src/containers/KeyInfo/PublicKeyCopy.js: -------------------------------------------------------------------------------- 1 | import * as PropTypes from 'prop-types'; 2 | import { connect } from 'react-redux'; 3 | import { encodeToBech32 } from '../../utils/bech32'; 4 | import Copy from '../../components/Copy'; 5 | import React from 'react'; 6 | 7 | const PublicKeyCopy = (props) => { 8 | const text = encodeToBech32(props.text, 'sentpub'); 9 | 10 | return ( 11 | 12 | ); 13 | }; 14 | 15 | PublicKeyCopy.propTypes = { 16 | text: PropTypes.string.isRequired, 17 | }; 18 | 19 | const stateToProps = (state) => { 20 | return { 21 | text: state.keys.post.info.publicKey, 22 | }; 23 | }; 24 | 25 | export default connect(stateToProps)(PublicKeyCopy); 26 | -------------------------------------------------------------------------------- /src/components/Tooltip/Tooltip.js: -------------------------------------------------------------------------------- 1 | import './index.css'; 2 | import * as PropTypes from 'prop-types'; 3 | import Icon from '../Icon'; 4 | import React from 'react'; 5 | 6 | const Tooltip = ({ 7 | value, 8 | icon, 9 | }) => { 10 | return ( 11 |
16 | 20 |
21 | ); 22 | }; 23 | 24 | Tooltip.propTypes = { 25 | icon: PropTypes.string.isRequired, 26 | value: PropTypes.string.isRequired, 27 | }; 28 | 29 | export default Tooltip; 30 | -------------------------------------------------------------------------------- /src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import account from './account'; 3 | import coingecko from './coingecko'; 4 | import configuration from './configuration'; 5 | import delegations from './delegations'; 6 | import keys from './keys'; 7 | import proposals from './proposals'; 8 | import snackbar from './snackbar'; 9 | import splash from './splash'; 10 | import transactions from './transactions'; 11 | import validators from './validators'; 12 | 13 | const root = combineReducers({ 14 | account, 15 | coingecko, 16 | configuration, 17 | delegations, 18 | keys, 19 | proposals, 20 | snackbar, 21 | splash, 22 | transactions, 23 | validators, 24 | }); 25 | 26 | export default root; 27 | -------------------------------------------------------------------------------- /src/utils/manager.js: -------------------------------------------------------------------------------- 1 | import { managerBaseURL } from '../constants/common'; 2 | import Async from 'async'; 3 | import Axios from 'axios'; 4 | 5 | export const isManagerRunning = (cb) => { 6 | Async.retry({ 7 | times: 5, 8 | interval: (count) => { 9 | return count * 1000; 10 | }, 11 | }, (next) => { 12 | const url = managerBaseURL(); 13 | Axios.get(url) 14 | .then(() => { 15 | next(null); 16 | }) 17 | .catch((err) => { 18 | if (err.response?.status === 404) { 19 | next(null); 20 | } else { 21 | next(err); 22 | } 23 | }); 24 | }, cb); 25 | }; 26 | -------------------------------------------------------------------------------- /src/containers/Wallet/Proposals/Row/ButtonNoWithVeto.js: -------------------------------------------------------------------------------- 1 | import * as PropTypes from 'prop-types'; 2 | import Button from '../../../../components/Button'; 3 | import React from 'react'; 4 | 5 | const ButtonNoWithVeto = (props) => { 6 | const onClick = () => { 7 | }; 8 | 9 | return ( 10 | 31 | ); 32 | }; 33 | 34 | Button.propTypes = { 35 | className: PropTypes.string.isRequired, 36 | disabled: PropTypes.bool.isRequired, 37 | inProgress: PropTypes.bool.isRequired, 38 | value: PropTypes.string.isRequired, 39 | onClick: PropTypes.func.isRequired, 40 | }; 41 | 42 | export default Button; 43 | -------------------------------------------------------------------------------- /cli/rest/staking/routes.go: -------------------------------------------------------------------------------- 1 | package staking 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/gorilla/mux" 7 | 8 | "github.com/sentinel-official/desktop-client/cli/context" 9 | ) 10 | 11 | func RegisterRoutes(r *mux.Router, ctx *context.Context) { 12 | r.Name("GetValidator"). 13 | Methods(http.MethodGet).Path("/validators/{address}"). 14 | HandlerFunc(HandlerGetValidator(ctx)) 15 | r.Name("GetValidators"). 16 | Methods(http.MethodGet).Path("/validators"). 17 | HandlerFunc(HandlerGetValidators(ctx)) 18 | 19 | r.Name("GetDelegations"). 20 | Methods(http.MethodGet).Path("/delegators/{address}/delegations"). 21 | HandlerFunc(HandlerGetDelegations(ctx)) 22 | r.Name("Delegate"). 23 | Methods(http.MethodPost).Path("/delegators/{address}/delegations"). 24 | HandlerFunc(HandlerDelegate(ctx)) 25 | r.Name("Redelegate"). 26 | Methods(http.MethodPost).Path("/delegators/{address}/delegations/redelegate"). 27 | HandlerFunc(HandlerRedelegate(ctx)) 28 | r.Name("Undelegate"). 29 | Methods(http.MethodPost).Path("/delegators/{address}/delegations/undelegate"). 30 | HandlerFunc(HandlerUndelegate(ctx)) 31 | } 32 | -------------------------------------------------------------------------------- /src/containers/common/SidebarOnboard.js: -------------------------------------------------------------------------------- 1 | import Image from '../../components/Image'; 2 | import Logo from '../../assets/Logo.svg'; 3 | import React from 'react'; 4 | import TextBox from '../../components/TextBox'; 5 | 6 | const SidebarOnboard = () => { 7 | return ( 8 |
9 | Logo 14 |
15 | 19 | 23 | 27 |
28 |
29 | ); 30 | }; 31 | 32 | export default SidebarOnboard; 33 | -------------------------------------------------------------------------------- /cli/services/wireguard/wireguard_linux.go: -------------------------------------------------------------------------------- 1 | package wireguard 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "strings" 7 | 8 | "golang.org/x/net/nettest" 9 | ) 10 | 11 | func (w *WireGuard) PreUp() error { 12 | iFace, err := nettest.RoutedInterface("ip", net.FlagUp|net.FlagBroadcast) 13 | if err != nil { 14 | return err 15 | } 16 | 17 | w.cfg.Interface.PostUp = strings.Join([]string{ 18 | "iptables -A FORWARD -i %i -j ACCEPT", 19 | fmt.Sprintf("iptables -t nat -A POSTROUTING -o %s -j MASQUERADE", iFace.Name), 20 | "ip6tables -A FORWARD -i %i -j ACCEPT", 21 | fmt.Sprintf("ip6tables -t nat -A POSTROUTING -o %s -j MASQUERADE", iFace.Name), 22 | }, ";") 23 | w.cfg.Interface.PostDown = strings.Join([]string{ 24 | "iptables -D FORWARD -i %i -j ACCEPT", 25 | fmt.Sprintf("iptables -t nat -D POSTROUTING -o %s -j MASQUERADE", iFace.Name), 26 | "ip6tables -D FORWARD -i %i -j ACCEPT", 27 | fmt.Sprintf("ip6tables -t nat -D POSTROUTING -o %s -j MASQUERADE", iFace.Name), 28 | }, ";") 29 | 30 | return w.cfg.WriteToFile(w.cfgDir) 31 | } 32 | 33 | func (w *WireGuard) RealInterface() (string, error) { 34 | return w.cfg.Name, nil 35 | } 36 | -------------------------------------------------------------------------------- /cli/x/plan/plan.go: -------------------------------------------------------------------------------- 1 | package plan 2 | 3 | import ( 4 | "time" 5 | 6 | plantypes "github.com/sentinel-official/hub/x/plan/types" 7 | 8 | "github.com/sentinel-official/desktop-client/cli/x/common" 9 | ) 10 | 11 | type Plan struct { 12 | Id uint64 `json:"id"` 13 | Provider string `json:"provider"` 14 | Price common.Coins `json:"price"` 15 | Validity int64 `json:"validity"` 16 | Bytes int64 `json:"bytes"` 17 | Status string `json:"status"` 18 | StatusAt time.Time `json:"status_at"` 19 | } 20 | 21 | func NewPlanFromRaw(item *plantypes.Plan) Plan { 22 | return Plan{ 23 | Id: item.Id, 24 | Provider: item.Provider, 25 | Price: common.NewCoinsFromRaw(item.Price), 26 | Validity: item.Validity.Nanoseconds(), 27 | Bytes: item.Bytes.Int64(), 28 | Status: item.Status.String(), 29 | StatusAt: item.StatusAt, 30 | } 31 | } 32 | 33 | type Plans []Plan 34 | 35 | func NewPlansFromRaw(items plantypes.Plans) Plans { 36 | plans := make(Plans, 0, len(items)) 37 | for _, item := range items { 38 | plans = append(plans, NewPlanFromRaw(&item)) 39 | } 40 | 41 | return plans 42 | } 43 | -------------------------------------------------------------------------------- /cli/x/staking/delegation.go: -------------------------------------------------------------------------------- 1 | package staking 2 | 3 | import ( 4 | stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" 5 | 6 | "github.com/sentinel-official/desktop-client/cli/x/common" 7 | ) 8 | 9 | type Delegation struct { 10 | DelegatorAddress string `json:"delegator_address"` 11 | ValidatorAddress string `json:"validator_address"` 12 | Shares string `json:"shares"` 13 | Balance common.Coin `json:"balance"` 14 | } 15 | 16 | func NewDelegationFromRaw(item stakingtypes.DelegationResponse) Delegation { 17 | return Delegation{ 18 | DelegatorAddress: item.Delegation.DelegatorAddress, 19 | ValidatorAddress: item.Delegation.ValidatorAddress, 20 | Shares: item.Delegation.Shares.String(), 21 | Balance: common.NewCoinFromRaw(&item.Balance), 22 | } 23 | } 24 | 25 | type Delegations []Delegation 26 | 27 | func NewDelegationsFromRaw(items stakingtypes.DelegationResponses) Delegations { 28 | delegations := make(Delegations, 0, len(items)) 29 | for _, item := range items { 30 | delegations = append(delegations, NewDelegationFromRaw(item)) 31 | } 32 | 33 | return delegations 34 | } 35 | -------------------------------------------------------------------------------- /src/containers/Wallet/Keys/ModalList/Create.js: -------------------------------------------------------------------------------- 1 | import * as PropTypes from 'prop-types'; 2 | import { connect } from 'react-redux'; 3 | import { showKeysCreateModal } from '../../../../actions/keys'; 4 | import AddIcon from '@material-ui/icons/Add'; 5 | import IconButton from '@material-ui/core/IconButton'; 6 | import React from 'react'; 7 | import Tooltip from '@material-ui/core/Tooltip'; 8 | 9 | const Create = ({ showKeysCreateModal }) => { 10 | const onClick = () => { 11 | showKeysCreateModal(); 12 | }; 13 | 14 | return ( 15 | 16 | 22 | 23 | 24 | 25 | ); 26 | }; 27 | 28 | Create.propTypes = { 29 | showKeysCreateModal: PropTypes.func.isRequired, 30 | }; 31 | 32 | const actionsToProps = { 33 | showKeysCreateModal, 34 | }; 35 | 36 | export default connect(null, actionsToProps)(Create); 37 | -------------------------------------------------------------------------------- /src/containers/Wallet/Proposals/Row/Description.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TextBox from '../../../../components/TextBox'; 3 | 4 | const Description = () => { 5 | const Description = 'The purpose of this proposal is to restore access to geneis ATOMs for a subset of donors who have been active participants in our community through the last year.\n' + 6 | 'The view of iqlusion is that this is an important moment for the Cosmos Hub. Stargate brings the fundraiser period to the end with delivery of IBC. This proposal resolves the open business of active members of our community who cannot access their ATOM. This is an opportunity is opporunity to bring this business to a close and setup the agenda for IBC powered innovation comming in 2021.We strongly encourage the Cosmos Community to verify the cryptographic evidence and bring these community members to full ATOM holder status.\n'; 7 | return ( 8 |
9 | 13 |
14 | 15 | ); 16 | }; 17 | 18 | export default Description; 19 | -------------------------------------------------------------------------------- /src/containers/KeyInfo/Continue.js: -------------------------------------------------------------------------------- 1 | import * as PropTypes from 'prop-types'; 2 | import { ValidateMnemonicSaved } from './_validation'; 3 | import { connect } from 'react-redux'; 4 | import Button from '../../components/Button'; 5 | import React from 'react'; 6 | 7 | const Continue = (props) => { 8 | const onClick = () => { 9 | props.history.push('/dashboard/wallet'); 10 | }; 11 | 12 | const disabled = ( 13 | ValidateMnemonicSaved(props.saved).message !== '' 14 | ); 15 | 16 | return ( 17 |