DAO DAO
LinksLaunch App
  • Welcome to DAO DAO
  • Introduction
    • Quickstart
      • Create your first DAO
      • Join a DAO
        • Joining and leaving a member-based DAO
        • Joining and leaving a token-based DAO
      • Create your first proposal
      • Voting
      • Congratulations!
    • What's a DAO?
    • What's a blockchain?
    • Technical breakdown
    • Contribute to DAO DAO!
  • DAO Management
    • Create a DAO
    • Update appearance
    • SubDAOs
      • What are SubDAOs?
      • How to create a SubDAO
      • How to act on behalf of a SubDAO
    • Treasury
      • Send tokens
      • Manage cross-chain tokens
      • Manage staking
      • Displaying tokens and NFTs
      • Enable vesting payments
    • Manage Members
      • Joining and leaving a member-based DAO
      • Joining and leaving a token-based DAO
    • Authz
      • Grant Authorization
      • Revoke Authorization
      • Execute via Authorization
      • Limitation
    • Cross-chain support
  • DAO Governance
    • Configuration
      • Voting
      • Proposal submission
      • Staking
    • Proposals
      • What are proposals?
      • Types of proposals
      • How to create a proposal
      • How to vote on a proposal
      • How to add a proposal module
      • How to change a pre-propose module
      • How to bulk import actions
      • How to create an autofill proposal link
    • Manage Vetoable DAOs
    • Migration
    • Notifications
      • Telegram Notifications
Powered by GitBook
On this page
  • Link format
  • IPFS
  • Proposal module adapter ID
  • Proposal module form data
  • Action keys
  • spend
  • execute
  • mintNft
  • mint
  • Example
Export as PDF
  1. DAO Governance
  2. Proposals

How to create an autofill proposal link

Proposals and the actions they contain can be generated programmatically and passed in via URL—this enables a more user-friendly experience for users of a specific app or service that rely on DAO DAO for their governance needs.

Similar to the bulk import actions feature, you must find the key and the shape of the data object for each action. However, unlike bulk import, you must also find the proposal module adapter ID, and the action key in the object must be actionKey instead of key.

Link format

The link is simply the proposal creation page with a prefill parameter added, like this:

https://daodao.zone/dao/<DAO_ADDRESS>/proposals/create?prefill=<PREFILL_DATA>

The prefill parameter can either be:

  • a stringified JSON object

  • a base64-encoded JSON object

Remember to URL-escape the prefill parameter, whichever format it's in. For example, base64 strings sometimes contain + and =, which must be escaped as %2B and %3D respectively, or else they'll be decoded incorrectly and fail to autofill the proposal.

The format of the prefill object is always:

{
  "id": "<PROPOSAL MODULE ADAPTER ID>",
  "data": {
    // PROPOSAL MODULE FORM DATA
  }
}

You can use base64encode.org to encode the JSON object to a base64 string and urlencoder.org to URL-escape the base64 string.

IPFS

The prefill object can get quite large which becomes impractical to use in a URL, so instead you can upload a JSON blob to IPFS and replace the prefill parameter with pi, pointing to the IPFS hash containing the object:

https://daodao.zone/dao/<DAO_ADDRESS>/proposals/create?pi=<IPFS_HASH>

Proposal module adapter ID

The proposal module adapter IDs can be found in @dao-dao/utils/constants/adapters.ts.

For dao-proposal-single (the most commonly used proposal module that supports proposals with Yes/No/Abstain votes), the ID is DaoProposalSingle. For dao-proposal-multiple (which supports multiple choice proposals), the ID is DaoProposalMultiple.

Proposal module form data

The form data structure can be found in @dao-dao/types/proposal-module-adapter.ts.

The single choice proposal form data is:

{
  "title": "<PROPOSAL TITLE>",
  "description": "<PROPOSAL DESCRIPTION>",
  "actionData": [
    {
      "actionKey": "<ACTION KEY>",
      "data": {
        // ACTION DATA
      }
    },
    ...
  ]
}

The multiple choice proposal form data is:

{
  "title": "<PROPOSAL TITLE>",
  "description": "<PROPOSAL DESCRIPTION>",
  "choices": [
    {
      "title": "<OPTION TITLE>",
      "description": "<OPTION DESCRIPTION>",
      "actionData": [
        {
          "actionKey": "<ACTION KEY>",
          "data": {
            // ACTION DATA
          }
        },
        ...
      ]
    },
    ...
  ]
}

See the bottom of this document for a complete example.

Action keys

The action keys can be found in @dao-dao/types/actions.ts in the ActionKey enum. For example:

  • spend

  • execute

  • mintNft

  • mint

The key and data format for an action are defined in its README.md, and the actions can be found in the following places:

  • @dao-dao/stateful/actions/core/actions — common actions to all DAOs.

  • @dao-dao/stateful/voting-module-adapter/adapters/*/actions — each voting module adapter may contain specific actions (for example: member-based DAOs include a Manage Members action).

  • @dao-dao/stateful/proposal-module-adapter/adapters/*/common/actions — each proposal module adapter may contain specific actions (for example: single choice proposals have a different Update Proposal Submission Config action from multiple choice proposals).

  • @dao-dao/stateful/modules/modules/*/actions — each module may contain specific actions (for example: the vesting payments module adds an action to manage vesting payments).

Here are some common ones:

spend

For sending money from the treasury.

{
  "fromChainId": "<CHAIN ID>",
  "toChainId": "<CHAIN ID>",
  "from": "<FROM ADDRESS>",
  "to": "<RECIPIENT ADDRESS>",
  "amount": "<AMOUNT>",
  "denom": "<DENOM>"
}

execute

For executing a smart contract.

{
  "chainId": "<CHAIN ID>",
  "sender": "<EXECUTOR ADDRESS>",
  "address": "<SMART CONTRACT ADDRESS>",
  "message": "<SMART CONTRACT MESSAGE>",
  "funds": [
    {
      "denom": "<DENOM>",
      "amount": "<AMOUNT>",
      "decimals": "<DECIMALS>"
    }
  ]
}

mintNft

For minting an NFT in a collection the DAO controls.

{
  "contractChosen": true,
  "collectionAddress": "<NFT COLLECTION ADDRESS>",
  "mintMsg": {
    "owner": "<RECIPIENT ADDRESS>",
    "token_id": "<UNIQUE TOKEN ID>",
    "token_uri": "<JSON METADATA URL>"
  }
}

mint

For minting governance tokens in a token-based DAO.

{
  "recipient": "<RECIPIENT ADDRESS>",
  "amount": "<TOKEN AMOUNT>"
}

Example

Here's an example of a proposal link that creates a single choice proposal with a spend action and an execute action in the DAO DAO DAO.

{
  "id": "DaoProposalSingle",
  "data": {
    "title": "Example Proposal",
    "description": "This proposal will send 100 JUNO to our community fund and update our voting module's unstaking duration.",
    "actionData": [
      {
        "actionKey": "spend",
        "data": {
          "fromChainId": "juno-1",
          "toChainId": "juno-1",
          "from": "juno10h0hc64jv006rr8qy0zhlu4jsxct8qwa0vtaleayh0ujz0zynf2s2r7v8q",
          "to": "juno1community...fund456",
          "amount": "100",
          "denom": "ujuno"
        }
      },
      {
        "actionKey": "execute",
        "data": {
          "chainId": "juno-1",
          "sender": "juno10h0hc64jv006rr8qy0zhlu4jsxct8qwa0vtaleayh0ujz0zynf2s2r7v8q",
          "address": "juno1voting...module789",
          "message": "{\"update_config\":{\"duration\":86400}}",
          "funds": []
        }
      }
    ]
  }
}

Base64-encoding the entire object:

ewogICJpZCI6ICJEYW9Qcm9wb3NhbFNpbmdsZSIsCiAgImRhdGEiOiB7CiAgICAidGl0bGUiOiAiRXhhbXBsZSBQcm9wb3NhbCIsCiAgICAiZGVzY3JpcHRpb24iOiAiVGhpcyBwcm9wb3NhbCB3aWxsIHNlbmQgMTAwIEpVTk8gdG8gb3VyIGNvbW11bml0eSBmdW5kIGFuZCB1cGRhdGUgb3VyIHZvdGluZyBtb2R1bGUncyB1bnN0YWtpbmcgZHVyYXRpb24uIiwKICAgICJhY3Rpb25EYXRhIjogWwogICAgICB7CiAgICAgICAgImFjdGlvbktleSI6ICJzcGVuZCIsCiAgICAgICAgImRhdGEiOiB7CiAgICAgICAgICAiZnJvbUNoYWluSWQiOiAianVuby0xIiwKICAgICAgICAgICJ0b0NoYWluSWQiOiAianVuby0xIiwKICAgICAgICAgICJmcm9tIjogImp1bm8xMGgwaGM2NGp2MDA2cnI4cXkwemhsdTRqc3hjdDhxd2EwdnRhbGVheWgwdWp6MHp5bmYyczJyN3Y4cSIsCiAgICAgICAgICAidG8iOiAianVubzFjb21tdW5pdHkuLi5mdW5kNDU2IiwKICAgICAgICAgICJhbW91bnQiOiAiMTAwIiwKICAgICAgICAgICJkZW5vbSI6ICJ1anVubyIKICAgICAgICB9CiAgICAgIH0sCiAgICAgIHsKICAgICAgICAiYWN0aW9uS2V5IjogImV4ZWN1dGUiLAogICAgICAgICJkYXRhIjogewogICAgICAgICAgImNoYWluSWQiOiAianVuby0xIiwKICAgICAgICAgICJzZW5kZXIiOiAianVubzEwaDBoYzY0anYwMDZycjhxeTB6aGx1NGpzeGN0OHF3YTB2dGFsZWF5aDB1anowenluZjJzMnI3djhxIiwKICAgICAgICAgICJhZGRyZXNzIjogImp1bm8xdm90aW5nLi4ubW9kdWxlNzg5IiwKICAgICAgICAgICJtZXNzYWdlIjogIntcInVwZGF0ZV9jb25maWdcIjp7XCJkdXJhdGlvblwiOjg2NDAwfX0iLAogICAgICAgICAgImZ1bmRzIjogW10KICAgICAgICB9CiAgICAgIH0KICAgIF0KICB9Cn0=

And then URL-escaping the base64 string simply replaces the = at the end with %3D:

ewogICJpZCI6ICJEYW9Qcm9wb3NhbFNpbmdsZSIsCiAgImRhdGEiOiB7CiAgICAidGl0bGUiOiAiRXhhbXBsZSBQcm9wb3NhbCIsCiAgICAiZGVzY3JpcHRpb24iOiAiVGhpcyBwcm9wb3NhbCB3aWxsIHNlbmQgMTAwIEpVTk8gdG8gb3VyIGNvbW11bml0eSBmdW5kIGFuZCB1cGRhdGUgb3VyIHZvdGluZyBtb2R1bGUncyB1bnN0YWtpbmcgZHVyYXRpb24uIiwKICAgICJhY3Rpb25EYXRhIjogWwogICAgICB7CiAgICAgICAgImFjdGlvbktleSI6ICJzcGVuZCIsCiAgICAgICAgImRhdGEiOiB7CiAgICAgICAgICAiZnJvbUNoYWluSWQiOiAianVuby0xIiwKICAgICAgICAgICJ0b0NoYWluSWQiOiAianVuby0xIiwKICAgICAgICAgICJmcm9tIjogImp1bm8xMGgwaGM2NGp2MDA2cnI4cXkwemhsdTRqc3hjdDhxd2EwdnRhbGVheWgwdWp6MHp5bmYyczJyN3Y4cSIsCiAgICAgICAgICAidG8iOiAianVubzFjb21tdW5pdHkuLi5mdW5kNDU2IiwKICAgICAgICAgICJhbW91bnQiOiAiMTAwIiwKICAgICAgICAgICJkZW5vbSI6ICJ1anVubyIKICAgICAgICB9CiAgICAgIH0sCiAgICAgIHsKICAgICAgICAiYWN0aW9uS2V5IjogImV4ZWN1dGUiLAogICAgICAgICJkYXRhIjogewogICAgICAgICAgImNoYWluSWQiOiAianVuby0xIiwKICAgICAgICAgICJzZW5kZXIiOiAianVubzEwaDBoYzY0anYwMDZycjhxeTB6aGx1NGpzeGN0OHF3YTB2dGFsZWF5aDB1anowenluZjJzMnI3djhxIiwKICAgICAgICAgICJhZGRyZXNzIjogImp1bm8xdm90aW5nLi4ubW9kdWxlNzg5IiwKICAgICAgICAgICJtZXNzYWdlIjogIntcInVwZGF0ZV9jb25maWdcIjp7XCJkdXJhdGlvblwiOjg2NDAwfX0iLAogICAgICAgICAgImZ1bmRzIjogW10KICAgICAgICB9CiAgICAgIH0KICAgIF0KICB9Cn0%3D

Using the DAO DAO DAO address and then adding the prefill parameter to the URL gives us the proposal creation page with the proposal prefilled:

https://daodao.zone/dao/juno10h0hc64jv006rr8qy0zhlu4jsxct8qwa0vtaleayh0ujz0zynf2s2r7v8q/proposals/create?prefill=ewogICJpZCI6ICJEYW9Qcm9wb3NhbFNpbmdsZSIsCiAgImRhdGEiOiB7CiAgICAidGl0bGUiOiAiRXhhbXBsZSBQcm9wb3NhbCIsCiAgICAiZGVzY3JpcHRpb24iOiAiVGhpcyBwcm9wb3NhbCB3aWxsIHNlbmQgMTAwIEpVTk8gdG8gb3VyIGNvbW11bml0eSBmdW5kIGFuZCB1cGRhdGUgb3VyIHZvdGluZyBtb2R1bGUncyB1bnN0YWtpbmcgZHVyYXRpb24uIiwKICAgICJhY3Rpb25EYXRhIjogWwogICAgICB7CiAgICAgICAgImFjdGlvbktleSI6ICJzcGVuZCIsCiAgICAgICAgImRhdGEiOiB7CiAgICAgICAgICAiZnJvbUNoYWluSWQiOiAianVuby0xIiwKICAgICAgICAgICJ0b0NoYWluSWQiOiAianVuby0xIiwKICAgICAgICAgICJmcm9tIjogImp1bm8xMGgwaGM2NGp2MDA2cnI4cXkwemhsdTRqc3hjdDhxd2EwdnRhbGVheWgwdWp6MHp5bmYyczJyN3Y4cSIsCiAgICAgICAgICAidG8iOiAianVubzFjb21tdW5pdHkuLi5mdW5kNDU2IiwKICAgICAgICAgICJhbW91bnQiOiAiMTAwIiwKICAgICAgICAgICJkZW5vbSI6ICJ1anVubyIKICAgICAgICB9CiAgICAgIH0sCiAgICAgIHsKICAgICAgICAiYWN0aW9uS2V5IjogImV4ZWN1dGUiLAogICAgICAgICJkYXRhIjogewogICAgICAgICAgImNoYWluSWQiOiAianVuby0xIiwKICAgICAgICAgICJzZW5kZXIiOiAianVubzEwaDBoYzY0anYwMDZycjhxeTB6aGx1NGpzeGN0OHF3YTB2dGFsZWF5aDB1anowenluZjJzMnI3djhxIiwKICAgICAgICAgICJhZGRyZXNzIjogImp1bm8xdm90aW5nLi4ubW9kdWxlNzg5IiwKICAgICAgICAgICJtZXNzYWdlIjogIntcInVwZGF0ZV9jb25maWdcIjp7XCJkdXJhdGlvblwiOjg2NDAwfX0iLAogICAgICAgICAgImZ1bmRzIjogW10KICAgICAgICB9CiAgICAgIH0KICAgIF0KICB9Cn0%3D

PreviousHow to bulk import actionsNextManage Vetoable DAOs

Last updated 5 days ago