2023-11-13 04:40:00 +00:00
|
|
|
package bitcoin
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Provider struct {
|
|
|
|
bitcoinAddresses []string // Slice of bitcoin addresses this provider monitors
|
|
|
|
ynabAccountID string // YNAB account ID this provider updates - all bitcoin addresses are summed up and mapped to this YNAB account
|
|
|
|
client *client // HTTP client for interacting with Questrade API
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Provider) Name() string {
|
|
|
|
return "Bitcoin - Blockstream.info"
|
|
|
|
}
|
|
|
|
|
|
|
|
// Configures the provider for usage via environment variables and persistentData
|
|
|
|
// If an error is returned, the provider will not be used
|
|
|
|
func (p *Provider) Configure() error {
|
|
|
|
var err error
|
|
|
|
|
|
|
|
// Load environment variables in continous series with suffix starting at 0
|
|
|
|
// Multiple addresses can be configured, (eg _1, _2)
|
|
|
|
// As soon as the series is interrupted, we assume we're done
|
|
|
|
p.bitcoinAddresses = make([]string, 0)
|
|
|
|
for i := 0; true; i++ {
|
|
|
|
bitcoinAddress := os.Getenv(fmt.Sprintf("bitcoin_address_%d", i))
|
|
|
|
if bitcoinAddress == "" {
|
|
|
|
if i == 0 {
|
|
|
|
return fmt.Errorf("this account provider is not configured")
|
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
p.bitcoinAddresses = append(p.bitcoinAddresses, bitcoinAddress)
|
|
|
|
}
|
|
|
|
p.ynabAccountID = os.Getenv("bitcoin_ynab_account")
|
|
|
|
|
|
|
|
// Create new HTTP client
|
|
|
|
p.client, err = newClient()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to create new bitcoin client: %v", err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns slices of account balances and mapped YNAB account IDs, along with an error
|
|
|
|
func (p *Provider) GetBalances() ([]int, []string, error) {
|
|
|
|
|
|
|
|
balances := make([]int, 0)
|
|
|
|
ynabAccountIDs := make([]string, 0)
|
|
|
|
var satoshiBalance int
|
|
|
|
for _, bitcoinAddress := range p.bitcoinAddresses {
|
2023-11-14 01:52:24 +00:00
|
|
|
addressResponse, err := p.client.getAddress(bitcoinAddress)
|
2023-11-13 04:40:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return balances, ynabAccountIDs, fmt.Errorf("failed to get bitcoin address '%s': %v", bitcoinAddress, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
satoshiBalance += addressResponse.ChainStats.FundedTxoSum - addressResponse.ChainStats.SpentTxoSum
|
|
|
|
}
|
|
|
|
|
|
|
|
fiatBalance, err := p.client.ConvertBTCToCAD(satoshiBalance)
|
|
|
|
if err != nil {
|
|
|
|
return balances, ynabAccountIDs, fmt.Errorf("failed to convert satoshi balance to fiat balance: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
balances = append(balances, fiatBalance)
|
|
|
|
ynabAccountIDs = append(ynabAccountIDs, p.ynabAccountID)
|
|
|
|
return balances, ynabAccountIDs, nil
|
|
|
|
}
|