From dd7fe29dafd8dbdbeeb20c30e975e83d132ea42e Mon Sep 17 00:00:00 2001 From: Marcus Aurelius Date: Fri, 9 Feb 2024 16:07:56 -0600 Subject: [PATCH] Add DCM supply bot --- .github/workflows/deploy.yaml | 2 +- k8s/dcm_supply/deployment_set_bot.yaml | 16 +++++ k8s/dcm_supply/kustomization.yaml | 13 ++++ k8s/kustomization.yaml | 2 +- k8s/secret.properties.template | 1 + src/constants.py | 4 ++ src/dcm_supply/__init__.py | 0 src/dcm_supply/main.py | 82 ++++++++++++++++++++++++++ src/staking_rewards/main.py | 17 +----- src/utils.py | 23 +++++++- 10 files changed, 142 insertions(+), 18 deletions(-) create mode 100644 k8s/dcm_supply/deployment_set_bot.yaml create mode 100644 k8s/dcm_supply/kustomization.yaml create mode 100644 src/dcm_supply/__init__.py create mode 100644 src/dcm_supply/main.py diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index cc26ba0..3b26d7f 100755 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -44,9 +44,9 @@ jobs: WEB3_PROVIDER_POLYGON_URL: ${{ secrets.WEB3_PROVIDER_POLYGON_URL }} DISCORD_BOT_TOKEN_REBASE: ${{ secrets.DISCORD_BOT_TOKEN_REBASE }} DISCORD_BOT_WEBHOOK_REBASE: ${{ secrets.DISCORD_BOT_WEBHOOK_REBASE }} - DISCORD_BOT_TOKEN_RUNWAY: ${{ secrets.DISCORD_BOT_TOKEN_RUNWAY }} DISCORD_BOT_TOKEN_DAO_FEE: ${{ secrets.DISCORD_BOT_TOKEN_DAO_FEE }} DISCORD_BOT_TOKEN_DAO_BALANCE: ${{ secrets.DISCORD_BOT_TOKEN_DAO_BALANCE }} + DISCORD_BOT_TOKEN_DCM_SUPPLY: ${{ secrets.DISCORD_BOT_TOKEN_DCM_SUPPLY }} DISCORD_BOT_TOKEN_KLIMA_BOND_ALERTS: ${{ secrets.DISCORD_BOT_TOKEN_KLIMA_BOND_ALERTS }} DISCORD_BOT_TOKEN_KLIMA_PRICE: ${{ secrets.DISCORD_BOT_TOKEN_KLIMA_PRICE }} DISCORD_BOT_TOKEN_BCT_PRICE: ${{ secrets.DISCORD_BOT_TOKEN_BCT_PRICE }} diff --git a/k8s/dcm_supply/deployment_set_bot.yaml b/k8s/dcm_supply/deployment_set_bot.yaml new file mode 100644 index 0000000..80ab579 --- /dev/null +++ b/k8s/dcm_supply/deployment_set_bot.yaml @@ -0,0 +1,16 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: bot +spec: + template: + spec: + containers: + - name: bot + args: ["src.dcm_supply.main"] + env: + - name: DISCORD_BOT_TOKEN + valueFrom: + secretKeyRef: + name: discord-bots-secret + key: DISCORD_BOT_TOKEN_DCM_SUPPLY diff --git a/k8s/dcm_supply/kustomization.yaml b/k8s/dcm_supply/kustomization.yaml new file mode 100644 index 0000000..211bf7e --- /dev/null +++ b/k8s/dcm_supply/kustomization.yaml @@ -0,0 +1,13 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - ../base + +namePrefix: dcm-supply- + +commonLabels: + bot: dcm-supply + +patchesStrategicMerge: + - deployment_set_bot.yaml diff --git a/k8s/kustomization.yaml b/k8s/kustomization.yaml index 236cce0..43b9bb0 100644 --- a/k8s/kustomization.yaml +++ b/k8s/kustomization.yaml @@ -19,10 +19,10 @@ resources: - ./treasury_carbon - ./treasury_market - ./ubo_price - - ./runway - ./retirement_fee_info - ./dao_fee - ./dao_balance + - ./dcm_supply - ./cco2_price namespace: discord-bots diff --git a/k8s/secret.properties.template b/k8s/secret.properties.template index 8b07b2e..19d8c1c 100644 --- a/k8s/secret.properties.template +++ b/k8s/secret.properties.template @@ -19,6 +19,7 @@ DISCORD_BOT_TOKEN_UBO_PRICE=${DISCORD_BOT_TOKEN_UBO_PRICE} DISCORD_BOT_TOKEN_RETIREMENT_FEE_INFO=${DISCORD_BOT_TOKEN_RETIREMENT_FEE_INFO} DISCORD_BOT_TOKEN_DAO_FEE=${DISCORD_BOT_TOKEN_DAO_FEE} DISCORD_BOT_TOKEN_DAO_BALANCE=${DISCORD_BOT_TOKEN_DAO_BALANCE} +DISCORD_BOT_TOKEN_DCM_SUPPLY=${DISCORD_BOT_TOKEN_DCM_SUPPLY} DISCORD_BOT_WEBHOOK_REBASE=${DISCORD_BOT_WEBHOOK_REBASE} DISCORD_WEBHOOK_BROKEN_BOND_ALERT=${DISCORD_WEBHOOK_BROKEN_BOND_ALERT} diff --git a/src/constants.py b/src/constants.py index c19d36a..cfb9cc7 100755 --- a/src/constants.py +++ b/src/constants.py @@ -1,5 +1,8 @@ from web3 import Web3 +# Hard-coded since Polygon block times have stabilized +AVG_BLOCK_SECS = 2.21 + # Token Decimals BCT_DECIMALS = 18 C3_DECIMALS = 18 @@ -46,3 +49,4 @@ KLIMA_PROTOCOL_SUBGRAPH = 'https://api.thegraph.com/subgraphs/name/klimadao/klimadao-protocol-metrics' KLIMA_CARBON_SUBGRAPH = 'https://api.thegraph.com/subgraphs/name/klimadao/polygon-bridged-carbon' KLIMA_BONDS_SUBGRAPH = 'https://api.thegraph.com/subgraphs/name/klimadao/klimadao-bonds' +POLYGON_DIGITAL_CARBON_SUBGRAPH = 'https://api.thegraph.com/subgraphs/name/klimadao/polygon-digital-carbon' diff --git a/src/dcm_supply/__init__.py b/src/dcm_supply/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/dcm_supply/main.py b/src/dcm_supply/main.py new file mode 100644 index 0000000..c6b30ee --- /dev/null +++ b/src/dcm_supply/main.py @@ -0,0 +1,82 @@ +import os +import math + +from discord.ext import tasks +from subgrounds.subgrounds import Subgrounds + +from ..utils import ( + get_discord_client, + update_nickname, + update_presence, + get_last_metric, + get_last_carbon, + prettify_number, + get_rebases_per_day +) + +BOT_TOKEN = os.environ["DISCORD_BOT_TOKEN"] + +# Initialized Discord client +client = get_discord_client() + +sg = Subgrounds() + + +def get_info(): + last_metric = get_last_metric(sg) + total_carbon = sg.query([last_metric.treasuryCarbon]) + + last_carbon = get_last_carbon(sg) + current_sma, credit_supply = sg.query( + [last_carbon.creditSMA, last_carbon.creditSupply] + ) + return total_carbon, current_sma, credit_supply + + +@client.event +async def on_ready(): + print("Logged in as {0.user}".format(client)) + if not update_info.is_running(): + update_info.start() + + +@tasks.loop(seconds=300) +async def update_info(): + rebases_per_day = get_rebases_per_day() + + treasury_carbon, carbon_sma, credit_supply = get_info() + + carbon_sma = carbon_sma / 1e18 + credit_supply = credit_supply / 1e18 + + print(treasury_carbon) + print(carbon_sma) + if ( + treasury_carbon is not None + and carbon_sma is not None + and rebases_per_day is not None + ): + sma_percent = carbon_sma / credit_supply + # ie, annualized reward % + supply_change_annual = math.pow(1 + sma_percent, 365 * rebases_per_day) - 1 + else: + return + + yield_text = f"{supply_change_annual*100:,.2f}% Δ DCM Supply" + print(yield_text) + + success = await update_nickname(client, yield_text) + if not success: + return + + presence_txt = f'Total DCM Supply: {prettify_number(credit_supply)}t' + success = await update_presence( + client, + presence_txt, + type='playing' + ) + if not success: + return + + +client.run(BOT_TOKEN) diff --git a/src/staking_rewards/main.py b/src/staking_rewards/main.py index ea82e01..4e24321 100755 --- a/src/staking_rewards/main.py +++ b/src/staking_rewards/main.py @@ -6,10 +6,8 @@ from discord.ext import tasks from ..constants import DISTRIBUTOR_ADDRESS, SKLIMA_ADDRESS -from ..utils import get_discord_client, get_polygon_web3, load_abi, update_nickname, update_presence - -# Hard-coded since Polygon block times have stabilized -AVG_BLOCK_SECS = 2.21 +from ..utils import get_discord_client, get_polygon_web3, load_abi, \ + update_nickname, update_presence, get_rebases_per_day BOT_TOKEN = os.environ["DISCORD_BOT_TOKEN"] SCAN_API_KEY = os.environ['POLYGONSCAN_API_KEY'] @@ -58,17 +56,6 @@ def get_circ_supply(): return None -def get_rebases_per_day(blocks_per_rebase): - ''' - Calculates the average number of rebases per day based on the average - block production time for the previous 1 million blocks - ''' - - secs_per_rebase = blocks_per_rebase * AVG_BLOCK_SECS - - return 24 / (secs_per_rebase / 60 / 60) - - @client.event async def on_ready(): print('Logged in as {0.user}'.format(client)) diff --git a/src/utils.py b/src/utils.py index 8626de8..bc86134 100755 --- a/src/utils.py +++ b/src/utils.py @@ -5,7 +5,7 @@ import json from web3 import Web3 -from .constants import KLIMA_PROTOCOL_SUBGRAPH +from .constants import KLIMA_PROTOCOL_SUBGRAPH, POLYGON_DIGITAL_CARBON_SUBGRAPH, AVG_BLOCK_SECS PROVIDER_POLYGON_URL = os.environ['WEB3_PROVIDER_POLYGON_URL'] PROVIDER_ETH_URL = os.environ['WEB3_PROVIDER_ETH_URL'] @@ -95,6 +95,16 @@ def get_last_metric(sg): return last_metric +def get_last_carbon(sg): + kpm = sg.load_subgraph(POLYGON_DIGITAL_CARBON_SUBGRAPH) + + last_carbon = kpm.Query.epoches( + orderBy=kpm.Epoch.epoch, orderDirection='desc', first=1 + ) + + return last_carbon + + def prettify_number(number): num = float('{:.3g}'.format(number)) magnitude = 0 @@ -102,3 +112,14 @@ def prettify_number(number): magnitude += 1 num /= 1000.0 return '{}{}'.format('{:f}'.format(num).rstrip('0').rstrip('.'), ['', 'K', 'M', 'B', 'T'][magnitude]) + + +def get_rebases_per_day(blocks_per_rebase): + ''' + Calculates the average number of rebases per day based on the average + block production time for the previous 1 million blocks + ''' + + secs_per_rebase = blocks_per_rebase * AVG_BLOCK_SECS + + return 24 / (secs_per_rebase / 60 / 60)