Compare commits

...

134 Commits

Author SHA1 Message Date
dd56d52f4c Merge pull request 'fix-amount-conversion' (#87) from fix-amount-conversion into master
Some checks failed
release / docker (push) Has been cancelled
Reviewed-on: #87
2025-06-26 14:07:29 +02:00
3592e7747c
add a test case with large decimal amount 2025-06-26 12:30:44 +03:00
7fe40faa9d
use the TruncateDecimalString helper function to format amounts to 2 d.p 2025-06-26 12:30:14 +03:00
02fd02dc21
add a test for the TruncateDecimalString 2025-06-26 12:26:49 +03:00
b884b82197
add test cases with high decimals for the ParseAndScaleAmount func 2025-06-26 12:20:34 +03:00
280c382a3d
add a helper function 'TruncateDecimalString' to format amounts to specified decimal places 2025-06-26 12:19:13 +03:00
88926480dc
Return finalAmount as a string with 0 decimal places (rounded) 2025-06-24 15:11:15 +03:00
dabdf7eba2
add a test case to ensure the stored amount is not rounded off 2025-06-24 14:55:37 +03:00
96f6ca7d08
truncate two decimal places without risking float rounding issues 2025-06-24 14:55:09 +03:00
bc48dddd99
use the correct ContractAddress for the Last10TxResponse struct 2025-06-24 14:04:07 +03:00
2ec612978d
update sarafu-api to correctly unmarshal nested pool details response in RetrievePoolDetails
Some checks failed
release / docker (push) Has been cancelled
2025-06-24 12:10:04 +03:00
632f891e16
use the updated alias endpoints from the sarafu-api
Some checks failed
release / docker (push) Has been cancelled
2025-06-24 10:51:15 +03:00
d758b37065
use the correct TokenHoldings struct instead of TokenDetails
Some checks failed
release / docker (push) Has been cancelled
2025-06-23 11:09:47 +03:00
929fb6a40d
add logs for the request and response body 2025-06-23 10:57:20 +03:00
5263af46d8
use a single ProcessVouchers due to similar data struct
Some checks failed
release / docker (push) Has been cancelled
2025-06-23 10:09:39 +03:00
383ef51134
use the TokenAddress instead of ContractAddress 2025-06-23 10:07:53 +03:00
5479580230
use the TokenHoldings instead of TokenDetails in getting the pool swappable vouchers
Some checks failed
release / docker (push) Has been cancelled
2025-06-23 09:50:13 +03:00
6f2d965b89
add log for the GetCurrentProfileInfo
Some checks failed
release / docker (push) Has been cancelled
2025-06-23 08:56:37 +03:00
150dc99201
log the response from GetPoolSwappableVouchers
Some checks failed
release / docker (push) Has been cancelled
2025-06-19 14:54:43 +03:00
b85c5a8788
log the metadata from GetSwapToVoucherData
Some checks failed
release / docker (push) Has been cancelled
2025-06-19 14:17:43 +03:00
23f1068402
Use InfoCtxf instead of TraceCtxf 2025-06-19 14:17:08 +03:00
e803048b13
Added more logging and display the actual activePoolSymbol
Some checks failed
release / docker (push) Has been cancelled
2025-06-19 12:54:33 +03:00
137a5dd599 cosmetic-fixes (#83)
Some checks failed
release / docker (push) Has been cancelled
Resolved issue #80

Reviewed-on: #83
Co-authored-by: alfred-mk <alfredmwaik@gmail.com>
Co-committed-by: alfred-mk <alfredmwaik@gmail.com>
2025-06-19 10:30:31 +02:00
61ff337464 Merge pull request 'hotfix/v1.2.5-rc.1' (#82) from hotfix/v1.2.5-rc.1 into master
Some checks failed
release / docker (push) Has been cancelled
Reviewed-on: #82
2025-06-18 11:53:30 +02:00
41c3b6d8e6
Merge branch 'master' into hotfix/v1.2.5-rc.1 2025-06-18 12:41:28 +03:00
42dadb5eea add-pool-selection (#79)
Some checks failed
release / docker (push) Has been cancelled
- Add pool selection under "Select vouchers" node
- Use the set pool contract address in the swap, or fall back to the default

Reviewed-on: #79
Co-authored-by: alfred-mk <alfredmwaik@gmail.com>
Co-committed-by: alfred-mk <alfredmwaik@gmail.com>
2025-06-09 13:38:19 +02:00
7228b818e3 swap-fix (#78)
Some checks failed
release / docker (push) Has been cancelled
- Resolves a "key not found error" on the swap max limit node
- Resolves double PIN requests when authorizing transactions #67

Reviewed-on: #78
Co-authored-by: alfred-mk <alfredmwaik@gmail.com>
Co-committed-by: alfred-mk <alfredmwaik@gmail.com>
2025-06-03 09:19:13 +02:00
3b44b4b9e7
updated go-vise to add full memory reset method
Some checks failed
release / docker (push) Has been cancelled
2025-05-28 16:09:15 +03:00
7c2454422e
remove misplaced CATCH statement
Some checks failed
release / docker (push) Has been cancelled
2025-05-23 16:54:05 +03:00
95de1dad2b
updated the go-vise package to commit hash a170e8a79da067e30b3c28a999a4d87fdd07ebaf 2025-05-23 16:53:10 +03:00
fac703576f
updated the go-vise package to commit hash a170e8a79da067e30b3c28a999a4d87fdd07ebaf
Some checks failed
release / docker (push) Has been cancelled
2025-05-23 15:30:48 +03:00
df8e0b4d4a
remove misplaced CATCH statement 2025-05-23 15:28:40 +03:00
b4bacfdc03
use the updated sarafu-api package with correct PoolSwapURL
Some checks failed
release / docker (push) Has been cancelled
2025-05-22 15:34:04 +03:00
8dc203d111
use the TemporaryValue to store the user's swap amount input
Some checks failed
release / docker (push) Has been cancelled
2025-05-22 15:18:52 +03:00
dcadea8737
Convert TokenDecimals (uint8) to string before storing it 2025-05-22 15:09:46 +03:00
71496d0015
change position of the catch statements
Some checks failed
release / docker (push) Has been cancelled
2025-05-22 12:41:49 +03:00
d9fc5440c5
prevent access to the swap menu if one does not have a voucher 2025-05-22 12:24:10 +03:00
0495472530
match the reset_incorrect_pin symbol to the function name 2025-05-22 12:13:50 +03:00
fd43060021
update the api failure template
Some checks failed
release / docker (push) Has been cancelled
2025-05-21 18:52:05 +03:00
cf6e105fb9
catch the api call error flag 2025-05-21 18:51:41 +03:00
91b57fece2
use the ProcessTokens function and remove the unused DATA_POOL_TO_BALANCES 2025-05-21 18:51:10 +03:00
043c79384c
correctly process TokenDetails 2025-05-21 18:39:45 +03:00
1cc1d00ffe
added a function to ProcessTokens from the GetPoolSwappableVouchers 2025-05-21 18:19:23 +03:00
d7987bf460
use the updated ussd-data-service and sarafu-api with TokenDetails 2025-05-21 18:18:15 +03:00
21da4b976b
use the updated sarafu-api that removes the publicKey from the GetPoolSwappableVouchers
Some checks failed
release / docker (push) Has been cancelled
2025-05-21 15:45:17 +03:00
169d85e2cb
added the INCLUDE_STABLES_PARAM env variable 2025-05-21 15:39:19 +03:00
3ab76b3d22
use updated sarafu-api with corrected JSON mapping for checkTokenInPool and getSwapFromTokenMaxLimit
Some checks failed
release / docker (push) Has been cancelled
2025-05-20 15:53:12 +03:00
b428e2e22d
add log for the CheckTokenInPool
Some checks failed
release / docker (push) Has been cancelled
2025-05-20 14:02:41 +03:00
1d23a0cc4b Merge pull request 'default-env-pool' (#76) from default-env-pool into master
Some checks failed
release / docker (push) Has been cancelled
Reviewed-on: #76
2025-05-20 12:18:30 +02:00
d3ad3b2db6
update the template and remove hardcoded values 2025-05-20 10:26:28 +03:00
5d8fee470a
use the default pool variables 2025-05-20 10:26:01 +03:00
cf237c592a
add the pool variables to the config 2025-05-20 10:25:27 +03:00
2d8333b89a
add the new env variables 2025-05-20 10:19:46 +03:00
c8146ea211 alfred/pool-swap (#33)
Some checks failed
release / docker (push) Has been cancelled
Pool swap functionality

Resolves issue #24

Reviewed-on: #33
Co-authored-by: alfred-mk <alfredmwaik@gmail.com>
Co-committed-by: alfred-mk <alfredmwaik@gmail.com>
2025-05-19 15:44:50 +02:00
d03c0c4c0e vouchers-input-selection (#75)
Some checks failed
release / docker (push) Has been cancelled
- Update the NEXT and PREV input selectors on the vouchers list
- Have the INCMPs before LOAD/RELOADs to prevent navigation inputs being passed to handler functions

Reviewed-on: #75
Reviewed-by: Mohamed Sohail <kamikazechaser@noreply.localhost>
Co-authored-by: alfred-mk <alfredmwaik@gmail.com>
Co-committed-by: alfred-mk <alfredmwaik@gmail.com>
2025-05-19 15:42:43 +02:00
e914d059e2
upgraded vise to refresh error logline for more context
Some checks failed
release / docker (push) Has been cancelled
2025-05-07 20:26:54 +03:00
7b1676bb37 fixes: recipient address and phone number (#74)
Some checks failed
release / docker (push) Has been cancelled
- Add functionality to checksum addresses...resolves #66
- Remove white spaces from the recipient input...resolves #70

Reviewed-on: #74
Reviewed-by: Mohamed Sohail <kamikazechaser@noreply.localhost>
Co-authored-by: alfred-mk <alfredmwaik@gmail.com>
Co-committed-by: alfred-mk <alfredmwaik@gmail.com>
2025-05-07 11:45:38 +02:00
db5d55d8e3 Merge pull request 'route-api-errors' (#46) from route-api-errors into master
Reviewed-on: #46
2025-04-29 13:55:54 +02:00
06cab56427
fix failing tests: menuhandlers missing the logdb 2025-04-29 13:25:31 +03:00
d0c181bca2
Merge branch 'master' into route-api-errors 2025-04-29 12:58:46 +03:00
e379129b3d Merge pull request 'logdb' (#56) from logdb into master
Some checks failed
release / docker (push) Has been cancelled
Reviewed-on: #56
2025-04-29 09:15:50 +02:00
29d35d1ec4
add write of the temporary and confirmed account pins to the log db 2025-04-28 15:49:40 +03:00
687447e73e
added the logdb to the testutil engine 2025-04-28 15:09:38 +03:00
ec1ddefeb3
updated packages for sarafu-api and vise 2025-04-28 12:50:36 +03:00
4166c9aed5 Merge branch 'master' into logdb 2025-04-28 12:38:27 +03:00
78e82edfb5
added the logdn to the menuhandler tests 2025-04-28 12:26:06 +03:00
a5c4866b23
add required logdb to menuhandler 2025-04-28 11:50:25 +03:00
b52239e6be
use direct key data type 2025-04-28 11:50:10 +03:00
5f02df64d7
upgrade visedriver dep 2025-04-28 11:40:28 +03:00
0ba65fc48c
use the updated phone and alias regexes from common 2025-04-28 11:39:37 +03:00
ce8cc8e0fd
use latest commit from sarafu-api 2025-04-28 11:38:45 +03:00
1499e4a29a
check recipient before sending an sms 2025-04-28 11:38:44 +03:00
5f24ff3b1b
feat: send invites when a recipient
is not resolved
2025-04-28 11:38:44 +03:00
6cdee7b58b
update sarafu-api dep 2025-04-28 11:38:43 +03:00
af5537abfc
updated the description of DATA_SELF_PIN_RESET 2025-04-28 11:37:45 +03:00
a6e569afb1
remove the verify_new_pin functionality that managed the unused flag_valid_pin 2025-04-28 11:37:44 +03:00
446514d8ce
remove unused function reset_valid_pin 2025-04-28 11:37:44 +03:00
131d106f38
use a single confirm_pin_change node 2025-04-28 11:37:43 +03:00
4d62f0222e
use the same check for flag_invalid_pin to move to the invalid_pin node 2025-04-28 11:37:43 +03:00
37cc3e1bc1
cleanup: remove extra space in all .vis files 2025-04-28 11:37:42 +03:00
491e97d8af
cleanup: remove extra space 2025-04-28 11:37:42 +03:00
d4fefe3c39
update the order for the INCMP statement 2025-04-28 11:37:41 +03:00
e8ff468c7b
update the reset flags in TestCheckBlockedStatus 2025-04-28 11:37:41 +03:00
965f343230
update the reset flags in TestConfirmPinChange 2025-04-28 11:37:40 +03:00
3426d31a9e
use the correct flag_invalid_pin in TestSaveTemporaryPin 2025-04-28 11:37:40 +03:00
8b2b667307
updated the expected content for the alias in view profile 2025-04-28 11:37:39 +03:00
c206fa1329
updated the menu flow for the admin reset others PIN in test 2025-04-28 11:37:39 +03:00
ad395c4b1a
remove code related to admins resetting a user's actual PIN 2025-04-28 11:37:38 +03:00
af7e6cc603
add a space 2025-04-28 11:37:38 +03:00
f90a188acc
updated the flags set and reset in SaveTemporaryPin and VerifyCreatePin 2025-04-28 11:37:37 +03:00
7a542d1f1c
updated the description of the flag_incorrect_pin 2025-04-28 11:37:37 +03:00
7d800d68a0
have the catch for create_pin above to catch accounts that do not have a PIN before the status on chain is checked 2025-04-28 11:37:36 +03:00
850458b5d8
use a single pin_mismatch node for a confirmed PIN that does not match the original PIN 2025-04-28 11:37:36 +03:00
ef8e3d5c35
allow the user to quit and move to invalid_pin node if the given input is invalid 2025-04-28 11:37:35 +03:00
982eebf374
move to the top node when one selects back 2025-04-28 11:37:35 +03:00
228d936a0e
use the confirm_self_pin_reset to confirm the new PIN 2025-04-28 11:37:34 +03:00
7c4d37b5b8
use the self_reset_pin node to reset PINs for accounts with a flag_account_pin_reset 2025-04-28 11:37:33 +03:00
e6e8bb6671
set the DATA_SELF_PIN_RESET as 0 and reset the flag_account_pin_reset 2025-04-28 11:37:33 +03:00
6385735b89
move back to the previous node if the admin user is not authorized 2025-04-28 11:34:27 +03:00
70815aabd1
request the admin to authorize the PIN reset 2025-04-28 11:34:27 +03:00
919899c704
move to the authorize_reset_others_pin if the given number is valid and registered 2025-04-28 11:34:26 +03:00
9a2ad99d07
updated the ResetOthersPin and ValidateBlockedNumber for the updated reset other's PIN functionality 2025-04-28 11:34:26 +03:00
2f4959e191
use the DATA_SELF_PIN_RESET to set the flag_account_pin_reset 2025-04-28 11:34:25 +03:00
1b2f3bb046
added a DATA_SELF_PIN_RESET to track when a user's PIN is reset by an admin 2025-04-28 11:34:24 +03:00
19a2b28367 Merge pull request 'extra-sms' (#64) from extra-sms into master
Reviewed-on: #64
2025-04-28 10:33:25 +02:00
25d124c58d
use updated go-vise that removes rollback on missing key 2025-04-25 17:10:46 +03:00
5b34ef28eb
added the logDb to async and http 2025-04-25 09:33:08 +03:00
f127fd7c0f
initialize log db ,attach it to the menuhandler 2025-04-14 11:34:37 +03:00
79bf09f3d1
add logdb to menuhandler and associated write operations 2025-04-09 14:55:35 +03:00
f4804546d9
add log db struct with associated methods 2025-04-09 14:52:57 +03:00
3fff03a164
update visedriver dep 2025-04-09 14:50:28 +03:00
094866c129
add a logdb field to lhs and setter function 2025-04-09 14:49:41 +03:00
58242c8d55
fix failing test: TestManageVouchers 2025-04-02 10:53:36 +03:00
cab90ed89a
set and reset flag_api_error flag 2025-04-02 10:48:04 +03:00
73c3486400
catch api call failure when manage vouchers is called 2025-04-02 10:47:33 +03:00
3c84fb5ae7
Merge branch 'master' into route-api-errors 2025-04-02 10:38:47 +03:00
04880b58a8
fix failing test 2025-04-01 12:49:10 +03:00
0458ac9498
fix failing test 2025-04-01 12:38:57 +03:00
a7e8c184f5
add some spacing 2025-04-01 11:59:31 +03:00
3615348efd
add swahili template 2025-04-01 11:57:59 +03:00
d0be79d817
set account creation failed flag 2025-04-01 11:30:00 +03:00
7883063e53
feat: set and reset api call failure flags 2025-03-31 15:42:27 +03:00
f562ce8adf
check for api call failure when setting the dafault voucher 2025-03-31 15:41:49 +03:00
cd2f4328a8
check for api call failure when checking transactions 2025-03-31 15:41:19 +03:00
95b9a6e486
catch api call failure when fetching voucher details 2025-03-28 16:09:53 +03:00
9674a04cbc
add handler to reset api call failure flag,set flag when requesting an alias fails 2025-03-28 15:51:56 +03:00
6c46c097fb
add explicit api call failure flag reset 2025-03-28 15:47:34 +03:00
c814c4ae5c
register handler to reset api call failure flag 2025-03-28 15:46:57 +03:00
bbecec0310
catch api call error when requesting an alias 2025-03-28 15:46:21 +03:00
eaa89c29df
Merge branch 'master' into route-api-errors 2025-03-28 15:22:40 +03:00
e832f46d22
return to top on retry 2025-03-26 14:40:54 +03:00
039117f40e
add api call failure catch 2025-03-26 14:40:32 +03:00
3532f72fbd
remove unneccessary catch 2025-03-26 14:39:37 +03:00
04c7e20457
set api call error flag to failing api calls 2025-03-26 14:38:47 +03:00
77 changed files with 2083 additions and 255 deletions

View File

@ -21,3 +21,11 @@ LANGUAGES=eng, swa
#Alias search domains #Alias search domains
ALIAS_SEARCH_DOMAINS=sarafu.local, sarafu.eth ALIAS_SEARCH_DOMAINS=sarafu.local, sarafu.eth
#Pool swap
DEFAULT_POOL_NAME="Kenya ROLA Pool"
DEFAULT_POOL_SYMBOL=ROLA
DEFAULT_POOL_CONTRACT_ADDRESS=0x48a953cA5cf5298bc6f6Af3C608351f537AAcb9e
DEFAULT_LIMITER_ADDRESS=
DEFAULT_VOUCHER_REGISTRY=
INCLUDE_STABLES_PARAM=false

View File

@ -44,6 +44,7 @@ func main() {
var err error var err error
var gettextDir string var gettextDir string
var langs args.LangVar var langs args.LangVar
var logDbConnStr string
flag.BoolVar(&engineDebug, "d", false, "use engine debug output") flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)") flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)")
@ -55,6 +56,7 @@ func main() {
flag.UintVar(&port, "p", config.Port(), "http port") flag.UintVar(&port, "p", config.Port(), "http port")
flag.StringVar(&gettextDir, "gettext", "", "use gettext translations from given directory") flag.StringVar(&gettextDir, "gettext", "", "use gettext translations from given directory")
flag.Var(&langs, "language", "add symbol resolution for language") flag.Var(&langs, "language", "add symbol resolution for language")
flag.StringVar(&logDbConnStr, "log-c", "db-logs", "log db connection string")
flag.Parse() flag.Parse()
config.Apply(override) config.Apply(override)
@ -100,6 +102,11 @@ func main() {
fmt.Fprintf(os.Stderr, "userdatadb: %v\n", err) fmt.Fprintf(os.Stderr, "userdatadb: %v\n", err)
os.Exit(1) os.Exit(1)
} }
logdb, err := menuStorageService.GetLogDb(ctx, userdataStore, logDbConnStr, "user-data")
if err != nil {
fmt.Fprintf(os.Stderr, "get log db error: %v\n", err)
os.Exit(1)
}
dbResource, ok := rs.(*resource.DbResource) dbResource, ok := rs.(*resource.DbResource)
if !ok { if !ok {
@ -113,6 +120,7 @@ func main() {
os.Exit(1) os.Exit(1)
} }
lhs.SetDataStore(&userdataStore) lhs.SetDataStore(&userdataStore)
lhs.SetLogDb(&logdb)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "setdatastore: %v\n", err) fmt.Fprintf(os.Stderr, "setdatastore: %v\n", err)
os.Exit(1) os.Exit(1)

View File

@ -56,6 +56,7 @@ func main() {
var err error var err error
var gettextDir string var gettextDir string
var langs args.LangVar var langs args.LangVar
var logDbConnStr string
flag.StringVar(&sessionId, "session-id", "075xx2123", "session id") flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)") flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)")
@ -69,6 +70,7 @@ func main() {
flag.UintVar(&port, "p", config.Port(), "http port") flag.UintVar(&port, "p", config.Port(), "http port")
flag.StringVar(&gettextDir, "gettext", "", "use gettext translations from given directory") flag.StringVar(&gettextDir, "gettext", "", "use gettext translations from given directory")
flag.Var(&langs, "language", "add symbol resolution for language") flag.Var(&langs, "language", "add symbol resolution for language")
flag.StringVar(&logDbConnStr, "log-c", "db-logs", "log db connection string")
flag.Parse() flag.Parse()
config.Apply(override) config.Apply(override)
@ -120,6 +122,12 @@ func main() {
fmt.Fprintf(os.Stderr, err.Error()) fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1) os.Exit(1)
} }
logdb, err := menuStorageService.GetLogDb(ctx, userdataStore, logDbConnStr, "user-data")
if err != nil {
fmt.Fprintf(os.Stderr, "get log db error: %v\n", err)
os.Exit(1)
}
//defer userdataStore.Close(ctx) //defer userdataStore.Close(ctx)
dbResource, ok := rs.(*resource.DbResource) dbResource, ok := rs.(*resource.DbResource)
@ -129,6 +137,7 @@ func main() {
lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs) lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs)
lhs.SetDataStore(&userdataStore) lhs.SetDataStore(&userdataStore)
lhs.SetLogDb(&logdb)
accountService := services.New(ctx, menuStorageService) accountService := services.New(ctx, menuStorageService)
hl, err := lhs.GetHandler(accountService) hl, err := lhs.GetHandler(accountService)

View File

@ -43,6 +43,7 @@ func main() {
var err error var err error
var gettextDir string var gettextDir string
var langs args.LangVar var langs args.LangVar
var logDbConnStr string
flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)") flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)")
flag.StringVar(&override.UserConn, "userdata", "?", "userdata store connection string") flag.StringVar(&override.UserConn, "userdata", "?", "userdata store connection string")
@ -55,6 +56,7 @@ func main() {
flag.UintVar(&port, "p", config.Port(), "http port") flag.UintVar(&port, "p", config.Port(), "http port")
flag.StringVar(&gettextDir, "gettext", "", "use gettext translations from given directory") flag.StringVar(&gettextDir, "gettext", "", "use gettext translations from given directory")
flag.Var(&langs, "language", "add symbol resolution for language") flag.Var(&langs, "language", "add symbol resolution for language")
flag.StringVar(&logDbConnStr, "log-c", "db-logs", "log db connection string")
flag.Parse() flag.Parse()
config.Apply(override) config.Apply(override)
@ -103,6 +105,12 @@ func main() {
os.Exit(1) os.Exit(1)
} }
logdb, err := menuStorageService.GetLogDb(ctx, userdataStore, logDbConnStr, "user-data")
if err != nil {
fmt.Fprintf(os.Stderr, "get log db error: %v\n", err)
os.Exit(1)
}
dbResource, ok := rs.(*resource.DbResource) dbResource, ok := rs.(*resource.DbResource)
if !ok { if !ok {
os.Exit(1) os.Exit(1)
@ -110,6 +118,7 @@ func main() {
lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs) lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs)
lhs.SetDataStore(&userdataStore) lhs.SetDataStore(&userdataStore)
lhs.SetLogDb(&logdb)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, err.Error()) fmt.Fprintf(os.Stderr, err.Error())

View File

@ -36,6 +36,7 @@ func main() {
var err error var err error
var gettextDir string var gettextDir string
var langs args.LangVar var langs args.LangVar
var logDbConnStr string
flag.StringVar(&sessionId, "session-id", "075xx2123", "session id") flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)") flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)")
@ -46,6 +47,7 @@ func main() {
flag.UintVar(&size, "s", 160, "max size of output") flag.UintVar(&size, "s", 160, "max size of output")
flag.StringVar(&gettextDir, "gettext", "", "use gettext translations from given directory") flag.StringVar(&gettextDir, "gettext", "", "use gettext translations from given directory")
flag.Var(&langs, "language", "add symbol resolution for language") flag.Var(&langs, "language", "add symbol resolution for language")
flag.StringVar(&logDbConnStr, "log-c", "db-logs", "log db connection string")
flag.Parse() flag.Parse()
config.Apply(override) config.Apply(override)
@ -110,6 +112,12 @@ func main() {
os.Exit(1) os.Exit(1)
} }
logdb, err := menuStorageService.GetLogDb(ctx, userdatastore, logDbConnStr, "user-data")
if err != nil {
fmt.Fprintf(os.Stderr, "get log db error: %v\n", err)
os.Exit(1)
}
dbResource, ok := rs.(*resource.DbResource) dbResource, ok := rs.(*resource.DbResource)
if !ok { if !ok {
fmt.Fprintf(os.Stderr, "get dbresource error: %v\n", err) fmt.Fprintf(os.Stderr, "get dbresource error: %v\n", err)
@ -118,6 +126,7 @@ func main() {
lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs) lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs)
lhs.SetDataStore(&userdatastore) lhs.SetDataStore(&userdatastore)
lhs.SetLogDb(&logdb)
lhs.SetPersister(pe) lhs.SetPersister(pe)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "localhandler service error: %v\n", err) fmt.Fprintf(os.Stderr, "localhandler service error: %v\n", err)

View File

@ -52,7 +52,6 @@ func SearchDomains() []string {
return ParsedDomains return ParsedDomains
} }
func Language() string { func Language() string {
return viseconfig.DefaultLanguage return viseconfig.DefaultLanguage
} }
@ -76,3 +75,15 @@ func PortSSH() uint {
func ATEndpoint() string { func ATEndpoint() string {
return env.GetEnv("AT_ENDPOINT", "/") return env.GetEnv("AT_ENDPOINT", "/")
} }
func DefaultPoolAddress() string {
return env.GetEnv("DEFAULT_POOL_CONTRACT_ADDRESS", "")
}
func DefaultPoolName() string {
return env.GetEnv("DEFAULT_POOL_NAME", "")
}
func DefaultPoolSymbol() string {
return env.GetEnv("DEFAULT_POOL_SYMBOL", "")
}

View File

@ -15,7 +15,7 @@ import (
const ( const (
changeHeadSrc = `LOAD reset_account_authorized 0 changeHeadSrc = `LOAD reset_account_authorized 0
LOAD reset_incorrect 0 LOAD reset_incorrect_pin 0
CATCH incorrect_pin flag_incorrect_pin 1 CATCH incorrect_pin flag_incorrect_pin 1
CATCH pin_entry flag_account_authorized 0 CATCH pin_entry flag_account_authorized 0
` `

34
go.mod
View File

@ -3,14 +3,15 @@ module git.grassecon.net/grassrootseconomics/sarafu-vise
go 1.23.4 go 1.23.4
require ( require (
git.defalsify.org/vise.git v0.3.2-0.20250401123711-d481b04a6805 git.defalsify.org/vise.git v0.3.2-0.20250528124150-03bf7bfc1b66
git.grassecon.net/grassrootseconomics/common v0.9.0-beta.1.0.20250417111317-2953f4c2f32e 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.20250417201442-5c0ed48e678c git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250624090744-339ba854c997
git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2 git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250408094335-e2d1f65bb306
git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694 git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694
github.com/alecthomas/assert/v2 v2.2.2 github.com/alecthomas/assert/v2 v2.2.2
github.com/gofrs/uuid v4.4.0+incompatible github.com/gofrs/uuid v4.4.0+incompatible
github.com/grassrootseconomics/ussd-data-service v1.2.0-beta github.com/grassrootseconomics/ethutils v1.3.1
github.com/grassrootseconomics/ussd-data-service v1.6.0-beta
github.com/jackc/pgx/v5 v5.7.1 github.com/jackc/pgx/v5 v5.7.1
github.com/peteole/testdata-loader v0.3.0 github.com/peteole/testdata-loader v0.3.0
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.9.0
@ -19,24 +20,49 @@ require (
) )
require ( require (
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/StackExchange/wmi v1.2.1 // indirect
github.com/alecthomas/participle/v2 v2.0.0 // indirect github.com/alecthomas/participle/v2 v2.0.0 // indirect
github.com/alecthomas/repr v0.2.0 // indirect github.com/alecthomas/repr v0.2.0 // indirect
github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c // indirect github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c // indirect
github.com/bits-and-blooms/bitset v1.14.3 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect
github.com/consensys/bavard v0.1.13 // indirect
github.com/consensys/gnark-crypto v0.12.1 // indirect
github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c // indirect
github.com/crate-crypto/go-kzg-4844 v1.0.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/deckarep/golang-set/v2 v2.6.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/ethereum/c-kzg-4844 v1.0.0 // indirect
github.com/ethereum/go-ethereum v1.14.9 // indirect
github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 // indirect
github.com/fxamacker/cbor/v2 v2.4.0 // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/grassrootseconomics/eth-custodial v1.3.0-beta // indirect github.com/grassrootseconomics/eth-custodial v1.3.0-beta // indirect
github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4 // indirect github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4 // indirect
github.com/hexops/gotextdiff v1.0.3 // indirect github.com/hexops/gotextdiff v1.0.3 // indirect
github.com/holiman/uint256 v1.3.1 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/joho/godotenv v1.5.1 // indirect github.com/joho/godotenv v1.5.1 // indirect
github.com/lmittmann/w3 v0.17.1 // indirect
github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a // indirect github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a // indirect
github.com/mmcloughlin/addchain v0.4.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
github.com/stretchr/objx v0.5.2 // indirect github.com/stretchr/objx v0.5.2 // indirect
github.com/supranational/blst v0.3.11 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/x448/float16 v0.8.4 // indirect github.com/x448/float16 v0.8.4 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
golang.org/x/sync v0.10.0 // indirect golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.29.0 // indirect golang.org/x/sys v0.29.0 // indirect
golang.org/x/text v0.21.0 // indirect golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.7.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
rsc.io/tmplfunc v0.0.3 // indirect
) )

179
go.sum
View File

@ -1,33 +1,29 @@
git.defalsify.org/vise.git v0.3.1 h1:A6FhMcur09ft/JzUPGXR+KpA17fltfeBnasyvLMZmq4= git.defalsify.org/vise.git v0.3.2-0.20250528124150-03bf7bfc1b66 h1:hmtb2Q3lHxq+SXqG+Gn43pKhTRYx+sw5j1LpgBfXN1o=
git.defalsify.org/vise.git v0.3.1/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck= git.defalsify.org/vise.git v0.3.2-0.20250528124150-03bf7bfc1b66/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck=
git.defalsify.org/vise.git v0.3.2-0.20250401123711-d481b04a6805 h1:FnT39aqXcP5YWhwPDBABopSjCu2SlbPFoOVitSpAVxU=
git.defalsify.org/vise.git v0.3.2-0.20250401123711-d481b04a6805/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck=
git.grassecon.net/grassrootseconomics/common v0.0.0-20250121134736-ba8cbbccea7d h1:5mzLas+jxTUtusOKx4XvU+n2QvrV/mH17MnJRy46siQ=
git.grassecon.net/grassrootseconomics/common v0.0.0-20250121134736-ba8cbbccea7d/go.mod h1:wgQJZGIS6QuNLHqDhcsvehsbn5PvgV7aziRebMnJi60=
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 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/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.20250310093912-8145b4bd004b h1:xiTpaqWWoF5qcnarY/9ZkT6aVdnKwqztb2gzIahJn4w= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250623063234-c1797e7a32b5 h1:VnRe01kHkZUBK/QjE7iV6gElSqSwQnAkWV3yCHtuYrI=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250310093912-8145b4bd004b/go.mod h1:gOn89ipaDcDvmQXRMQYKUqcw/sJcwVOPVt2eC6Geip8= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250623063234-c1797e7a32b5/go.mod h1:H97hR+VOnZvR5BiGVb0ScCPwH/IoKBOlKM+yrQNVpq0=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250401111804-2eed990921c5 h1:DwBZHP4sebfHxK8EU2nlA2CXU81+a7Kj/pnC5vDPcf4= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250623070026-d945964b0b46 h1:0+XkSRe7XSHa9WHXKpGPuC0myDszjchr4syH006lQ28=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250401111804-2eed990921c5/go.mod h1:gOn89ipaDcDvmQXRMQYKUqcw/sJcwVOPVt2eC6Geip8= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250623070026-d945964b0b46/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250401115503-5b41c8dc6440 h1:eWrBZMM3pBMCFyRl4rO/aaR+OmOMFJxogNyFAFry+EM= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250623075057-7b42d509e6d4 h1:W+8CC7x5eCPylkGy2TEoOpfJuiIlqzEzyYTzCLlY/u8=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250401115503-5b41c8dc6440/go.mod h1:gOn89ipaDcDvmQXRMQYKUqcw/sJcwVOPVt2eC6Geip8= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250623075057-7b42d509e6d4/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250401122510-441e289854ad h1:tYjanaCf6mF+iXRtDx5gckQm5vhZYx9N/JlNIBZj1m0= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250624074830-5aa032400c12 h1:vD8biQmN36eouuE+TdxgXQjKisRf5cTGu/tMPv3afs0=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250401122510-441e289854ad/go.mod h1:gOn89ipaDcDvmQXRMQYKUqcw/sJcwVOPVt2eC6Geip8= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250624074830-5aa032400c12/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250411080608-34957e5b6ff8 h1:Emesd0rybSLhPwZwqdvLsk/P9ZsT+7CQwQV/mrjQp3o= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250624090744-339ba854c997 h1:8bCKyYoV4YiVBvCZlRclc3aQlBYpWhgtM35mvniDFD8=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250411080608-34957e5b6ff8/go.mod h1:gOn89ipaDcDvmQXRMQYKUqcw/sJcwVOPVt2eC6Geip8= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250624090744-339ba854c997/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250417155812-58366274c3e1 h1:Yt9S+9JtCB4Y6jw6Xo1WGoVVu591n3/tSRIwM3kw1uY= git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250408094335-e2d1f65bb306 h1:Jo+yWysWw/N5BJQtAyEMN8ePVvAyPHv+JG4lQti+1N4=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250417155812-58366274c3e1/go.mod h1:gOn89ipaDcDvmQXRMQYKUqcw/sJcwVOPVt2eC6Geip8= git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250408094335-e2d1f65bb306/go.mod h1:FdLwYtzsjOIcDiW4uDgDYnB4Wdzq12uJUe0QHSSPbSo=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250417191830-86cfb9c02028 h1:HuIL9BClNieD7QCikCW1sJ9HyIo9iqRDFqULJGHxbrM=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250417191830-86cfb9c02028/go.mod h1:gOn89ipaDcDvmQXRMQYKUqcw/sJcwVOPVt2eC6Geip8=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250417200733-5ff139b6494b h1:0Ldq9SKqu+oNljNaKpQFyUgl3cOi6LJulGZwf5vXuWo=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250417200733-5ff139b6494b/go.mod h1:gOn89ipaDcDvmQXRMQYKUqcw/sJcwVOPVt2eC6Geip8=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250417201442-5c0ed48e678c h1:fO8NGQ/sLdwpbi3UWzZZxqOXGrEzMVXyxER5ziGuZLI=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250417201442-5c0ed48e678c/go.mod h1:gOn89ipaDcDvmQXRMQYKUqcw/sJcwVOPVt2eC6Geip8=
git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2 h1:YFztSsexCUgFo6M0tbngRwYdgJd3LQV3RO/Jw09u3+k=
git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2/go.mod h1:6B6ByxXOiRY0NR7K02Bf3fEu7z+2c/6q8PFVNjC5G8w=
git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694 h1:DjJlBSz0S13acft5XZDWk7ZYnzElym0xLMYEVgyNJ+E= git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694 h1:DjJlBSz0S13acft5XZDWk7ZYnzElym0xLMYEVgyNJ+E=
git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694/go.mod h1:DpibtYpnT3nG4Kn556hRAkdu4+CtiI/6MbnQHal51mQ= git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694/go.mod h1:DpibtYpnT3nG4Kn556hRAkdu4+CtiI/6MbnQHal51mQ=
github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA=
github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI=
github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI=
github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk= github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk=
github.com/alecthomas/assert/v2 v2.2.2/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ= github.com/alecthomas/assert/v2 v2.2.2/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ=
github.com/alecthomas/participle/v2 v2.0.0 h1:Fgrq+MbuSsJwIkw3fEj9h75vDP0Er5JzepJ0/HNHv0g= github.com/alecthomas/participle/v2 v2.0.0 h1:Fgrq+MbuSsJwIkw3fEj9h75vDP0Er5JzepJ0/HNHv0g=
@ -36,21 +32,91 @@ github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk
github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c h1:H9Nm+I7Cg/YVPpEV1RzU3Wq2pjamPc/UtHDgItcb7lE= github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c h1:H9Nm+I7Cg/YVPpEV1RzU3Wq2pjamPc/UtHDgItcb7lE=
github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c/go.mod h1:rGod7o6KPeJ+hyBpHfhi4v7blx9sf+QsHsA7KAsdN6U= github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c/go.mod h1:rGod7o6KPeJ+hyBpHfhi4v7blx9sf+QsHsA7KAsdN6U=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bits-and-blooms/bitset v1.14.3 h1:Gd2c8lSNf9pKXom5JtD7AaKO8o7fGQ2LtFj1436qilA=
github.com/bits-and-blooms/bitset v1.14.3/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ=
github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I=
github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8=
github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4=
github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M=
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE=
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs=
github.com/cockroachdb/pebble v1.1.2 h1:CUh2IPtR4swHlEj48Rhfzw6l/d0qA31fItcIszQVIsA=
github.com/cockroachdb/pebble v1.1.2/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU=
github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30=
github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo=
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ=
github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI=
github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M=
github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY=
github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c h1:uQYC5Z1mdLRPrZhHjHxufI8+2UG/i25QG92j0Er9p6I=
github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs=
github.com/crate-crypto/go-kzg-4844 v1.0.0 h1:TsSgHwrkTKecKJ4kadtHi4b3xHW5dCFUDFnUp1TsawI=
github.com/crate-crypto/go-kzg-4844 v1.0.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM=
github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA=
github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
github.com/ethereum/go-ethereum v1.14.9 h1:J7iwXDrtUyE9FUjUYbd4c9tyzwMh6dTJsKzo9i6SrwA=
github.com/ethereum/go-ethereum v1.14.9/go.mod h1:QeW+MtTpRdBEm2pUFoonByee8zfHv7kGp0wK0odvU1I=
github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 h1:8NfxH2iXvJ60YRB8ChToFTUzl8awsc3cJ8CbLjGIl/A=
github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk=
github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88=
github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps=
github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk=
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grassrootseconomics/eth-custodial v1.3.0-beta h1:twrMBhl89GqDUL9PlkzQxMP/6OST1BByrNDj+rqXDmU= github.com/grassrootseconomics/eth-custodial v1.3.0-beta h1:twrMBhl89GqDUL9PlkzQxMP/6OST1BByrNDj+rqXDmU=
github.com/grassrootseconomics/eth-custodial v1.3.0-beta/go.mod h1:7uhRcdnJplX4t6GKCEFkbeDhhjlcaGJeJqevbcvGLZo= github.com/grassrootseconomics/eth-custodial v1.3.0-beta/go.mod h1:7uhRcdnJplX4t6GKCEFkbeDhhjlcaGJeJqevbcvGLZo=
github.com/grassrootseconomics/ussd-data-service v1.2.0-beta h1:fn1gwbWIwHVEBtUC2zi5OqTlfI/5gU1SMk0fgGixIXk= github.com/grassrootseconomics/ethutils v1.3.1 h1:LlQO90HjJkl7ejC8fv6jP7RJUrAm1j4VMMCYfsoIrhU=
github.com/grassrootseconomics/ussd-data-service v1.2.0-beta/go.mod h1:omfI0QtUwIdpu9gMcUqLMCG8O1XWjqJGBx1qUMiGWC0= github.com/grassrootseconomics/ethutils v1.3.1/go.mod h1:Wuv1VEZrkLIXqTSEYI3Nh9HG/ZHOUQ+U+xvWJ8QtjgQ=
github.com/grassrootseconomics/ussd-data-service v1.5.0-beta h1:BSSQL/yPEvTVku9ja/ENZyZdwZkEaiTzzOUfg72bTy4=
github.com/grassrootseconomics/ussd-data-service v1.5.0-beta/go.mod h1:9sGnorpKaK76FmOGXoh/xv7x5siSFNYdXxQo9BKW4DI=
github.com/grassrootseconomics/ussd-data-service v1.6.0-beta h1:pY6zns6ifXyClRxP+JJaWrged3oRE7tTS2xaftF9clA=
github.com/grassrootseconomics/ussd-data-service v1.6.0-beta/go.mod h1:9sGnorpKaK76FmOGXoh/xv7x5siSFNYdXxQo9BKW4DI=
github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4 h1:U4kkNYryi/qfbBF8gh7Vsbuz+cVmhf5kt6pE9bYYyLo= github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4 h1:U4kkNYryi/qfbBF8gh7Vsbuz+cVmhf5kt6pE9bYYyLo=
github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4/go.mod h1:zpZDgZFzeq9s0MIeB1P50NIEWDFFHSFBohI/NbaTD/Y= github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4/go.mod h1:zpZDgZFzeq9s0MIeB1P50NIEWDFFHSFBohI/NbaTD/Y=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
github.com/holiman/uint256 v1.3.1 h1:JfTzmih28bittyHM8z360dCjIA9dbPIBlcTI6lmctQs=
github.com/holiman/uint256 v1.3.1/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
@ -61,21 +127,52 @@ github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
github.com/lmittmann/w3 v0.17.1 h1:zdXIimmNmYfqOFur+Jqc9Yqwtq6jwnsQufbTOnSAtW4=
github.com/lmittmann/w3 v0.17.1/go.mod h1:WVUGMbL83WYBu4Sge3SVlW3qIG4VaHe+S8+UUnwz9Eg=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a h1:0Q3H0YXzMHiciXtRcM+j0jiCe8WKPQHoRgQiRTnfcLY= github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a h1:0Q3H0YXzMHiciXtRcM+j0jiCe8WKPQHoRgQiRTnfcLY=
github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a/go.mod h1:CdTTBOYzS5E4mWS1N8NWP6AHI19MP0A2B18n3hLzRMk= github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a/go.mod h1:CdTTBOYzS5E4mWS1N8NWP6AHI19MP0A2B18n3hLzRMk=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=
github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU=
github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/pashagolub/pgxmock/v4 v4.3.0 h1:DqT7fk0OCK6H0GvqtcMsLpv8cIwWqdxWgfZNLeHCb/s= github.com/pashagolub/pgxmock/v4 v4.3.0 h1:DqT7fk0OCK6H0GvqtcMsLpv8cIwWqdxWgfZNLeHCb/s=
github.com/pashagolub/pgxmock/v4 v4.3.0/go.mod h1:9VoVHXwS3XR/yPtKGzwQvwZX1kzGB9sM8SviDcHDa3A= github.com/pashagolub/pgxmock/v4 v4.3.0/go.mod h1:9VoVHXwS3XR/yPtKGzwQvwZX1kzGB9sM8SviDcHDa3A=
github.com/peteole/testdata-loader v0.3.0 h1:8jckE9KcyNHgyv/VPoaljvKZE0Rqr8+dPVYH6rfNr9I= github.com/peteole/testdata-loader v0.3.0 h1:8jckE9KcyNHgyv/VPoaljvKZE0Rqr8+dPVYH6rfNr9I=
github.com/peteole/testdata-loader v0.3.0/go.mod h1:Mt0ZbRtb56u8SLJpNP+BnQbENljMorYBpqlvt3cS83U= github.com/peteole/testdata-loader v0.3.0/go.mod h1:Mt0ZbRtb56u8SLJpNP+BnQbENljMorYBpqlvt3cS83U=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg=
github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a h1:CmF68hwI0XsOQ5UwlBopMi2Ow4Pbg32akc4KIVCOm+Y=
github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU=
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
@ -83,23 +180,45 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4=
github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/leonelquinteros/gotext.v1 v1.3.1 h1:8d9/fdTG0kn/B7NNGV1BsEyvektXFAbkMsTZS2sFSCc= gopkg.in/leonelquinteros/gotext.v1 v1.3.1 h1:8d9/fdTG0kn/B7NNGV1BsEyvektXFAbkMsTZS2sFSCc=
gopkg.in/leonelquinteros/gotext.v1 v1.3.1/go.mod h1:X1WlGDeAFIYsW6GjgMm4VwUwZ2XjI7Zan2InxSUQWrU= gopkg.in/leonelquinteros/gotext.v1 v1.3.1/go.mod h1:X1WlGDeAFIYsW6GjgMm4VwUwZ2XjI7Zan2InxSUQWrU=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU=
rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA=

File diff suppressed because it is too large Load Diff

View File

@ -62,6 +62,25 @@ func InitializeTestStore(t *testing.T) (context.Context, *store.UserDataStore) {
return ctx, store return ctx, store
} }
// InitializeTestLogdbStore sets up and returns an in-memory database and logdb store.
func InitializeTestLogdbStore(t *testing.T) (context.Context, *store.UserDataStore) {
ctx := context.Background()
// Initialize memDb
db := memdb.NewMemDb()
err := db.Connect(ctx, "")
require.NoError(t, err, "Failed to connect to memDb")
// Create UserDataStore with memDb
logdb := &store.UserDataStore{Db: db}
t.Cleanup(func() {
db.Close(ctx) // Ensure the DB is closed after each test
})
return ctx, logdb
}
func InitializeTestSubPrefixDb(t *testing.T, ctx context.Context) *storedb.SubPrefixDb { func InitializeTestSubPrefixDb(t *testing.T, ctx context.Context) *storedb.SubPrefixDb {
db := memdb.NewMemDb() db := memdb.NewMemDb()
err := db.Connect(ctx, "") err := db.Connect(ctx, "")
@ -76,6 +95,7 @@ func InitializeTestSubPrefixDb(t *testing.T, ctx context.Context) *storedb.SubPr
func TestNewMenuHandlers(t *testing.T) { func TestNewMenuHandlers(t *testing.T) {
_, store := InitializeTestStore(t) _, store := InitializeTestStore(t)
_, logdb := InitializeTestLogdbStore(t)
fm, err := NewFlagManager(flagsPath) fm, err := NewFlagManager(flagsPath)
if err != nil { if err != nil {
@ -86,7 +106,7 @@ func TestNewMenuHandlers(t *testing.T) {
// Test case for valid UserDataStore // Test case for valid UserDataStore
t.Run("Valid UserDataStore", func(t *testing.T) { t.Run("Valid UserDataStore", func(t *testing.T) {
handlers, err := NewMenuHandlers(fm, store, &accountService, mockReplaceSeparator) handlers, err := NewMenuHandlers(fm, store, logdb, &accountService, mockReplaceSeparator)
if err != nil { if err != nil {
t.Fatalf("expected no error, got %v", err) t.Fatalf("expected no error, got %v", err)
} }
@ -110,7 +130,7 @@ func TestNewMenuHandlers(t *testing.T) {
// Test case for nil UserDataStore // Test case for nil UserDataStore
t.Run("Nil UserDataStore", func(t *testing.T) { t.Run("Nil UserDataStore", func(t *testing.T) {
handlers, err := NewMenuHandlers(fm, nil, &accountService, mockReplaceSeparator) handlers, err := NewMenuHandlers(fm, nil, logdb, &accountService, mockReplaceSeparator)
if err == nil { if err == nil {
t.Fatal("expected an error, got none") t.Fatal("expected an error, got none")
} }
@ -192,8 +212,13 @@ func TestInit(t *testing.T) {
func TestCreateAccount(t *testing.T) { func TestCreateAccount(t *testing.T) {
sessionId := "session123" sessionId := "session123"
ctx, store := InitializeTestStore(t) ctx, userStore := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
_, logdb := InitializeTestLogdbStore(t)
logDb := store.LogDb{
Db: logdb,
}
fm, err := NewFlagManager(flagsPath) fm, err := NewFlagManager(flagsPath)
if err != nil { if err != nil {
@ -201,6 +226,8 @@ func TestCreateAccount(t *testing.T) {
} }
flag_account_created, err := fm.GetFlag("flag_account_created") flag_account_created, err := fm.GetFlag("flag_account_created")
flag_account_creation_failed, _ := fm.GetFlag("flag_account_creation_failed")
if err != nil { if err != nil {
t.Logf(err.Error()) t.Logf(err.Error())
} }
@ -218,6 +245,7 @@ func TestCreateAccount(t *testing.T) {
}, },
expectedResult: resource.Result{ expectedResult: resource.Result{
FlagSet: []uint32{flag_account_created}, FlagSet: []uint32{flag_account_created},
FlagReset: []uint32{flag_account_creation_failed},
}, },
}, },
} }
@ -226,8 +254,9 @@ func TestCreateAccount(t *testing.T) {
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: userStore,
accountService: mockAccountService, accountService: mockAccountService,
logDb: logDb,
flagManager: fm, flagManager: fm,
} }
@ -265,8 +294,13 @@ func TestWithPersister_PanicWhenAlreadySet(t *testing.T) {
func TestSaveFirstname(t *testing.T) { func TestSaveFirstname(t *testing.T) {
sessionId := "session123" sessionId := "session123"
ctx, store := InitializeTestStore(t) ctx, userStore := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
_, logdb := InitializeTestLogdbStore(t)
logDb := store.LogDb{
Db: logdb,
}
fm, _ := NewFlagManager(flagsPath) fm, _ := NewFlagManager(flagsPath)
@ -282,7 +316,7 @@ func TestSaveFirstname(t *testing.T) {
// Define test data // Define test data
firstName := "John" firstName := "John"
if err := store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(firstName)); err != nil { if err := userStore.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(firstName)); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -290,9 +324,10 @@ func TestSaveFirstname(t *testing.T) {
// Create the MenuHandlers instance with the mock store // Create the MenuHandlers instance with the mock store
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: userStore,
flagManager: fm, flagManager: fm,
st: mockState, st: mockState,
logDb: logDb,
} }
// Call the method // Call the method
@ -303,14 +338,19 @@ func TestSaveFirstname(t *testing.T) {
assert.Equal(t, expectedResult, res) assert.Equal(t, expectedResult, res)
// Verify that the DATA_FIRST_NAME entry has been updated with the temporary value // Verify that the DATA_FIRST_NAME entry has been updated with the temporary value
storedFirstName, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_FIRST_NAME) storedFirstName, _ := userStore.ReadEntry(ctx, sessionId, storedb.DATA_FIRST_NAME)
assert.Equal(t, firstName, string(storedFirstName)) assert.Equal(t, firstName, string(storedFirstName))
} }
func TestSaveFamilyname(t *testing.T) { func TestSaveFamilyname(t *testing.T) {
sessionId := "session123" sessionId := "session123"
ctx, store := InitializeTestStore(t) ctx, userStore := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
_, logdb := InitializeTestLogdbStore(t)
logDb := store.LogDb{
Db: logdb,
}
fm, _ := NewFlagManager(flagsPath) fm, _ := NewFlagManager(flagsPath)
@ -328,15 +368,16 @@ func TestSaveFamilyname(t *testing.T) {
// Define test data // Define test data
familyName := "Doeee" familyName := "Doeee"
if err := store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(familyName)); err != nil { if err := userStore.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(familyName)); err != nil {
t.Fatal(err) t.Fatal(err)
} }
// Create the MenuHandlers instance with the mock store // Create the MenuHandlers instance with the mock store
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: userStore,
st: mockState, st: mockState,
flagManager: fm, flagManager: fm,
logDb: logDb,
} }
// Call the method // Call the method
@ -347,14 +388,19 @@ func TestSaveFamilyname(t *testing.T) {
assert.Equal(t, expectedResult, res) assert.Equal(t, expectedResult, res)
// Verify that the DATA_FAMILY_NAME entry has been updated with the temporary value // Verify that the DATA_FAMILY_NAME entry has been updated with the temporary value
storedFamilyName, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_FAMILY_NAME) storedFamilyName, _ := userStore.ReadEntry(ctx, sessionId, storedb.DATA_FAMILY_NAME)
assert.Equal(t, familyName, string(storedFamilyName)) assert.Equal(t, familyName, string(storedFamilyName))
} }
func TestSaveYoB(t *testing.T) { func TestSaveYoB(t *testing.T) {
sessionId := "session123" sessionId := "session123"
ctx, store := InitializeTestStore(t) ctx, userStore := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
_, logdb := InitializeTestLogdbStore(t)
logDb := store.LogDb{
Db: logdb,
}
fm, _ := NewFlagManager(flagsPath) fm, _ := NewFlagManager(flagsPath)
@ -370,7 +416,7 @@ func TestSaveYoB(t *testing.T) {
// Define test data // Define test data
yob := "1980" yob := "1980"
if err := store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(yob)); err != nil { if err := userStore.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(yob)); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -378,9 +424,10 @@ func TestSaveYoB(t *testing.T) {
// Create the MenuHandlers instance with the mock store // Create the MenuHandlers instance with the mock store
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: userStore,
flagManager: fm, flagManager: fm,
st: mockState, st: mockState,
logDb: logDb,
} }
// Call the method // Call the method
@ -391,14 +438,19 @@ func TestSaveYoB(t *testing.T) {
assert.Equal(t, expectedResult, res) assert.Equal(t, expectedResult, res)
// Verify that the DATA_YOB entry has been updated with the temporary value // Verify that the DATA_YOB entry has been updated with the temporary value
storedYob, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_YOB) storedYob, _ := userStore.ReadEntry(ctx, sessionId, storedb.DATA_YOB)
assert.Equal(t, yob, string(storedYob)) assert.Equal(t, yob, string(storedYob))
} }
func TestSaveLocation(t *testing.T) { func TestSaveLocation(t *testing.T) {
sessionId := "session123" sessionId := "session123"
ctx, store := InitializeTestStore(t) ctx, userStore := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
_, logdb := InitializeTestLogdbStore(t)
logDb := store.LogDb{
Db: logdb,
}
fm, _ := NewFlagManager(flagsPath) fm, _ := NewFlagManager(flagsPath)
@ -414,7 +466,7 @@ func TestSaveLocation(t *testing.T) {
// Define test data // Define test data
location := "Kilifi" location := "Kilifi"
if err := store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(location)); err != nil { if err := userStore.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(location)); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -422,9 +474,10 @@ func TestSaveLocation(t *testing.T) {
// Create the MenuHandlers instance with the mock store // Create the MenuHandlers instance with the mock store
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: userStore,
flagManager: fm, flagManager: fm,
st: mockState, st: mockState,
logDb: logDb,
} }
// Call the method // Call the method
@ -435,14 +488,19 @@ func TestSaveLocation(t *testing.T) {
assert.Equal(t, expectedResult, res) assert.Equal(t, expectedResult, res)
// Verify that the DATA_LOCATION entry has been updated with the temporary value // Verify that the DATA_LOCATION entry has been updated with the temporary value
storedLocation, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_LOCATION) storedLocation, _ := userStore.ReadEntry(ctx, sessionId, storedb.DATA_LOCATION)
assert.Equal(t, location, string(storedLocation)) assert.Equal(t, location, string(storedLocation))
} }
func TestSaveOfferings(t *testing.T) { func TestSaveOfferings(t *testing.T) {
sessionId := "session123" sessionId := "session123"
ctx, store := InitializeTestStore(t) ctx, userStore := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
_, logdb := InitializeTestLogdbStore(t)
logDb := store.LogDb{
Db: logdb,
}
fm, _ := NewFlagManager(flagsPath) fm, _ := NewFlagManager(flagsPath)
@ -458,7 +516,7 @@ func TestSaveOfferings(t *testing.T) {
// Define test data // Define test data
offerings := "Bananas" offerings := "Bananas"
if err := store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(offerings)); err != nil { if err := userStore.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(offerings)); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -466,9 +524,10 @@ func TestSaveOfferings(t *testing.T) {
// Create the MenuHandlers instance with the mock store // Create the MenuHandlers instance with the mock store
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: userStore,
flagManager: fm, flagManager: fm,
st: mockState, st: mockState,
logDb: logDb,
} }
// Call the method // Call the method
@ -479,14 +538,19 @@ func TestSaveOfferings(t *testing.T) {
assert.Equal(t, expectedResult, res) assert.Equal(t, expectedResult, res)
// Verify that the DATA_OFFERINGS entry has been updated with the temporary value // Verify that the DATA_OFFERINGS entry has been updated with the temporary value
storedOfferings, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_OFFERINGS) storedOfferings, _ := userStore.ReadEntry(ctx, sessionId, storedb.DATA_OFFERINGS)
assert.Equal(t, offerings, string(storedOfferings)) assert.Equal(t, offerings, string(storedOfferings))
} }
func TestSaveGender(t *testing.T) { func TestSaveGender(t *testing.T) {
sessionId := "session123" sessionId := "session123"
ctx, store := InitializeTestStore(t) ctx, userStore := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
_, logdb := InitializeTestLogdbStore(t)
logDb := store.LogDb{
Db: logdb,
}
fm, _ := NewFlagManager(flagsPath) fm, _ := NewFlagManager(flagsPath)
@ -526,16 +590,17 @@ func TestSaveGender(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
if err := store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(tt.expectedGender)); err != nil { if err := userStore.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(tt.expectedGender)); err != nil {
t.Fatal(err) t.Fatal(err)
} }
mockState.ExecPath = append(mockState.ExecPath, tt.executingSymbol) mockState.ExecPath = append(mockState.ExecPath, tt.executingSymbol)
// Create the MenuHandlers instance with the mock store // Create the MenuHandlers instance with the mock store
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: userStore,
st: mockState, st: mockState,
flagManager: fm, flagManager: fm,
logDb: logDb,
} }
expectedResult := resource.Result{} expectedResult := resource.Result{}
@ -550,7 +615,7 @@ func TestSaveGender(t *testing.T) {
assert.Equal(t, expectedResult, res) assert.Equal(t, expectedResult, res)
// Verify that the DATA_GENDER entry has been updated with the temporary value // Verify that the DATA_GENDER entry has been updated with the temporary value
storedGender, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_GENDER) storedGender, _ := userStore.ReadEntry(ctx, sessionId, storedb.DATA_GENDER)
assert.Equal(t, tt.expectedGender, string(storedGender)) assert.Equal(t, tt.expectedGender, string(storedGender))
}) })
} }
@ -558,9 +623,15 @@ func TestSaveGender(t *testing.T) {
func TestSaveTemporaryPin(t *testing.T) { func TestSaveTemporaryPin(t *testing.T) {
sessionId := "session123" sessionId := "session123"
ctx, store := InitializeTestStore(t)
ctx, userdatastore := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
_, logdb := InitializeTestLogdbStore(t)
logDb := store.LogDb{
Db: logdb,
}
fm, err := NewFlagManager(flagsPath) fm, err := NewFlagManager(flagsPath)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
@ -571,7 +642,8 @@ func TestSaveTemporaryPin(t *testing.T) {
// Create the MenuHandlers instance with the mock flag manager // Create the MenuHandlers instance with the mock flag manager
h := &MenuHandlers{ h := &MenuHandlers{
flagManager: fm, flagManager: fm,
userdataStore: store, userdataStore: userdatastore,
logDb: logDb,
} }
// Define test cases // Define test cases
@ -612,9 +684,15 @@ func TestSaveTemporaryPin(t *testing.T) {
func TestCheckIdentifier(t *testing.T) { func TestCheckIdentifier(t *testing.T) {
sessionId := "session123" sessionId := "session123"
ctx, store := InitializeTestStore(t) ctx, userdatastore := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
_, logdb := InitializeTestLogdbStore(t)
logDb := store.LogDb{
Db: logdb,
}
// Define test cases // Define test cases
tests := []struct { tests := []struct {
name string name string
@ -634,14 +712,15 @@ func TestCheckIdentifier(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
err := store.WriteEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY, []byte(tt.publicKey)) err := userdatastore.WriteEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY, []byte(tt.publicKey))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
// Create the MenuHandlers instance with the mock store // Create the MenuHandlers instance with the mock store
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: userdatastore,
logDb: logDb,
} }
// Call the method // Call the method
@ -1037,7 +1116,6 @@ func TestAuthorize(t *testing.T) {
flag_incorrect_pin, _ := fm.GetFlag("flag_incorrect_pin") flag_incorrect_pin, _ := fm.GetFlag("flag_incorrect_pin")
flag_account_authorized, _ := fm.GetFlag("flag_account_authorized") flag_account_authorized, _ := fm.GetFlag("flag_account_authorized")
flag_allow_update, _ := fm.GetFlag("flag_allow_update") flag_allow_update, _ := fm.GetFlag("flag_allow_update")
flag_invalid_pin, _ := fm.GetFlag("flag_invalid_pin")
// Set 1234 is the correct account pin // Set 1234 is the correct account pin
accountPIN := "1234" accountPIN := "1234"
@ -1055,7 +1133,7 @@ func TestAuthorize(t *testing.T) {
expectedResult resource.Result expectedResult resource.Result
}{ }{
{ {
name: "Test with correct pin", name: "Test with correct PIN",
input: []byte("1234"), input: []byte("1234"),
expectedResult: resource.Result{ expectedResult: resource.Result{
FlagReset: []uint32{flag_incorrect_pin}, FlagReset: []uint32{flag_incorrect_pin},
@ -1063,18 +1141,18 @@ func TestAuthorize(t *testing.T) {
}, },
}, },
{ {
name: "Test with incorrect pin", name: "Test with incorrect PIN",
input: []byte("1235"), input: []byte("1235"),
expectedResult: resource.Result{ expectedResult: resource.Result{
FlagReset: []uint32{flag_account_authorized}, FlagReset: []uint32{flag_account_authorized, flag_allow_update},
FlagSet: []uint32{flag_incorrect_pin}, FlagSet: []uint32{flag_incorrect_pin},
}, },
}, },
{ {
name: "Test with pin that is not a 4 digit", name: "Test with PIN that is not a 4 digit",
input: []byte("1235aqds"), input: []byte("1235aqds"),
expectedResult: resource.Result{ expectedResult: resource.Result{
FlagSet: []uint32{flag_invalid_pin}, FlagReset: []uint32{flag_account_authorized, flag_allow_update},
}, },
}, },
} }
@ -1600,6 +1678,22 @@ func TestValidateAmount(t *testing.T) {
Content: "0.02ms", Content: "0.02ms",
}, },
}, },
{
name: "Test with valid decimal amount",
input: []byte("0.149"),
activeBal: []byte("5"),
expectedResult: resource.Result{
Content: "0.14",
},
},
{
name: "Test with valid large decimal amount",
input: []byte("1.8599999999"),
activeBal: []byte("5"),
expectedResult: resource.Result{
Content: "1.85",
},
},
} }
for _, tt := range tests { for _, tt := range tests {
@ -1639,11 +1733,14 @@ func TestValidateRecipient(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
input []byte input []byte
expectError bool
expectedRecipient []byte
expectedResult resource.Result expectedResult resource.Result
}{ }{
{ {
name: "Test with invalid recepient", name: "Test with invalid recepient",
input: []byte("7?1234"), input: []byte("7?1234"),
expectError: true,
expectedResult: resource.Result{ expectedResult: resource.Result{
FlagSet: []uint32{flag_invalid_recipient}, FlagSet: []uint32{flag_invalid_recipient},
Content: "7?1234", Content: "7?1234",
@ -1652,6 +1749,7 @@ func TestValidateRecipient(t *testing.T) {
{ {
name: "Test with valid unregistered recepient", name: "Test with valid unregistered recepient",
input: []byte("0712345678"), input: []byte("0712345678"),
expectError: true,
expectedResult: resource.Result{ expectedResult: resource.Result{
FlagSet: []uint32{flag_invalid_recipient_with_invite}, FlagSet: []uint32{flag_invalid_recipient_with_invite},
Content: "0712345678", Content: "0712345678",
@ -1660,16 +1758,36 @@ func TestValidateRecipient(t *testing.T) {
{ {
name: "Test with valid registered recepient", name: "Test with valid registered recepient",
input: []byte("0711223344"), input: []byte("0711223344"),
expectError: false,
expectedRecipient: []byte(publicKey),
expectedResult: resource.Result{}, expectedResult: resource.Result{},
}, },
{ {
name: "Test with address", name: "Test with address",
input: []byte("0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9"), input: []byte("0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9"),
expectError: false,
expectedRecipient: []byte("0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9"),
expectedResult: resource.Result{}, expectedResult: resource.Result{},
}, },
{ {
name: "Test with alias recepient", name: "Test with alias recepient",
input: []byte("alias123.sarafu.local"), input: []byte("alias123.sarafu.local"),
expectError: false,
expectedRecipient: []byte("0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9"),
expectedResult: resource.Result{},
},
{
name: "Test for checksummed address",
input: []byte("0x5523058cdffe5f3c1eadadd5015e55c6e00fb439"),
expectError: false,
expectedRecipient: []byte("0x5523058cdFfe5F3c1EaDADD5015E55C6E00fb439"),
expectedResult: resource.Result{},
},
{
name: "Test with valid registered recepient that has white spaces",
input: []byte("0711 22 33 44"),
expectError: false,
expectedRecipient: []byte(publicKey),
expectedResult: resource.Result{}, expectedResult: resource.Result{},
}, },
} }
@ -1703,6 +1821,12 @@ func TestValidateRecipient(t *testing.T) {
t.Error(err) t.Error(err)
} }
if !tt.expectError {
storedRecipientAddress, err := store.ReadEntry(ctx, sessionId, storedb.DATA_RECIPIENT)
assert.NoError(t, err)
assert.Equal(t, tt.expectedRecipient, storedRecipientAddress)
}
// Assert that the Result FlagSet has the required flags after language switch // Assert that the Result FlagSet has the required flags after language switch
assert.Equal(t, res, tt.expectedResult, "Result should contain flag(s) that have been reset") assert.Equal(t, res, tt.expectedResult, "Result should contain flag(s) that have been reset")
}) })
@ -1950,8 +2074,13 @@ func TestManageVouchers(t *testing.T) {
sessionId := "session123" sessionId := "session123"
publicKey := "0X13242618721" publicKey := "0X13242618721"
ctx, store := InitializeTestStore(t) ctx, userStore := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
_, logdb := InitializeTestLogdbStore(t)
logDb := store.LogDb{
Db: logdb,
}
fm, err := NewFlagManager(flagsPath) fm, err := NewFlagManager(flagsPath)
if err != nil { if err != nil {
@ -1961,8 +2090,13 @@ func TestManageVouchers(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
flag_api_error, err := fm.GetFlag("flag_api_call_error")
err = store.WriteEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY, []byte(publicKey)) if err != nil {
t.Fatal(err)
}
err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY, []byte(publicKey))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -1982,13 +2116,14 @@ func TestManageVouchers(t *testing.T) {
expectedUpdatedAddress: []byte(""), expectedUpdatedAddress: []byte(""),
expectedResult: resource.Result{ expectedResult: resource.Result{
FlagSet: []uint32{flag_no_active_voucher}, FlagSet: []uint32{flag_no_active_voucher},
FlagReset: []uint32{flag_api_error},
}, },
}, },
{ {
name: "Set default voucher when no active voucher is set", name: "Set default voucher when no active voucher is set",
vouchersResp: []dataserviceapi.TokenHoldings{ vouchersResp: []dataserviceapi.TokenHoldings{
{ {
ContractAddress: "0x123", TokenAddress: "0x123",
TokenSymbol: "TOKEN1", TokenSymbol: "TOKEN1",
TokenDecimals: "18", TokenDecimals: "18",
Balance: "100", Balance: "100",
@ -1997,20 +2132,20 @@ func TestManageVouchers(t *testing.T) {
expectedVoucherSymbols: []byte("1:TOKEN1"), expectedVoucherSymbols: []byte("1:TOKEN1"),
expectedUpdatedAddress: []byte("0x123"), expectedUpdatedAddress: []byte("0x123"),
expectedResult: resource.Result{ expectedResult: resource.Result{
FlagReset: []uint32{flag_no_active_voucher}, FlagReset: []uint32{flag_api_error, flag_no_active_voucher},
}, },
}, },
{ {
name: "Check and update active voucher balance", name: "Check and update active voucher balance",
vouchersResp: []dataserviceapi.TokenHoldings{ vouchersResp: []dataserviceapi.TokenHoldings{
{ContractAddress: "0xd4c288865Ce", TokenSymbol: "SRF", TokenDecimals: "6", Balance: "100"}, {TokenAddress: "0xd4c288865Ce", TokenSymbol: "SRF", TokenDecimals: "6", Balance: "100"},
{ContractAddress: "0x41c188d63Qa", TokenSymbol: "MILO", TokenDecimals: "4", Balance: "200"}, {TokenAddress: "0x41c188d63Qa", TokenSymbol: "MILO", TokenDecimals: "4", Balance: "200"},
}, },
storedActiveVoucher: "SRF", storedActiveVoucher: "SRF",
expectedVoucherSymbols: []byte("1:SRF\n2:MILO"), expectedVoucherSymbols: []byte("1:SRF\n2:MILO"),
expectedUpdatedAddress: []byte("0xd4c288865Ce"), expectedUpdatedAddress: []byte("0xd4c288865Ce"),
expectedResult: resource.Result{ expectedResult: resource.Result{
FlagReset: []uint32{flag_no_active_voucher}, FlagReset: []uint32{flag_api_error, flag_no_active_voucher},
}, },
}, },
} }
@ -2020,20 +2155,21 @@ func TestManageVouchers(t *testing.T) {
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: userStore,
accountService: mockAccountService, accountService: mockAccountService,
flagManager: fm, flagManager: fm,
logDb: logDb,
} }
mockAccountService.On("FetchVouchers", string(publicKey)).Return(tt.vouchersResp, nil) mockAccountService.On("FetchVouchers", string(publicKey)).Return(tt.vouchersResp, nil)
// Store active voucher if needed // Store active voucher if needed
if tt.storedActiveVoucher != "" { if tt.storedActiveVoucher != "" {
err := store.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_SYM, []byte(tt.storedActiveVoucher)) err := userStore.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_SYM, []byte(tt.storedActiveVoucher))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
err = store.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_ADDRESS, []byte("0x41c188D45rfg6ds")) err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_ADDRESS, []byte("0x41c188D45rfg6ds"))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -2045,12 +2181,12 @@ func TestManageVouchers(t *testing.T) {
if tt.storedActiveVoucher != "" { if tt.storedActiveVoucher != "" {
// Validate stored voucher symbols // Validate stored voucher symbols
voucherData, err := store.ReadEntry(ctx, sessionId, storedb.DATA_VOUCHER_SYMBOLS) voucherData, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_VOUCHER_SYMBOLS)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, tt.expectedVoucherSymbols, voucherData) assert.Equal(t, tt.expectedVoucherSymbols, voucherData)
// Validate stored active contract address // Validate stored active contract address
updatedAddress, err := store.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_ADDRESS) updatedAddress, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_ADDRESS)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, tt.expectedUpdatedAddress, updatedAddress) assert.Equal(t, tt.expectedUpdatedAddress, updatedAddress)
@ -2138,10 +2274,10 @@ func TestSetVoucher(t *testing.T) {
TokenSymbol: "SRF", TokenSymbol: "SRF",
Balance: "200", Balance: "200",
TokenDecimals: "6", TokenDecimals: "6",
ContractAddress: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", TokenAddress: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9",
} }
expectedData := fmt.Sprintf("%s,%s,%s,%s", tempData.TokenSymbol, tempData.Balance, tempData.TokenDecimals, tempData.ContractAddress) expectedData := fmt.Sprintf("%s,%s,%s,%s", tempData.TokenSymbol, tempData.Balance, tempData.TokenDecimals, tempData.TokenAddress)
// store the expectedData // store the expectedData
if err := store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(expectedData)); err != nil { if err := store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(expectedData)); err != nil {
@ -2161,6 +2297,8 @@ func TestGetVoucherDetails(t *testing.T) {
if err != nil { if err != nil {
t.Logf(err.Error()) t.Logf(err.Error())
} }
flag_api_error, _ := fm.GetFlag("flag_api_call_error")
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
sessionId := "session123" sessionId := "session123"
@ -2188,8 +2326,8 @@ func TestGetVoucherDetails(t *testing.T) {
"Name: %s\nSymbol: %s\nCommodity: %s\nLocation: %s", tokenDetails.TokenName, tokenDetails.TokenSymbol, tokenDetails.TokenCommodity, tokenDetails.TokenLocation, "Name: %s\nSymbol: %s\nCommodity: %s\nLocation: %s", tokenDetails.TokenName, tokenDetails.TokenSymbol, tokenDetails.TokenCommodity, tokenDetails.TokenLocation,
) )
mockAccountService.On("VoucherData", string(tokA_AAddress)).Return(tokenDetails, nil) mockAccountService.On("VoucherData", string(tokA_AAddress)).Return(tokenDetails, nil)
res, err := h.GetVoucherDetails(ctx, "SessionId", []byte("")) res, err := h.GetVoucherDetails(ctx, "SessionId", []byte(""))
expectedResult.FlagReset = append(expectedResult.FlagReset, flag_api_error)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, expectedResult, res) assert.Equal(t, expectedResult, res)
} }
@ -2377,8 +2515,14 @@ func TestCheckTransactions(t *testing.T) {
sessionId := "session123" sessionId := "session123"
publicKey := "0X13242618721" publicKey := "0X13242618721"
ctx, store := InitializeTestStore(t) ctx, userStore := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
_, logdb := InitializeTestLogdbStore(t)
logDb := store.LogDb{
Db: logdb,
}
spdb := InitializeTestSubPrefixDb(t, ctx) spdb := InitializeTestSubPrefixDb(t, ctx)
fm, err := NewFlagManager(flagsPath) fm, err := NewFlagManager(flagsPath)
@ -2387,13 +2531,14 @@ func TestCheckTransactions(t *testing.T) {
} }
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: userStore,
accountService: mockAccountService, accountService: mockAccountService,
prefixDb: spdb, prefixDb: spdb,
logDb: logDb,
flagManager: fm, flagManager: fm,
} }
err = store.WriteEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY, []byte(publicKey)) err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY, []byte(publicKey))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -27,6 +27,7 @@ type LocalHandlerService struct {
DbRs *resource.DbResource DbRs *resource.DbResource
Pe *persist.Persister Pe *persist.Persister
UserdataStore *db.Db UserdataStore *db.Db
LogDb *db.Db
Cfg engine.Config Cfg engine.Config
Rs resource.Resource Rs resource.Resource
first resource.EntryFunc first resource.EntryFunc
@ -57,12 +58,16 @@ func (ls *LocalHandlerService) SetDataStore(db *db.Db) {
ls.UserdataStore = db ls.UserdataStore = db
} }
func (ls *LocalHandlerService) SetLogDb(db *db.Db) {
ls.LogDb = db
}
func (ls *LocalHandlerService) GetHandler(accountService remote.AccountService) (*application.MenuHandlers, error) { func (ls *LocalHandlerService) GetHandler(accountService remote.AccountService) (*application.MenuHandlers, error) {
replaceSeparatorFunc := func(input string) string { replaceSeparatorFunc := func(input string) string {
return strings.ReplaceAll(input, ":", ls.Cfg.MenuSeparator) return strings.ReplaceAll(input, ":", ls.Cfg.MenuSeparator)
} }
appHandlers, err := application.NewMenuHandlers(ls.Parser, *ls.UserdataStore, accountService, replaceSeparatorFunc) appHandlers, err := application.NewMenuHandlers(ls.Parser, *ls.UserdataStore, *ls.LogDb, accountService, replaceSeparatorFunc)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -86,7 +91,7 @@ func (ls *LocalHandlerService) GetHandler(accountService remote.AccountService)
ls.DbRs.AddLocalFunc("get_recipient", appHandlers.GetRecipient) ls.DbRs.AddLocalFunc("get_recipient", appHandlers.GetRecipient)
ls.DbRs.AddLocalFunc("get_sender", appHandlers.GetSender) ls.DbRs.AddLocalFunc("get_sender", appHandlers.GetSender)
ls.DbRs.AddLocalFunc("get_amount", appHandlers.GetAmount) ls.DbRs.AddLocalFunc("get_amount", appHandlers.GetAmount)
ls.DbRs.AddLocalFunc("reset_incorrect", appHandlers.ResetIncorrectPin) ls.DbRs.AddLocalFunc("reset_incorrect_pin", appHandlers.ResetIncorrectPin)
ls.DbRs.AddLocalFunc("save_firstname", appHandlers.SaveFirstname) ls.DbRs.AddLocalFunc("save_firstname", appHandlers.SaveFirstname)
ls.DbRs.AddLocalFunc("save_familyname", appHandlers.SaveFamilyname) ls.DbRs.AddLocalFunc("save_familyname", appHandlers.SaveFamilyname)
ls.DbRs.AddLocalFunc("save_gender", appHandlers.SaveGender) ls.DbRs.AddLocalFunc("save_gender", appHandlers.SaveGender)
@ -107,6 +112,10 @@ func (ls *LocalHandlerService) GetHandler(accountService remote.AccountService)
ls.DbRs.AddLocalFunc("view_voucher", appHandlers.ViewVoucher) ls.DbRs.AddLocalFunc("view_voucher", appHandlers.ViewVoucher)
ls.DbRs.AddLocalFunc("set_voucher", appHandlers.SetVoucher) ls.DbRs.AddLocalFunc("set_voucher", appHandlers.SetVoucher)
ls.DbRs.AddLocalFunc("get_voucher_details", appHandlers.GetVoucherDetails) 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("validate_blocked_number", appHandlers.ValidateBlockedNumber)
ls.DbRs.AddLocalFunc("retrieve_blocked_number", appHandlers.RetrieveBlockedNumber) ls.DbRs.AddLocalFunc("retrieve_blocked_number", appHandlers.RetrieveBlockedNumber)
ls.DbRs.AddLocalFunc("reset_unregistered_number", appHandlers.ResetUnregisteredNumber) ls.DbRs.AddLocalFunc("reset_unregistered_number", appHandlers.ResetUnregisteredNumber)
@ -124,7 +133,11 @@ func (ls *LocalHandlerService) GetHandler(accountService remote.AccountService)
ls.DbRs.AddLocalFunc("get_suggested_alias", appHandlers.GetSuggestedAlias) ls.DbRs.AddLocalFunc("get_suggested_alias", appHandlers.GetSuggestedAlias)
ls.DbRs.AddLocalFunc("confirm_new_alias", appHandlers.ConfirmNewAlias) ls.DbRs.AddLocalFunc("confirm_new_alias", appHandlers.ConfirmNewAlias)
ls.DbRs.AddLocalFunc("check_account_created", appHandlers.CheckAccountCreated) ls.DbRs.AddLocalFunc("check_account_created", appHandlers.CheckAccountCreated)
ls.DbRs.AddLocalFunc("reset_api_call_failure", appHandlers.ResetApiCallFailure)
ls.DbRs.AddLocalFunc("swap_to_list", appHandlers.LoadSwapToList)
ls.DbRs.AddLocalFunc("swap_max_limit", appHandlers.SwapMaxLimit)
ls.DbRs.AddLocalFunc("swap_preview", appHandlers.SwapPreview)
ls.DbRs.AddLocalFunc("initiate_swap", appHandlers.InitiateSwap)
ls.first = appHandlers.Init ls.first = appHandlers.Init
return appHandlers, nil return appHandlers, nil

View File

@ -11,7 +11,7 @@
}, },
{ {
"input": "1", "input": "1",
"expectedContent": "Do you agree to terms and conditions?\nhttps://grassecon.org/pages/terms-and-conditions\n\n1:Yes\n2:No" "expectedContent": "Do you agree to terms and conditions?\nhttps://grassecon.org/tos\n\n1:Yes\n2:No"
}, },
{ {
"input": "1", "input": "1",
@ -31,7 +31,7 @@
}, },
{ {
"input": "1234", "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", "input": "1",
"expectedContent": "Do you agree to terms and conditions?\nhttps://grassecon.org/pages/terms-and-conditions\n\n1:Yes\n2:No" "expectedContent": "Do you agree to terms and conditions?\nhttps://grassecon.org/tos\n\n1:Yes\n2:No"
}, },
{ {
"input": "2", "input": "2",

View File

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

View File

@ -1 +1 @@
Failed to connect to the custodial service.Please try again. Your request failed. Please try again later.

View File

@ -1,5 +1,7 @@
LOAD reset_api_call_failure 6
RELOAD reset_api_call_failure
MOUT retry 1 MOUT retry 1
MOUT quit 9 MOUT quit 9
HALT HALT
INCMP _ 1 INCMP ^ 1
INCMP quit 9 INCMP quit 9

View File

@ -0,0 +1 @@
Ombi lako halikufaulu. Tafadhali jaribu tena baadaye.

View File

@ -1,5 +1,5 @@
LOAD reset_account_authorized 0 LOAD reset_account_authorized 0
LOAD reset_incorrect 0 LOAD reset_incorrect_pin 0
CATCH incorrect_pin flag_incorrect_pin 1 CATCH incorrect_pin flag_incorrect_pin 1
CATCH pin_entry flag_account_authorized 0 CATCH pin_entry flag_account_authorized 0
MOUT english 1 MOUT english 1

View File

@ -1,5 +1,6 @@
LOAD check_transactions 0 LOAD check_transactions 0
RELOAD check_transactions RELOAD check_transactions
CATCH api_failure flag_api_call_error 1
CATCH no_transfers flag_no_transfers 1 CATCH no_transfers flag_no_transfers 1
LOAD authorize_account 6 LOAD authorize_account 6
MOUT back 0 MOUT back 0

View File

@ -1,4 +1,4 @@
LOAD reset_incorrect 6 LOAD reset_incorrect_pin 6
LOAD fetch_community_balance 0 LOAD fetch_community_balance 0
CATCH api_failure flag_api_call_error 1 CATCH api_failure flag_api_call_error 1
MAP fetch_community_balance MAP fetch_community_balance

View File

@ -1 +1 @@
Incorrect PIN. You have: {{.reset_incorrect}} remaining attempt(s). Incorrect PIN. You have: {{.reset_incorrect_pin}} remaining attempt(s).

View File

@ -1,6 +1,6 @@
LOAD reset_incorrect 0 LOAD reset_incorrect_pin 0
RELOAD reset_incorrect RELOAD reset_incorrect_pin
MAP reset_incorrect MAP reset_incorrect_pin
CATCH blocked_account flag_account_blocked 1 CATCH blocked_account flag_account_blocked 1
MOUT retry 1 MOUT retry 1
MOUT quit 9 MOUT quit 9

View File

@ -1 +1 @@
PIN ulioeka sio sahihi, una majaribio: {{.reset_incorrect}} yaliyobaki PIN ulioeka sio sahihi, una majaribio: {{.reset_incorrect_pin}} yaliyobaki

View File

@ -31,6 +31,14 @@ msgstr "Salio la Kikundi: 0.00"
msgid "Symbol: %s\nBalance: %s" msgid "Symbol: %s\nBalance: %s"
msgstr "Sarafu: %s\nSalio: %s" msgstr "Sarafu: %s\nSalio: %s"
msgid "Your request has been sent. You will receive an SMS when your %s %s has been swapped for %s."
msgstr "Ombi lako limetumwa. Utapokea SMS wakati %s %s yako itakapobadilishwa kuwa %s."
msgid "%s balance: %s\n" msgid "%s balance: %s\n"
msgstr "%s salio: %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"

View File

@ -0,0 +1 @@
Available amount {{.swap_max_limit}} is too low, please try again:

View File

@ -0,0 +1,6 @@
MAP swap_max_limit
MOUT retry 1
MOUT quit 9
HALT
INCMP _ 1
INCMP quit 9

View File

@ -0,0 +1 @@
Kiasi kinachopatikana {{.swap_max_limit}} ni cha chini sana, tafadhali jaribu tena:

View File

@ -2,19 +2,21 @@ LOAD clear_temporary_value 2
RELOAD clear_temporary_value RELOAD clear_temporary_value
LOAD manage_vouchers 160 LOAD manage_vouchers 160
RELOAD manage_vouchers RELOAD manage_vouchers
CATCH api_failure flag_api_call_error 1
LOAD check_balance 128 LOAD check_balance 128
RELOAD check_balance RELOAD check_balance
CATCH api_failure flag_api_call_error 1
MAP check_balance MAP check_balance
MOUT send 1 MOUT send 1
MOUT vouchers 2 MOUT swap 2
MOUT account 3 MOUT vouchers 3
MOUT help 4 MOUT account 4
MOUT help 5
MOUT quit 9 MOUT quit 9
HALT HALT
INCMP send 1 INCMP send 1
INCMP my_vouchers 2 INCMP swap_to_list 2
INCMP my_account 3 INCMP my_vouchers 3
INCMP help 4 INCMP my_account 4
INCMP help 5
INCMP quit 9 INCMP quit 9
INCMP . * INCMP . *

View File

@ -0,0 +1 @@
{{.swap_to_list}}

View File

@ -0,0 +1,6 @@
MAP swap_to_list
MOUT back 0
MOUT quit 9
HALT
INCMP ^ 0
INCMP quit 9

View File

@ -0,0 +1 @@
{{.swap_to_list}}

View File

@ -5,4 +5,5 @@ HALT
INCMP _ 0 INCMP _ 0
LOAD request_custom_alias 0 LOAD request_custom_alias 0
RELOAD request_custom_alias RELOAD request_custom_alias
CATCH api_failure flag_api_call_error 1
INCMP confirm_new_alias * INCMP confirm_new_alias *

View File

@ -1,4 +1,4 @@
LOAD reset_incorrect 6 LOAD reset_incorrect_pin 6
LOAD check_balance 0 LOAD check_balance 0
CATCH api_failure flag_api_call_error 1 CATCH api_failure flag_api_call_error 1
MAP check_balance MAP check_balance

View File

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

View File

@ -1,4 +1,4 @@
RELOAD reset_incorrect RELOAD reset_incorrect_pin
MOUT back 0 MOUT back 0
HALT HALT
INCMP _ 0 INCMP _ 0

View File

@ -2,7 +2,7 @@ LOAD set_back 6
LOAD authorize_account 16 LOAD authorize_account 16
LOAD reset_allow_update 4 LOAD reset_allow_update 4
LOAD save_temporary_pin 1 LOAD save_temporary_pin 1
LOAD reset_incorrect 0 LOAD reset_incorrect_pin 0
LOAD reset_invalid_pin 6 LOAD reset_invalid_pin 6
MOUT change_pin 1 MOUT change_pin 1
MOUT reset_pin 2 MOUT reset_pin 2

View File

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

View File

@ -0,0 +1,10 @@
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

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

View File

@ -31,4 +31,7 @@ flag,flag_back_set,37,this is set when it is a back navigation
flag,flag_account_blocked,38,this is set when an account has been blocked after the allowed incorrect PIN attempts have been exceeded flag,flag_account_blocked,38,this is set when an account has been blocked after the allowed incorrect PIN attempts have been exceeded
flag,flag_invalid_pin,39,this is set when the given PIN is invalid(is less than or more than 4 digits) flag,flag_invalid_pin,39,this is set when the given PIN is invalid(is less than or more than 4 digits)
flag,flag_alias_set,40,this is set when an account alias has been assigned to a user flag,flag_alias_set,40,this is set when an account alias has been assigned to a user
flag,flag_account_pin_reset,41,this is set on an account when an admin triggers a PIN reset for them flag,flag_account_pin_reset,41,this is set on an account when an admin triggers a PIN reset for themflag,flag_incorrect_pool,39,this is set when the user selects an invalid pool
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

Can't render this file because it has a wrong number of fields in line 34.

View File

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

View File

@ -0,0 +1,20 @@
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

@ -0,0 +1 @@
Select pool

View File

@ -0,0 +1 @@
Chagua Bwawa

View File

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

View File

@ -3,14 +3,14 @@ LOAD get_vouchers 0
MAP get_vouchers MAP get_vouchers
MOUT back 0 MOUT back 0
MOUT quit 99 MOUT quit 99
MNEXT next 11 MNEXT next 88
MPREV prev 22 MPREV prev 98
HALT HALT
INCMP > 88
INCMP < 98
INCMP _ 0
INCMP quit 99
LOAD view_voucher 80 LOAD view_voucher 80
RELOAD view_voucher RELOAD view_voucher
CATCH . flag_incorrect_voucher 1 CATCH . flag_incorrect_voucher 1
INCMP _ 0
INCMP quit 99
INCMP > 11
INCMP < 22
INCMP view_voucher * INCMP view_voucher *

View File

@ -5,6 +5,7 @@ MOUT back 0
HALT HALT
LOAD validate_recipient 50 LOAD validate_recipient 50
RELOAD validate_recipient RELOAD validate_recipient
CATCH api_failure flag_api_call_error 1
CATCH invalid_recipient flag_invalid_recipient 1 CATCH invalid_recipient flag_invalid_recipient 1
CATCH invite_recipient flag_invalid_recipient_with_invite 1 CATCH invite_recipient flag_invalid_recipient_with_invite 1
INCMP _ 0 INCMP _ 0

View File

@ -0,0 +1,4 @@
LOAD reset_incorrect_pin 6
CATCH _ flag_account_authorized 0
LOAD initiate_swap 0
HALT

View File

@ -0,0 +1 @@
{{.swap_max_limit}}

View File

@ -0,0 +1,5 @@
MAP swap_max_limit
MOUT back 0
HALT
INCMP _ 0
INCMP swap_preview *

View File

@ -0,0 +1 @@
{{.swap_max_limit}}

View File

@ -0,0 +1 @@
Swap

View File

@ -0,0 +1,3 @@
{{.swap_preview}}
Please enter your PIN to confirm:

View File

@ -0,0 +1,12 @@
LOAD swap_preview 0
MAP swap_preview
CATCH api_failure flag_api_call_error 1
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 swap_initiated *

View File

@ -0,0 +1,3 @@
{{.swap_preview}}
Tafadhali weka PIN yako kudhibitisha:

View File

@ -0,0 +1,2 @@
Select number or symbol to swap TO:
{{.swap_to_list}}

View File

@ -0,0 +1,14 @@
CATCH no_voucher flag_no_active_voucher 1
LOAD swap_to_list 0
RELOAD swap_to_list
MAP swap_to_list
CATCH missing_voucher flag_incorrect_voucher 1
MOUT back 0
HALT
LOAD swap_max_limit 64
RELOAD swap_max_limit
CATCH api_failure flag_api_call_error 1
CATCH . flag_incorrect_voucher 1
CATCH low_swap_amount flag_low_swap_amount 1
INCMP _ 0
INCMP swap_limit *

View File

@ -0,0 +1,2 @@
Chagua nambari au ishara ya sarafu kubadilisha KWENDA:
{{.swap_to_list}}

View File

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

View File

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

View File

@ -1,5 +1,4 @@
LOAD reset_incorrect 6 LOAD reset_incorrect_pin 6
CATCH incorrect_pin flag_incorrect_pin 1
CATCH _ flag_account_authorized 0 CATCH _ flag_account_authorized 0
RELOAD get_amount RELOAD get_amount
MAP get_amount MAP get_amount

View File

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

View File

@ -0,0 +1,10 @@
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

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

View File

@ -1,6 +1,6 @@
LOAD get_profile_info 0 LOAD get_profile_info 0
MAP get_profile_info MAP get_profile_info
LOAD reset_incorrect 6 LOAD reset_incorrect_pin 6
CATCH incorrect_pin flag_incorrect_pin 1 CATCH incorrect_pin flag_incorrect_pin 1
CATCH pin_entry flag_account_authorized 0 CATCH pin_entry flag_account_authorized 0
MOUT back 0 MOUT back 0

View File

@ -1,5 +1,7 @@
CATCH no_voucher flag_no_active_voucher 1 CATCH no_voucher flag_no_active_voucher 1
LOAD get_voucher_details 0 LOAD get_voucher_details 0
RELOAD get_voucher_details
CATCH api_failure flag_api_call_error 1
MAP get_voucher_details MAP get_voucher_details
MOUT back 0 MOUT back 0
HALT HALT

View File

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

View File

@ -67,6 +67,28 @@ const (
DATA_SUGGESTED_ALIAS DATA_SUGGESTED_ALIAS
//Key used to store a value of 1 for a user to reset their own PIN once they access the menu. //Key used to store a value of 1 for a user to reset their own PIN once they access the menu.
DATA_SELF_PIN_RESET DATA_SELF_PIN_RESET
// Holds the active pool contract address for the swap
DATA_ACTIVE_POOL_ADDRESS
// Currently active swap from symbol for the swap
DATA_ACTIVE_SWAP_FROM_SYM
// Currently active swap from decimal count for the swap
DATA_ACTIVE_SWAP_FROM_DECIMAL
// Holds the active swap from contract address for the swap
DATA_ACTIVE_SWAP_FROM_ADDRESS
// Currently active swap from to for the swap
DATA_ACTIVE_SWAP_TO_SYM
// Currently active swap to decimal count for the swap
DATA_ACTIVE_SWAP_TO_DECIMAL
// Holds the active pool contract address for the swap
DATA_ACTIVE_SWAP_TO_ADDRESS
// Holds the max swap amount for the swap
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 ( const (
@ -105,6 +127,31 @@ const (
DATA_TRANSACTIONS = 1024 + iota DATA_TRANSACTIONS = 1024 + iota
) )
const (
// List of voucher symbols in the top pools context.
DATA_POOL_NAMES = 2048 + iota
// List of symbols in the top pools context.
DATA_POOL_SYMBOLS
// List of contact addresses in the top pools context
DATA_POOL_ADDRESSES
// List of swap from voucher symbols in the user context.
DATA_POOL_FROM_SYMBOLS
// List of swap from balances for vouchers valid in the pools context.
DATA_POOL_FROM_BALANCES
// List of swap from decimal counts for vouchers valid in the pools context.
DATA_POOL_FROM_DECIMALS
// List of swap from EVM addresses for vouchers valid in the pools context.
DATA_POOL_FROM_ADDRESSES
// List of swap to voucher symbols in the user context.
DATA_POOL_TO_SYMBOLS
// List of swap to balances for vouchers valid in the pools context.
DATA_POOL_TO_BALANCES
// List of swap to decimal counts for vouchers valid in the pools context.
DATA_POOL_TO_DECIMALS
// List of swap to EVM addresses for vouchers valid in the pools context.
DATA_POOL_TO_ADDRESSES
)
var ( var (
logg = logging.NewVanilla().WithDomain("urdt-common") logg = logging.NewVanilla().WithDomain("urdt-common")
) )

27
store/log_db.go Normal file
View File

@ -0,0 +1,27 @@
package store
import (
"context"
visedb "git.defalsify.org/vise.git/db"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
)
type LogDb struct {
visedb.Db
}
func (db *LogDb) WriteLogEntry(ctx context.Context, sessionId string, typ db.DataTyp, v []byte) error {
db.SetPrefix(visedb.DATATYPE_USERDATA)
db.SetSession(sessionId)
k := storedb.ToBytes(typ)
return db.Put(ctx, k, v)
}
func (db *LogDb) ReadLogEntry(ctx context.Context, sessionId string, typ db.DataTyp) ([]byte, error) {
db.SetPrefix(visedb.DATATYPE_USERDATA)
db.SetSession(sessionId)
k := storedb.ToBytes(typ)
return db.Get(ctx, k)
}

142
store/pools.go Normal file
View File

@ -0,0 +1,142 @@
package store
import (
"context"
"fmt"
"strings"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
)
// PoolsMetadata helps organize data fields
type PoolsMetadata struct {
PoolNames string
PoolSymbols string
PoolContractAdrresses string
}
// ProcessPools converts pools into formatted strings
func ProcessPools(pools []dataserviceapi.PoolDetails) PoolsMetadata {
var data PoolsMetadata
var poolNames, poolSymbols, poolContractAdrresses []string
for i, p := range pools {
poolNames = append(poolNames, fmt.Sprintf("%d:%s", i+1, p.PoolName))
poolSymbols = append(poolSymbols, fmt.Sprintf("%d:%s", i+1, p.PoolSymbol))
poolContractAdrresses = append(poolContractAdrresses, fmt.Sprintf("%d:%s", i+1, p.PoolContractAdrress))
}
data.PoolNames = strings.Join(poolNames, "\n")
data.PoolSymbols = strings.Join(poolSymbols, "\n")
data.PoolContractAdrresses = strings.Join(poolContractAdrresses, "\n")
return data
}
// GetPoolData retrieves and matches pool data
// if no match is found, it fetches the API with the symbol
func GetPoolData(ctx context.Context, store DataStore, sessionId string, input string) (*dataserviceapi.PoolDetails, error) {
keys := []storedb.DataTyp{
storedb.DATA_POOL_NAMES,
storedb.DATA_POOL_SYMBOLS,
storedb.DATA_POOL_ADDRESSES,
}
data := make(map[storedb.DataTyp]string)
for _, key := range keys {
value, err := store.ReadEntry(ctx, sessionId, key)
if err != nil {
return nil, fmt.Errorf("failed to get data key %x: %v", key, err)
}
data[key] = string(value)
}
name, symbol, address := MatchPool(input,
data[storedb.DATA_POOL_NAMES],
data[storedb.DATA_POOL_SYMBOLS],
data[storedb.DATA_POOL_ADDRESSES],
)
if symbol == "" {
return nil, nil
}
return &dataserviceapi.PoolDetails{
PoolName: string(name),
PoolSymbol: string(symbol),
PoolContractAdrress: string(address),
}, nil
}
// MatchPool finds the matching pool name, symbol and pool contract address based on the input.
func MatchPool(input, names, symbols, addresses string) (name, symbol, address string) {
nameList := strings.Split(names, "\n")
symList := strings.Split(symbols, "\n")
addrList := strings.Split(addresses, "\n")
for i, sym := range symList {
parts := strings.SplitN(sym, ":", 2)
if input == parts[0] || strings.EqualFold(input, parts[1]) {
symbol = parts[1]
if i < len(nameList) {
name = strings.SplitN(nameList[i], ":", 2)[1]
}
if i < len(addrList) {
address = strings.SplitN(addrList[i], ":", 2)[1]
}
break
}
}
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
}

189
store/swap.go Normal file
View File

@ -0,0 +1,189 @@
package store
import (
"context"
"errors"
"fmt"
"reflect"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
)
type SwapData struct {
PublicKey string
ActivePoolAddress string
ActiveSwapFromSym string
ActiveSwapFromDecimal string
ActiveSwapFromAddress string
ActiveSwapToSym string
ActiveSwapToAddress string
}
type SwapPreviewData struct {
TemporaryValue string
PublicKey string
ActiveSwapMaxAmount string
ActiveSwapFromDecimal string
ActivePoolAddress string
ActiveSwapFromAddress string
ActiveSwapFromSym string
ActiveSwapToAddress string
ActiveSwapToSym string
ActiveSwapToDecimal string
}
func ReadSwapData(ctx context.Context, store DataStore, sessionId string) (SwapData, error) {
data := SwapData{}
fieldToKey := map[string]storedb.DataTyp{
"PublicKey": storedb.DATA_PUBLIC_KEY,
"ActivePoolAddress": storedb.DATA_ACTIVE_POOL_ADDRESS,
"ActiveSwapFromSym": storedb.DATA_ACTIVE_SYM,
"ActiveSwapFromDecimal": storedb.DATA_ACTIVE_DECIMAL,
"ActiveSwapFromAddress": storedb.DATA_ACTIVE_ADDRESS,
"ActiveSwapToSym": storedb.DATA_ACTIVE_SWAP_TO_SYM,
"ActiveSwapToAddress": storedb.DATA_ACTIVE_SWAP_TO_ADDRESS,
}
v := reflect.ValueOf(&data).Elem()
for fieldName, key := range fieldToKey {
field := v.FieldByName(fieldName)
if !field.IsValid() || !field.CanSet() {
return data, errors.New("invalid struct field: " + fieldName)
}
value, err := ReadStringEntry(ctx, store, sessionId, key)
if err != nil {
return data, err
}
field.SetString(value)
}
return data, nil
}
func ReadSwapPreviewData(ctx context.Context, store DataStore, sessionId string) (SwapPreviewData, error) {
data := SwapPreviewData{}
fieldToKey := map[string]storedb.DataTyp{
"TemporaryValue": storedb.DATA_TEMPORARY_VALUE,
"PublicKey": storedb.DATA_PUBLIC_KEY,
"ActiveSwapMaxAmount": storedb.DATA_ACTIVE_SWAP_MAX_AMOUNT,
"ActiveSwapFromDecimal": storedb.DATA_ACTIVE_DECIMAL,
"ActivePoolAddress": storedb.DATA_ACTIVE_POOL_ADDRESS,
"ActiveSwapFromAddress": storedb.DATA_ACTIVE_ADDRESS,
"ActiveSwapFromSym": storedb.DATA_ACTIVE_SYM,
"ActiveSwapToAddress": storedb.DATA_ACTIVE_SWAP_TO_ADDRESS,
"ActiveSwapToSym": storedb.DATA_ACTIVE_SWAP_TO_SYM,
"ActiveSwapToDecimal": storedb.DATA_ACTIVE_SWAP_TO_DECIMAL,
}
v := reflect.ValueOf(&data).Elem()
for fieldName, key := range fieldToKey {
field := v.FieldByName(fieldName)
if !field.IsValid() || !field.CanSet() {
return data, errors.New("invalid struct field: " + fieldName)
}
value, err := ReadStringEntry(ctx, store, sessionId, key)
if err != nil {
return data, err
}
field.SetString(value)
}
return data, nil
}
// GetSwapFromVoucherData retrieves and matches swap from voucher data
func GetSwapFromVoucherData(ctx context.Context, store DataStore, sessionId string, input string) (*dataserviceapi.TokenHoldings, error) {
keys := []storedb.DataTyp{
storedb.DATA_POOL_FROM_SYMBOLS,
storedb.DATA_POOL_FROM_BALANCES,
storedb.DATA_POOL_FROM_DECIMALS,
storedb.DATA_POOL_FROM_ADDRESSES,
}
data := make(map[storedb.DataTyp]string)
for _, key := range keys {
value, err := store.ReadEntry(ctx, sessionId, key)
if err != nil {
return nil, fmt.Errorf("failed to get data key %x: %v", key, err)
}
data[key] = string(value)
}
symbol, balance, decimal, address := MatchVoucher(input,
data[storedb.DATA_POOL_FROM_SYMBOLS],
data[storedb.DATA_POOL_FROM_BALANCES],
data[storedb.DATA_POOL_FROM_DECIMALS],
data[storedb.DATA_POOL_FROM_ADDRESSES],
)
if symbol == "" {
return nil, nil
}
return &dataserviceapi.TokenHoldings{
TokenSymbol: string(symbol),
Balance: string(balance),
TokenDecimals: string(decimal),
TokenAddress: string(address),
}, nil
}
// GetSwapToVoucherData retrieves and matches token data
func GetSwapToVoucherData(ctx context.Context, store DataStore, sessionId string, input string) (*dataserviceapi.TokenHoldings, error) {
keys := []storedb.DataTyp{
storedb.DATA_POOL_TO_SYMBOLS,
storedb.DATA_POOL_TO_BALANCES,
storedb.DATA_POOL_TO_DECIMALS,
storedb.DATA_POOL_TO_ADDRESSES,
}
data := make(map[storedb.DataTyp]string)
for _, key := range keys {
value, err := store.ReadEntry(ctx, sessionId, key)
if err != nil {
return nil, fmt.Errorf("failed to get data key %x: %v", key, err)
}
data[key] = string(value)
}
symbol, balance, decimal, address := MatchVoucher(input,
data[storedb.DATA_POOL_TO_SYMBOLS],
data[storedb.DATA_POOL_TO_BALANCES],
data[storedb.DATA_POOL_TO_DECIMALS],
data[storedb.DATA_POOL_TO_ADDRESSES],
)
if symbol == "" {
return nil, nil
}
return &dataserviceapi.TokenHoldings{
TokenSymbol: string(symbol),
Balance: string(balance),
TokenDecimals: string(decimal),
TokenAddress: string(address),
}, nil
}
// UpdateSwapToVoucherData updates the active swap to voucher data in the DataStore.
func UpdateSwapToVoucherData(ctx context.Context, store DataStore, sessionId string, data *dataserviceapi.TokenHoldings) error {
logg.InfoCtxf(ctx, "UpdateSwapToVoucherData", "data", data)
// Active swap to voucher data entries
activeEntries := map[storedb.DataTyp][]byte{
storedb.DATA_ACTIVE_SWAP_TO_SYM: []byte(data.TokenSymbol),
storedb.DATA_ACTIVE_SWAP_TO_DECIMAL: []byte(data.TokenDecimals),
storedb.DATA_ACTIVE_SWAP_TO_ADDRESS: []byte(data.TokenAddress),
}
// Write active data
for key, value := range activeEntries {
if err := store.WriteEntry(ctx, sessionId, key, value); err != nil {
return err
}
}
return nil
}

146
store/swap_test.go Normal file
View File

@ -0,0 +1,146 @@
package store
import (
"testing"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/alecthomas/assert/v2"
)
func TestReadSwapData(t *testing.T) {
sessionId := "session123"
publicKey := "0X13242618721"
ctx, store := InitializeTestDb(t)
// Test swap data
swapData := map[storedb.DataTyp]string{
storedb.DATA_PUBLIC_KEY: publicKey,
storedb.DATA_ACTIVE_POOL_ADDRESS: "0x48a953cA5cf5298bc6f6Af3C608351f537AAcb9e",
storedb.DATA_ACTIVE_SWAP_FROM_SYM: "AMANI",
storedb.DATA_ACTIVE_SWAP_FROM_DECIMAL: "6",
storedb.DATA_ACTIVE_SWAP_FROM_ADDRESS: "0xc7B78Ac9ACB9E025C8234621FC515bC58179dEAe",
storedb.DATA_ACTIVE_SWAP_TO_SYM: "cUSD",
storedb.DATA_ACTIVE_SWAP_TO_ADDRESS: "0x765DE816845861e75A25fCA122bb6898B8B1282a",
}
// Store the data
for key, value := range swapData {
if err := store.WriteEntry(ctx, sessionId, key, []byte(value)); err != nil {
t.Fatal(err)
}
}
expectedResult := SwapData{
PublicKey: "0X13242618721",
ActivePoolAddress: "0x48a953cA5cf5298bc6f6Af3C608351f537AAcb9e",
ActiveSwapFromSym: "AMANI",
ActiveSwapFromDecimal: "6",
ActiveSwapFromAddress: "0xc7B78Ac9ACB9E025C8234621FC515bC58179dEAe",
ActiveSwapToSym: "cUSD",
ActiveSwapToAddress: "0x765DE816845861e75A25fCA122bb6898B8B1282a",
}
data, err := ReadSwapData(ctx, store, sessionId)
assert.NoError(t, err)
assert.Equal(t, expectedResult, data)
}
func TestReadSwapPreviewData(t *testing.T) {
sessionId := "session123"
publicKey := "0X13242618721"
ctx, store := InitializeTestDb(t)
// Test swap preview data
swapPreviewData := map[storedb.DataTyp]string{
storedb.DATA_PUBLIC_KEY: publicKey,
storedb.DATA_ACTIVE_SWAP_MAX_AMOUNT: "1339482",
storedb.DATA_ACTIVE_SWAP_FROM_DECIMAL: "6",
storedb.DATA_ACTIVE_POOL_ADDRESS: "0x48a953cA5cf5298bc6f6Af3C608351f537AAcb9e",
storedb.DATA_ACTIVE_SWAP_FROM_ADDRESS: "0xc7B78Ac9ACB9E025C8234621FC515bC58179dEAe",
storedb.DATA_ACTIVE_SWAP_FROM_SYM: "AMANI",
storedb.DATA_ACTIVE_SWAP_TO_ADDRESS: "0x765DE816845861e75A25fCA122bb6898B8B1282a",
storedb.DATA_ACTIVE_SWAP_TO_SYM: "cUSD",
storedb.DATA_ACTIVE_SWAP_TO_DECIMAL: "18",
}
// Store the data
for key, value := range swapPreviewData {
if err := store.WriteEntry(ctx, sessionId, key, []byte(value)); err != nil {
t.Fatal(err)
}
}
expectedResult := SwapPreviewData{
PublicKey: "0X13242618721",
ActiveSwapMaxAmount: "1339482",
ActiveSwapFromDecimal: "6",
ActivePoolAddress: "0x48a953cA5cf5298bc6f6Af3C608351f537AAcb9e",
ActiveSwapFromAddress: "0xc7B78Ac9ACB9E025C8234621FC515bC58179dEAe",
ActiveSwapFromSym: "AMANI",
ActiveSwapToAddress: "0x765DE816845861e75A25fCA122bb6898B8B1282a",
ActiveSwapToSym: "cUSD",
ActiveSwapToDecimal: "18",
}
data, err := ReadSwapPreviewData(ctx, store, sessionId)
assert.NoError(t, err)
assert.Equal(t, expectedResult, data)
}
func TestGetSwapFromVoucherData(t *testing.T) {
sessionId := "session123"
ctx, store := InitializeTestDb(t)
// Test pool swap data
mockData := map[storedb.DataTyp][]byte{
storedb.DATA_POOL_FROM_SYMBOLS: []byte("1:AMANI\n2:AMUA"),
storedb.DATA_POOL_FROM_BALANCES: []byte("1:\n2:"),
storedb.DATA_POOL_FROM_DECIMALS: []byte("1:6\n2:4"),
storedb.DATA_POOL_FROM_ADDRESSES: []byte("1:0xc7B78Ac9ACB9E025C8234621FC515bC58179dEAe\n2:0xF0C3C7581b8b96B59a97daEc8Bd48247cE078674"),
}
// Put the data
for key, value := range mockData {
if err := store.WriteEntry(ctx, sessionId, key, []byte(value)); err != nil {
t.Fatal(err)
}
}
result, err := GetSwapFromVoucherData(ctx, store, sessionId, "1")
assert.NoError(t, err)
assert.Equal(t, "AMANI", result.TokenSymbol)
assert.Equal(t, "", result.Balance)
assert.Equal(t, "6", result.TokenDecimals)
assert.Equal(t, "0xc7B78Ac9ACB9E025C8234621FC515bC58179dEAe", result.TokenAddress)
}
func TestGetSwapToVoucherData(t *testing.T) {
sessionId := "session123"
ctx, store := InitializeTestDb(t)
// Test pool swap data
mockData := map[storedb.DataTyp][]byte{
storedb.DATA_POOL_TO_SYMBOLS: []byte("1:cUSD\n2:AMUA"),
storedb.DATA_POOL_TO_BALANCES: []byte("1:\n2:"),
storedb.DATA_POOL_TO_DECIMALS: []byte("1:6\n2:4"),
storedb.DATA_POOL_TO_ADDRESSES: []byte("1:0xc7B78Ac9ACB9E025C8234621\n2:0xF0C3C7581b8b96B59a97daEc8Bd48247cE078674"),
}
// Put the data
for key, value := range mockData {
if err := store.WriteEntry(ctx, sessionId, key, []byte(value)); err != nil {
t.Fatal(err)
}
}
result, err := GetSwapToVoucherData(ctx, store, sessionId, "1")
assert.NoError(t, err)
assert.Equal(t, "cUSD", result.TokenSymbol)
assert.Equal(t, "", result.Balance)
assert.Equal(t, "6", result.TokenDecimals)
assert.Equal(t, "0xc7B78Ac9ACB9E025C8234621", result.TokenAddress)
}

View File

@ -3,6 +3,7 @@ package store
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"math/big" "math/big"
"reflect" "reflect"
"strconv" "strconv"
@ -20,6 +21,27 @@ type TransactionData struct {
ActiveAddress string ActiveAddress string
} }
// TruncateDecimalString safely truncates the input amount to the specified decimal places
func TruncateDecimalString(input string, decimalPlaces int) (string, error) {
num, ok := new(big.Float).SetString(input)
if !ok {
return "", fmt.Errorf("invalid input")
}
// Multiply by 10^decimalPlaces
scale := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimalPlaces)), nil))
scaled := new(big.Float).Mul(num, scale)
// Truncate by converting to int (chops off decimals)
intPart, _ := scaled.Int(nil)
// Divide back to get truncated float
truncated := new(big.Float).Quo(new(big.Float).SetInt(intPart), scale)
// Format with fixed decimals
return truncated.Text('f', decimalPlaces), nil
}
func ParseAndScaleAmount(storedAmount, activeDecimal string) (string, error) { func ParseAndScaleAmount(storedAmount, activeDecimal string) (string, error) {
// Parse token decimal // Parse token decimal
tokenDecimal, err := strconv.Atoi(activeDecimal) tokenDecimal, err := strconv.Atoi(activeDecimal)
@ -38,11 +60,8 @@ func ParseAndScaleAmount(storedAmount, activeDecimal string) (string, error) {
multiplier := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(tokenDecimal)), nil)) multiplier := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(tokenDecimal)), nil))
finalAmount := new(big.Float).Mul(amount, multiplier) finalAmount := new(big.Float).Mul(amount, multiplier)
// Convert finalAmount to a string // Return finalAmount as a string with 0 decimal places (rounded)
finalAmountStr := new(big.Int) return finalAmount.Text('f', 0), nil
finalAmount.Int(finalAmountStr)
return finalAmountStr.String(), nil
} }
func ReadTransactionData(ctx context.Context, store DataStore, sessionId string) (TransactionData, error) { func ReadTransactionData(ctx context.Context, store DataStore, sessionId string) (TransactionData, error) {
@ -64,7 +83,7 @@ func ReadTransactionData(ctx context.Context, store DataStore, sessionId string)
return data, errors.New("invalid struct field: " + fieldName) return data, errors.New("invalid struct field: " + fieldName)
} }
value, err := readStringEntry(ctx, store, sessionId, key) value, err := ReadStringEntry(ctx, store, sessionId, key)
if err != nil { if err != nil {
return data, err return data, err
} }
@ -74,7 +93,7 @@ func ReadTransactionData(ctx context.Context, store DataStore, sessionId string)
return data, nil return data, nil
} }
func readStringEntry(ctx context.Context, store DataStore, sessionId string, key storedb.DataTyp) (string, error) { func ReadStringEntry(ctx context.Context, store DataStore, sessionId string, key storedb.DataTyp) (string, error) {
entry, err := store.ReadEntry(ctx, sessionId, key) entry, err := store.ReadEntry(ctx, sessionId, key)
if err != nil { if err != nil {
return "", err return "", err

View File

@ -7,6 +7,109 @@ import (
"github.com/alecthomas/assert/v2" "github.com/alecthomas/assert/v2"
) )
func TestTruncateDecimalString(t *testing.T) {
tests := []struct {
name string
input string
decimalPlaces int
want string
expectError bool
}{
{
name: "whole number",
input: "4",
decimalPlaces: 2,
want: "4.00",
expectError: false,
},
{
name: "single decimal",
input: "4.1",
decimalPlaces: 2,
want: "4.10",
expectError: false,
},
{
name: "one decimal place",
input: "4.19",
decimalPlaces: 1,
want: "4.1",
expectError: false,
},
{
name: "truncates to 2 dp",
input: "0.149",
decimalPlaces: 2,
want: "0.14",
expectError: false,
},
{
name: "does not round",
input: "1.8599999999",
decimalPlaces: 2,
want: "1.85",
expectError: false,
},
{
name: "high precision input",
input: "123.456789",
decimalPlaces: 4,
want: "123.4567",
expectError: false,
},
{
name: "zero",
input: "0",
decimalPlaces: 2,
want: "0.00",
expectError: false,
},
{
name: "invalid input string",
input: "abc",
decimalPlaces: 2,
want: "",
expectError: true,
},
{
name: "edge rounding case",
input: "4.99999999",
decimalPlaces: 2,
want: "4.99",
expectError: false,
},
{
name: "small value",
input: "0.0001",
decimalPlaces: 2,
want: "0.00",
expectError: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := TruncateDecimalString(tt.input, tt.decimalPlaces)
if tt.expectError {
if err == nil {
t.Errorf("TruncateDecimalString(%q, %d) expected error, got nil", tt.input, tt.decimalPlaces)
}
return
}
if err != nil {
t.Errorf("TruncateDecimalString(%q, %d) unexpected error: %v", tt.input, tt.decimalPlaces, err)
return
}
if got != tt.want {
t.Errorf("TruncateDecimalString(%q, %d) = %q, want %q", tt.input, tt.decimalPlaces, got, tt.want)
}
})
}
}
func TestParseAndScaleAmount(t *testing.T) { func TestParseAndScaleAmount(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
@ -64,6 +167,20 @@ func TestParseAndScaleAmount(t *testing.T) {
want: "0", want: "0",
expectError: false, expectError: false,
}, },
{
name: "high decimals",
amount: "1.85",
decimals: "18",
want: "1850000000000000000",
expectError: false,
},
{
name: "6 d.p",
amount: "2.32",
decimals: "6",
want: "2320000",
expectError: false,
},
} }
for _, tt := range tests { for _, tt := range tests {

View File

@ -36,7 +36,7 @@ func ProcessVouchers(holdings []dataserviceapi.TokenHoldings) VoucherMetadata {
balances = append(balances, fmt.Sprintf("%d:%s", i+1, scaledBalance)) balances = append(balances, fmt.Sprintf("%d:%s", i+1, scaledBalance))
decimals = append(decimals, fmt.Sprintf("%d:%s", i+1, h.TokenDecimals)) decimals = append(decimals, fmt.Sprintf("%d:%s", i+1, h.TokenDecimals))
addresses = append(addresses, fmt.Sprintf("%d:%s", i+1, h.ContractAddress)) addresses = append(addresses, fmt.Sprintf("%d:%s", i+1, h.TokenAddress))
} }
data.Symbols = strings.Join(symbols, "\n") data.Symbols = strings.Join(symbols, "\n")
@ -100,7 +100,7 @@ func GetVoucherData(ctx context.Context, store DataStore, sessionId string, inpu
TokenSymbol: string(symbol), TokenSymbol: string(symbol),
Balance: string(balance), Balance: string(balance),
TokenDecimals: string(decimal), TokenDecimals: string(decimal),
ContractAddress: string(address), TokenAddress: string(address),
}, nil }, nil
} }
@ -134,7 +134,7 @@ func MatchVoucher(input, symbols, balances, decimals, addresses string) (symbol,
// StoreTemporaryVoucher saves voucher metadata as temporary entries in the DataStore. // StoreTemporaryVoucher saves voucher metadata as temporary entries in the DataStore.
func StoreTemporaryVoucher(ctx context.Context, store DataStore, sessionId string, data *dataserviceapi.TokenHoldings) error { func StoreTemporaryVoucher(ctx context.Context, store DataStore, sessionId string, data *dataserviceapi.TokenHoldings) error {
tempData := fmt.Sprintf("%s,%s,%s,%s", data.TokenSymbol, data.Balance, data.TokenDecimals, data.ContractAddress) tempData := fmt.Sprintf("%s,%s,%s,%s", data.TokenSymbol, data.Balance, data.TokenDecimals, data.TokenAddress)
if err := store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(tempData)); err != nil { if err := store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(tempData)); err != nil {
return err return err
@ -157,7 +157,7 @@ func GetTemporaryVoucherData(ctx context.Context, store DataStore, sessionId str
data.TokenSymbol = values[0] data.TokenSymbol = values[0]
data.Balance = values[1] data.Balance = values[1]
data.TokenDecimals = values[2] data.TokenDecimals = values[2]
data.ContractAddress = values[3] data.TokenAddress = values[3]
return data, nil return data, nil
} }
@ -170,7 +170,7 @@ func UpdateVoucherData(ctx context.Context, store DataStore, sessionId string, d
storedb.DATA_ACTIVE_SYM: []byte(data.TokenSymbol), storedb.DATA_ACTIVE_SYM: []byte(data.TokenSymbol),
storedb.DATA_ACTIVE_BAL: []byte(data.Balance), storedb.DATA_ACTIVE_BAL: []byte(data.Balance),
storedb.DATA_ACTIVE_DECIMAL: []byte(data.TokenDecimals), storedb.DATA_ACTIVE_DECIMAL: []byte(data.TokenDecimals),
storedb.DATA_ACTIVE_ADDRESS: []byte(data.ContractAddress), storedb.DATA_ACTIVE_ADDRESS: []byte(data.TokenAddress),
} }
// Write active data // Write active data

View File

@ -59,8 +59,8 @@ func TestMatchVoucher(t *testing.T) {
func TestProcessVouchers(t *testing.T) { func TestProcessVouchers(t *testing.T) {
holdings := []dataserviceapi.TokenHoldings{ holdings := []dataserviceapi.TokenHoldings{
{ContractAddress: "0xd4c288865Ce", TokenSymbol: "SRF", TokenDecimals: "6", Balance: "100000000"}, {TokenAddress: "0xd4c288865Ce", TokenSymbol: "SRF", TokenDecimals: "6", Balance: "100000000"},
{ContractAddress: "0x41c188d63Qa", TokenSymbol: "MILO", TokenDecimals: "4", Balance: "200000000"}, {TokenAddress: "0x41c188d63Qa", TokenSymbol: "MILO", TokenDecimals: "4", Balance: "200000000"},
} }
expectedResult := VoucherMetadata{ expectedResult := VoucherMetadata{
@ -101,7 +101,7 @@ func TestGetVoucherData(t *testing.T) {
assert.Equal(t, "SRF", result.TokenSymbol) assert.Equal(t, "SRF", result.TokenSymbol)
assert.Equal(t, "100", result.Balance) assert.Equal(t, "100", result.Balance)
assert.Equal(t, "6", result.TokenDecimals) assert.Equal(t, "6", result.TokenDecimals)
assert.Equal(t, "0xd4c288865Ce", result.ContractAddress) assert.Equal(t, "0xd4c288865Ce", result.TokenAddress)
} }
func TestStoreTemporaryVoucher(t *testing.T) { func TestStoreTemporaryVoucher(t *testing.T) {
@ -113,7 +113,7 @@ func TestStoreTemporaryVoucher(t *testing.T) {
TokenSymbol: "SRF", TokenSymbol: "SRF",
Balance: "200", Balance: "200",
TokenDecimals: "6", TokenDecimals: "6",
ContractAddress: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", TokenAddress: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9",
} }
// Execute the function being tested // Execute the function being tested
@ -137,7 +137,7 @@ func TestGetTemporaryVoucherData(t *testing.T) {
TokenSymbol: "SRF", TokenSymbol: "SRF",
Balance: "200", Balance: "200",
TokenDecimals: "6", TokenDecimals: "6",
ContractAddress: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", TokenAddress: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9",
} }
// Store the data // Store the data
@ -159,7 +159,7 @@ func TestUpdateVoucherData(t *testing.T) {
TokenSymbol: "SRF", TokenSymbol: "SRF",
Balance: "200", Balance: "200",
TokenDecimals: "6", TokenDecimals: "6",
ContractAddress: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", TokenAddress: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9",
} }
// Old temporary data // Old temporary data
@ -167,7 +167,7 @@ func TestUpdateVoucherData(t *testing.T) {
TokenSymbol: "OLD", TokenSymbol: "OLD",
Balance: "100", Balance: "100",
TokenDecimals: "8", TokenDecimals: "8",
ContractAddress: "0xold", TokenAddress: "0xold",
} }
require.NoError(t, StoreTemporaryVoucher(ctx, store, sessionId, tempData)) require.NoError(t, StoreTemporaryVoucher(ctx, store, sessionId, tempData))
@ -180,7 +180,7 @@ func TestUpdateVoucherData(t *testing.T) {
storedb.DATA_ACTIVE_SYM: []byte(newData.TokenSymbol), storedb.DATA_ACTIVE_SYM: []byte(newData.TokenSymbol),
storedb.DATA_ACTIVE_BAL: []byte(newData.Balance), storedb.DATA_ACTIVE_BAL: []byte(newData.Balance),
storedb.DATA_ACTIVE_DECIMAL: []byte(newData.TokenDecimals), storedb.DATA_ACTIVE_DECIMAL: []byte(newData.TokenDecimals),
storedb.DATA_ACTIVE_ADDRESS: []byte(newData.ContractAddress), storedb.DATA_ACTIVE_ADDRESS: []byte(newData.TokenAddress),
} }
for key, expectedValue := range activeEntries { for key, expectedValue := range activeEntries {

View File

@ -113,6 +113,12 @@ func TestEngine(sessionId string) (engine.Engine, func(), chan bool, *persist.Pe
os.Exit(1) os.Exit(1)
} }
logdb, err := menuStorageService.GetLogDb(ctx, userDataStore, "test-db-logs", "user-data")
if err != nil {
fmt.Fprintf(os.Stderr, "get log db error: %v\n", err)
os.Exit(1)
}
dbResource, ok := rs.(*resource.DbResource) dbResource, ok := rs.(*resource.DbResource)
if !ok { if !ok {
fmt.Fprintf(os.Stderr, "dbresource cast error") fmt.Fprintf(os.Stderr, "dbresource cast error")
@ -121,6 +127,7 @@ func TestEngine(sessionId string) (engine.Engine, func(), chan bool, *persist.Pe
lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs) lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs)
lhs.SetDataStore(&userDataStore) lhs.SetDataStore(&userDataStore)
lhs.SetLogDb(&logdb)
lhs.SetPersister(pe) lhs.SetPersister(pe)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, err.Error()) fmt.Fprintf(os.Stderr, err.Error())
@ -154,6 +161,7 @@ func TestEngine(sessionId string) (engine.Engine, func(), chan bool, *persist.Pe
en := lhs.GetEngine(lhs.Cfg, rs, pe) en := lhs.GetEngine(lhs.Cfg, rs, pe)
cleanFn := func() { cleanFn := func() {
logdb.Close(ctx)
err := en.Finish(ctx) err := en.Finish(ctx)
if err != nil { if err != nil {
logg.Errorf(err.Error()) logg.Errorf(err.Error())