package bitcoinElectrum import ( "fmt" "os" "github.com/btcsuite/btcd/btcutil/hdkeychain" ) type Provider struct { masterKey *hdkeychain.ExtendedKey ynabAccountID string // YNAB account ID this provider updates - all bitcoin addresses are summed up and mapped to this YNAB account spvServer string gapLimit int coinGeckoApiKey string } func (p *Provider) Name() string { return "Bitcoin - Electrum SPV" } func (p *Provider) Configure() error { var err error zpub := os.Getenv("bitcoin_zpub") p.ynabAccountID = os.Getenv("bitcoin_ynab_account") p.spvServer = os.Getenv("bitcoin_spv_server") p.coinGeckoApiKey = os.Getenv("bitcoin_coingecko_api_key") p.gapLimit = 10 if zpub == "" || p.ynabAccountID == "" || p.spvServer == "" || p.coinGeckoApiKey == "" { return fmt.Errorf("this account provider is not configured") } p.masterKey, err = hdkeychain.NewKeyFromString(zpub) if err != nil { return fmt.Errorf("failed to obtain master key from zpub: %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) { var totalSats int64 // branch 0 = regular // branch 1 = change addresses for _, branch := range []uint32{0, 1} { branchSats, err := scanBranch(p.masterKey, branch, p.gapLimit, p.spvServer) if err != nil { return nil, nil, fmt.Errorf("failed to scan branch '%v': %v", branch, err) } totalSats += branchSats } cad, err := convertBTCToCAD(totalSats, p.coinGeckoApiKey) if err != nil { return nil, nil, fmt.Errorf("failed to convert sats to CAD: %v", err) } balances := make([]int, 0) accounts := make([]string, 0) balances = append(balances, int(cad)) accounts = append(accounts, p.ynabAccountID) return balances, accounts, nil }