def setUp(self):
     # Test only the hatch setup.
     self.impact_hour_data = read_impact_hour_data()
     self.total_impact_hours = self.impact_hour_data['Assumed IH'].sum(),
     self.config = config_bounds.hatch['tech']
     self.tech = TECH(total_impact_hours=self.total_impact_hours,
                      impact_hour_data=self.impact_hour_data,
                      total_cstk_tokens=1000000,
                      config=self.config)
def test_TECH():
    df, _ = read_impact_hour_data()
    t = TECH(total_impact_hours=500,
             impact_hour_data=df,
             total_cstk_tokens=8500)
    pn.Row(pn.Column(t, t.funding_pool_data_view),
           pn.Column(t.impact_hours_view, t.funding_pool_view, t.payout_view))
    scenarios = t.get_raise_scenarios()
    target_raise = t.target_raise
    rates = t.impact_hours_formula(0, t.min_max_raise[1])
    target_rate_1 = t.target_impact_hour_rate
    target_rate_2 = t.get_impact_hour_rate(raise_amount=t.target_raise)
    assert ((target_rate_1 - target_rate_2) < 1)
    funding_pools = t.get_funding_pool_data()
Пример #3
0
def load_app(config_file):
    pn.config.sizing_mode = 'stretch_both'

    impact_hour_data_1, impact_hour_data_2 = read_impact_hour_data()
    impact_hours_data = ImpactHoursData()

    # ImpactHoursData
    i = ImpactHoursData()

    # TECH
    t = TECH(total_impact_hours=i.total_impact_hours,
             impact_hour_data=impact_hour_data_1,
             total_cstk_tokens=1000000,
             config=config_file['tech'])

    # ImpactHoursFormula
    #impact_hours_rewards = ImpactHoursFormula(i.total_impact_hours, impact_hour_data_1)
    #impact_rewards_view = pn.Column(impact_hours_rewards.impact_hours_rewards,
    # impact_hours_rewards.redeemable,
    # impact_hours_rewards.cultural_build_tribute)

    # Hatch
    cstk_data = read_cstk_data()
    #hatch = Hatch(cstk_data, impact_hours_rewards.target_raise,
    # i.total_impact_hours,
    # impact_hours_rewards.target_impact_hour_rate)

    # DandelionVoting
    dandelion = DandelionVoting(17e6, config=config_file['dandelion_voting'])

    # Import Params Button
    import_params_button = pn.widgets.Button(name='Import params',
                                             button_type='primary')
    import_description = pn.pane.Markdown(
        '<h4>To import the parameters, click on the button below:</h4>')

    # Share Button
    comments = pn.widgets.TextAreaInput(
        name='Comments',
        max_length=1024,
        placeholder='Explain your thoughts on why you choose the params...')
    share_button = pn.widgets.Button(name='Share your results on GitHub!',
                                     button_type='primary')
    url = pn.widgets.TextInput(name='URL', value='')
    share_button.js_on_click(args={'target': url},
                             code='window.open(target.value)')
    results_button = pn.widgets.Button(name='See your results',
                                       button_type='success')

    def update_params_by_url_query():
        queries = curdoc().session_context.request.arguments
        queries = {i: j[0] for i, j in queries.items()}
        if queries:
            if 'ihminr' in queries:
                t.min_raise = int(queries['ihminr'])
            if 'ihmaxr' in queries:
                t.max_raise = int(queries['ihmaxr'])
            if 'hs' in queries:
                t.impact_hour_slope = float(queries['hs'])
            if 'maxihr' in queries:
                t.maximum_impact_hour_rate = float(queries['maxihr'])
            if 'ihtr' in queries:
                t.target_raise = int(queries['ihtr'])
            if 'hor' in queries:
                t.hatch_oracle_ratio = float(queries['hor'])
            if 'hpd' in queries:
                t.hatch_period_days = int(queries['hpd'])
            if 'her' in queries:
                t.hatch_exchange_rate = float(queries['her'])
            if 'ht' in queries:
                t.hatch_tribute_percentage = int(queries['ht'])
            if 'sr' in queries:
                dandelion.support_required_percentage = int(queries['sr'])
            if 'maq' in queries:
                dandelion.minimum_accepted_quorum_percentage = int(
                    queries['maq'])
            if 'vdd' in queries:
                dandelion.vote_duration_days = int(queries['vdd'])
            if 'vbh' in queries:
                dandelion.vote_buffer_hours = int(queries['vbh'])
            if 'rqh' in queries:
                dandelion.rage_quit_hours = int(queries['rqh'])
            if 'tfx' in queries:
                dandelion.tollgate_fee_xdai = float(queries['tfx'])

            t.param.trigger('action')  # Update dashboard

    @pn.depends(results_button)
    def update_result_score(results_button_on):
        data_table = {
            'Parameters': [
                "Target raise (wxDai)", "Maximum raise (wxDai)",
                "Minimum raise (wxDai)", "Impact hour slope (wxDai/IH)",
                "Maximum impact hour rate (wxDai/IH)",
                "Hatch oracle ratio (wxDai/CSTK)", "Hatch period (days)",
                "Hatch exchange rate (TECH/wxDai)", "Hatch tribute (%)",
                "Support required (%)", "Minimum accepted quorum (%)",
                "Vote duration (days)", "Vote buffer (hours)",
                "Rage quit (hours)", "Tollgate fee (wxDai)"
            ],
            'Values': [
                int(t.target_raise),
                int(t.max_raise),
                int(t.min_raise), t.impact_hour_slope,
                t.maximum_impact_hour_rate, t.hatch_oracle_ratio,
                t.hatch_period_days, t.hatch_exchange_rate,
                t.hatch_tribute_percentage,
                dandelion.support_required_percentage,
                dandelion.minimum_accepted_quorum_percentage,
                dandelion.vote_duration_days, dandelion.vote_buffer_hours,
                dandelion.rage_quit_hours, dandelion.tollgate_fee_xdai
            ]
        }
        df = pd.DataFrame(data=data_table)

        if results_button_on:
            # Define output pane
            output_pane = pn.Row(
                pn.Column(t.impact_hours_view, t.redeemable_plot,
                          t.cultural_build_tribute_plot),
                pn.Column(dandelion.vote_pass_view, t.funding_pool_view))
            output_pane.save('output.html')
            pn.panel(t.output_scenarios_out_issue().hvplot.table()).save(
                'out_scenarios.html')

            scenarios = codecs.open("out_scenarios.html", 'r')
            charts = codecs.open("output.html", 'r')

            data_charts = {
                'html': charts.read(),
                'css':
                ".box { color: white; background-color: #0f79b9; padding: 10px; font-family: Roboto }",
                'google_fonts': "Roboto"
            }
            data_scenarios = {
                'html': scenarios.read(),
                'css':
                ".box { color: white; background-color: #0f79b9; padding: 10px; font-family: Roboto }",
                'google_fonts': "Roboto"
            }

            charts = requests.post(url=HCTI_API_ENDPOINT,
                                   data=data_charts,
                                   auth=(HCTI_API_USER_ID, HCTI_API_KEY))
            scenarios = requests.post(url=HCTI_API_ENDPOINT,
                                      data=data_scenarios,
                                      auth=(HCTI_API_USER_ID, HCTI_API_KEY))

            output_data = """

<h1>Output Charts</h1>

![image]({image_charts})

<h1>Output Scenarios</h1>

![image]({image_scenarios})
            """.format(image_charts=charts.json()['url'],
                       image_scenarios=scenarios.json()['url'])

            parameters_data = """

<h1>Parameters</h1>

{params_table}
            """.format(
                params_table=df.to_markdown(index=False, floatfmt=",.2f"))

            string_data = """
<h1>Results</h1>

<p>{comments}</p>

- It costs {tollgate_fee_xdai} wxDAI to make a proposal.

- Votes will be voted on for {vote_duration_days} days.

- TECH token holders will have {rage_quit_hours} Hours to exit the DAO if they don't like the result of a vote (as long as they don't vote yes).

- There will be a minimum of {vote_buffer_hours} hours between proposals so people can exit safely in weird edge case scenarios.

- A proposal that passes can be executed {proposal_execution_hours} hours after it was proposed.

- A CSTK Token holder that has 2000 CSTK can send a max of {max_wxdai_ratio} wxDai to the Hatch.

Play with my parameters [here]({url}?ihminr={ihf_minimum_raise}&hs={hour_slope}&maxihr={maximum_impact_hour_rate}&ihtr={ihf_target_raise}&ihmaxr={ifh_maximum_raise}&hor={hatch_oracle_ratio}&hpd={hatch_period_days}&her={hatch_exchange_rate}&ht={hatch_tribute_percentage}&sr={support_required}&maq={minimum_accepted_quorum}&vdd={vote_duration_days}&vbh={vote_buffer_hours}&rqh={rage_quit_hours}&tfx={tollgate_fee_xdai}).

            """.format(comments=comments.value,
                       tollgate_fee_xdai=dandelion.tollgate_fee_xdai,
                       vote_duration_days=dandelion.vote_duration_days,
                       rage_quit_hours=dandelion.rage_quit_hours,
                       ihf_minimum_raise=int(t.min_raise),
                       hour_slope=t.impact_hour_slope,
                       maximum_impact_hour_rate=t.maximum_impact_hour_rate,
                       ihf_target_raise=t.target_raise,
                       ifh_maximum_raise=int(t.max_raise),
                       hatch_oracle_ratio=t.hatch_oracle_ratio,
                       hatch_period_days=t.hatch_period_days,
                       hatch_exchange_rate=t.hatch_exchange_rate,
                       hatch_tribute_percentage=t.hatch_tribute_percentage,
                       support_required=dandelion.support_required_percentage,
                       minimum_accepted_quorum=dandelion.
                       minimum_accepted_quorum_percentage,
                       vote_buffer_hours=dandelion.vote_buffer_hours,
                       proposal_execution_hours=dandelion.vote_buffer_hours +
                       dandelion.rage_quit_hours,
                       max_wxdai_ratio=int(2000 * t.hatch_oracle_ratio),
                       url=config_file['url'])

            markdown_panel = pn.pane.Markdown(parameters_data + string_data +
                                              output_data)
            body = urllib.parse.quote(markdown_panel.object, safe='')
            url.value = config_file[
                'repo'] + "/issues/new?title=Vote%20for%20My%20Params&labels=" + config_file[
                    'label'] + "&body=" + body
            results_button.name = "Update your results"

        else:
            string_data = ""
        markdown_panel = pn.pane.Markdown(string_data)
        return pn.Row(df.hvplot.table(), markdown_panel)

    pn.state.onload(update_params_by_url_query)

    # Front-end
    tmpl = pn.Template(template=template)
    tmpl.add_variable('app_title', config_file['title'])
    tmpl.add_panel('A', i.impact_hours_accumulation)
    tmpl.add_panel('B', t)
    tmpl.add_panel('C', t.funding_pool_data_view)
    tmpl.add_panel('E', t.payout_view)
    tmpl.add_panel(
        'D',
        pn.Column(t.impact_hours_view, t.redeemable_plot,
                  t.cultural_build_tribute_plot))
    tmpl.add_panel('M', t.trigger_target_cultural_build_tribute_too_high)
    tmpl.add_panel('F', t.funding_pool_view)
    tmpl.add_panel('V', dandelion)
    tmpl.add_panel('W', dandelion.vote_pass_view)
    tmpl.add_panel('G', pn.pane.GIF('media/inputs_outputs.gif'))

    tmpl.add_panel('R', update_result_score)
    tmpl.add_panel('CO', comments)
    tmpl.add_panel('BU', pn.Column(results_button, share_button, url))
    tmpl.servable(title=config_file['title'])
Пример #4
0
def load_app(config_file):
    pn.config.sizing_mode = 'stretch_both'

    impact_hour_data = read_impact_hour_data()

    # TECH
    t = TECH(
        total_impact_hours=impact_hour_data['Assumed IH'].sum(),
        impact_hour_data=impact_hour_data, total_cstk_tokens=1000000,
        config=config_file['tech'])

    # DandelionVoting
    dandelion = DandelionVoting(17e6, config=config_file['dandelion_voting'])

    updating_results = pn.widgets.Button(name="Updating", disabled=True)

    # Share Button
    comments_tech = pn.widgets.TextAreaInput(
                                        name='What is your Hatch Strategy?',
                                        max_length=1024,
                                        placeholder='Tell us why you configured the Hatch this way')
    comments_dandelion = pn.widgets.TextAreaInput(
                                        name='What is your Dandelion Voting strategy?',
                                        max_length=1024,
                                        placeholder='What intended effects will your Dandelion Voting Parameters have?')
    share_button = pn.widgets.Button(name='Submit Hatch Config Proposal',
                                     button_type='primary',
                                     disabled=True)
    url = pn.widgets.TextInput(name='URL', value='')
    share_button.js_on_click(args={'target': url},
                             code='window.open(target.value)')
    results_button = pn.widgets.Button(name='See your results',
                                       button_type='success')

    # Run buttons
    run_dandelion = pn.widgets.Button(name='Run simulation',
                                      button_type='success')
    run_impact_hours = pn.widgets.Button(name='Run simulation',
                                         button_type='success')

    def update_params_by_url_query():
        queries = curdoc().session_context.request.arguments
        queries = {i: j[0] for i, j in queries.items()}
        if queries:
            if 'ihminr' in queries:
                t.min_raise = int(queries['ihminr'])
            if 'ihmaxr' in queries:
                t.max_raise = int(queries['ihmaxr'])
            if 'tgihr' in queries:
                t.impact_hour_rate_at_target_goal = float(queries['tgihr'])
            if 'maxihr' in queries:
                t.maximum_impact_hour_rate = float(queries['maxihr'])
            if 'ihtr' in queries:
                t.target_raise = int(queries['ihtr'])
            if 'hor' in queries:
                t.hatch_oracle_ratio = float(queries['hor'])
            if 'hpd' in queries:
                t.hatch_period_days = int(queries['hpd'])
            if 'her' in queries:
                t.hatch_exchange_rate = float(queries['her'])
            if 'ht' in queries:
                t.hatch_tribute_percentage = int(queries['ht'])
            if 'sr' in queries:
                dandelion.support_required_percentage = int(queries['sr'])
            if 'maq' in queries:
                dandelion.minimum_accepted_quorum_percentage = int(queries['maq'])
            if 'vdd' in queries:
                dandelion.vote_duration_days = int(queries['vdd'])
            if 'vbh' in queries:
                dandelion.vote_buffer_hours = int(queries['vbh'])
            if 'rqh' in queries:
                dandelion.rage_quit_hours = int(queries['rqh'])
            if 'tfx' in queries:
                dandelion.tollgate_fee_xdai = float(queries['tfx'])

            t.param.trigger('action')  # Update dashboard
            dandelion.param.trigger('action')

    @pn.depends(updating_results)
    def update_input_output_pane(results_button_on):
        if results_button_on:
            input_output_pane = pn.pane.GIF('media/inputs_outputs.gif')
        else:
            input_output_pane = pn.pane.Markdown('')

        return input_output_pane

    @pn.depends(updating_results)
    def update_output_scenarios(results_button_on):
        if results_button_on:
            output_scenarios = pn.panel(t.output_scenarios_view()
                                         .hvplot.table())
        else:
            output_scenarios = pn.pane.Markdown('')

        return output_scenarios

    @pn.depends(updating_results)
    def update_result_score(results_button_on):
        if results_button_on:
            t.param.trigger('action')  # Update dashboard
            dandelion.param.trigger('action')
            data_table = {
                'Parameters': [
                    "Target Goal (wxDai)",
                    "Maximum Goal (wxDai)",
                    "Minimum Goal (wxDai)",
                    "Impact Hour Rate at Target Goal (wxDai/IH)",
                    "Impact Hour Rate at Infinity (wxDai/IH)",
                    "Hatch Membership Ratio (wxDai/CSTK)",
                    "Hatch Period (days)",
                    "Hatch Minting rate (TECH/wxDai)",
                    "Hatch Tribute (%)",
                    "Support Required (%)",
                    "Minimum Quorum (%)",
                    "Vote Duration (days)",
                    "Vote Buffer (hours)",
                    "Ragequit Delay (hours)",
                    "Tollgate Fee (wxDai)"],
                'Values': [
                    int(t.target_raise),
                    int(t.max_raise),
                    int(t.min_raise),
                    t.impact_hour_rate_at_target_goal,
                    t.maximum_impact_hour_rate,
                    t.hatch_oracle_ratio,
                    t.hatch_period_days,
                    t.hatch_exchange_rate,
                    t.hatch_tribute_percentage,
                    dandelion.support_required_percentage,
                    dandelion.minimum_accepted_quorum_percentage,
                    dandelion.vote_duration_days,
                    dandelion.vote_buffer_hours,
                    dandelion.rage_quit_hours,
                    dandelion.tollgate_fee_xdai]
                }
            df = pd.DataFrame(data=data_table)

            # Define output pane
            output_pane = pn.Row(pn.Column(t.impact_hours_plot,
                                           t.redeemable_plot),
                                 pn.Column(dandelion.vote_pass_view,
                                           t.pie_charts_view))
            output_pane.save('output.html')
            pn.panel(t.output_scenarios_view()
                      .hvplot.table()).save('out_scenarios.html')

            scenarios = codecs.open("out_scenarios.html", 'r')
            charts = codecs.open("output.html", 'r')

            data_charts = {
                'html': charts.read(),
                'css': ".box { color: white; background-color: #0f79b9; padding: 10px; font-family: Roboto }",
                'google_fonts': "Roboto"}
            data_scenarios = {
                'html': scenarios.read(),
                'css': ".box { color: white; background-color: #0f79b9; padding: 10px; font-family: Roboto }",
                'google_fonts': "Roboto"}

            charts = requests.post(url=HCTI_API_ENDPOINT,
                                   data=data_charts,
                                   auth=(HCTI_API_USER_ID, HCTI_API_KEY))
            scenarios = requests.post(url=HCTI_API_ENDPOINT,
                                      data=data_scenarios,
                                      auth=(HCTI_API_USER_ID, HCTI_API_KEY))
            # Parameters string
            url_fork = '{url}?ihminr={ihf_minimum_raise}&tgihr={impact_hour_rate_at_target_goal}&maxihr={maximum_impact_hour_rate}&ihtr={ihf_target_raise}&ihmaxr={ifh_maximum_raise}&hor={hatch_oracle_ratio}&hpd={hatch_period_days}&her={hatch_exchange_rate}&ht={hatch_tribute_percentage}&sr={support_required}&maq={minimum_accepted_quorum}&vdd={vote_duration_days}&vbh={vote_buffer_hours}&rqh={rage_quit_hours}&tfx={tollgate_fee_xdai}"'.format(tollgate_fee_xdai=dandelion.tollgate_fee_xdai,
            vote_duration_days=dandelion.vote_duration_days,
            rage_quit_hours=dandelion.rage_quit_hours,
            ihf_minimum_raise=int(t.min_raise),
            impact_hour_rate_at_target_goal=t.impact_hour_rate_at_target_goal,
            maximum_impact_hour_rate=t.maximum_impact_hour_rate,
            ihf_target_raise=t.target_raise,
            ifh_maximum_raise=int(t.max_raise),
            hatch_oracle_ratio=t.hatch_oracle_ratio,
            hatch_period_days=t.hatch_period_days,
            hatch_exchange_rate=t.hatch_exchange_rate,
            hatch_tribute_percentage=t.hatch_tribute_percentage,
            support_required=dandelion.support_required_percentage,
            minimum_accepted_quorum=dandelion.minimum_accepted_quorum_percentage,
            vote_buffer_hours=dandelion.vote_buffer_hours,
            max_wxdai_ratio=int(1125*t.hatch_oracle_ratio),
            total_votes_per_year=int(24/dandelion.vote_buffer_hours*365),
            single_tech_mint=float(1/t.hatch_exchange_rate),
            url=config_file['url'])

            # Title
            title = '## Check out my proposal for the Hatch! <a href="' + url_fork + ' target="_blank">Click here to preload the Hatch Configuration Dashboard with my parameters if you think you can do better</a>.'
            meme_image = """

![image](https://i.imgflip.com/57zyrl.jpg)
"""
            graphical_summary = """
# Graphical Summary

![image]({image_charts})
""".format(image_charts=charts.json()['url'])


            graph_descriptions = """
## Graph Descriptions

- Top Left, **Impact Hour Rate vs wxDai Collected**: The Impact Hour Rate determines the Minting Rate for Builders, making 1 Impact Hour equivalent to sending this amount of wxDai to the Hatch.
- Top Right, **Proposal Acceptance Criteria**: Shows the range of possibilities for DAO vote outcomes and whether they succeed or not given the Support Required & Minimum Quorum I chose.
- Bottom Left, **Backer's Rage Quit % vs wxDai Collected**: The Backer's Rage Quit % is the percent of wxDai that the Backers sent to the Hatch that would be returned if they decide to Ragequit.
- Bottom Right, **Redeem-ability of the DAO's wxDai**: Shows who has rights to the wxDai held by the DAO. All of the DAO's funds are collectively governed but some can be withdrawn if token holders Ragequit. This shows the results of my parameter choices at the 3 different goals.
"""
            simulated_outcomes = """
# Simulated Outcomes

![image]({image_scenarios})
            """.format(image_scenarios=scenarios.json()['url'])

            parameters_data = """
# My Hatch Configuration

| Parameter|Value|
|:-|-:|
|Target Goal (wxDai)|{target_goal:,}|
|Maximum Goal (wxDai)|{max_goal:,}|
|Minimum Goal (wxDai)|{min_goal:,}|
|Impact Hour Rate at Target Goal (wxDai/IH)|{ih_rate_tg_goal:,}|
|Impact Hour Rate at Infinity (wxDai/IH)|{ih_rate_infinity:,}|
|Hatch Membership Ratio (wxDai/CSTK)|{hatch_membership_ratio:,}|
|Hatch Period (days)|{hatch_period_days}|
|Hatch Minting rate (TECH/wxDai)|{hatch_minting_rate:,}|
|Hatch Tribute (%)|{hatch_tribute}|
|Support Required (%)|{support_required}|
|Minimum Quorum (%)|{minimum_quorum}|
|Vote Duration (days)|{vote_duration_days}|
|Vote Buffer (hours)|{vote_buffer_hours}|
|Ragequit (hours)|{ragequit}|
|Tollgate Fee (wxDai)|{tollgate_fee:,}|</a>""".format(target_goal=t.target_raise,
           max_goal=t.max_raise,
           min_goal=t.min_raise,
           ih_rate_tg_goal=t.impact_hour_rate_at_target_goal,
           ih_rate_infinity=t.maximum_impact_hour_rate,
           hatch_membership_ratio=t.hatch_oracle_ratio,
           hatch_period_days=t.hatch_period_days,
           hatch_minting_rate=t.hatch_exchange_rate,
           hatch_tribute=t.hatch_tribute_percentage,
           support_required=dandelion.support_required_percentage,
           minimum_quorum=dandelion.minimum_accepted_quorum_percentage,
           vote_duration_days=dandelion.vote_duration_days,
           vote_buffer_hours=dandelion.vote_buffer_hours,
           ragequit=dandelion.rage_quit_hours,
           tollgate_fee=dandelion.tollgate_fee_xdai)

            results_header = """
# Summary
"""

            default_comment = "To use the defaults... Technocracy for the win"
            if not comments_tech.value: 
                print(comments_tech.value)
                comment_tech = default_comment
            else:
                comment_tech = comments_tech.value
            
            if not comments_dandelion.value: 
                comment_dandelion = default_comment
            else:
                comment_dandelion = comments_dandelion.value

            string_comments_tech = """
## Hatch Strategy

<p>{comments}</p>
            """.format(comments=comment_tech)

            string_comments_dandelion = """
## DAO Strategy

<p>{comments}</p>
            """.format(comments=comment_dandelion)

            string_data = """
  <h2>Hatch Details</h2>

- Trusted Seed members can send wxDai to the Hatch for {hatch_period_days} days.

- The target goal will be {ihf_target_raise} wxDai, with a minimum of {ihf_minimum_raise} wxDai necessary for the TEC Hatch DAO to be launched and a cap at {ifh_maximum_raise} wxDai.

- Backers will need to send in {single_tech_mint} wxDai to mint 1 TECH.

- The membership ratio is set at {hatch_oracle_ratio} wxDai/CSTK, so a Trusted Seed member with the minimum CSTK Score of 1125 CSTK can send up to {max_wxdai_ratio}  wxDai to the Hatch.

<h2>TEC Hatch DAO Voting Details</h2>

- Proposals will be voted on for {vote_duration_days} days. They will require at least {support_required}% support, and a minimum of {minimum_accepted_quorum}% of the TECH Tokens will have to vote yes for a proposal to pass.

- TECH token holders will have {rage_quit_hours} hours to exit the DAO if they don't like the result of a vote (as long as they didn't vote yes) before it is executed.

- There will be a minimum of {vote_buffer_hours} hours between proposals so people always have time to exit safely if they voted yes on a previous vote, this means we can have at most {total_votes_per_year} votes per year.

- To prevent griefing attacks, it will cost {tollgate_fee_xdai} wxDai to make a proposal.

If you have Impact Hours, you can see how much money you will get with my configuration <a href="{url}?ihminr={ihf_minimum_raise}&tgihr={impact_hour_rate_at_target_goal}&maxihr={maximum_impact_hour_rate}&ihtr={ihf_target_raise}&ihmaxr={ifh_maximum_raise}&hor={hatch_oracle_ratio}&hpd={hatch_period_days}&her={hatch_exchange_rate}&ht={hatch_tribute_percentage}&sr={support_required}&maq={minimum_accepted_quorum}&vdd={vote_duration_days}&vbh={vote_buffer_hours}&rqh={rage_quit_hours}&tfx={tollgate_fee_xdai}" target="_blank">here, just check out the Impact Hour Results table.
            """.format(tollgate_fee_xdai=dandelion.tollgate_fee_xdai,
            vote_duration_days=dandelion.vote_duration_days,
            rage_quit_hours=dandelion.rage_quit_hours,
            ihf_minimum_raise=int(t.min_raise),
            impact_hour_rate_at_target_goal=t.impact_hour_rate_at_target_goal,
            maximum_impact_hour_rate=t.maximum_impact_hour_rate,
            ihf_target_raise=t.target_raise,
            ifh_maximum_raise=int(t.max_raise),
            hatch_oracle_ratio=t.hatch_oracle_ratio,
            hatch_period_days=t.hatch_period_days,
            hatch_exchange_rate=t.hatch_exchange_rate,
            hatch_tribute_percentage=t.hatch_tribute_percentage,
            support_required=dandelion.support_required_percentage,
            minimum_accepted_quorum=dandelion.minimum_accepted_quorum_percentage,
            vote_buffer_hours=dandelion.vote_buffer_hours,
            max_wxdai_ratio=int(1125*t.hatch_oracle_ratio),
            total_votes_per_year=int(24/dandelion.vote_buffer_hours*365),
            single_tech_mint=float(1/t.hatch_exchange_rate),
            url=config_file['url'])

            markdown_panel = pn.pane.Markdown(parameters_data +
                                              string_comments_tech +
                                              string_comments_dandelion +
                                              results_header +
                                              string_data +
                                              graphical_summary)
            markdown_panel = pn.pane.Markdown(title +
                                              meme_image +
                                              graphical_summary +
                                              graph_descriptions +
                                              simulated_outcomes +
                                              string_comments_tech +
                                              string_comments_dandelion +
                                              results_header +
                                              string_data +
                                              parameters_data)
            body = urllib.parse.quote(markdown_panel.object, safe='')
            url.value = (config_file['repo'] +
                         "/issues/new?title=Vote%20for%20My%20Params&labels=" +
                         config_file['label'] + "&body=" + body)
            results_button.name = "Update your results"
            markdown_panel = pn.pane.Markdown(results_header + string_data)
            return markdown_panel

    pn.state.onload(update_params_by_url_query)

    def help_icon(href, text):
        return """
        <style>
        .tooltip {{
            position: relative;
            display: inline-block;
            align-self: flex-end;
        }}

        .tooltip .tooltiptext {{
            visibility: hidden;
            width: 200px;
            background-color: #555;
            color: #fff;
            text-align: center;
            border-radius: 6px;
            padding: 10px;
            position: absolute;
            z-index: 1;
            bottom: 125%;
            left: 50%;
            margin-left: -110px;
            opacity: 0;
            transition: opacity 0.3s;
        }}

        .tooltip .tooltiptext::after {{
            content: "";
            position: absolute;
            top: 100%;
            left: 50%;
            margin-left: -5px;
            border-style: solid;
            border-color: #555 transparent transparent transparent;
        }}

        .tooltip:hover .tooltiptext {{
            visibility: visible;
            opacity: 1;
        }}

        .icon {{
            width: 24px;
            height: 24px;
        }}

        .flex {{
            height: 100%;
            display: flex;
            justify-content: center;
        }}
        </style>
        <div class="flex">
            <div class="tooltip">
                <a href="{href}" target="_blank">
                    <img class="icon" src="http://cdn.onlinewebfonts.com/svg/img_295214.png" />
                </a>
                <span class="tooltiptext">{text}</span>
            </div>
        </div>
        """.format(href=href, text=text)

    def param_with_tooltip(param, tooltip, height=50):
        return pn.Row(pn.Column(param, sizing_mode="stretch_width"),
                      pn.pane.HTML(help_icon(tooltips[tooltip]['href'],
                                   tooltips[tooltip]['text']),
                                   sizing_mode="fixed",
                                   width=30, height=height, align="end"))

    def run_simulation_dandelion(event):
        dandelion.param.trigger('action')

    def run_simulation_impact_hours(event):
        t.param.trigger('action')
    
    def update_results(event):
        results_button.disabled = True
        share_button.disabled = True
        updating_results.value = True
        share_button.disabled = False
        results_button.disabled = False
        updating_results.value = False

    results_button.on_click(update_results)
    run_dandelion.on_click(run_simulation_dandelion)
    run_impact_hours.on_click(run_simulation_impact_hours)

    # Front-end
    tmpl = pn.Template(template=template)
    tmpl.add_variable('app_title', config_file['title'])
    tmpl.add_panel('B', pn.Column(
        param_with_tooltip(
            t.param.min_raise,
            tooltip='min_raise'),
        param_with_tooltip(
            t.param.max_raise,
            tooltip='max_raise'),
        param_with_tooltip(
            t.param.target_raise,
            tooltip='target_raise'),
        param_with_tooltip(
            t.param.impact_hour_rate_at_target_goal,
            tooltip='impact_hour_rate_at_target_goal'),
        param_with_tooltip(
            t.param.maximum_impact_hour_rate,
            tooltip='maximum_impact_hour_rate', height=40),
        param_with_tooltip(
            t.param.hatch_tribute_percentage,
            tooltip='hatch_tribute_percentage'),
        param_with_tooltip(
            t.param.hatch_oracle_ratio,
            tooltip='hatch_oracle_ratio'),
        param_with_tooltip(
            t.param.hatch_period_days,
            tooltip='hatch_period_days'),
        param_with_tooltip(
            t.param.hatch_exchange_rate,
            tooltip='hatch_exchange_rate'),
        run_impact_hours
    ))
    tmpl.add_panel('C', t.outputs_overview_view)
    tmpl.add_panel('E', t.payout_view)
    tmpl.add_panel('D', pn.Column(t.redeemable_plot, t.impact_hours_plot))
    tmpl.add_panel('M', t.trigger_unbalanced_parameters)
    tmpl.add_panel('F', t.pie_charts_view)
    tmpl.add_panel('V', pn.Column(
        param_with_tooltip(
            pn.Column(dandelion.param.support_required_percentage),
            tooltip='support_required_percentage', height=40),
        param_with_tooltip(
            dandelion.param.minimum_accepted_quorum_percentage,
            tooltip='minimum_accepted_quorum_percentage', height=40),
        param_with_tooltip(
            dandelion.param.vote_buffer_hours,
            tooltip='vote_buffer_hours'),
        param_with_tooltip(
            dandelion.param.tollgate_fee_xdai,
            tooltip='tollgate_fee_xdai'),
        param_with_tooltip(
            dandelion.param.vote_duration_days,
            tooltip='vote_duration_days'),
        param_with_tooltip(
            dandelion.param.rage_quit_hours,
            tooltip='rage_quit_hours'),
        run_dandelion
    ))
    tmpl.add_panel('W', dandelion.vote_pass_view)
    tmpl.add_panel('G', update_input_output_pane)
    tmpl.add_panel('R', update_result_score)
    tmpl.add_panel('CO', pn.Column(comments_tech, comments_dandelion))
    tmpl.add_panel('BU', pn.Column(results_button, share_button, url))
    tmpl.add_panel('OU', update_output_scenarios)
    tmpl.servable(title=config_file['title'])
Пример #5
0
def load_app(config_file):
    pn.config.sizing_mode = 'stretch_both'

    impact_hour_data = read_impact_hour_data()
    # ImpactHoursData
    i = ImpactHoursData()

    # TECH
    t = TECH(total_impact_hours = impact_hour_data['Assumed IH'].sum(),
            impact_hour_data=impact_hour_data, total_cstk_tokens=1000000,
            config=config_file['tech'])


    # ImpactHoursFormula
    #impact_hours_rewards = ImpactHoursFormula(i.total_impact_hours, impact_hour_data_1)
    #impact_rewards_view = pn.Column(impact_hours_rewards.impact_hours_rewards,
    # impact_hours_rewards.redeemable,
    # impact_hours_rewards.cultural_build_tribute)

    # Hatch
    cstk_data = read_cstk_data()
    #hatch = Hatch(cstk_data, impact_hours_rewards.target_raise,
    # i.total_impact_hours,
    # impact_hours_rewards.target_impact_hour_rate)

    # DandelionVoting
    dandelion = DandelionVoting(17e6,config=config_file['dandelion_voting'])

    # Import Params Button
    import_params_button = pn.widgets.Button(name='Import params', button_type = 'primary')
    import_description = pn.pane.Markdown('<h4>To import the parameters, click on the button below:</h4>')

    # Share Button
    comments = pn.widgets.TextAreaInput(name='Comments', max_length=1024, placeholder='Explain your thoughts on why you choose the params...')
    share_button = pn.widgets.Button(name='Share your results on GitHub!', button_type = 'primary')
    url = pn.widgets.TextInput(name='URL', value = '')
    share_button.js_on_click(args={'target': url}, code='window.open(target.value)')
    results_button = pn.widgets.Button(name='See your results', button_type = 'success')

    def update_params_by_url_query():
        queries = curdoc().session_context.request.arguments
        queries = { i: j[0] for i, j in queries.items() }
        if queries:
            if 'ihminr' in queries:
                t.min_raise = int(queries['ihminr'])
            if 'ihmaxr' in queries:
                t.max_raise = int(queries['ihmaxr'])
            if 'hs' in queries:
                t.impact_hour_slope = float(queries['hs'])
            if 'maxihr' in queries:
                t.maximum_impact_hour_rate = float(queries['maxihr'])
            if 'ihtr' in queries:
                t.target_raise = int(queries['ihtr'])
            if 'hor' in queries:
                t.hatch_oracle_ratio = float(queries['hor'])
            if 'hpd' in queries:
                t.hatch_period_days = int(queries['hpd'])
            if 'her' in queries:
                t.hatch_exchange_rate = float(queries['her'])
            if 'ht' in queries:
                t.hatch_tribute_percentage = int(queries['ht'])
            if 'sr' in queries:
                dandelion.support_required_percentage = int(queries['sr'])
            if 'maq' in queries:
                dandelion.minimum_accepted_quorum_percentage = int(queries['maq'])
            if 'vdd' in queries:
                dandelion.vote_duration_days = int(queries['vdd'])
            if 'vbh' in queries:
                dandelion.vote_buffer_hours = int(queries['vbh'])
            if 'rqh' in queries:
                dandelion.rage_quit_hours = int(queries['rqh'])
            if 'tfx' in queries:
                dandelion.tollgate_fee_xdai = float(queries['tfx'])

            t.param.trigger('action')  # Update dashboard
            dandelion.param.trigger('action')


    @pn.depends(results_button)
    def update_input_output_pane(results_button_on):
        if results_button_on:
            input_output_pane = pn.pane.GIF('media/inputs_outputs.gif')
        else:
            input_output_pane = pn.pane.Markdown('')
        
        return input_output_pane 
    

    @pn.depends(results_button)
    def update_result_score(results_button_on):
        if results_button_on:
            t.param.trigger('action')  # Update dashboard
            dandelion.param.trigger('action')
            data_table = {'Parameters': ["Target raise (wxDai)", "Maximum raise (wxDai)", "Minimum raise (wxDai)",
            "Impact hour slope (wxDai/IH)", "Maximum impact hour rate (wxDai/IH)",
            "Hatch oracle ratio (wxDai/CSTK)", "Hatch period (days)",
            "Hatch exchange rate (TECH/wxDai)", "Hatch tribute (%)", "Support required (%)",
            "Minimum accepted quorum (%)", "Vote duration (days)", "Vote buffer (hours)",
            "Rage quit (hours)", "Tollgate fee (wxDai)"],
            'Values': [int(t.target_raise), int(t.max_raise),
            int(t.min_raise), t.impact_hour_slope,
            t.maximum_impact_hour_rate, t.hatch_oracle_ratio,
            t.hatch_period_days, t.hatch_exchange_rate, t.hatch_tribute_percentage,
            dandelion.support_required_percentage, dandelion.minimum_accepted_quorum_percentage, dandelion.vote_duration_days,
            dandelion.vote_buffer_hours, dandelion.rage_quit_hours, dandelion.tollgate_fee_xdai]}
            df = pd.DataFrame(data=data_table)

            # Define output pane
            output_pane = pn.Row(pn.Column(t.impact_hours_view,
                                        t.redeemable_plot),
            pn.Column(dandelion.vote_pass_view, t.funding_pool_view))
            output_pane.save('output.html')
            pn.panel(t.output_scenarios_out_issue().hvplot.table()).save('out_scenarios.html')

            scenarios = codecs.open("out_scenarios.html", 'r')
            charts = codecs.open("output.html", 'r')

            data_charts = { 'html': charts.read(),
            'css': ".box { color: white; background-color: #0f79b9; padding: 10px; font-family: Roboto }",
            'google_fonts': "Roboto" }
            data_scenarios = { 'html': scenarios.read(),
            'css': ".box { color: white; background-color: #0f79b9; padding: 10px; font-family: Roboto }",
            'google_fonts': "Roboto" }

            charts = requests.post(url = HCTI_API_ENDPOINT, data = data_charts, auth=(HCTI_API_USER_ID, HCTI_API_KEY))
            scenarios = requests.post(url = HCTI_API_ENDPOINT, data = data_scenarios, auth=(HCTI_API_USER_ID, HCTI_API_KEY))

            output_data = """

<h1>Output Charts</h1>

![image]({image_charts})

<h1>Output Scenarios</h1>

![image]({image_scenarios})
            """.format(image_charts=charts.json()['url'],
            image_scenarios=scenarios.json()['url'])

            parameters_data = """

<h1>Parameters</h1>

{params_table}
            """.format(params_table=df.to_markdown(index=False, floatfmt=",.2f"))

            string_data = """
<h1>Results</h1>

<p>{comments}</p>

- It costs {tollgate_fee_xdai} wxDai to make a proposal.

- Votes will be voted on for {vote_duration_days} days.

- TECH token holders will have {rage_quit_hours} Hours to exit the DAO if they don't like the result of a vote (as long as they don't vote yes).

- There will be a minimum of {vote_buffer_hours} hours between proposals so people can exit safely in weird edge case scenarios.

- A proposal that passes can be executed {proposal_execution_hours} hours after it was proposed.

- A CSTK Token holder that has 2000 CSTK can send a max of {max_wxdai_ratio} wxDai to the Hatch.

Play with my parameters [here]({url}?ihminr={ihf_minimum_raise}&hs={hour_slope}&maxihr={maximum_impact_hour_rate}&ihtr={ihf_target_raise}&ihmaxr={ifh_maximum_raise}&hor={hatch_oracle_ratio}&hpd={hatch_period_days}&her={hatch_exchange_rate}&ht={hatch_tribute_percentage}&sr={support_required}&maq={minimum_accepted_quorum}&vdd={vote_duration_days}&vbh={vote_buffer_hours}&rqh={rage_quit_hours}&tfx={tollgate_fee_xdai}).

To see the value of your individual Impact Hours, click [here to go to the Hatch Config Dashboard with these parameters]({url}?ihminr={ihf_minimum_raise}&hs={hour_slope}&maxihr={maximum_impact_hour_rate}&ihtr={ihf_target_raise}&ihmaxr={ifh_maximum_raise}&hor={hatch_oracle_ratio}&hpd={hatch_period_days}&her={hatch_exchange_rate}&ht={hatch_tribute_percentage}&sr={support_required}&maq={minimum_accepted_quorum}&vdd={vote_duration_days}&vbh={vote_buffer_hours}&rqh={rage_quit_hours}&tfx={tollgate_fee_xdai}) and explore the Impact Hour Results table.
            """.format(comments=comments.value,
            tollgate_fee_xdai=dandelion.tollgate_fee_xdai,
            vote_duration_days=dandelion.vote_duration_days,
            rage_quit_hours=dandelion.rage_quit_hours,
            ihf_minimum_raise=int(t.min_raise),
            hour_slope=t.impact_hour_slope,
            maximum_impact_hour_rate=t.maximum_impact_hour_rate,
            ihf_target_raise=t.target_raise,
            ifh_maximum_raise=int(t.max_raise),
            hatch_oracle_ratio=t.hatch_oracle_ratio,
            hatch_period_days=t.hatch_period_days,
            hatch_exchange_rate=t.hatch_exchange_rate,
            hatch_tribute_percentage=t.hatch_tribute_percentage,
            support_required=dandelion.support_required_percentage,
            minimum_accepted_quorum=dandelion.minimum_accepted_quorum_percentage,
            vote_buffer_hours=dandelion.vote_buffer_hours,
            proposal_execution_hours=dandelion.vote_buffer_hours+dandelion.rage_quit_hours,
            max_wxdai_ratio=int(2000*t.hatch_oracle_ratio),
            url=config_file['url'])

            markdown_panel = pn.pane.Markdown(parameters_data + string_data + output_data)
            body = urllib.parse.quote(markdown_panel.object, safe='')
            url.value = config_file['repo'] + "/issues/new?title=Vote%20for%20My%20Params&labels=" + config_file['label'] + "&body=" + body
            results_button.name = "Update your results"
            markdown_panel = pn.pane.Markdown(string_data)
            return pn.Row(df.hvplot.table(),markdown_panel)


    pn.state.onload(update_params_by_url_query)

    def help_icon(text):
        return """
        <style>
        .tooltip {{
            position: relative;
            display: inline-block;
            align-self: flex-end;
        }}

        .tooltip .tooltiptext {{
            visibility: hidden;
            width: 200px;
            background-color: #555;
            color: #fff;
            text-align: center;
            border-radius: 6px;
            padding: 10px;
            position: absolute;
            z-index: 1;
            bottom: 125%;
            left: 50%;
            margin-left: -110px;
            opacity: 0;
            transition: opacity 0.3s;
        }}

        .tooltip .tooltiptext::after {{
            content: "";
            position: absolute;
            top: 100%;
            left: 50%;
            margin-left: -5px;
            border-style: solid;
            border-color: #555 transparent transparent transparent;
        }}

        .tooltip:hover .tooltiptext {{
            visibility: visible;
            opacity: 1;
        }}

        .icon {{
            width: 24px;
            height: 24px;
        }}

        .flex {{
            height: 100%;
            display: flex;
            justify-content: center;
        }}
        </style>
        <div class="flex">
            <div class="tooltip">
                <a href="https://forum.tecommons.org/t/tec-test-hatch-implementation-specification/226" target="_blank">
                    <img class="icon" src="http://cdn.onlinewebfonts.com/svg/img_295214.png" />
                </a>
                <span class="tooltiptext">{text}</span>
            </div>
        </div>
        """.format(text=text)

    def param_with_tooltip(param, tooltip, height=50):
        return pn.Row(pn.Column(param, sizing_mode="stretch_width"), pn.pane.HTML(help_icon(tooltips[tooltip]), sizing_mode="fixed", width=30, height=height, align="end"))

    # Front-end
    tmpl = pn.Template(template=template)
    tmpl.add_variable('app_title', config_file['title'])
    tmpl.add_panel('B', pn.Column(
        param_with_tooltip(t.param.target_raise, tooltip='target_raise'), 
        param_with_tooltip(t.param.min_raise, tooltip='min_raise'),
        param_with_tooltip(t.param.max_raise, tooltip='max_raise'),
        param_with_tooltip(t.param.hatch_tribute_percentage, tooltip='hatch_tribute_percentage'),
        param_with_tooltip(t.param.maximum_impact_hour_rate, tooltip='maximum_impact_hour_rate', height=40),
        param_with_tooltip(t.param.impact_hour_slope, tooltip='impact_hour_slope', height=40),
        param_with_tooltip(t.param.hatch_oracle_ratio, tooltip='hatch_oracle_ratio'),
        param_with_tooltip(t.param.hatch_period_days, tooltip='hatch_period_days'),
        param_with_tooltip(t.param.hatch_exchange_rate, tooltip='hatch_exchange_rate'),
        t.param.action,
        #t.param.target_impact_hour_rate,
        #t.param.target_redeemable,
        #t.param.target_cultural_build_tribute
    ))
    tmpl.add_panel('C', t.funding_pool_data_view)
    tmpl.add_panel('E', t.payout_view)
    tmpl.add_panel('D', pn.Column(t.impact_hours_view, t.redeemable_plot))
    tmpl.add_panel('M', t.trigger_unbalanced_parameters)
    tmpl.add_panel('F', t.funding_pool_view)
    tmpl.add_panel('V', pn.Column(
        param_with_tooltip(pn.Column(dandelion.param.support_required_percentage), tooltip='support_required_percentage', height=40), 
        param_with_tooltip(dandelion.param.minimum_accepted_quorum_percentage, tooltip='minimum_accepted_quorum_percentage', height=40),
        param_with_tooltip(dandelion.param.vote_duration_days, tooltip='vote_duration_days'),
        param_with_tooltip(dandelion.param.vote_buffer_hours, tooltip='vote_buffer_hours'),
        param_with_tooltip(dandelion.param.rage_quit_hours, tooltip='rage_quit_hours'),
        param_with_tooltip(dandelion.param.tollgate_fee_xdai, tooltip='tollgate_fee_xdai'),
        dandelion.param.action
    ))
    tmpl.add_panel('W', dandelion.vote_pass_view)
    tmpl.add_panel('G', update_input_output_pane)
    tmpl.add_panel('R', update_result_score)
    tmpl.add_panel('CO', comments)
    tmpl.add_panel('BU', pn.Column(results_button, share_button, url))
    tmpl.servable(title=config_file['title'])