Skip to content

Onchain delegations to multiple delegates with cascading weight calculations

License

Notifications You must be signed in to change notification settings

gnosisguild/split-delegation

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Split Delegation

A general-purpose delegate registry.

Features

  • Delegate to multiple addresses (specify the percentage of your vote-weight for each).
  • Cascading delegations (Delegate A -> Delegate B -> Delegate C = Delegate C's total voting power = A + B + C)
  • Expiring delegations
  • Automatic vote weight adjustment based on token balance changes.
  • Delegation revocation at any time.

Using with Snapshot

We Split-Delegation to be used with snapshot, and have integrated it into a corresponding snapshot strategy, so you can use this delegation registry natively in the Snapshot UI.

To integrate it into your Snapshot space, follow these steps:

  1. Create a Snapshot space if you do not already have one

  2. Choose the 'Split-Delegation' strategy during space creation, or select it in your space settings.

    • 'Split-Delegation' must be your only top-level strategy. In the parameters for this strategy, you can add more strategies that will be used as sub-strategies. Sub-strategies added here will be used to compute a score for any address that can then be combined with delegation weights to compute that address's total voting power. Move all of your existing strategies under Split-Delegation's strategies field (remove any existing delegation strategies).

    • For reference, here is an example of the JSON for a 'Split-Delegation' strategy:

    {
      "name": "split-delegation",
      "params": {
        "backendUrl": "https://delegate-api.gnosisguild.org",
        "totalSupply": 1000000000, // denominated in ether NOT wei
        "strategies": [
          {
            "name": "erc20-balance-of",
            "params": {
              "symbol": "SAFE",
              "address": "0x5aFE3855358E112B5647B952709E6165e1c1eEEe",
              "decimals": 18
            },
            "network": 1
          }
        ]
      }
    }
    • totalSupply is used to display useful metrics in the Snapshot UI (e.g. percentage of vote or delegators controlled by one account), and is not used in final vote power calculations.
  3. Setup the split-delegation settings for your snapshot space ui

    • In your space settings, navigate to the 'Delegation' page, and select 'Split-Delegation' from the dropdown.
    • For the contract address use 0xDE1e8A7E184Babd9F0E3af18f40634e9Ed6F0905 (unless using your own deployment of the delegate registry)
    • For the delegation UI, use https://delegate-api.gnosisguild.org (if using your own instance of the delegate api, use that url)

The delegation dashboard should now be useable on the 'Delegates' page of your snapshot space.

Upgrading from existing Delegation Registry

Split-Delegation takes into account delegations made with the v1 contract, and can be used simultaneously with v1, allowing graceful upgrading. This means that delegations made on the v1 contract and on the Split-Delegation contract will be used when calculating total vote power. To use Split-Delegation, remove your existing delegation strategy when following the instructions above.

Packages

API

The api package is responsible for indexing, computing, caching and exposing each address's delegated voting power. It provides a set of API endpoints that allow you to interact with the delegate registry. It computes voting power based on scores and weights associated with an address.

Endpoints

Each endpoint has two identifying components in its path: space and tag. Space defines which snapshot space should be queried (e.g. safe.eth). Tag defines a time up to when the query should return. Possible values for tag are: a block number, a viem blocktag, or 'pin', which returns our cached value that updates every ten minutes. 'Pin' should be used in most cases, to reduce load on the server.

Note

  • Expired delegations are not returned
  • Delegations to an address that has opted-out are not returned
POST /api/v1/[space]/[tag]/top-delegates
  • Query params:
    • limit - number - used for pagination, defaults to 100
    • offset - number - used for pagination, defaults to 0
    • orderBy - required - must be either power or count. Power returns delegates sorted by voting power descending; count returns delegates sorted by amount of delegations descending.
  • Request body must contain a valid split-delegation strategy:
      {
        "strategy": {
          "name": "split-delegation",
          "network": "1",
          "params": {
            "delegationOverride": false
            "totalSupply": 1000000000000
            "strategies": [{
              "name": "erc20-balance-of",
              "params": {
                "symbol": "vCOW (mainnet)",
                "address": "0xd057b63f5e69cf1b929b356b579cba08d7688048",
                "decimals": 18
              },
              "network": "1"
            }]
          }
        }
      }
    
  • Return value:
    {
      "chainId": "1",
      "blockNumber": "19947439",
      "delegates": [
        {
          "address": "0x37F1eE65C2F8610741cd9Dff1057F926809C4078",
          "delegatorCount": 5,
          "percentOfDelegators": 600,
          "votingPower": 21.41231,
          "percentOfVotingPower": 211
        }...
      ]
    }
    
POST /api/v1/[space]/[tag]/[address]
  • Request body must contain a valid split-delegation strategy:

      {
        "strategy": {
          "name": "split-delegation",
          "network": "1",
          "params": {
            "delegationOverride": false
            "totalSupply": 1000000000000
            "strategies": [{
              "name": "erc20-balance-of",
              "params": {
                "symbol": "vCOW (mainnet)",
                "address": "0xd057b63f5e69cf1b929b356b579cba08d7688048",
                "decimals": 18
              },
              "network": "1"
            }]
          }
        }
      }
    
  • Return value:

    {
      "chainId": "1",
      "blockNumber": "19947439",
      "address": "0x37F1eE65C2F8610741cd9Dff1057F926809C4078",
      "expiration": 1724091264,
      "votingPower": 21.41231,
      "incomingPower": 21.41231,
      "outgoingPower": 10.00000,
      "percentOfVotingPower": 211,
      "percentOfDelegators": 600,
      delegators: [
        "0x485E60C486671E932fd9C53d4110cdEab1E7F0eb"
      ],
      delegatorTree [
        {
          "delegator": "0x485E60C486671E932fd9C53d4110cdEab1E7F0eb",
          "expiration": 1724091264,
          "weight": 10000,
          "delegatedPower": 21.71540506,
          "parents": []
        }
      ],
      delegates [
        "0xD476B79539781e499396761CE7e21ab28AeA828F"
      ],
      delegateTree [
        {
          "delegate": "0xD476B79539781e499396761CE7e21ab28AeA828F",
          "expiration": 1724091264,
          "weight": 5000,
          "delegatedPower": 10.00000,
          "children": []
        }
      ],
    }
    
POST /api/v1/[space]/[tag]/voting-power
  • Request body must contain a valid split-delegation strategy, and an array of addresses. This endpoint is designed to be consumed by Snapshot during the voting process.

      {
        "strategy": {
          "name": "split-delegation",
          "network": "1",
          "params": {
            "delegationOverride": false
            "totalSupply": 1000000000000
            "strategies": [{
              "name": "erc20-balance-of",
              "params": {
                "symbol": "vCOW (mainnet)",
                "address": "0xd057b63f5e69cf1b929b356b579cba08d7688048",
                "decimals": 18
              },
              "network": "1"
            }]
          }
        },
        addresses: [
          "0xD476B79539781e499396761CE7e21ab28AeA828F",
          "0x485E60C486671E932fd9C53d4110cdEab1E7F0eb",
          "0x37F1eE65C2F8610741cd9Dff1057F926809C4078",
        ]
      }
    
    • Return value:
    {
      "0x37F1eE65C2F8610741cd9Dff1057F926809C4078": 0,
      "0x485E60C486671E932fd9C53d4110cdEab1E7F0eb": 21.71540506,
      "0xD476B79539781e499396761CE7e21ab28AeA828F": 10.0000,
    }
    

Key Terms

  • Score - value given to an address based on the sub-strategies applied to the Split-Delegation strategy.
    • For example: an erc20-balance-of strategy will return scores based on the amount of tokens an address holds
  • Weight - value given to an address based on delegations made to that address.
  • Voting Power - computed value given to an address using score * weight

EVM

The evm package contains the Ethereum Virtual Machine (EVM) contracts for the delegate registry. These contracts are written in Solidity and can be deployed to any EVM-compatible blockchain. The package also includes a Hardhat configuration for compiling the contracts and running tests, as well as scripts for deploying the contracts and interacting with them on a blockchain.