Compare commits

..

No commits in common. "ce36e584dde347263e95ea1cb9c1d820bf0b1ff8" and "0f7be3147e501f66ff7c014b296b1b98f0c298b9" have entirely different histories.

9 changed files with 42 additions and 89 deletions

View File

@ -37,6 +37,3 @@ MAX_MPESA_SEND_AMOUNT=250000
DEFAULT_MPESA_ASSET=cUSD DEFAULT_MPESA_ASSET=cUSD
MPESA_BEARER_TOKEN=eyJeSIsInRcCI6IkpXVCJ.yJwdWJsaWNLZXkiOiIwrrrrrr MPESA_BEARER_TOKEN=eyJeSIsInRcCI6IkpXVCJ.yJwdWJsaWNLZXkiOiIwrrrrrr
MPESA_ONRAMP_BASE=https://pretium.v1.grassecon.net MPESA_ONRAMP_BASE=https://pretium.v1.grassecon.net
# Stable vouchers allowed for Pay Debt (USDT, USDm)
STABLE_VOUCHER_ADDRESSES=0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e,0x765DE816845861e75A25fCA122bb6898B8B1282a

View File

@ -114,22 +114,3 @@ func MaxMpesaSendAmount() float64 {
func DefaultMpesaAsset() string { func DefaultMpesaAsset() string {
return env.GetEnv("DEFAULT_MPESA_ASSET", "") return env.GetEnv("DEFAULT_MPESA_ASSET", "")
} }
func StableVoucherAddresses() []string {
var parsed []string
raw := env.GetEnv("STABLE_VOUCHER_ADDRESSES", "")
if raw == "" {
return parsed
}
list := strings.Split(raw, ",")
for _, addr := range list {
clean := strings.ToLower(strings.TrimSpace(addr))
if clean != "" {
parsed = append(parsed, clean)
}
}
return parsed
}

View File

@ -119,85 +119,86 @@ func (h *MenuHandlers) CalculateCreditAndDebt(ctx context.Context, sym string, i
l.AddDomain("default") l.AddDomain("default")
flag_api_call_error, _ := h.flagManager.GetFlag("flag_api_call_error") flag_api_call_error, _ := h.flagManager.GetFlag("flag_api_call_error")
flag_no_pay_debt_vouchers, _ := h.flagManager.GetFlag("flag_no_pay_debt_vouchers")
// default response // set the default flag set/reset and content
res.FlagReset = append(res.FlagReset, flag_api_call_error) res.FlagReset = append(res.FlagReset, flag_api_call_error)
res.Content = l.Get("Credit: %s KSH\nDebt: %s KSH\n", "0", "0") res.Content = l.Get("Credit: %s KSH\nDebt: %s KSH\n", "0", "0")
// Fetch session data // Fetch session data
_, _, activeSym, _, publicKey, _, err := h.getSessionData(ctx, sessionId) _, _, activeSym, _, publicKey, _, err := h.getSessionData(ctx, sessionId)
if err != nil { if err != nil {
// return if the user does not have an active voucher
return res, nil return res, nil
} }
// Resolve active pool // Get active pool address and symbol or fall back to default
activePoolAddress, _, err := h.resolveActivePoolDetails(ctx, sessionId) activePoolAddress, _, err := h.resolveActivePoolDetails(ctx, sessionId)
if err != nil { if err != nil {
return res, err return res, err
} }
// Fetch swappable vouchers // call the api using the activePoolAddress to get a list of SwapToSymbolsData
swappableVouchers, err := h.accountService.GetPoolSwappableFromVouchers(ctx, string(activePoolAddress), string(publicKey)) swappableVouchers, err := h.accountService.GetPoolSwappableFromVouchers(ctx, string(activePoolAddress), string(publicKey))
if err != nil { if err != nil {
logg.ErrorCtxf(ctx, "failed on GetPoolSwappableFromVouchers", "error", err) logg.ErrorCtxf(ctx, "failed on GetPoolSwappableFromVouchers", "error", err)
return res, nil return res, nil
} }
logg.InfoCtxf(ctx, "GetPoolSwappableFromVouchers", "swappable vouchers", swappableVouchers)
// Return if there are no vouchers
if len(swappableVouchers) == 0 { if len(swappableVouchers) == 0 {
return res, nil return res, nil
} }
// Filter stable vouchers (excluding active voucher) // Filter out the active voucher from swappableVouchers
filteredSwappableVouchers := make([]dataserviceapi.TokenHoldings, 0) filteredSwappableVouchers := make([]dataserviceapi.TokenHoldings, 0, len(swappableVouchers))
for _, v := range swappableVouchers { for _, s := range swappableVouchers {
if v.TokenSymbol == string(activeSym) { if s.TokenSymbol != string(activeSym) {
continue filteredSwappableVouchers = append(filteredSwappableVouchers, s)
}
if isStableVoucher(v.TokenAddress) {
filteredSwappableVouchers = append(filteredSwappableVouchers, v)
} }
} }
// No stable vouchers → cannot pay debt // Store as filtered swap to list data (excluding the current active voucher) for future reference
if len(filteredSwappableVouchers) == 0 {
res.FlagSet = append(res.FlagSet, flag_no_pay_debt_vouchers)
return res, nil
}
res.FlagReset = append(res.FlagReset, flag_no_pay_debt_vouchers)
// Process stable vouchers for later use
data := store.ProcessVouchers(filteredSwappableVouchers) data := store.ProcessVouchers(filteredSwappableVouchers)
// Find active voucher data logg.InfoCtxf(ctx, "ProcessVouchers", "data", data)
// Find the matching voucher data
activeSymStr := string(activeSym) activeSymStr := string(activeSym)
var activeData *dataserviceapi.TokenHoldings var activeData *dataserviceapi.TokenHoldings
for _, v := range swappableVouchers { for _, voucher := range swappableVouchers {
if v.TokenSymbol == activeSymStr { if voucher.TokenSymbol == activeSymStr {
activeData = &v activeData = &voucher
break break
} }
} }
if activeData == nil { if activeData == nil {
logg.InfoCtxf(ctx, "activeSym not found in vouchers, returning 0", "activeSym", activeSymStr)
return res, nil return res, nil
} }
// Credit = active voucher balance // Scale down the active balance (credit)
scaledCredit := store.ScaleDownBalance( // Max swappable value from pool using the active token
activeData.Balance, scaledCredit := store.ScaleDownBalance(activeData.Balance, activeData.TokenDecimals)
activeData.TokenDecimals,
)
// Debt = sum of stable vouchers only // Calculate total debt (sum of other vouchers)
scaledDebt := "0" scaledDebt := "0"
for _, v := range filteredSwappableVouchers {
scaled := store.ScaleDownBalance(v.Balance, v.TokenDecimals) for _, voucher := range swappableVouchers {
// Skip the active token
if voucher.TokenSymbol == activeSymStr {
continue
}
scaled := store.ScaleDownBalance(voucher.Balance, voucher.TokenDecimals)
// Add scaled balances (decimal-safe)
scaledDebt = store.AddDecimalStrings(scaledDebt, scaled) scaledDebt = store.AddDecimalStrings(scaledDebt, scaled)
} }
// Fetch MPESA rates // call the mpesa rates API to get the rates
rates, err := h.accountService.GetMpesaOnrampRates(ctx) rates, err := h.accountService.GetMpesaOnrampRates(ctx)
if err != nil { if err != nil {
res.FlagSet = append(res.FlagSet, flag_api_call_error) res.FlagSet = append(res.FlagSet, flag_api_call_error)
@ -207,15 +208,13 @@ func (h *MenuHandlers) CalculateCreditAndDebt(ctx context.Context, sym string, i
} }
creditFloat, _ := strconv.ParseFloat(scaledCredit, 64) creditFloat, _ := strconv.ParseFloat(scaledCredit, 64)
creditksh := fmt.Sprintf("%f", creditFloat*rates.Buy)
kshFormattedCredit, _ := store.TruncateDecimalString(creditksh, 0)
debtFloat, _ := strconv.ParseFloat(scaledDebt, 64) debtFloat, _ := strconv.ParseFloat(scaledDebt, 64)
debtksh := fmt.Sprintf("%f", debtFloat*rates.Buy)
kshFormattedDebt, _ := store.TruncateDecimalString(debtksh, 0)
creditKsh := fmt.Sprintf("%f", creditFloat*rates.Buy)
debtKsh := fmt.Sprintf("%f", debtFloat*rates.Buy)
kshFormattedCredit, _ := store.TruncateDecimalString(creditKsh, 0)
kshFormattedDebt, _ := store.TruncateDecimalString(debtKsh, 0)
// Persist swap data
dataMap := map[storedb.DataTyp]string{ dataMap := map[storedb.DataTyp]string{
storedb.DATA_POOL_TO_SYMBOLS: data.Symbols, storedb.DATA_POOL_TO_SYMBOLS: data.Symbols,
storedb.DATA_POOL_TO_BALANCES: data.Balances, storedb.DATA_POOL_TO_BALANCES: data.Balances,
@ -223,6 +222,7 @@ func (h *MenuHandlers) CalculateCreditAndDebt(ctx context.Context, sym string, i
storedb.DATA_POOL_TO_ADDRESSES: data.Addresses, storedb.DATA_POOL_TO_ADDRESSES: data.Addresses,
} }
// Write data entries
for key, value := range dataMap { for key, value := range dataMap {
if err := userStore.WriteEntry(ctx, sessionId, key, []byte(value)); err != nil { 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) logg.ErrorCtxf(ctx, "Failed to write data entry for sessionId: %s", sessionId, "key", key, "error", err)
@ -230,11 +230,7 @@ func (h *MenuHandlers) CalculateCreditAndDebt(ctx context.Context, sym string, i
} }
} }
res.Content = l.Get( res.Content = l.Get("Credit: %s KSH\nDebt: %s KSH\n", kshFormattedCredit, kshFormattedDebt)
"Credit: %s KSH\nDebt: %s KSH\n",
kshFormattedCredit,
kshFormattedDebt,
)
return res, nil return res, nil
} }

View File

@ -4,10 +4,8 @@ import (
"context" "context"
"fmt" "fmt"
"strconv" "strconv"
"strings"
"git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/sarafu-vise/config"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store" "git.grassecon.net/grassrootseconomics/sarafu-vise/store"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"gopkg.in/leonelquinteros/gotext.v1" "gopkg.in/leonelquinteros/gotext.v1"
@ -267,13 +265,3 @@ func (h *MenuHandlers) InitiatePayDebt(ctx context.Context, sym string, input []
res.FlagReset = append(res.FlagReset, flag_account_authorized) res.FlagReset = append(res.FlagReset, flag_account_authorized)
return res, nil return res, nil
} }
func isStableVoucher(tokenAddress string) bool {
addr := strings.ToLower(strings.TrimSpace(tokenAddress))
for _, stable := range config.StableVoucherAddresses() {
if addr == stable {
return true
}
}
return false
}

View File

@ -1 +0,0 @@
No stable voucher found

View File

@ -1,5 +0,0 @@
MOUT back 0
MOUT quit 9
HALT
INCMP ^ 0
INCMP quit 9

View File

@ -1 +0,0 @@
Hakuna sarafu thabiti iliyopatikana

View File

@ -1,5 +1,4 @@
CATCH no_voucher flag_no_active_voucher 1 CATCH no_voucher flag_no_active_voucher 1
CATCH no_stable_voucher flag_no_pay_debt_vouchers 1
LOAD calculate_max_pay_debt 0 LOAD calculate_max_pay_debt 0
RELOAD calculate_max_pay_debt RELOAD calculate_max_pay_debt
MAP calculate_max_pay_debt MAP calculate_max_pay_debt

View File

@ -36,4 +36,3 @@ flag,flag_incorrect_pool,42,this is set when the user selects an invalid pool
flag,flag_low_swap_amount,43,this is set when the swap max limit is less than 0.1 flag,flag_low_swap_amount,43,this is set when the swap max limit is less than 0.1
flag,flag_alias_unavailable,44,this is set when the preferred alias is not available flag,flag_alias_unavailable,44,this is set when the preferred alias is not available
flag,flag_swap_transaction,45,this is set when the transaction will involve performing a swap flag,flag_swap_transaction,45,this is set when the transaction will involve performing a swap
flag,flag_no_pay_debt_vouchers,46,this is set when the user does not have a stable voucher to pay debt

1 flag flag_language_set 8 checks whether the user has set their prefered language
36 flag flag_low_swap_amount 43 this is set when the swap max limit is less than 0.1
37 flag flag_alias_unavailable 44 this is set when the preferred alias is not available
38 flag flag_swap_transaction 45 this is set when the transaction will involve performing a swap
flag flag_no_pay_debt_vouchers 46 this is set when the user does not have a stable voucher to pay debt