From 6c962baa816e51aba201f344389aa98a01277613 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 3 Jul 2025 16:20:59 +0300 Subject: [PATCH] added pools.go for pool related functions --- handlers/application/menuhandler.go | 775 ---------------------------- handlers/application/pools.go | 163 ++++++ handlers/application/poolswap.go | 46 -- 3 files changed, 163 insertions(+), 821 deletions(-) create mode 100644 handlers/application/pools.go diff --git a/handlers/application/menuhandler.go b/handlers/application/menuhandler.go index b953ce3..110595f 100644 --- a/handlers/application/menuhandler.go +++ b/handlers/application/menuhandler.go @@ -22,7 +22,6 @@ import ( commonlang "git.grassecon.net/grassrootseconomics/common/lang" "git.grassecon.net/grassrootseconomics/common/pin" "git.grassecon.net/grassrootseconomics/sarafu-api/remote" - "git.grassecon.net/grassrootseconomics/sarafu-vise/config" "git.grassecon.net/grassrootseconomics/sarafu-vise/internal/sms" "git.grassecon.net/grassrootseconomics/sarafu-vise/profile" "git.grassecon.net/grassrootseconomics/sarafu-vise/store" @@ -558,780 +557,6 @@ func (h *MenuHandlers) FetchCommunityBalance(ctx context.Context, sym string, in return res, nil } -// ValidateRecipient validates that the given input is valid. -// -// TODO: split up functino -func (h *MenuHandlers) ValidateRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - var AliasAddressResult string - var AliasAddress *models.AliasAddress - store := h.userdataStore - - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - flag_invalid_recipient, _ := h.flagManager.GetFlag("flag_invalid_recipient") - flag_invalid_recipient_with_invite, _ := h.flagManager.GetFlag("flag_invalid_recipient_with_invite") - flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") - - // remove white spaces - recipient := strings.ReplaceAll(string(input), " ", "") - - if recipient != "0" { - recipientType, err := identity.CheckRecipient(recipient) - if err != nil { - // Invalid recipient format (not a phone number, address, or valid alias format) - res.FlagSet = append(res.FlagSet, flag_invalid_recipient) - res.Content = recipient - - return res, nil - } - - // save the recipient as the temporaryRecipient - err = store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(recipient)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write temporaryRecipient entry with", "key", storedb.DATA_TEMPORARY_VALUE, "value", recipient, "error", err) - return res, err - } - - switch recipientType { - case "phone number": - // format the phone number - formattedNumber, err := phone.FormatPhoneNumber(recipient) - if err != nil { - logg.ErrorCtxf(ctx, "Failed to format the phone number: %s", recipient, "error", err) - return res, err - } - - // Check if the phone number is registered - publicKey, err := store.ReadEntry(ctx, formattedNumber, storedb.DATA_PUBLIC_KEY) - if err != nil { - if db.IsNotFound(err) { - logg.InfoCtxf(ctx, "Unregistered phone number: %s", recipient) - res.FlagSet = append(res.FlagSet, flag_invalid_recipient_with_invite) - res.Content = recipient - return res, nil - } - - logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", storedb.DATA_PUBLIC_KEY, "error", err) - return res, err - } - - // Save the publicKey as the recipient - err = store.WriteEntry(ctx, sessionId, storedb.DATA_RECIPIENT, publicKey) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write recipient entry with", "key", storedb.DATA_RECIPIENT, "value", string(publicKey), "error", err) - return res, err - } - - case "address": - // checksum the address - address := ethutils.ChecksumAddress(recipient) - - // Save the valid Ethereum address as the recipient - err = store.WriteEntry(ctx, sessionId, storedb.DATA_RECIPIENT, []byte(address)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write recipient entry with", "key", storedb.DATA_RECIPIENT, "value", recipient, "error", err) - return res, err - } - - case "alias": - if strings.Contains(recipient, ".") { - AliasAddress, err = h.accountService.CheckAliasAddress(ctx, recipient) - if err == nil { - AliasAddressResult = AliasAddress.Address - } else { - logg.ErrorCtxf(ctx, "failed to resolve alias", "alias", recipient, "error_alias_check", err) - } - } else { - //Perform a search for each search domain,break on first match - for _, domain := range config.SearchDomains() { - fqdn := fmt.Sprintf("%s.%s", recipient, domain) - logg.InfoCtxf(ctx, "Resolving with fqdn alias", "alias", fqdn) - AliasAddress, err = h.accountService.CheckAliasAddress(ctx, fqdn) - if err == nil { - res.FlagReset = append(res.FlagReset, flag_api_error) - AliasAddressResult = AliasAddress.Address - continue - } else { - res.FlagSet = append(res.FlagSet, flag_api_error) - logg.ErrorCtxf(ctx, "failed to resolve alias", "alias", recipient, "error_alias_check", err) - return res, nil - } - } - } - if AliasAddressResult == "" { - res.Content = recipient - res.FlagSet = append(res.FlagSet, flag_invalid_recipient) - return res, nil - } else { - err = store.WriteEntry(ctx, sessionId, storedb.DATA_RECIPIENT, []byte(AliasAddressResult)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write recipient entry with", "key", storedb.DATA_RECIPIENT, "value", AliasAddressResult, "error", err) - return res, err - } - } - } - } - - return res, nil -} - -// TransactionReset resets the previous transaction data (Recipient and Amount) -// as well as the invalid flags. -func (h *MenuHandlers) TransactionReset(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - var err error - - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - - flag_invalid_recipient, _ := h.flagManager.GetFlag("flag_invalid_recipient") - flag_invalid_recipient_with_invite, _ := h.flagManager.GetFlag("flag_invalid_recipient_with_invite") - store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, storedb.DATA_AMOUNT, []byte("")) - if err != nil { - return res, nil - } - - err = store.WriteEntry(ctx, sessionId, storedb.DATA_RECIPIENT, []byte("")) - if err != nil { - return res, nil - } - - res.FlagReset = append(res.FlagReset, flag_invalid_recipient, flag_invalid_recipient_with_invite) - - return res, nil -} - -// InviteValidRecipient sends an invitation to the valid phone number. -func (h *MenuHandlers) InviteValidRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - store := h.userdataStore - smsservice := h.smsService - - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - - code := codeFromCtx(ctx) - l := gotext.NewLocale(translationDir, code) - l.AddDomain("default") - - recipient, err := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE) - if err != nil { - logg.ErrorCtxf(ctx, "Failed to read invalid recipient info", "error", err) - return res, err - } - - if !phone.IsValidPhoneNumber(string(recipient)) { - logg.InfoCtxf(ctx, "corrupted recipient", "key", storedb.DATA_TEMPORARY_VALUE, "recipient", recipient) - return res, nil - } - - _, err = smsservice.Accountservice.SendUpsellSMS(ctx, sessionId, string(recipient)) - if err != nil { - res.Content = l.Get("Your invite request for %s to Sarafu Network failed. Please try again later.", string(recipient)) - return res, nil - } - res.Content = l.Get("Your invitation to %s to join Sarafu Network has been sent.", string(recipient)) - return res, nil -} - -// ResetTransactionAmount resets the transaction amount and invalid flag. -func (h *MenuHandlers) ResetTransactionAmount(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - var err error - - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - - flag_invalid_amount, _ := h.flagManager.GetFlag("flag_invalid_amount") - store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, storedb.DATA_AMOUNT, []byte("")) - if err != nil { - return res, nil - } - - res.FlagReset = append(res.FlagReset, flag_invalid_amount) - - return res, nil -} - -// MaxAmount gets the current balance from the API and sets it as -// the result content. -func (h *MenuHandlers) MaxAmount(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - var err error - - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - store := h.userdataStore - - activeBal, err := store.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_BAL) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read activeBal entry with", "key", storedb.DATA_ACTIVE_BAL, "error", err) - return res, err - } - - res.Content = string(activeBal) - - return res, nil -} - -// ValidateAmount ensures that the given input is a valid amount and that -// it is not more than the current balance. -func (h *MenuHandlers) ValidateAmount(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - flag_invalid_amount, _ := h.flagManager.GetFlag("flag_invalid_amount") - userStore := h.userdataStore - - var balanceValue float64 - - // retrieve the active balance - activeBal, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_BAL) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read activeBal entry with", "key", storedb.DATA_ACTIVE_BAL, "error", err) - return res, err - } - balanceValue, err = strconv.ParseFloat(string(activeBal), 64) - if err != nil { - logg.ErrorCtxf(ctx, "Failed to convert the activeBal to a float", "error", err) - return res, err - } - - // Extract numeric part from the input amount - amountStr := strings.TrimSpace(string(input)) - inputAmount, err := strconv.ParseFloat(amountStr, 64) - if err != nil { - res.FlagSet = append(res.FlagSet, flag_invalid_amount) - res.Content = amountStr - return res, nil - } - - if inputAmount > balanceValue { - res.FlagSet = append(res.FlagSet, flag_invalid_amount) - res.Content = amountStr - return res, nil - } - - // Format the amount to 2 decimal places before saving (truncated) - formattedAmount, err := store.TruncateDecimalString(amountStr, 2) - if err != nil { - res.FlagSet = append(res.FlagSet, flag_invalid_amount) - res.Content = amountStr - return res, nil - } - - err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_AMOUNT, []byte(formattedAmount)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write amount entry with", "key", storedb.DATA_AMOUNT, "value", formattedAmount, "error", err) - return res, err - } - - res.Content = formattedAmount - return res, nil -} - -// GetRecipient returns the transaction recipient phone number from the gdbm. -func (h *MenuHandlers) GetRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - store := h.userdataStore - recipient, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE) - if len(recipient) == 0 { - logg.ErrorCtxf(ctx, "recipient is empty", "key", storedb.DATA_TEMPORARY_VALUE) - return res, fmt.Errorf("Data error encountered") - } - - res.Content = string(recipient) - - return res, nil -} - -// RetrieveBlockedNumber gets the current number during the pin reset for other's is in progress. -func (h *MenuHandlers) RetrieveBlockedNumber(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - store := h.userdataStore - blockedNumber, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_BLOCKED_NUMBER) - - res.Content = string(blockedNumber) - - return res, nil -} - -// GetSender returns the sessionId (phoneNumber). -func (h *MenuHandlers) GetSender(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - - res.Content = sessionId - - return res, nil -} - -// GetAmount retrieves the amount from teh Gdbm Db. -func (h *MenuHandlers) GetAmount(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - store := h.userdataStore - - // retrieve the active symbol - activeSym, err := store.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_SYM) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read activeSym entry with", "key", storedb.DATA_ACTIVE_SYM, "error", err) - return res, err - } - - amount, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_AMOUNT) - - res.Content = fmt.Sprintf("%s %s", string(amount), string(activeSym)) - - return res, nil -} - -// InitiateTransaction calls the TokenTransfer and returns a confirmation based on the result. -func (h *MenuHandlers) InitiateTransaction(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - var err error - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - - flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized") - - code := codeFromCtx(ctx) - l := gotext.NewLocale(translationDir, code) - l.AddDomain("default") - - data, err := store.ReadTransactionData(ctx, h.userdataStore, sessionId) - if err != nil { - return res, err - } - - finalAmountStr, err := store.ParseAndScaleAmount(data.Amount, data.ActiveDecimal) - if err != nil { - return res, err - } - - // Call TokenTransfer - r, err := h.accountService.TokenTransfer(ctx, finalAmountStr, data.PublicKey, data.Recipient, data.ActiveAddress) - if err != nil { - flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") - res.FlagSet = append(res.FlagSet, flag_api_error) - res.Content = l.Get("Your request failed. Please try again later.") - logg.ErrorCtxf(ctx, "failed on TokenTransfer", "error", err) - return res, nil - } - - trackingId := r.TrackingId - logg.InfoCtxf(ctx, "TokenTransfer", "trackingId", trackingId) - - res.Content = l.Get( - "Your request has been sent. %s will receive %s %s from %s.", - data.TemporaryValue, - data.Amount, - data.ActiveSym, - sessionId, - ) - - res.FlagReset = append(res.FlagReset, flag_account_authorized) - return res, nil -} - -// ManageVouchers retrieves the token holdings from the API using the "PublicKey" and -// 1. sets the first as the default voucher if no active voucher is set. -// 2. Stores list of vouchers -// 3. updates the balance of the active voucher -func (h *MenuHandlers) ManageVouchers(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - userStore := h.userdataStore - logdb := h.logDb - - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - - flag_no_active_voucher, _ := h.flagManager.GetFlag("flag_no_active_voucher") - flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") - - publicKey, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read publicKey entry", "key", storedb.DATA_PUBLIC_KEY, "error", err) - return res, err - } - - // Fetch vouchers from API - vouchersResp, err := h.accountService.FetchVouchers(ctx, string(publicKey)) - if err != nil { - res.FlagSet = append(res.FlagSet, flag_api_error) - return res, nil - } - res.FlagReset = append(res.FlagReset, flag_api_error) - - if len(vouchersResp) == 0 { - res.FlagSet = append(res.FlagSet, flag_no_active_voucher) - return res, nil - } - - res.FlagReset = append(res.FlagReset, flag_no_active_voucher) - - // Check if user has an active voucher with proper error handling - activeSym, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_SYM) - if err != nil { - if db.IsNotFound(err) { - // No active voucher, set the first one as default - firstVoucher := vouchersResp[0] - defaultSym := firstVoucher.TokenSymbol - defaultBal := firstVoucher.Balance - defaultDec := firstVoucher.TokenDecimals - defaultAddr := firstVoucher.TokenAddress - - // Scale down the balance - scaledBalance := store.ScaleDownBalance(defaultBal, defaultDec) - - firstVoucherMap := map[storedb.DataTyp]string{ - storedb.DATA_ACTIVE_SYM: defaultSym, - storedb.DATA_ACTIVE_BAL: scaledBalance, - storedb.DATA_ACTIVE_DECIMAL: defaultDec, - storedb.DATA_ACTIVE_ADDRESS: defaultAddr, - } - - for key, value := range firstVoucherMap { - if err := userStore.WriteEntry(ctx, sessionId, key, []byte(value)); err != nil { - logg.ErrorCtxf(ctx, "Failed to write active voucher data", "key", key, "error", err) - return res, err - } - err = logdb.WriteLogEntry(ctx, sessionId, key, []byte(value)) - if err != nil { - logg.DebugCtxf(ctx, "Failed to write voucher db log entry", "key", key, "value", value) - } - } - - logg.InfoCtxf(ctx, "Default voucher set", "symbol", defaultSym, "balance", defaultBal, "decimals", defaultDec, "address", defaultAddr) - } else { - logg.ErrorCtxf(ctx, "failed to read activeSym entry with", "key", storedb.DATA_ACTIVE_SYM, "error", err) - return res, err - } - } else { - // Update active voucher balance - activeSymStr := string(activeSym) - - // Find the matching voucher data - var activeData *dataserviceapi.TokenHoldings - for _, voucher := range vouchersResp { - if voucher.TokenSymbol == activeSymStr { - activeData = &voucher - break - } - } - - if activeData == nil { - logg.ErrorCtxf(ctx, "activeSym not found in vouchers, setting the first voucher as the default", "activeSym", activeSymStr) - firstVoucher := vouchersResp[0] - activeData = &firstVoucher - } - - // Scale down the balance - scaledBalance := store.ScaleDownBalance(activeData.Balance, activeData.TokenDecimals) - - // Update the balance field with the scaled value - activeData.Balance = scaledBalance - - // Pass the matching voucher data to UpdateVoucherData - if err := store.UpdateVoucherData(ctx, h.userdataStore, sessionId, activeData); err != nil { - logg.ErrorCtxf(ctx, "failed on UpdateVoucherData", "error", err) - return res, err - } - } - - // Store all voucher data - data := store.ProcessVouchers(vouchersResp) - dataMap := map[storedb.DataTyp]string{ - storedb.DATA_VOUCHER_SYMBOLS: data.Symbols, - storedb.DATA_VOUCHER_BALANCES: data.Balances, - storedb.DATA_VOUCHER_DECIMALS: data.Decimals, - storedb.DATA_VOUCHER_ADDRESSES: data.Addresses, - } - - // Write data entries - for key, value := range dataMap { - if err := userStore.WriteEntry(ctx, sessionId, key, []byte(value)); err != nil { - logg.ErrorCtxf(ctx, "Failed to write data entry for sessionId: %s", sessionId, "key", key, "error", err) - continue - } - } - - return res, nil -} - -// GetVoucherList fetches the list of vouchers and formats them. -func (h *MenuHandlers) GetVoucherList(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - - userStore := h.userdataStore - - // Read vouchers from the store - voucherData, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_VOUCHER_SYMBOLS) - logg.InfoCtxf(ctx, "reading voucherData in GetVoucherList", "sessionId", sessionId, "key", storedb.DATA_VOUCHER_SYMBOLS, "voucherData", voucherData) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read voucherData entires with", "key", storedb.DATA_VOUCHER_SYMBOLS, "error", err) - return res, err - } - - voucherBalances, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_VOUCHER_BALANCES) - logg.InfoCtxf(ctx, "reading voucherBalances in GetVoucherList", "sessionId", sessionId, "key", storedb.DATA_VOUCHER_BALANCES, "voucherBalances", voucherBalances) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read voucherData entires with", "key", storedb.DATA_VOUCHER_BALANCES, "error", err) - return res, err - } - - formattedVoucherList := store.FormatVoucherList(ctx, string(voucherData), string(voucherBalances)) - finalOutput := strings.Join(formattedVoucherList, "\n") - - logg.InfoCtxf(ctx, "final output for GetVoucherList", "sessionId", sessionId, "finalOutput", finalOutput) - - res.Content = finalOutput - - return res, nil -} - -// ViewVoucher retrieves the token holding and balance from the subprefixDB -// and displays it to the user for them to select it. -func (h *MenuHandlers) ViewVoucher(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - - code := codeFromCtx(ctx) - l := gotext.NewLocale(translationDir, code) - l.AddDomain("default") - - flag_incorrect_voucher, _ := h.flagManager.GetFlag("flag_incorrect_voucher") - - inputStr := string(input) - - metadata, err := store.GetVoucherData(ctx, h.userdataStore, sessionId, inputStr) - if err != nil { - return res, fmt.Errorf("failed to retrieve voucher data: %v", err) - } - - if metadata == nil { - res.FlagSet = append(res.FlagSet, flag_incorrect_voucher) - return res, nil - } - - if err := store.StoreTemporaryVoucher(ctx, h.userdataStore, sessionId, metadata); err != nil { - logg.ErrorCtxf(ctx, "failed on StoreTemporaryVoucher", "error", err) - return res, err - } - - res.FlagReset = append(res.FlagReset, flag_incorrect_voucher) - res.Content = l.Get("Symbol: %s\nBalance: %s", metadata.TokenSymbol, metadata.Balance) - - return res, nil -} - -// SetVoucher retrieves the temp voucher data and sets it as the active data. -func (h *MenuHandlers) SetVoucher(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - - // Get temporary data - tempData, err := store.GetTemporaryVoucherData(ctx, h.userdataStore, sessionId) - if err != nil { - logg.ErrorCtxf(ctx, "failed on GetTemporaryVoucherData", "error", err) - return res, err - } - - // Set as active and clear temporary data - if err := store.UpdateVoucherData(ctx, h.userdataStore, sessionId, tempData); err != nil { - logg.ErrorCtxf(ctx, "failed on UpdateVoucherData", "error", err) - return res, err - } - - res.Content = tempData.TokenSymbol - return res, nil -} - -// GetVoucherDetails retrieves the voucher details. -func (h *MenuHandlers) GetVoucherDetails(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - store := h.userdataStore - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") - - // get the active address - activeAddress, err := store.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_ADDRESS) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read activeAddress entry with", "key", storedb.DATA_ACTIVE_ADDRESS, "error", err) - return res, err - } - - // use the voucher contract address to get the data from the API - voucherData, err := h.accountService.VoucherData(ctx, string(activeAddress)) - if err != nil { - res.FlagSet = append(res.FlagSet, flag_api_error) - return res, nil - } - res.FlagReset = append(res.FlagReset, flag_api_error) - - res.Content = fmt.Sprintf( - "Name: %s\nSymbol: %s\nCommodity: %s\nLocation: %s", voucherData.TokenName, voucherData.TokenSymbol, voucherData.TokenCommodity, voucherData.TokenLocation, - ) - - return res, nil -} - -// GetDefaultPool returns the current user's Pool. If none is set, it returns the default config pool. -func (h *MenuHandlers) GetDefaultPool(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - - userStore := h.userdataStore - activePoolSym, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_POOL_SYM) - if err != nil { - if db.IsNotFound(err) { - // set the default as the response - res.Content = config.DefaultPoolSymbol() - return res, nil - } - - logg.ErrorCtxf(ctx, "failed to read the activePoolSym entry with", "key", storedb.DATA_ACTIVE_POOL_SYM, "error", err) - return res, err - } - - res.Content = string(activePoolSym) - - return res, nil -} - -// ViewPool retrieves the pool details from the user store -// and displays it to the user for them to select it. -func (h *MenuHandlers) ViewPool(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - - code := codeFromCtx(ctx) - l := gotext.NewLocale(translationDir, code) - l.AddDomain("default") - - flag_incorrect_pool, _ := h.flagManager.GetFlag("flag_incorrect_pool") - - inputStr := string(input) - - poolData, err := store.GetPoolData(ctx, h.userdataStore, sessionId, inputStr) - if err != nil { - return res, fmt.Errorf("failed to retrieve pool data: %v", err) - } - - if poolData == nil { - flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") - - // no match found. Call the API using the inputStr as the symbol - poolResp, err := h.accountService.RetrievePoolDetails(ctx, inputStr) - if err != nil { - res.FlagSet = append(res.FlagSet, flag_api_error) - return res, nil - } - - if len(poolResp.PoolSymbol) == 0 { - // If the API does not return the data, set the flag - res.FlagSet = append(res.FlagSet, flag_incorrect_pool) - return res, nil - } - - poolData = poolResp - } - - if err := store.StoreTemporaryPool(ctx, h.userdataStore, sessionId, poolData); err != nil { - logg.ErrorCtxf(ctx, "failed on StoreTemporaryPool", "error", err) - return res, err - } - - res.FlagReset = append(res.FlagReset, flag_incorrect_pool) - res.Content = l.Get("Name: %s\nSymbol: %s", poolData.PoolName, poolData.PoolSymbol) - - return res, nil -} - -// SetPool retrieves the temp pool data and sets it as the active data. -func (h *MenuHandlers) SetPool(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - - // Get temporary data - tempData, err := store.GetTemporaryPoolData(ctx, h.userdataStore, sessionId) - if err != nil { - logg.ErrorCtxf(ctx, "failed on GetTemporaryPoolData", "error", err) - return res, err - } - - // Set as active and clear temporary data - if err := store.UpdatePoolData(ctx, h.userdataStore, sessionId, tempData); err != nil { - logg.ErrorCtxf(ctx, "failed on UpdatePoolData", "error", err) - return res, err - } - - res.Content = tempData.PoolSymbol - return res, nil -} - // persistInitialLanguageCode receives an initial language code and persists it to the store func (h *MenuHandlers) persistInitialLanguageCode(ctx context.Context, sessionId string, code string) error { store := h.userdataStore diff --git a/handlers/application/pools.go b/handlers/application/pools.go new file mode 100644 index 0000000..c53fa82 --- /dev/null +++ b/handlers/application/pools.go @@ -0,0 +1,163 @@ +package application + +import ( + "context" + "fmt" + + "git.defalsify.org/vise.git/db" + "git.defalsify.org/vise.git/resource" + "git.grassecon.net/grassrootseconomics/sarafu-vise/config" + "git.grassecon.net/grassrootseconomics/sarafu-vise/store" + storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" + "gopkg.in/leonelquinteros/gotext.v1" +) + +// GetPools fetches a list of 5 top pools +func (h *MenuHandlers) GetPools(ctx context.Context, sym string, input []byte) (resource.Result, error) { + var res resource.Result + sessionId, ok := ctx.Value("SessionId").(string) + if !ok { + return res, fmt.Errorf("missing session") + } + userStore := h.userdataStore + + flag_api_error, _ := h.flagManager.GetFlag("flag_api_error") + + // call the api to get a list of top 5 pools sorted by swaps + topPools, err := h.accountService.FetchTopPools(ctx) + if err != nil { + res.FlagSet = append(res.FlagSet, flag_api_error) + logg.ErrorCtxf(ctx, "failed on FetchTransactions", "error", err) + return res, err + } + + // Return if there are no pools + if len(topPools) == 0 { + return res, nil + } + + data := store.ProcessPools(topPools) + + // Store all Pool data + dataMap := map[storedb.DataTyp]string{ + storedb.DATA_POOL_NAMES: data.PoolNames, + storedb.DATA_POOL_SYMBOLS: data.PoolSymbols, + storedb.DATA_POOL_ADDRESSES: data.PoolContractAdrresses, + } + + // Write data entries + for key, value := range dataMap { + if err := userStore.WriteEntry(ctx, sessionId, key, []byte(value)); err != nil { + logg.ErrorCtxf(ctx, "Failed to write data entry for sessionId: %s", sessionId, "key", key, "error", err) + continue + } + } + + res.Content = h.ReplaceSeparatorFunc(data.PoolSymbols) + + return res, nil +} + +// GetDefaultPool returns the current user's Pool. If none is set, it returns the default config pool. +func (h *MenuHandlers) GetDefaultPool(ctx context.Context, sym string, input []byte) (resource.Result, error) { + var res resource.Result + sessionId, ok := ctx.Value("SessionId").(string) + if !ok { + return res, fmt.Errorf("missing session") + } + + userStore := h.userdataStore + activePoolSym, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_POOL_SYM) + if err != nil { + if db.IsNotFound(err) { + // set the default as the response + res.Content = config.DefaultPoolSymbol() + return res, nil + } + + logg.ErrorCtxf(ctx, "failed to read the activePoolSym entry with", "key", storedb.DATA_ACTIVE_POOL_SYM, "error", err) + return res, err + } + + res.Content = string(activePoolSym) + + return res, nil +} + +// ViewPool retrieves the pool details from the user store +// and displays it to the user for them to select it. +func (h *MenuHandlers) ViewPool(ctx context.Context, sym string, input []byte) (resource.Result, error) { + var res resource.Result + sessionId, ok := ctx.Value("SessionId").(string) + if !ok { + return res, fmt.Errorf("missing session") + } + + code := codeFromCtx(ctx) + l := gotext.NewLocale(translationDir, code) + l.AddDomain("default") + + flag_incorrect_pool, _ := h.flagManager.GetFlag("flag_incorrect_pool") + + inputStr := string(input) + + poolData, err := store.GetPoolData(ctx, h.userdataStore, sessionId, inputStr) + if err != nil { + return res, fmt.Errorf("failed to retrieve pool data: %v", err) + } + + if poolData == nil { + flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") + + // no match found. Call the API using the inputStr as the symbol + poolResp, err := h.accountService.RetrievePoolDetails(ctx, inputStr) + if err != nil { + res.FlagSet = append(res.FlagSet, flag_api_error) + return res, nil + } + + if len(poolResp.PoolSymbol) == 0 { + // If the API does not return the data, set the flag + res.FlagSet = append(res.FlagSet, flag_incorrect_pool) + return res, nil + } + + poolData = poolResp + } + + if err := store.StoreTemporaryPool(ctx, h.userdataStore, sessionId, poolData); err != nil { + logg.ErrorCtxf(ctx, "failed on StoreTemporaryPool", "error", err) + return res, err + } + + res.FlagReset = append(res.FlagReset, flag_incorrect_pool) + res.Content = l.Get("Name: %s\nSymbol: %s", poolData.PoolName, poolData.PoolSymbol) + + return res, nil +} + +// SetPool retrieves the temp pool data and sets it as the active data. +func (h *MenuHandlers) SetPool(ctx context.Context, sym string, input []byte) (resource.Result, error) { + var res resource.Result + + sessionId, ok := ctx.Value("SessionId").(string) + if !ok { + return res, fmt.Errorf("missing session") + } + + // Get temporary data + tempData, err := store.GetTemporaryPoolData(ctx, h.userdataStore, sessionId) + if err != nil { + logg.ErrorCtxf(ctx, "failed on GetTemporaryPoolData", "error", err) + return res, err + } + + // Set as active and clear temporary data + if err := store.UpdatePoolData(ctx, h.userdataStore, sessionId, tempData); err != nil { + logg.ErrorCtxf(ctx, "failed on UpdatePoolData", "error", err) + return res, err + } + + res.Content = tempData.PoolSymbol + return res, nil +} diff --git a/handlers/application/poolswap.go b/handlers/application/poolswap.go index 816dfcf..ca728e6 100644 --- a/handlers/application/poolswap.go +++ b/handlers/application/poolswap.go @@ -13,52 +13,6 @@ import ( "gopkg.in/leonelquinteros/gotext.v1" ) -// GetPools fetches a list of 5 top pools -func (h *MenuHandlers) GetPools(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - userStore := h.userdataStore - - flag_api_error, _ := h.flagManager.GetFlag("flag_api_error") - - // call the api to get a list of top 5 pools sorted by swaps - topPools, err := h.accountService.FetchTopPools(ctx) - if err != nil { - res.FlagSet = append(res.FlagSet, flag_api_error) - logg.ErrorCtxf(ctx, "failed on FetchTransactions", "error", err) - return res, err - } - - // Return if there are no pools - if len(topPools) == 0 { - return res, nil - } - - data := store.ProcessPools(topPools) - - // Store all Pool data - dataMap := map[storedb.DataTyp]string{ - storedb.DATA_POOL_NAMES: data.PoolNames, - storedb.DATA_POOL_SYMBOLS: data.PoolSymbols, - storedb.DATA_POOL_ADDRESSES: data.PoolContractAdrresses, - } - - // Write data entries - for key, value := range dataMap { - if err := userStore.WriteEntry(ctx, sessionId, key, []byte(value)); err != nil { - logg.ErrorCtxf(ctx, "Failed to write data entry for sessionId: %s", sessionId, "key", key, "error", err) - continue - } - } - - res.Content = h.ReplaceSeparatorFunc(data.PoolSymbols) - - return res, nil -} - // LoadSwapFromList returns a list of possible vouchers to swap to func (h *MenuHandlers) LoadSwapToList(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result