diff --git a/data_bags/credentials/kosmos-rs.json b/data_bags/credentials/kosmos-rs.json new file mode 100644 index 0000000..8856bd3 --- /dev/null +++ b/data_bags/credentials/kosmos-rs.json @@ -0,0 +1,10 @@ +{ + "id": "kosmos-rs", + "auth_tokens": { + "encrypted_data": "fiznpRw7VKlm232+U6XV1rqkAf2Z8CpoD8KyvuvOH2JniaymlcTHgazGWQ8s\nGeqK4RU9l4d29e9i+Mh0k4vnhO4q\n", + "iv": "SvurcL2oNSNWjlxp\n", + "auth_tag": "JLQ7vGXAuYYJpLEpL6C+Rw==\n", + "version": 3, + "cipher": "aes-256-gcm" + } +} \ No newline at end of file diff --git a/data_bags/credentials/lndhub-go.json b/data_bags/credentials/lndhub-go.json index 94cf1c4..cca76d1 100644 --- a/data_bags/credentials/lndhub-go.json +++ b/data_bags/credentials/lndhub-go.json @@ -1,30 +1,30 @@ { "id": "lndhub-go", "jwt_secret": { - "encrypted_data": "3T4JYnoISKXCnatCBeLCXyE8wVjzphw5/JU5A0vHfQ2xSDZreIRQ\n", - "iv": "bGQZjCk6FtD/hqVj\n", - "auth_tag": "CS87+UK1ZIFMiNcNaoyO6w==\n", + "encrypted_data": "lJsKBTCRzI83xmRHXzpnuRH/4cuMOR+Rd+SBU50G9HdibadIEDhS\n", + "iv": "f/SvsWtZIYOVc54X\n", + "auth_tag": "YlJ78EuJbcPfjCPc2eH+ug==\n", "version": 3, "cipher": "aes-256-gcm" }, "postgresql_password": { - "encrypted_data": "u8kf/6WdSTzyIz2kF+24JgOPLndWH2WmTFZ3CToJsnay\n", - "iv": "KqLtV2UuaAzJx7C8\n", - "auth_tag": "3aqx45+epb2NFkNfOfG89A==\n", + "encrypted_data": "aT0yNlWjvk/0S4z2kZB4Ye1u/ngk5J6fGPbwZSfdq6cy\n", + "iv": "OgUttF4LlSrL/7gH\n", + "auth_tag": "pcbbGqbQ2RjU+i9dt8c3OQ==\n", "version": 3, "cipher": "aes-256-gcm" }, "admin_token": { - "encrypted_data": "Z737fXqRE9JHfunRhc2GG281dFFN1bvBvTzTDzl/Vb8O\n", - "iv": "oKLQJbD67tiz2235\n", - "auth_tag": "SlVIqC9d9SRoO78M7cBjTw==\n", + "encrypted_data": "I9EsqCCxMIw+fX6sfu6KX8B5fJj9DX5Y4tbX30jdnmxr\n", + "iv": "vnERvIWYInO6+Y8q\n", + "auth_tag": "gO+MprZUQgPEWJQUmSF1sA==\n", "version": 3, "cipher": "aes-256-gcm" }, "sentry_dsn": { - "encrypted_data": "gmDHGDWkTIvaXjcWMs1dnKnbqtsADPJ2mLmWw8Idj6RVevU5CabjvviAxEo1\n3hs2LWuObumRSCQt2QKap191uMq3CL2+da53hbsv+JUkxl4=\n", - "iv": "Yt0fSsxL4SNicwUY\n", - "auth_tag": "j7BWbcNnymHHMNTADWmCNw==\n", + "encrypted_data": "+sUXWgl6dXpA1/0FqjKC3Jnl54aor6gtM+19EM/NsHwg4qu672YnSgxV+c9x\nHM3JZBYxBYvJ+HYGAvMmhlGvaOOEIvLmFUpCCJeVUXR32S8=\n", + "iv": "82+DzAnHiptaX7sO\n", + "auth_tag": "CDx44iRBVhSIF8DOxb2c+w==\n", "version": 3, "cipher": "aes-256-gcm" } diff --git a/nodes/bitcoin-2.json b/nodes/bitcoin-2.json index bd9f1cf..e16415b 100644 --- a/nodes/bitcoin-2.json +++ b/nodes/bitcoin-2.json @@ -38,6 +38,7 @@ "kosmos-bitcoin::dotnet", "kosmos-bitcoin::nbxplorer", "kosmos-bitcoin::btcpay", + "kosmos-bitcoin::price_tracking", "apt::default", "timezone_iii::default", "timezone_iii::debian", @@ -102,6 +103,7 @@ "role[bitcoind]", "role[lnd]", "role[lndhub]", - "role[btcpay]" + "role[btcpay]", + "recipe[kosmos-bitcoin::price_tracking]" ] } \ No newline at end of file diff --git a/site-cookbooks/kosmos-bitcoin/attributes/default.rb b/site-cookbooks/kosmos-bitcoin/attributes/default.rb index cba71ab..4646c17 100644 --- a/site-cookbooks/kosmos-bitcoin/attributes/default.rb +++ b/site-cookbooks/kosmos-bitcoin/attributes/default.rb @@ -111,3 +111,5 @@ node.default['btcpay']['postgres']['user'] = 'satoshi' node.default['peerswap']['repo'] = 'https://github.com/ElementsProject/peerswap.git' node.default['peerswap']['revision'] = 'master' node.default['peerswap-lnd']['source_dir'] = '/opt/peerswap' + +node.default['price_tracking']['rs_base_url'] = "https://storage.kosmos.org/kosmos/public/btc-price" diff --git a/site-cookbooks/kosmos-bitcoin/recipes/price_tracking.rb b/site-cookbooks/kosmos-bitcoin/recipes/price_tracking.rb new file mode 100644 index 0000000..5525fa3 --- /dev/null +++ b/site-cookbooks/kosmos-bitcoin/recipes/price_tracking.rb @@ -0,0 +1,59 @@ +# +# Cookbook:: kosmos-bitcoin +# Recipe:: price_tracking +# +# Track BTC rates and publish them via remoteStorage +# + +%w[curl jq].each do |pkg| + apt_package pkg +end + +daily_tracker_path = "/usr/local/bin/btc-price-tracker-daily" + +credentials = Chef::EncryptedDataBagItem.load('credentials', 'kosmos-rs') + +template daily_tracker_path do + source "btc-price-tracker-daily.sh.erb" + mode '0740' + variables rs_base_url: node['price_tracking']['rs_base_url'] + notifies :restart, "systemd_unit[lnd-channel-backup.service]", :delayed +end + +systemd_unit 'btc-price-tracker-daily.service' do + content({ + Unit: { + Description: 'BTC price tracker (daily rates)', + After: 'network-online.target', + Wants: 'network-online.target' + }, + Service: { + Type: 'oneshot', + ExecStart: daily_tracker_path, + Environment: "RS_AUTH=#{credentials["auth_tokens"]["/btc-price"]}" + }, + Install: { + WantedBy: 'multi-user.target' + } + }) + sensitive true + triggers_reload true + action [:create] +end + +systemd_unit 'btc-price-tracker-daily.timer' do + content({ + Unit: { + Description: 'Run BTC price tracker daily' + }, + Timer: { + OnCalendar: '*-*-* 00:00:00', + Persistent: 'true' + }, + Install: { + WantedBy: 'timers.target' + } + }) + triggers_reload true + action [:create, :enable, :start] +end diff --git a/site-cookbooks/kosmos-bitcoin/templates/btc-price-tracker-daily.sh.erb b/site-cookbooks/kosmos-bitcoin/templates/btc-price-tracker-daily.sh.erb new file mode 100644 index 0000000..7d3a2ce --- /dev/null +++ b/site-cookbooks/kosmos-bitcoin/templates/btc-price-tracker-daily.sh.erb @@ -0,0 +1,49 @@ +#!/bin/bash + +# Calculate yesterday's date in YYYY-MM-DD format +YESTERDAY=$(date -d "yesterday" +%Y-%m-%d) +echo "Starting price tracking for $YESTERDAY" >&2 + +# Fetch and process rates for a fiat currency +get_price_data() { + local currency=$1 + local data avg open24 last + + data=$(curl -s "https://www.bitstamp.net/api/v2/ticker/btc${currency,,}/") + if [ $? -eq 0 ] && [ ! -z "$data" ]; then + echo "Successfully retrieved ${currency} price data" >&2 + open24=$(echo "$data" | jq -r '.open_24') + last=$(echo "$data" | jq -r '.last') + avg=$(( (${open24%.*} + ${last%.*}) / 2 )) + echo $avg + else + echo "ERROR: Failed to retrieve ${currency} price data" >&2 + exit 1 + fi +} + +# Get price data for each currency +usd_avg=$(get_price_data "USD") +eur_avg=$(get_price_data "EUR") +gbp_avg=$(get_price_data "GBP") + +# Create JSON +json="{\"EUR\":$eur_avg,\"USD\":$usd_avg,\"GBP\":$gbp_avg}" +echo "Rates: $json" >&2 + +# PUT in remote storage +response=$(curl -X PUT \ + -H "Authorization: Bearer $RS_AUTH" \ + -H "Content-Type: application/json" \ + -d "$json" \ + -w "%{http_code}" \ + -s \ + -o /dev/null \ + "<%= @rs_base_url %>/$YESTERDAY") + +if [ "$response" -eq 200 ] || [ "$response" -eq 201 ]; then + echo "Successfully uploaded price data" >&2 +else + echo "ERROR: Failed to upload price data. HTTP status: $response" >&2 + exit 1 +fi