added pools.go for pool related functions
This commit is contained in:
parent
e6b97b9256
commit
6c962baa81
@ -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
|
||||
|
163
handlers/application/pools.go
Normal file
163
handlers/application/pools.go
Normal file
@ -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
|
||||
}
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user