manage vouchers in single function #42

Merged
lash merged 6 commits from manage-vouchers-in-single-function into master 2025-04-01 21:26:28 +02:00
4 changed files with 113 additions and 181 deletions

View File

@ -1946,9 +1946,11 @@ func (h *MenuHandlers) InitiateTransaction(ctx context.Context, sym string, inpu
return res, nil
}
// SetDefaultVoucher retrieves the current vouchers
// and sets the first as the default voucher, if no active voucher is set.
func (h *MenuHandlers) SetDefaultVoucher(ctx context.Context, sym string, input []byte) (resource.Result, error) {
// ManageVouchers retrieves the token holdings from the API using the "PublicKey" and
// 1. sets the first as the default voucher if no active voucher is set.
// 2. Stores list of vouchers
// 3. updates the balance of the active voucher
func (h *MenuHandlers) ManageVouchers(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result
userStore := h.userdataStore
@ -1959,30 +1961,31 @@ func (h *MenuHandlers) SetDefaultVoucher(ctx context.Context, sym string, input
flag_no_active_voucher, _ := h.flagManager.GetFlag("flag_no_active_voucher")
// check if the user has an active sym
_, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_SYM)
publicKey, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY)
if err != nil {
logg.ErrorCtxf(ctx, "failed to read publicKey entry", "key", storedb.DATA_PUBLIC_KEY, "error", err)
return res, err
}
// Fetch vouchers from API
vouchersResp, err := h.accountService.FetchVouchers(ctx, string(publicKey))
if err != nil {
res.FlagSet = append(res.FlagSet, flag_no_active_voucher)
return res, nil
}
if len(vouchersResp) == 0 {
res.FlagSet = append(res.FlagSet, flag_no_active_voucher)
return res, nil
}
res.FlagReset = append(res.FlagReset, flag_no_active_voucher)
// Check if user has an active voucher with proper error handling
Alfred-mk marked this conversation as resolved
Review

is this log line a bit noisy? it prints the whole voucher response, cluttering the logs. the list perhaps better in debug?

is this log line a bit noisy? it prints the whole voucher response, cluttering the logs. the list perhaps better in debug?
Review

This has been cleaned up. The logs were related to debug

This has been cleaned up. The logs were related to debug
activeSym, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_SYM)
if err != nil {
if db.IsNotFound(err) {
publicKey, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY)
if err != nil {
logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", storedb.DATA_PUBLIC_KEY, "error", err)
return res, err
}
// Fetch vouchers from the API using the public key
vouchersResp, err := h.accountService.FetchVouchers(ctx, string(publicKey))
if err != nil {
res.FlagSet = append(res.FlagSet, flag_no_active_voucher)
return res, nil
}
// Return if there is no voucher
if len(vouchersResp) == 0 {
res.FlagSet = append(res.FlagSet, flag_no_active_voucher)
return res, nil
}
// Use only the first voucher
// No active voucher, set the first one as default
firstVoucher := vouchersResp[0]
defaultSym := firstVoucher.TokenSymbol
defaultBal := firstVoucher.Balance
@ -1992,71 +1995,27 @@ func (h *MenuHandlers) SetDefaultVoucher(ctx context.Context, sym string, input
// Scale down the balance
scaledBalance := store.ScaleDownBalance(defaultBal, defaultDec)
// TODO: implement atomic transaction
// set the active symbol
err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_SYM, []byte(defaultSym))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write defaultSym entry with", "key", storedb.DATA_ACTIVE_SYM, "value", defaultSym, "error", err)
return res, err
}
// set the active balance
err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_BAL, []byte(scaledBalance))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write defaultBal entry with", "key", storedb.DATA_ACTIVE_BAL, "value", scaledBalance, "error", err)
return res, err
}
// set the active decimals
err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_DECIMAL, []byte(defaultDec))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write defaultDec entry with", "key", storedb.DATA_ACTIVE_DECIMAL, "value", defaultDec, "error", err)
return res, err
}
// set the active contract address
err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_ADDRESS, []byte(defaultAddr))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write defaultAddr entry with", "key", storedb.DATA_ACTIVE_ADDRESS, "value", defaultAddr, "error", err)
return res, err
firstVoucherMap := map[storedb.DataTyp]string{
storedb.DATA_ACTIVE_SYM: defaultSym,
storedb.DATA_ACTIVE_BAL: scaledBalance,
storedb.DATA_ACTIVE_DECIMAL: defaultDec,
storedb.DATA_ACTIVE_ADDRESS: defaultAddr,
}
return res, nil
for key, value := range firstVoucherMap {
if err := userStore.WriteEntry(ctx, sessionId, key, []byte(value)); err != nil {
logg.ErrorCtxf(ctx, "Failed to write active voucher data", "key", key, "error", err)
return res, err
}
}
logg.InfoCtxf(ctx, "Default voucher set", "symbol", defaultSym, "balance", defaultBal, "decimals", defaultDec, "address", defaultAddr)
} else {
logg.ErrorCtxf(ctx, "failed to read activeSym entry with", "key", storedb.DATA_ACTIVE_SYM, "error", err)
return res, err
}
logg.ErrorCtxf(ctx, "failed to read activeSym entry with", "key", storedb.DATA_ACTIVE_SYM, "error", err)
return res, err
}
res.FlagReset = append(res.FlagReset, flag_no_active_voucher)
return res, nil
}
// CheckVouchers retrieves the token holdings from the API using the "PublicKey" and stores
// them to gdbm.
func (h *MenuHandlers) CheckVouchers(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
userStore := h.userdataStore
publicKey, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY)
if err != nil {
logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", storedb.DATA_PUBLIC_KEY, "error", err)
return res, err
}
// Fetch vouchers from the API using the public key
vouchersResp, err := h.accountService.FetchVouchers(ctx, string(publicKey))
if err != nil {
return res, nil
}
logg.InfoCtxf(ctx, "fetched user vouchers", "public_key", string(publicKey), "vouchers", vouchersResp)
// check the current active sym and update the data
activeSym, _ := userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_SYM)
if activeSym != nil {
} else {
// Update active voucher balance
activeSymStr := string(activeSym)
// Find the matching voucher data
@ -2086,14 +2045,8 @@ func (h *MenuHandlers) CheckVouchers(ctx context.Context, sym string, input []by
}
}
activeBal, _ := userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_BAL)
activeAddr, _ := userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_ADDRESS)
logg.InfoCtxf(ctx, "The active data in CheckVouchers:", "activeSym", string(activeSym), string(activeBal), string(activeAddr))
data := store.ProcessVouchers(vouchersResp)
// Store all voucher data
data := store.ProcessVouchers(vouchersResp)
dataMap := map[storedb.DataTyp]string{
storedb.DATA_VOUCHER_SYMBOLS: data.Symbols,
storedb.DATA_VOUCHER_BALANCES: data.Balances,
@ -2103,7 +2056,6 @@ func (h *MenuHandlers) CheckVouchers(ctx context.Context, sym string, input []by
// Write data entries
for key, value := range dataMap {
logg.InfoCtxf(ctx, "Writing data entry for sessionId: %s", sessionId, "key", key, "value", value)
if err := userStore.WriteEntry(ctx, sessionId, key, []byte(value)); err != nil {
logg.ErrorCtxf(ctx, "Failed to write data entry for sessionId: %s", sessionId, "key", key, "error", err)
continue

View File

@ -1990,36 +1990,46 @@ func TestFetchCommunityBalance(t *testing.T) {
}
}
func TestSetDefaultVoucher(t *testing.T) {
func TestManageVouchers(t *testing.T) {
sessionId := "session123"
publicKey := "0X13242618721"
ctx, store := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId)
fm, err := NewFlagManager(flagsPath)
if err != nil {
t.Logf(err.Error())
t.Fatal(err)
}
flag_no_active_voucher, err := fm.GetFlag("flag_no_active_voucher")
if err != nil {
t.Logf(err.Error())
t.Fatal(err)
}
publicKey := "0X13242618721"
err = store.WriteEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY, []byte(publicKey))
if err != nil {
t.Fatal(err)
}
tests := []struct {
name string
vouchersResp []dataserviceapi.TokenHoldings
expectedResult resource.Result
name string
vouchersResp []dataserviceapi.TokenHoldings
storedActiveVoucher string
expectedVoucherSymbols []byte
expectedUpdatedAddress []byte
expectedResult resource.Result
}{
{
name: "Test no vouchers available",
vouchersResp: []dataserviceapi.TokenHoldings{},
name: "No vouchers available",
vouchersResp: []dataserviceapi.TokenHoldings{},
expectedVoucherSymbols: []byte(""),
expectedUpdatedAddress: []byte(""),
expectedResult: resource.Result{
FlagSet: []uint32{flag_no_active_voucher},
},
},
{
name: "Test set default voucher when no active voucher is set",
name: "Set default voucher when no active voucher is set",
vouchersResp: []dataserviceapi.TokenHoldings{
{
ContractAddress: "0x123",
@ -2028,7 +2038,24 @@ func TestSetDefaultVoucher(t *testing.T) {
Balance: "100",
},
},
expectedResult: resource.Result{},
expectedVoucherSymbols: []byte("1:TOKEN1"),
expectedUpdatedAddress: []byte("0x123"),
expectedResult: resource.Result{
FlagReset: []uint32{flag_no_active_voucher},
},
},
{
name: "Check and update active voucher balance",
vouchersResp: []dataserviceapi.TokenHoldings{
{ContractAddress: "0xd4c288865Ce", TokenSymbol: "SRF", TokenDecimals: "6", Balance: "100"},
{ContractAddress: "0x41c188d63Qa", TokenSymbol: "MILO", TokenDecimals: "4", Balance: "200"},
},
storedActiveVoucher: "SRF",
expectedVoucherSymbols: []byte("1:SRF\n2:MILO"),
expectedUpdatedAddress: []byte("0xd4c288865Ce"),
expectedResult: resource.Result{
FlagReset: []uint32{flag_no_active_voucher},
},
},
}
@ -2042,85 +2069,41 @@ func TestSetDefaultVoucher(t *testing.T) {
flagManager: fm,
}
err := store.WriteEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY, []byte(publicKey))
if err != nil {
t.Fatal(err)
}
mockAccountService.On("FetchVouchers", string(publicKey)).Return(tt.vouchersResp, nil)
res, err := h.SetDefaultVoucher(ctx, "set_default_voucher", []byte("some-input"))
// Store active voucher if needed
if tt.storedActiveVoucher != "" {
err := store.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_SYM, []byte(tt.storedActiveVoucher))
if err != nil {
t.Fatal(err)
}
err = store.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_ADDRESS, []byte("0x41c188D45rfg6ds"))
if err != nil {
t.Fatal(err)
}
}
res, err := h.ManageVouchers(ctx, "manage_vouchers", []byte(""))
assert.NoError(t, err)
assert.Equal(t, tt.expectedResult, res)
assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result")
if tt.storedActiveVoucher != "" {
// Validate stored voucher symbols
voucherData, err := store.ReadEntry(ctx, sessionId, storedb.DATA_VOUCHER_SYMBOLS)
assert.NoError(t, err)
assert.Equal(t, tt.expectedVoucherSymbols, voucherData)
mockAccountService.AssertExpectations(t)
// Validate stored active contract address
updatedAddress, err := store.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_ADDRESS)
assert.NoError(t, err)
assert.Equal(t, tt.expectedUpdatedAddress, updatedAddress)
mockAccountService.AssertExpectations(t)
}
})
}
}
func TestCheckVouchers(t *testing.T) {
mockAccountService := new(mocks.MockAccountService)
sessionId := "session123"
publicKey := "0X13242618721"
ctx, store := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId)
h := &MenuHandlers{
userdataStore: store,
accountService: mockAccountService,
}
err := store.WriteEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY, []byte(publicKey))
if err != nil {
t.Fatal(err)
}
mockVouchersResponse := []dataserviceapi.TokenHoldings{
{ContractAddress: "0xd4c288865Ce", TokenSymbol: "SRF", TokenDecimals: "6", Balance: "100"},
{ContractAddress: "0x41c188d63Qa", TokenSymbol: "MILO", TokenDecimals: "4", Balance: "200"},
}
// store the default voucher data
err = store.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_SYM, []byte("SRF"))
if err != nil {
t.Fatal(err)
}
err = store.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_ADDRESS, []byte("0x41c188D45rfg6ds"))
if err != nil {
t.Fatal(err)
}
expectedSym := []byte("1:SRF\n2:MILO")
expectedUpdatedAddress := []byte("0xd4c288865Ce")
mockAccountService.On("FetchVouchers", string(publicKey)).Return(mockVouchersResponse, nil)
_, err = h.CheckVouchers(ctx, "check_vouchers", []byte(""))
assert.NoError(t, err)
// Read voucher sym data from the store
voucherData, err := store.ReadEntry(ctx, sessionId, storedb.DATA_VOUCHER_SYMBOLS)
if err != nil {
t.Fatal(err)
}
// Read active contract address from the store
updatedAddress, err := store.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_ADDRESS)
if err != nil {
t.Fatal(err)
}
// assert that the data is stored correctly
assert.Equal(t, expectedSym, voucherData)
// assert that the address is updated
assert.Equal(t, expectedUpdatedAddress, updatedAddress)
mockAccountService.AssertExpectations(t)
}
func TestGetVoucherList(t *testing.T) {
sessionId := "session123"

View File

@ -103,8 +103,7 @@ func (ls *LocalHandlerService) GetHandler(accountService remote.AccountService)
ls.DbRs.AddLocalFunc("confirm_pin_change", appHandlers.ConfirmPinChange)
ls.DbRs.AddLocalFunc("quit_with_help", appHandlers.QuitWithHelp)
ls.DbRs.AddLocalFunc("fetch_community_balance", appHandlers.FetchCommunityBalance)
ls.DbRs.AddLocalFunc("set_default_voucher", appHandlers.SetDefaultVoucher)
ls.DbRs.AddLocalFunc("check_vouchers", appHandlers.CheckVouchers)
ls.DbRs.AddLocalFunc("manage_vouchers", appHandlers.ManageVouchers)
ls.DbRs.AddLocalFunc("get_vouchers", appHandlers.GetVoucherList)
ls.DbRs.AddLocalFunc("view_voucher", appHandlers.ViewVoucher)
ls.DbRs.AddLocalFunc("set_voucher", appHandlers.SetVoucher)

View File

@ -1,9 +1,7 @@
LOAD clear_temporary_value 2
RELOAD clear_temporary_value
LOAD set_default_voucher 8
RELOAD set_default_voucher
LOAD check_vouchers 10
RELOAD check_vouchers
LOAD manage_vouchers 160
RELOAD manage_vouchers
LOAD check_balance 128
RELOAD check_balance
CATCH api_failure flag_api_call_error 1