Compare commits

..

9 Commits

Author SHA1 Message Date
alfred-mk
a96802f10f use a single FlagReset append statement 2025-05-30 05:09:27 +03:00
alfred-mk
3075070e14 remove unused CATCH statement for the flag_incorrect_pin 2025-05-30 05:06:29 +03:00
alfred-mk
9891a51f90 update the resetIncorrectPINAttempts to cater for edge cases with more than 3 invalid attempts 2025-05-30 05:01:58 +03:00
alfred-mk
7f9da1ec10 remove unused CATCH statement 2025-05-30 04:58:55 +03:00
alfred-mk
6a4b59cedf update the Authorize test 2025-05-30 04:58:20 +03:00
alfred-mk
4f02924cbd refactor the Authorize function to prevent double PIN requests 2025-05-30 04:57:32 +03:00
alfred-mk
b30e15caa5 remove additional RELOAD
Some checks failed
release / docker (push) Has been cancelled
2025-05-29 10:01:48 +03:00
alfred-mk
71b4eff35e add a catch for api failures 2025-05-29 10:00:44 +03:00
alfred-mk
20954d287b store the DATA_POOL_TO_BALANCES 2025-05-29 09:59:41 +03:00
25 changed files with 27 additions and 276 deletions

4
go.mod
View File

@@ -3,9 +3,9 @@ module git.grassecon.net/grassrootseconomics/sarafu-vise
go 1.23.4
require (
git.defalsify.org/vise.git v0.3.2-0.20250528124150-03bf7bfc1b66
git.defalsify.org/vise.git v0.3.2-0.20250507135825-a170e8a79da0
git.grassecon.net/grassrootseconomics/common v0.9.0-beta.1.0.20250417111317-2953f4c2f32e
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250606194235-b5ccaea57560
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250522123108-24224e553de5
git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250408094335-e2d1f65bb306
git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694
github.com/alecthomas/assert/v2 v2.2.2

6
go.sum
View File

@@ -4,8 +4,6 @@ git.defalsify.org/vise.git v0.3.2-0.20250507135825-a170e8a79da0 h1:ByRD+b39zVOjO
git.defalsify.org/vise.git v0.3.2-0.20250507135825-a170e8a79da0/go.mod h1:flN+Gu+0BX0F6trZc5VpJcO4e6mj/+HUw0Z/UqVTFhk=
git.defalsify.org/vise.git v0.3.2-0.20250507172020-cb22240f1cb9 h1:4kjbYw25MHZe9fqSbujPzpFXrYutFfVipvLrcWYnYks=
git.defalsify.org/vise.git v0.3.2-0.20250507172020-cb22240f1cb9/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck=
git.defalsify.org/vise.git v0.3.2-0.20250528124150-03bf7bfc1b66 h1:hmtb2Q3lHxq+SXqG+Gn43pKhTRYx+sw5j1LpgBfXN1o=
git.defalsify.org/vise.git v0.3.2-0.20250528124150-03bf7bfc1b66/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck=
git.grassecon.net/grassrootseconomics/common v0.9.0-beta.1.0.20250417111317-2953f4c2f32e h1:DcC9qkNl9ny3hxQmsMK6W81+5R/j4ZwYUbvewMI/rlc=
git.grassecon.net/grassrootseconomics/common v0.9.0-beta.1.0.20250417111317-2953f4c2f32e/go.mod h1:wgQJZGIS6QuNLHqDhcsvehsbn5PvgV7aziRebMnJi60=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250428082711-5d221b8d565f h1:OAHCP3YR1C5h1WFnnEnLs5kn6jTxQHQYWYtQaMZJIMY=
@@ -24,10 +22,6 @@ git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250521141246-
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250521141246-6c3719e3b652/go.mod h1:wKHPy1mpOCr9ahkRltwm1yi9qH/3m9xb8hMCX5C0L1o=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250522123108-24224e553de5 h1:7gVnkpybzg5lC7C8Rl4dejTbmBVpu5xfMMfda+d498U=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250522123108-24224e553de5/go.mod h1:wKHPy1mpOCr9ahkRltwm1yi9qH/3m9xb8hMCX5C0L1o=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250605174108-bf830e92dea2 h1:8cxGb7lSoNGJxjauIRGskp//EqisuOOZPoPj4oDwswE=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250605174108-bf830e92dea2/go.mod h1:wKHPy1mpOCr9ahkRltwm1yi9qH/3m9xb8hMCX5C0L1o=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250606194235-b5ccaea57560 h1:14QVGEgLdl1LyVS/mJFDVRGXHsH5IgmloNPKfk26K6M=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250606194235-b5ccaea57560/go.mod h1:wKHPy1mpOCr9ahkRltwm1yi9qH/3m9xb8hMCX5C0L1o=
git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250408094335-e2d1f65bb306 h1:Jo+yWysWw/N5BJQtAyEMN8ePVvAyPHv+JG4lQti+1N4=
git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250408094335-e2d1f65bb306/go.mod h1:FdLwYtzsjOIcDiW4uDgDYnB4Wdzq12uJUe0QHSSPbSo=
git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694 h1:DjJlBSz0S13acft5XZDWk7ZYnzElym0xLMYEVgyNJ+E=

View File

@@ -2245,110 +2245,6 @@ func (h *MenuHandlers) GetVoucherDetails(ctx context.Context, sym string, input
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
}
// CheckTransactions retrieves the transactions from the API using the "PublicKey" and stores to prefixDb.
func (h *MenuHandlers) CheckTransactions(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result
@@ -2820,59 +2716,39 @@ func (h *MenuHandlers) LoadSwapToList(ctx context.Context, sym string, input []b
return res, nil
}
// Get active pool address and symbol or fall back to default
var activePoolAddress []byte
activePoolAddress, err = userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_POOL_ADDRESS)
if err != nil {
if db.IsNotFound(err) {
defaultPoolAddress := config.DefaultPoolAddress()
// store the default as the active pool address
err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_POOL_ADDRESS, []byte(defaultPoolAddress))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write default PoolContractAdrress", "key", storedb.DATA_ACTIVE_POOL_ADDRESS, "value", defaultPoolAddress, "error", err)
return res, err
}
activePoolAddress = []byte(defaultPoolAddress)
} else {
logg.ErrorCtxf(ctx, "failed to read active PoolContractAdrress", "key", storedb.DATA_ACTIVE_POOL_ADDRESS, "error", err)
return res, err
}
defaultPool := dataserviceapi.PoolDetails{
PoolName: config.DefaultPoolName(),
PoolSymbol: config.DefaultPoolSymbol(),
PoolContractAdrress: config.DefaultPoolAddress(),
LimiterAddress: "",
VoucherRegistry: "",
}
var activePoolSymbol []byte
activePoolSymbol, err = userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_POOL_SYM)
activePoolAddress := defaultPool.PoolContractAdrress
// set the active pool contract address
err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_POOL_ADDRESS, []byte(activePoolAddress))
if err != nil {
if db.IsNotFound(err) {
defaultPoolSym := config.DefaultPoolName()
// store the default as the active pool symbol
err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_POOL_SYM, []byte(defaultPoolSym))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write default Pool Symbol", "key", storedb.DATA_ACTIVE_POOL_SYM, "value", defaultPoolSym, "error", err)
return res, err
}
activePoolSymbol = []byte(defaultPoolSym)
} else {
logg.ErrorCtxf(ctx, "failed to read active Pool symbol", "key", storedb.DATA_ACTIVE_POOL_SYM, "error", err)
return res, err
}
logg.ErrorCtxf(ctx, "failed to write active PoolContractAdrress entry with", "key", storedb.DATA_ACTIVE_POOL_ADDRESS, "value", activePoolAddress, "error", err)
return res, err
}
// call the api using the ActivePoolAddress and ActiveVoucherAddress to check if it is part of the pool
r, err := h.accountService.CheckTokenInPool(ctx, string(activePoolAddress), string(activeAddress))
r, err := h.accountService.CheckTokenInPool(ctx, activePoolAddress, string(activeAddress))
if err != nil {
res.FlagSet = append(res.FlagSet, flag_api_error)
logg.ErrorCtxf(ctx, "failed on CheckTokenInPool", "error", err)
return res, err
}
logg.InfoCtxf(ctx, "CheckTokenInPool", "response", r, "active_pool_address", string(activePoolAddress), "active_symbol_address", string(activeAddress))
logg.InfoCtxf(ctx, "CheckTokenInPool", "response", r, "active_pool_address", activePoolAddress, "address", activeAddress)
if !r.CanSwapFrom {
res.FlagSet = append(res.FlagSet, flag_incorrect_voucher)
res.Content = l.Get(
"%s is not in %s. Please update your voucher and try again.",
activeSym,
activePoolSymbol,
config.DefaultPoolName(),
)
return res, nil
}
@@ -2944,8 +2820,6 @@ func (h *MenuHandlers) SwapMaxLimit(ctx context.Context, sym string, input []byt
return res, nil
}
logg.InfoCtxf(ctx, "Metadata from GetSwapToVoucherData:", "metadata", metadata)
// Store the active swap_to data
if err := store.UpdateSwapToVoucherData(ctx, userStore, sessionId, metadata); err != nil {
logg.ErrorCtxf(ctx, "failed on UpdateSwapToVoucherData", "error", err)
@@ -2958,11 +2832,10 @@ func (h *MenuHandlers) SwapMaxLimit(ctx context.Context, sym string, input []byt
}
// call the api using the ActivePoolAddress, ActiveSwapFromAddress, ActiveSwapToAddress and PublicKey to get the swap max limit
logg.InfoCtxf(ctx, "Call GetSwapFromTokenMaxLimit with:", "ActivePoolAddress", swapData.ActivePoolAddress, "ActiveSwapFromAddress", swapData.ActiveSwapFromAddress, "ActiveSwapToAddress", swapData.ActiveSwapToAddress, "publicKey", swapData.PublicKey)
r, err := h.accountService.GetSwapFromTokenMaxLimit(ctx, swapData.ActivePoolAddress, swapData.ActiveSwapFromAddress, swapData.ActiveSwapToAddress, swapData.PublicKey)
if err != nil {
res.FlagSet = append(res.FlagSet, flag_api_error)
logg.ErrorCtxf(ctx, "failed on GetSwapFromTokenMaxLimit", "error", err)
logg.ErrorCtxf(ctx, "failed on FetchTransactions", "error", err)
return res, err
}

View File

@@ -112,10 +112,6 @@ func (ls *LocalHandlerService) GetHandler(accountService remote.AccountService)
ls.DbRs.AddLocalFunc("view_voucher", appHandlers.ViewVoucher)
ls.DbRs.AddLocalFunc("set_voucher", appHandlers.SetVoucher)
ls.DbRs.AddLocalFunc("get_voucher_details", appHandlers.GetVoucherDetails)
ls.DbRs.AddLocalFunc("get_default_pool", appHandlers.GetDefaultPool)
ls.DbRs.AddLocalFunc("get_pools", appHandlers.GetPools)
ls.DbRs.AddLocalFunc("view_pool", appHandlers.ViewPool)
ls.DbRs.AddLocalFunc("set_pool", appHandlers.SetPool)
ls.DbRs.AddLocalFunc("validate_blocked_number", appHandlers.ValidateBlockedNumber)
ls.DbRs.AddLocalFunc("retrieve_blocked_number", appHandlers.RetrieveBlockedNumber)
ls.DbRs.AddLocalFunc("reset_unregistered_number", appHandlers.ResetUnregisteredNumber)

View File

@@ -11,7 +11,7 @@
},
{
"input": "1",
"expectedContent": "Do you agree to terms and conditions?\nhttps://grassecon.org/tos\n\n1:Yes\n2:No"
"expectedContent": "Do you agree to terms and conditions?\nhttps://grassecon.org/pages/terms-and-conditions\n\n1:Yes\n2:No"
},
{
"input": "1",
@@ -31,7 +31,7 @@
},
{
"input": "1234",
"expectedContent": "Your account is being created. Thank you for using Sarafu. Goodbye!"
"expectedContent": "Your account is being created...Thank you for using Sarafu. Goodbye!"
}
]
},
@@ -44,7 +44,7 @@
},
{
"input": "1",
"expectedContent": "Do you agree to terms and conditions?\nhttps://grassecon.org/tos\n\n1:Yes\n2:No"
"expectedContent": "Do you agree to terms and conditions?\nhttps://grassecon.org/pages/terms-and-conditions\n\n1:Yes\n2:No"
},
{
"input": "2",

View File

@@ -1 +1 @@
Your account is being created.
Your account is being created...

View File

@@ -38,7 +38,4 @@ msgid "%s balance: %s\n"
msgstr "%s salio: %s\n"
msgid "%s is not in %s. Please update your voucher and try again."
msgstr "%s haipo kwenye %s. Tafadhali badilisha sarafu yako na ujaribu tena."
msgid "Name: %s\nSymbol: %s"
msgstr "Jina: %s\nSarafu: %s"
msgstr "%s haipo kwenye %s. Tafadhali badilisha sarafu yako na ujaribu tena."

View File

@@ -2,11 +2,8 @@ LOAD reset_account_authorized 16
RELOAD reset_account_authorized
MOUT select_voucher 1
MOUT voucher_details 2
MOUT select_pool 3
MOUT back 0
HALT
INCMP _ 0
INCMP select_voucher 1
INCMP voucher_details 2
INCMP select_pool 3
INCMP . *

View File

@@ -1 +0,0 @@
Success! {{.set_pool}} is now your active pool.

View File

@@ -1,10 +0,0 @@
LOAD reset_incorrect_pin 6
CATCH _ flag_account_authorized 0
LOAD set_pool 20
MAP set_pool
MOUT back 0
MOUT quit 9
HALT
INCMP ^ 0
INCMP quit 9
INCMP ^ *

View File

@@ -1 +0,0 @@
Hongera! {{.set_pool}} ni bwawa la Sarafu linalotumika sasa.

View File

@@ -1,3 +0,0 @@
Enter number or symbol to set the default pool:
Current: {{.get_default_pool}}
{{.get_pools}}

View File

@@ -1,20 +0,0 @@
CATCH no_voucher flag_no_active_voucher 1
LOAD get_pools 0
MAP get_pools
LOAD get_default_pool 20
RELOAD get_default_pool
MAP get_default_pool
MOUT back 0
MOUT quit 99
MNEXT next 88
MPREV prev 98
HALT
INCMP > 88
INCMP < 98
INCMP _ 0
INCMP quit 99
LOAD view_pool 80
RELOAD view_pool
CATCH api_failure flag_api_call_error 1
CATCH . flag_incorrect_pool 1
INCMP view_pool *

View File

@@ -1 +0,0 @@
Select pool

View File

@@ -1 +0,0 @@
Chagua Bwawa

View File

@@ -1,3 +0,0 @@
Chagua nambari au ishara kuweka bwawa la sarafu:
La sasa: {{.get_default_pool}}
{{.get_pools}}

View File

@@ -1,2 +1,2 @@
Do you agree to terms and conditions?
https://grassecon.org/tos
https://grassecon.org/pages/terms-and-conditions

View File

@@ -1,2 +1,2 @@
Kwa kutumia hii huduma umekubali sheria na masharti?
https://grassecon.org/tos
https://grassecon.org/pages/terms-and-conditions

View File

@@ -1,2 +0,0 @@
Enter PIN to confirm selection:
{{.view_pool}}

View File

@@ -1,10 +0,0 @@
MAP view_pool
MOUT back 0
MOUT quit 9
LOAD authorize_account 6
HALT
RELOAD authorize_account
CATCH incorrect_pin flag_incorrect_pin 1
INCMP _ 0
INCMP quit 9
INCMP pool_set *

View File

@@ -1,2 +0,0 @@
Weka PIN ili kuthibitisha chaguo:
{{.view_pool}}

View File

@@ -1,4 +1,5 @@
LOAD reset_incorrect_pin 6
CATCH incorrect_pin flag_incorrect_pin 1
CATCH _ flag_account_authorized 0
LOAD set_voucher 12
MAP set_voucher

View File

@@ -85,10 +85,6 @@ const (
DATA_ACTIVE_SWAP_MAX_AMOUNT
// Holds the active swap amount for the swap
DATA_ACTIVE_SWAP_AMOUNT
// Holds the active pool name for the swap
DATA_ACTIVE_POOL_NAME
// Holds the active pool symbol for the swap
DATA_ACTIVE_POOL_SYM
)
const (

View File

@@ -91,52 +91,3 @@ func MatchPool(input, names, symbols, addresses string) (name, symbol, address s
}
return
}
// StoreTemporaryPool saves pool metadata as temporary entries in the DataStore.
func StoreTemporaryPool(ctx context.Context, store DataStore, sessionId string, data *dataserviceapi.PoolDetails) error {
tempData := fmt.Sprintf("%s,%s,%s", data.PoolName, data.PoolSymbol, data.PoolContractAdrress)
if err := store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(tempData)); err != nil {
return err
}
return nil
}
// GetTemporaryPoolData retrieves temporary pool metadata from the DataStore.
func GetTemporaryPoolData(ctx context.Context, store DataStore, sessionId string) (*dataserviceapi.PoolDetails, error) {
temp_data, err := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE)
if err != nil {
return nil, err
}
values := strings.SplitN(string(temp_data), ",", 3)
data := &dataserviceapi.PoolDetails{}
data.PoolName = values[0]
data.PoolSymbol = values[1]
data.PoolContractAdrress = values[2]
return data, nil
}
// UpdatePoolData updates the active pool data in the DataStore.
func UpdatePoolData(ctx context.Context, store DataStore, sessionId string, data *dataserviceapi.PoolDetails) error {
logg.InfoCtxf(ctx, "UpdatePoolData", "data", data)
// Active pool data entry
activeEntries := map[storedb.DataTyp][]byte{
storedb.DATA_ACTIVE_POOL_NAME: []byte(data.PoolName),
storedb.DATA_ACTIVE_POOL_SYM: []byte(data.PoolSymbol),
storedb.DATA_ACTIVE_POOL_ADDRESS: []byte(data.PoolContractAdrress),
}
// Write active data
for key, value := range activeEntries {
if err := store.WriteEntry(ctx, sessionId, key, value); err != nil {
return err
}
}
return nil
}

View File

@@ -176,7 +176,7 @@ func GetSwapToVoucherData(ctx context.Context, store DataStore, sessionId string
// UpdateSwapToVoucherData updates the active swap to voucher data in the DataStore.
func UpdateSwapToVoucherData(ctx context.Context, store DataStore, sessionId string, data *dataserviceapi.TokenDetails) error {
logg.InfoCtxf(ctx, "UpdateSwapToVoucherData", "data", data)
logg.TraceCtxf(ctx, "UpdateSwapToVoucherData", "data", data)
// Convert TokenDecimals (uint8) to string
tokenDecimalsStr := strconv.FormatUint(uint64(data.TokenDecimals), 10)