{"id":26183833,"url":"https://github.com/glamsystems/jupiter-vote-service","last_synced_at":"2025-07-10T17:06:53.310Z","repository":{"id":281223222,"uuid":"913349651","full_name":"glamsystems/jupiter-vote-service","owner":"glamsystems","description":"Jupiter DAO Representative Automation","archived":false,"fork":false,"pushed_at":"2025-05-30T00:21:46.000Z","size":237,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-05-30T01:25:49.896Z","etag":null,"topics":["java","jupiter-dao","solana"],"latest_commit_sha":null,"homepage":"https://fatcat.vote","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/glamsystems.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-01-07T14:12:44.000Z","updated_at":"2025-05-30T00:21:50.000Z","dependencies_parsed_at":"2025-05-20T12:37:53.623Z","dependency_job_id":null,"html_url":"https://github.com/glamsystems/jupiter-vote-service","commit_stats":null,"previous_names":["glamsystems/jupiter-vote-service"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/glamsystems/jupiter-vote-service","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glamsystems%2Fjupiter-vote-service","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glamsystems%2Fjupiter-vote-service/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glamsystems%2Fjupiter-vote-service/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glamsystems%2Fjupiter-vote-service/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/glamsystems","download_url":"https://codeload.github.com/glamsystems/jupiter-vote-service/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glamsystems%2Fjupiter-vote-service/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264614779,"owners_count":23637654,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java","jupiter-dao","solana"],"created_at":"2025-03-11T22:49:32.385Z","updated_at":"2025-07-10T17:06:53.294Z","avatar_url":"https://github.com/glamsystems.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GLAM Jupiter Vote Service\n\nAutomates the task for a Jupiter DAO representative to vote on-behalf of their constituents.\n\nIf a GLAM is observed to cast their own vote the service will NOT override the users vote for that proposal.\n\n## Compile \u0026 Run\n\n### GitHub Access Token\n\nNeeded to access dependencies hosted on GitHub Package Repository.\n\nCreate a `gradle.properties` file in this directory or under `$HOME/.gradle/`.\n\n[Generate a classic token](https://github.com/settings/tokens) with the `read:packages` scope.\n\n```properties\ngpr.user=GITHUB_USERNAME\ngpr.token=GITHUB_TOKEN\n```\n\n### Common Run Args\n\nWith dry run enabled all code paths will still be hit, excluding only publishing transactions.\n\n* dryRun=\"false\"\n* jvmArgs=\"-server -XX:+UseZGC -Xms128M -Xmx896M\"\n* logLevel=\"INFO\"\n\n### Docker\n\n#### Build\n\nBuilds an Alpine based image with a custom runtime image using Java jlink.\n\nIf your gradle properties file is not local you can pass your GitHub access token via environment variables.\n\n```shell\nexport GITHUB_ACTOR=\"GITHUB_USERNAME\"\nexport GITHUB_TOKEN=\"GITHUB_TOKEN\"\ndocker build \\\n  --secret type=env,id=GITHUB_ACTOR,env=GITHUB_ACTOR \\\n  --secret type=env,id=GITHUB_TOKEN,env=GITHUB_TOKEN \\\n    -t glam-systems/jupiter-vote-service:latest .\n```\n\n#### Run Script\n\n`configDirectory` must be absolute.\n\n##### Args\n\n* configFileName=\"\"\n* configDirectory=\"$(pwd)/.config\"\n* dockerImageName=\"glam-systems/jupiter-vote-service:latest\"\n* dockerRunFlags=\"--detach --name jupiter_vote_service --memory 1g\"\n\n```shell\n./runDockerImage.sh --configFileName=vote_service.json\n```\n\n### Local Compile Script\n\nJava JDK 23 or later is required.\n\nCompiles a custom runtime image using Java jlink, that can be found at\n`jupiter_vote_service/build/jupiter_vote_service/bin/java`.\n\n```shell\n ./compile.sh\n```\n\n### Local Run Script\n\n#### Args\n\n* configFile=\"\"\n* screen=[0|1]\n\n```shell\n./runService.sh --configFile=.config/vote_service.json\n```\n\n-Dsystems.glam.jupiter_vote_service.config=.config/vote_service.json\n-Dsystems.glam.jupiter_vote_service.dry_run=false\n\n## Configuration\n\n### Primitives\n\n#### Time\n\nDurations/windows/delays are [ISO-8601 duration](https://en.wikipedia.org/wiki/ISO_8601#Durations) formatted\n`PnDTnHnMn.nS`,  `PT` may be omitted.\n\n#### `capacity`\n\nRequest capacity limits for constrained resources.\n\n* `maxCapacity`: Maximum requests that can be made within `resetDuration`\n* `resetDuration`: `maxCapacity` is added over the course of this duration.\n* `minCapacityDuration`: Maximum time before capacity should recover to a positive value, given that no additional\n  failures happen.\n\n#### `backoff`\n\nBackoff strategy in response to errors.\n\n* `type`: single, linear, fibonacci, exponential\n* `initialRetryDelay`\n* `maxRetryDelay`\n\n### Example\n\nSee context below.\n\n```json\n{\n  \"signingService\": {\n    \"factoryClass\": \"software.sava.kms.core.signing.MemorySignerFromFilePointerFactory\",\n    \"config\": {\n      \"filePath\": \".config/service_key.json\"\n    }\n  },\n  \"workDir\": \".vote\",\n  \"ballotFilePath\": \".config/glam_ballot.json\",\n  \"formatter\": {\n    \"sig\": \"https://solscan.io/tx/%s\",\n    \"address\": \"https://solscan.io/account/%s\"\n  },\n  \"api\": {\n    \"basePath\": \"/api/v0/\",\n    \"port\": 7073\n  },\n  \"notificationHooks\": [\n    {\n      \"endpoint\": \"https://hooks.slack.com/\u003cURL_PATH_PROVIDED_BY_SLACK\u003e\",\n      \"provider\": \"SLACK\",\n      \"capacity\": {\n        \"maxCapacity\": 2,\n        \"resetDuration\": \"1S\",\n        \"minCapacityDuration\": \"8S\"\n      }\n    }\n  ],\n  \"rpcCallWeights\": {\n    \"getProgramAccounts\": 2,\n    \"getTransaction\": 5,\n    \"sendTransaction\": 10\n  },\n  \"rpc\": {\n    \"defaultCapacity\": {\n      \"minCapacityDuration\": \"PT8S\",\n      \"maxCapacity\": 4,\n      \"resetDuration\": \"PT1S\"\n    },\n    \"endpoints\": [\n      {\n        \"url\": \"https://mainnet.helius-rpc.com/?api-key=\",\n        \"capacity\": {\n          \"minCapacityDuration\": \"PT5S\",\n          \"maxCapacity\": 50,\n          \"resetDuration\": \"PT1S\"\n        }\n      },\n      {\n        \"url\": \"https://solana-mainnet.rpc.extrnode.com/\"\n      }\n    ]\n  },\n  \"sendRPC\": {\n    \"defaultCapacity\": {\n      \"maxCapacity\": 1,\n      \"resetDuration\": \"1S\",\n      \"minCapacityDuration\": \"8S\"\n    },\n    \"endpoints\": [\n      {\n        \"url\": \"https://staked.helius-rpc.com/?api-key=\"\n      }\n    ]\n  },\n  \"websocket\": {\n    \"endpoint\": \"wss://mainnet.helius-rpc.com/?api-key=\"\n  },\n  \"helius\": {\n    \"url\": \"https://mainnet.helius-rpc.com/?api-key=\",\n    \"capacity\": {\n      \"maxCapacity\": 2,\n      \"resetDuration\": \"1S\",\n      \"minCapacityDuration\": \"8S\"\n    }\n  },\n  \"schedule\": {\n    \"initialDelay\": 0,\n    \"delay\": 1,\n    \"timeUnit\": \"HOURS\"\n  },\n  \"minLockedToVote\": 1,\n  \"stopVotingBeforeEndDuration\": \"42S\",\n  \"newVoteBatchSize\": 3,\n  \"changeVoteBatchSize\": 6,\n  \"maxSOLPriorityFee\": 0.00042\n}\n```\n\n\u003c!-- TOC --\u003e\n\n* [signingService](#signingservice)\n  * [Delegation Requirements](#delegation-requirements)\n* [workDir](#workdir)\n* [ballotFilePath](#ballotfilepath)\n* [formatter](#formatter)\n* [notificationHooks](#notificationhooks)\n* [rpcCallWeights](#rpccallweights)\n* [rpc](#rpc)\n* [sendRPC](#sendrpc)\n* [helius](#helius)\n* [websocket](#websocket)\n* [minLockedToVote](#minlockedtovote)\n* [stopVotingBeforeEndDuration](#stopvotingbeforeendduration)\n* [newVoteBatchSize](#newvotebatchsize)\n* [changeVoteBatchSize](#changevotebatchsize)\n* [maxSOLPriorityFee](#maxSOLPriorityFee)\n\n\u003c!-- TOC --\u003e\n\n### `signingService`\n\nService key used to pay for transactions.\n\nSee [Sava KMS](https://sava.software/libraries/kms#service-configuration) for some example options and configuration.\n\n#### Delegation Requirements\n\nEach GLAM that delegates to this service key must have the following minimum configuration.\n\n##### Integrations\n\n* JupiterVote\n\n##### Permissions\n\n* VoteOnProposal\n\n### `workDir`\n\nUsed to cache run time state and track the proposal vote state for each delegated GLAM.\n\n### `ballotFilePath`\n\nHolds the representatives vote side for each proposal they wish to vote on.\n\nThe `proposal` key can be found in the URL for each proposal page hosted by vote.jup.ag,\ne.g., https://vote.jup.ag/proposal/ByQ21v3hqdQVwPHsfwurrtEAH8pB3DYuLdp9jU2Hwnd4.\n\nThe representative may change their vote by updating this file and restarting the service.\n\n#### JSON Configuration\n\nTODO: Map text based side to int.\n\n```json\n[\n  {\n    \"proposal\": \"ByQ21v3hqdQVwPHsfwurrtEAH8pB3DYuLdp9jU2Hwnd4\",\n    \"side\": 3\n  }\n]\n```\n\n### [`formatter`](https://sava.software/libraries/ravina#chain-item-formatter)\n\n### [`notificationHooks`](https://sava.software/libraries/ravina#webhook-configuration)\n\nDetailed JSON messages will be POSTed to each webhook endpoint.\n\n### `api`\n\nLocal webserver to provide service information.\n\n#### Defaults\n\n```json\n{\n  \"basePath\": \"/api/v0/\",\n  \"port\": 7073\n}\n```\n\n### `rpcCallWeights`\n\nDefine call weights per RPC call to help match your providers API limits. See\nthe [CallWeights](https://github.com/sava-software/services/blob/main/solana/src/main/java/software/sava/services/solana/remote/call/CallWeights.java)\nclass for which are supported.\n\n#### Defaults\n\n```json\n{\n  \"getProgramAccounts\": 2,\n  \"getTransaction\": 5,\n  \"sendTransaction\": 10\n}\n```\n\n### `rpc`\n\n* `defaultCapacity`\n* `defaultBackoff`\n* `endpoints`: Array of RPC node configurations.\n  * `url`\n  * `capacity`: Overrides `defaultCapacity`\n  * `backoff`: Overrides `defaultBackoff`\n\n#### Defaults\n\n```json\n{\n  \"defaultCapacity\": {\n    \"maxCapacity\": 10,\n    \"resetDuration\": \"1S\",\n    \"minCapacityDuration\": \"13S\"\n  }\n}\n```\n\n### `sendRPC`\n\nSame as `rpc` but only used for publishing transactions to the network. Defaults to the `rpc` configuration if not\nprovided.\n\n#### Defaults\n\n```json\n{\n  \"defaultCapacity\": {\n    \"maxCapacity\": 1,\n    \"resetDuration\": \"1S\",\n    \"minCapacityDuration\": \"5S\"\n  }\n}\n```\n\n### `helius`\n\nSame as a single `rpc` `endpoint` entry. Only used for estimating priority fees.\n\n#### Defaults\n\n```json\n{\n  \"capacity\": {\n    \"maxCapacity\": 3,\n    \"resetDuration\": \"1S\",\n    \"minCapacityDuration\": \"5S\"\n  }\n}\n```\n\n### `websocket`\n\nUsed to track GLAM Vault account changes.\n\n* `endpoint`\n* `backoff`\n\n### `minLockedToVote`\n\nDefaults to 1 JUP.\n\n### `stopVotingBeforeEndDuration`\n\nStop executing vote transactions this close to the end of the proposal conclusion.\n\n### `newVoteBatchSize`\n\nNumber of GLAM vaults to cast new votes for per transaction. Each new vote requires two instructions, create vote\naccount and cast vote. The service will dynamically reduce this size if a transaction exceeds the size limit.\n\nDefaults to 5.\n\n### `changeVoteBatchSize`\n\nNumber of GLAM vaults to change votes for per transaction. Each vote change requires one instruction, cast vote. The\nservice will dynamically reduce this size if a transaction exceeds the size limit.\n\nDefaults to 10.\n\n### `maxSOLPriorityFee`\n\nCaps the maximum priority fee for all transactions within the system. Default is 0.00042 SOL.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fglamsystems%2Fjupiter-vote-service","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fglamsystems%2Fjupiter-vote-service","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fglamsystems%2Fjupiter-vote-service/lists"}