Voting Integration

This is a detailed doc for the voting integration and for voting directly from the contract if needed.

Allocating your votes to the reactors (and exchanges) of your choice can occur in a few different ways depending on which chain you want to transact on. Votes are tracked and tallied in our Vote Tracker contract on Polygon. You can submit direct to that contract, or submit through a bridge on mainnet. The payload for either of those transactions requires multiple pieces of information so we'll go through that first.

Please note: This document covers Liquidity Director voting. Voting for C.o.R.E. events follow the same structure and mechanics but contract addresses will be different.

Building the Vote Payload

First, lets look at a final payload and then we'll break down its various parts:

const vote = {
  account: "0x3d146A937Ddada8AfA2536367832128F3F967E29",
  voteSessionKey: "0x3100000000000000000000000000000000000000000000000000000000000000",
  nonce: 15,
  chainId: 137,
  totalVotes: "104158000000000000000000",
  allocations: [
	    reactorKey: "0x7463722d64656661756c74000000000000000000000000000000000000000000",
	    amount: "104158000000000000000000",
  • account - The wallet that has staked and that you submitting votes for

  • voteSessionKey - Ties the vote submission to the current cycle

    • While your votes will persist from cycle to cycle, we want to be sure that when they are submitted they are taken into account for the intended cycle

    • The contract will only allow submissions that have a voteSessionKey matching its currently recorded value

    • Query settings() returns ((address, uint256, uint256, bytes32 voteSessionKey)) to find the value you should use for your next submission

  • nonce - Unique value for each accounts vote submission

    • Given the various ways votes can be submitted, this value is managed by the Vote Tracker contract

    • Query userNonces(address account) returns (uint256) to find the value you should use for your next submission

  • chainId - Polygon's chain id, always 137

  • totalVotes - With the current allocations applied, this is your total votes used across all reactors/exchanges

    • Votes have 18 decimals of precision (they are tied to TOKE)

    • When submitting your vote, it is only required to submit allocations for reactors you are changing

    • However, totalVotes should reflect both the reactors you are changing, and those already submitted that you are not

      • For example, lets say the first time you vote you submit 2 votes to TCR, 2 votes to FXS. You'd submit a totalVotes of 4

      • Second time you vote you have extra votes to use because of a new TOKE deposit, you want to increase your TCR votes to 5. You would submit a payload with your TCR = 5, and a totalVotes of 7 (5 for TCR, 2 for FXS)

    • Query getUserVotes(address account) returns (( (uint256 totalUsedVotes, uint256 totalAvailableVotes) details, (bytes32 reactorKey, uint256 amount)[] votes ))

      to find your starting totalUsedVotes to work with

  • allocations - An array for all reactors/exchanges you are changing with this submission

    • If you are trying to remove all votes for a reactor, submit a 0 amount

    • Reactor keys are computed based on the underlying token symbol for that reactor. For example:

      • Tracer DAO, the overall reactor key would be tcr-default

      • While this is subject to change, when voting to a specific exchange (future functionality), this key would be tcr-uni or tcr-balancer , etc.

      • This value is then converted to a bytes32 string to get the final value: ethers.utils.formatBytes32String("tcr-default") "0x7463722d64656661756c74000000000000000000000000000000000000000000"

Direct to Contract

Your cheapest and fastest option to vote will be going direct to the contract. The payload you built above can be submitted to the Vote Tracker via: voteDirect(tuple(...) userVotePayload)


  • The msg.sender must match the account property in the payload

Via L1 Bridge

If your only option is to transact on L1 mainnet, you can submit the payload you built to our On Chain Vote L1 contract via:

vote(tuple(...) userVotePayload)


  • The msg.sender must match the account property in the payload

  • There will be a ~10 minute delay in your votes showing up in the UI while the message is bridged

  • Ensure you make your votes via this route at least 30 minutes before cycle rollover to ensure it is recorded for the current cycle.



Mainnet Addresses

  • Vote Tracker (Polygon) - 0x7A9A3395afB32F923a142dBC56467Ae5675Ce5ec

  • On Chain Vote L1 - 0x43094eD6D6d214e43C31C38dA91231D2296Ca511

Last updated