Integrate Streamflow with Realms

By

By

Streamflow

Streamflow

Feb 6, 2023

Feb 6, 2023

Problem to Solve:

A seamless frontend for streamflow payouts would majorly improve the user experience and increase the pace of grants and vesting.

Possible Solution:

Allow SPL Governance users to vest tokens or give out grants through the realms.today interface.

Intro

SPL Governance

Program for controlling assets by making proposals, discussions, and voting.

De facto UI for SPL governance: https://realms.today/

Streamflow

JS SDK for interaction with the on-chain program: https://github.com/streamflow-finance/js-sdk

Token vesting using Streamflow

A step-by-step guide on setting up token vesting contracts on Solana - https://docs.streamflow.finance/help/tutorials/token-vesting

How will integration be done

  1. Brief with Streamflow team (after reading this document)

  2. Streamflow to provide the required access to: Figma, Github, any additional resources needed.

  3. Use Streamflow UI fork of Realms UI, branch with working PoC (a bit stale, so please merge the latest version, and create a PR [in draft]

  4. Develop UI requirements (listed below) in the following chunks:(Each step should be approved by Streamflow)
    - Add Streamflow instruction to the instructions dropdown (0.5d)
    - Develop Create Vesting Form, validations and prepare data object for the SDK to be invoked (2d)
    - Serialize instruction using JS-SDK and prepare it for the proposal (1d)
    - Integrate instruction with the Realms proposal plugin system (2d)
    - Finalize first requirement — execute the flow on devnet (0.5)
    - Display details of the form in the proposal instructions section (2d)
    - Finalize third requirement - execute the flow on devnet (1d)
    - Display the details of cancel proposal (1d)

  5. Test using devnet
    - Setup a test token
    - setup test governance with SOL and test token treasuries

  6. Testing with Streamflow team
    - Showcase the flow of all requirements to the team
    - Have one of our team members do the QA to check for the design and requirements match

  7. Deploy by submitting PR to the official governance UI repository


Requirements

  1. User creates a proposal to Create a Vesting contract

  2. New Proposal - When creating a new proposal, add “Streamflow: Create Vesting Contract” as one of the Transactions options in the transactions dropdown

  3. Once the option is selected, these fields should appear:
    - Amount (numeric input field)
    - Recipient Wallet Address (input field)
    - Token treasury (dropdown, where you choose the treasury)
    - Start Date (date field)
    - End Date (date field)
    - Release frequency
    - Multiplier (Input field) - defaults to 1
    - Time unit (select field) - defaults to month
    - Amount released at start (absolute value, number of tokens)
    - Cancellable? (Yes/No)

  1. Technical details: Contract fields mapping -

    sender: sol account,
    senderTokens: form.governedTokenAccount,
    recipient: form.recipient,
    mint: form.Treasury.mint,
    start: form.start,
    depositedAmount: form.amount,
    period: form.releaseFrequency,
    cliff: form.start,
    cliffAmount: form.releasedAtStart,
    amountPerPeriod: calculated,
    name: form.proposalName,
    canTopup: false,
    cancelableBySender: form.whoCanCancel,
    cancelableByRecipient: form.whoCanCancel,
    transferableBySender: false,
    transferableByRecipient: false,
    automaticWithdrawal: true,
    withdrawalFrequency: form.releaseFrequency,
    partner: null

  2. Validation rules:
    - recipient: type only
    - mint: type only
    - start: must be > now + proposal time (how long the proposal will live before expiring) + 1 hour
    - cliffAmount: must be < depositedAmount
    - name: must fit into 64 bytes ( when encoded with TextEncoder().encode(name), Uint8Array should be less then 65 bytes long, if it is, validation error should be displayed

  3. Calculating amountPerPeriod
    Protocol asks for:
    - Net amount deposit
    - Amount per period
    - Period

    Form asks for End date, which means we have to calculate the amount per period to satisfy that end date. Note here that most of the time we won’t be able to set the end date exactly to what user specified, because end - start might not be divisible by the period. Setting up period to monthly, and specifying end date to 45 days after start will not be possible with the way protocol works. So we look at the End as latest the stream will end at. So the calculation would look like:

    const amount = depositedAmount - cliffAmount;
    const numberOfReleases = Math.floor((end - cliff) / period);
    const amountPerPeriod = numberOfReleases > 1 ? amount / numberOfReleases : amount;
    const log = Math.floor(Math.log10(amountPerPeriod));
    const factor = Math.pow(10, Math.min(decimals, 15 - log));
    return Math.ceil(amountPerPeriod * factor) / factor;

    Proposal in Realms protocol is made by packaging deserialized Streamflow instruction inside of the Realms proposal.
    Streamflow instructions can be generated using https://github.com/streamflow-finance/js-sdk instructions module.
    Instruction is then serialized and stored on-chain in the Realms createInstruction method. We should use their plugin system and just provide Streamflow instruction the same way others did (check Solend, Token transfer, other custom instructions)

  4. Calculating fees
    Fees are calculated as:

    - Fixed amount 0,010619 SOL
    - Fixed amount 0.25% of token being transferred
    - Variable amount X SOL for autowithdrawals
    - Calculated:
    const startTime = cliff > 0 ? cliff : start;
    const withdrawalsCounter = Math.floor((end - startTime) / withdrawalFrequency) || 1;
    return 0.000005 * withdrawalsCounter;

    Proof of concept of the application is available at: https://github.com/streamflow-finance/governance-ui/tree/feat/streamflow

  5. User can see the details of a Vesting contract proposal

  6. Once the proposal is created, in the Instruction accordion we should present all of the accounts taking part in the “Create” instruction.

  7. Beneath the account data, we present a contract (stream) overview:
    - Total Amount & Token (e.g. 1000 STRM)
    - Duration: MM/DD/YYYY — MM/DD/YYYY
    - Release Rate (e.g. 10 STRM per N days) [N is up to discussion if needed, or it’s going to be dialy/weekly/montlhy]
    - Amount released at the start
    - Contract is cancellable: YES/NO
    - Progress bar - amount unlocked as % of total amount
    - Check the amount unlocked design here.

  8. Technical details
    -
    Proposals are saved on chain, so a way to display them is to fetch the account from the chain, deserialize it and display the info in the UI. For this, sdk method getOne can be used: https://github.com/streamflow-finance/js-sdk/blob/master/packages/stream/StreamClient.ts#L552
    -
    Thinking of code design of governance UI app, there is a module where serialization of proposal happens. We can extend this code piece to:
    a. fetch data for that proposal using getOne
    b. generating custom jsx element rendered by the governance app

  9. Calculating amount unlocked
    Amount unlocked can be calculated by using Stream method unlocked() within the js sdk.example:
    const resp = await new StreamClient().getOne('some_id');
    resp.unlocked()

  10. Calculating next release rate is not available in the sdk, but the calculations can be done by using this logic:
    const currentTime = getUnixTime(new Date());
    if (currentTime <= cliff) return cliffAmount > 0 ? cliff : cliff + period;
    const numberOfPeriods = Math.ceil((currentTime - cliff) / period);
    const nextUnlockTime = cliff + numberOfPeriods * period;
    return nextUnlockTime <= end ? nextUnlockTime : end;

    Something was already done in the Proof of concept app: https://github.com/streamflow-finance/governance-ui/blob/feat/streamflow/components/instructions/programs/streamflow.tsx

  11. User can create a proposal to Cancel the vesting contract (This is available only after the Create Vesting Contract proposal has been executed.)

  12. Proposals that successfully passed the proposal stage and were actually executed, can be interacted with.

  13. One way is the cancel method. In realms UI, we must make a proposal for cancellation that also needs to pass the voting phase.

  14. Associated with the initial vesting proposal, there should be a button of the available actions:
    - cancel
    - pause/unpause

  15. Once the button is triggered, a new proposal is created with correctly serialized instruction for that method.*This part was not done in the proof of concept, and should be researched

  16. User can see the details of Cancel proposal for a vesting contract
    - Stream ID
    - Recipient
    - Token
    - Token amount

Demo (PoC)

https://www.loom.com/share/ec2a95a27180435db742c89f42059ef5


UI Designs

https://www.figma.com/file/uqcsWF1qMtMi2KmhqrcLZH/Streamflow-x-Realms-integration?node-id=0%3A1

Resources:

  1. The Streamflow SDK

  2. Streamflow Docs

  3. Realms Docs

If you want to build this, apply for a grant here.

© 2023 Superteam. All rights reserved.

© 2023 Superteam. All rights reserved.

© 2023 Superteam. All rights reserved.