feat: Add lending positions
All checks were successful
Build Docker / BuildImage (push) Successful in 36s

This commit is contained in:
Nathan Woodburn 2024-12-09 15:43:22 +11:00
parent 24cff2a523
commit c3d6e681ce
Signed by: nathanwoodburn
GPG Key ID: 203B000478AD0EF1
19 changed files with 104 additions and 32 deletions

View File

@ -5,7 +5,7 @@ import threading
from functools import wraps from functools import wraps
from time import time, sleep from time import time, sleep
def file_cache(folder="cache", ttl=3600): def file_cache(ttl=3600):
""" """
Decorator to cache function results in the specified folder with a TTL. Decorator to cache function results in the specified folder with a TTL.
@ -13,6 +13,7 @@ def file_cache(folder="cache", ttl=3600):
folder (str): Directory where cached files will be stored. folder (str): Directory where cached files will be stored.
ttl (int): Time-to-live for the cache in seconds. ttl (int): Time-to-live for the cache in seconds.
""" """
folder="cache"
if not os.path.exists(folder): if not os.path.exists(folder):
os.makedirs(folder) os.makedirs(folder)

View File

@ -1 +1 @@
{"timestamp": 1733709841.1727908, "result": 3951.21} {"timestamp": 1733719019.8687048, "result": 3917.66}

View File

@ -1 +1 @@
{"timestamp": 1733709904.048873, "result": 1.17} {"timestamp": 1733718944.0457852, "result": 1.16}

View File

@ -1 +1 @@
{"timestamp": 1733709837.4863276, "result": 4.19} {"timestamp": 1733719021.134048, "result": 4.19}

View File

@ -1 +1 @@
{"timestamp": 1733709838.508297, "result": 246.79} {"timestamp": 1733719018.4388325, "result": 245.52}

View File

@ -1 +1 @@
{"timestamp": 1733709902.6437316, "result": 4.22} {"timestamp": 1733719082.3050148, "result": 4.18}

View File

@ -1 +1 @@
{"timestamp": 1733709835.4421465, "result": 232.42} {"timestamp": 1733718865.254725, "result": 231.94}

View File

@ -1 +1 @@
{"timestamp": 1733709903.0252566, "result": 4.38} {"timestamp": 1733719142.596215, "result": 4.32}

View File

@ -1 +1 @@
{"timestamp": 1733709833.6583126, "result": 303.899783283} {"timestamp": 1733719398.4783282, "result": 326.899783283}

View File

@ -1 +1 @@
{"timestamp": 1733709835.0307581, "result": 0.009281764} {"timestamp": 1733718864.8976314, "result": 0.038218578}

View File

@ -1 +1 @@
{"timestamp": 1733709839.3296363, "result": 0.99943} {"timestamp": 1733719021.178202, "result": 1.0}

View File

@ -1 +1 @@
{"timestamp": 1733709841.9973485, "result": 99348} {"timestamp": 1733719020.2031393, "result": 98929}

View File

@ -1 +1 @@
{"timestamp": 1733709903.03487, "result": [{"mint": "27G8MtK7VtTcCHkpASjSDdkWWYfoqT6ggEuKidVJidD4", "balance": 24.661756, "price": 4.19, "value": 103.33275764000001, "name": "Jupiter Perpetuals Liquidity Provider Token", "symbol": "jlp"}, {"mint": "jupSoLaHXQiZZTSfEWMTRRgpnyFm8f6sZdosWBjx93v", "balance": 0.039815492, "price": 246.79, "value": 9.82606527068, "name": "Jupiter Staked SOL", "symbol": "jupsol"}, {"mint": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", "balance": 0.00255735, "price": 3951.21, "value": 10.104626893499999, "name": "Ethereum (Wormhole)", "symbol": "eth"}, {"mint": "3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh", "balance": 0.00035766, "price": 99348, "value": 35.532805679999996, "name": "Wrapped BTC (Wormhole)", "symbol": "wbtc"}, {"mint": "0x2::sui::SUI", "balance": 0.902850107, "price": 4.22, "value": 3.81002745154, "name": "Sui", "symbol": "sui"}, {"mint": "0x549e8b69270defbfafd4f94e17ec44cdbdd99820b33bda2278dea3b9a32d3f55::cert::CERT", "balance": 9.658874002, "price": 4.38, "value": 42.30586812876, "name": "Volo Staked SUI", "symbol": "vsui"}]} {"timestamp": 1733719142.5989292, "result": [{"mint": "jupSoLaHXQiZZTSfEWMTRRgpnyFm8f6sZdosWBjx93v", "balance": 0.039815492, "price": 245.52, "value": 9.775499595840001, "name": "Jupiter Staked SOL", "symbol": "jupsol"}, {"mint": "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", "balance": 0.00255735, "price": 3917.66, "value": 10.018827800999999, "name": "Ethereum (Wormhole)", "symbol": "eth"}, {"mint": "3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh", "balance": 0.00035766, "price": 98929, "value": 35.38294614, "name": "Wrapped BTC (Wormhole)", "symbol": "wbtc"}, {"mint": "27G8MtK7VtTcCHkpASjSDdkWWYfoqT6ggEuKidVJidD4", "balance": 19.88979, "price": 4.19, "value": 83.33822010000002, "name": "Jupiter Perpetuals Liquidity Provider Token", "symbol": "jlp"}, {"mint": "0x2::sui::SUI", "balance": 0.902850107, "price": 4.18, "value": 3.77391344726, "name": "Sui", "symbol": "sui"}, {"mint": "0x549e8b69270defbfafd4f94e17ec44cdbdd99820b33bda2278dea3b9a32d3f55::cert::CERT", "balance": 9.658874002, "price": 4.32, "value": 41.72633568864, "name": "Volo Staked SUI", "symbol": "vsui"}]}

View File

@ -1 +1 @@
{"timestamp": 1733709903.0345013, "result": [{"mint": "0x2::sui::SUI", "balance": 0.902850107, "price": 4.22, "value": 3.81002745154, "name": "Sui", "symbol": "sui"}, {"mint": "0x549e8b69270defbfafd4f94e17ec44cdbdd99820b33bda2278dea3b9a32d3f55::cert::CERT", "balance": 9.658874002, "price": 4.38, "value": 42.30586812876, "name": "Volo Staked SUI", "symbol": "vsui"}]} {"timestamp": 1733719142.5983186, "result": [{"mint": "0x2::sui::SUI", "balance": 0.902850107, "price": 4.18, "value": 3.77391344726, "name": "Sui", "symbol": "sui"}, {"mint": "0x549e8b69270defbfafd4f94e17ec44cdbdd99820b33bda2278dea3b9a32d3f55::cert::CERT", "balance": 9.658874002, "price": 4.32, "value": 41.72633568864, "name": "Volo Staked SUI", "symbol": "vsui"}]}

View File

@ -1 +1 @@
{"timestamp": 1733709903.5823874, "result": 82.815227} {"timestamp": 1733719016.3804839, "result": 82.815227}

View File

@ -0,0 +1 @@
{"timestamp": 1733719016.581333, "result": [{"name": "Kamino USDC Lending", "description": "Kamino USDC Lending", "apy": 26.85, "url": "https://app.kamino.finance/lending/reserve/DxXdAyU3kCjnyggvHmY5nAwg5cRbbmdyX3npfDMjjMek/Ga4rZytCpq1unD4DbEJ5bkHeUz9g3oh9AAFEi6vSauXp", "value": 20, "updated": "1733717057", "type": "Lending"}, {"name": "dYdX MegaVault", "description": "dYdX MegaVault", "apy": 46, "url": "https://app.kamino.finance/lending/reserve/DxXdAyU3kCjnyggvHmY5nAwg5cRbbmdyX3npfDMjjMek/Ga4rZytCpq1unD4DbEJ5bkHeUz9g3oh9AAFEi6vSauXp", "value": 23, "updated": "1733717057", "type": "Lending"}]}

View File

@ -123,20 +123,23 @@ def index():
vaultBalance = getVaultBalance() vaultBalance = getVaultBalance()
vaultBalance = "{:.2f}".format(vaultBalance) vaultBalance = "{:.2f}".format(vaultBalance)
# For testing # pie_chart_data = [(token['symbol'].upper(), token['value'], f"{token['name']}: ${'{:.2f}'.format(token['value'])}") for token in tokens]
# tokenSupply = 20 # pie_chart_data.append(("SOL", solValue, f"Solana: ${'{:.2f}'.format(solValue)}"))
# tokenValue = 1.01
# tokens = [{"symbol":"stWDBRN","name":"Stake With Us","value":1.01}]
# solValue = 10
# vaultBalance = "20.00"
pie_chart_data = [(token['symbol'].upper(), token['value'], f"{token['name']}: ${'{:.2f}'.format(token['value'])}") for token in tokens] # cardanoBalance = getCardanoValue(vault_cardano_address)
pie_chart_data.append(("SOL", solValue, f"Solana: ${'{:.2f}'.format(solValue)}")) # cardanoBalance = "{:.2f}".format(cardanoBalance)
# pie_chart_data.append(
# ("ADA", cardanoBalance, f"Cardano: ${cardanoBalance}"))
cardanoBalance = getCardanoValue(vault_cardano_address) # other_investment_types = {}
cardanoBalance = "{:.2f}".format(cardanoBalance) # other_investments = getOtherInvestments()
pie_chart_data.append( # for investment in other_investments:
("ADA", cardanoBalance, f"Cardano: ${cardanoBalance}")) # if investment["type"] not in other_investment_types:
# other_investment_types[investment["type"]] = 0
# other_investment_types[investment["type"]] += investment["value"]
# for investment_type in other_investment_types:
# pie_chart_data.append((investment_type, other_investment_types[investment_type], f"{investment_type}: ${other_investment_types[investment_type]}"))
return render_template("index.html", value=tokenValue, supply=tokenSupply, vault=vaultBalance) return render_template("index.html", value=tokenValue, supply=tokenSupply, vault=vaultBalance)
@ -192,7 +195,7 @@ def getTokenSupplyString() -> str:
supply = getTokenSupply() supply = getTokenSupply()
return "{:.2f}".format(supply) return "{:.2f}".format(supply)
@cache.file_cache() @cache.file_cache(60)
def getTokenSupply() -> int: def getTokenSupply() -> int:
supply = solana_client.get_token_supply(stWDBRN_token_mint) supply = solana_client.get_token_supply(stWDBRN_token_mint)
return supply.value.ui_amount return supply.value.ui_amount
@ -219,10 +222,11 @@ def getVaultBalance() -> int:
vaultBalance += tokenValue vaultBalance += tokenValue
vaultBalance += getCardanoValue(vault_cardano_address) vaultBalance += getCardanoValue(vault_cardano_address)
vaultBalance += getOtherInvestmentsValue()
return vaultBalance return vaultBalance
@cache.file_cache() @cache.file_cache(300)
def getTokens(chain:str=None): def getTokens(chain:str=None):
tokens = [] tokens = []
@ -299,7 +303,7 @@ def getTokenPrice():
get_cardano_balance_cache = TTLCache(maxsize=1, ttl=3600) get_cardano_balance_cache = TTLCache(maxsize=1, ttl=3600)
@cache.file_cache() @cache.file_cache(300)
def getCardanoBalance(address: str): def getCardanoBalance(address: str):
# Get balance of cardano address # Get balance of cardano address
try: try:
@ -325,7 +329,7 @@ def getCardanoValue(address: str):
# endregion # endregion
# region Sui # region Sui
@cache.file_cache() @cache.file_cache(300)
def getSuiTokens(address: str): def getSuiTokens(address: str):
url = "https://fullnode.mainnet.sui.io/" url = "https://fullnode.mainnet.sui.io/"
@ -369,6 +373,37 @@ def getSuiTokens(address: str):
# endregion # endregion
# region Other Investments
@cache.file_cache(300)
def getOtherInvestments():
data = requests.get("https://cloud.woodburn.au/s/stwdbrn_other/download/other_investments.json")
return data.json()
def getOtherInvestmentTypes():
data = getOtherInvestments()
types = {}
for investment in data:
if investment["type"] not in types:
types[investment["type"]] = {
"name": investment["type"],
"description": investment["type"],
"value": 0,
"amount": 0,
}
types[investment["type"]]["value"] += investment["value"]
types[investment["type"]]["amount"] += 1
return types
def getOtherInvestmentsValue():
data = getOtherInvestments()
value = 0
for investment in data:
value += investment["value"]
return value
# endregion
# region API Routes # region API Routes
@app.route("/api/v1/tokens") @app.route("/api/v1/tokens")
@ -425,6 +460,15 @@ def api_token():
for key in token: for key in token:
token[key]["tooltip"] = f"{token[key]['amount']} {key} (${token[key]['value']})" token[key]["tooltip"] = f"{token[key]['amount']} {key} (${token[key]['value']})"
other_investment_types = getOtherInvestmentTypes()
for investment_type in other_investment_types:
token[investment_type] = {
"name": f'{other_investment_types[investment_type]["name"]} Positions',
"description": other_investment_types[investment_type]["description"],
"value": round(other_investment_types[investment_type]["value"] / supply,2),
"amount": other_investment_types[investment_type]["amount"],
"tooltip": f"{other_investment_types[investment_type]['amount']} Positions (${other_investment_types[investment_type]['value']})"
}
token["total"] = { token["total"] = {
"name": "stWDBRN", "name": "stWDBRN",
@ -481,6 +525,19 @@ def api_vault():
for key in vault: for key in vault:
vault[key]["tooltip"] = f"{vault[key]['amount']} {key} (${vault[key]['value']})" vault[key]["tooltip"] = f"{vault[key]['amount']} {key} (${vault[key]['value']})"
other_investment_types = getOtherInvestmentTypes()
for investment_type in other_investment_types:
vault[investment_type] = {
"name": f'{other_investment_types[investment_type]["name"]} Positions',
"description": other_investment_types[investment_type]["description"],
"value": other_investment_types[investment_type]["value"],
"amount": other_investment_types[investment_type]["amount"],
"tooltip": f"{other_investment_types[investment_type]['amount']} Positions (${other_investment_types[investment_type]['value']})"
}
vault["total"] = { vault["total"] = {
"name": "Vault", "name": "Vault",
"description": "Total Vault value (USD)", "description": "Total Vault value (USD)",
@ -489,6 +546,11 @@ def api_vault():
return jsonify(vault) return jsonify(vault)
@app.route("/api/v1/other")
def api_other_investments():
data = getOtherInvestments()
return jsonify(data)
@app.route("/api/v1/deposit",methods=["POST"]) @app.route("/api/v1/deposit",methods=["POST"])
def api_deposit(): def api_deposit():
# Get authorization header # Get authorization header

Binary file not shown.

View File

@ -164,7 +164,15 @@
nameCell.style.padding = '8px 20px'; nameCell.style.padding = '8px 20px';
const amountCell = document.createElement('td'); const amountCell = document.createElement('td');
// If token in other investments
otherInvestments = ["Lending"]
if (otherInvestments.includes(token)) {
amountCell.textContent = `${data[token].amount} Positions`;
}
else {
amountCell.textContent = `${data[token].amount} ${token}`; amountCell.textContent = `${data[token].amount} ${token}`;
}
amountCell.style.border = '1px solid #ccc'; amountCell.style.border = '1px solid #ccc';
amountCell.style.padding = '8px 20px'; amountCell.style.padding = '8px 20px';