project-tidyup - menuhandler and tests #90
| @ -2309,416 +2309,3 @@ func (h *MenuHandlers) ClearTemporaryValue(ctx context.Context, sym string, inpu | |||||||
| 	} | 	} | ||||||
| 	return res, nil | 	return res, nil | ||||||
| } | } | ||||||
| 
 |  | ||||||
| // GetPools fetches a list of 5 top pools
 |  | ||||||
| func (h *MenuHandlers) GetPools(ctx context.Context, sym string, input []byte) (resource.Result, error) { |  | ||||||
| 	var res resource.Result |  | ||||||
| 	sessionId, ok := ctx.Value("SessionId").(string) |  | ||||||
| 	if !ok { |  | ||||||
| 		return res, fmt.Errorf("missing session") |  | ||||||
| 	} |  | ||||||
| 	userStore := h.userdataStore |  | ||||||
| 
 |  | ||||||
| 	flag_api_error, _ := h.flagManager.GetFlag("flag_api_error") |  | ||||||
| 
 |  | ||||||
| 	// call the api to get a list of top 5 pools sorted by swaps
 |  | ||||||
| 	topPools, err := h.accountService.FetchTopPools(ctx) |  | ||||||
| 	if err != nil { |  | ||||||
| 		res.FlagSet = append(res.FlagSet, flag_api_error) |  | ||||||
| 		logg.ErrorCtxf(ctx, "failed on FetchTransactions", "error", err) |  | ||||||
| 		return res, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Return if there are no pools
 |  | ||||||
| 	if len(topPools) == 0 { |  | ||||||
| 		return res, nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	data := store.ProcessPools(topPools) |  | ||||||
| 
 |  | ||||||
| 	// Store all Pool data
 |  | ||||||
| 	dataMap := map[storedb.DataTyp]string{ |  | ||||||
| 		storedb.DATA_POOL_NAMES:     data.PoolNames, |  | ||||||
| 		storedb.DATA_POOL_SYMBOLS:   data.PoolSymbols, |  | ||||||
| 		storedb.DATA_POOL_ADDRESSES: data.PoolContractAdrresses, |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Write data entries
 |  | ||||||
| 	for key, value := range dataMap { |  | ||||||
| 		if err := userStore.WriteEntry(ctx, sessionId, key, []byte(value)); err != nil { |  | ||||||
| 			logg.ErrorCtxf(ctx, "Failed to write data entry for sessionId: %s", sessionId, "key", key, "error", err) |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	res.Content = h.ReplaceSeparatorFunc(data.PoolSymbols) |  | ||||||
| 
 |  | ||||||
| 	return res, nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // LoadSwapFromList returns a list of possible vouchers to swap to
 |  | ||||||
| func (h *MenuHandlers) LoadSwapToList(ctx context.Context, sym string, input []byte) (resource.Result, error) { |  | ||||||
| 	var res resource.Result |  | ||||||
| 	sessionId, ok := ctx.Value("SessionId").(string) |  | ||||||
| 	if !ok { |  | ||||||
| 		return res, fmt.Errorf("missing session") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	userStore := h.userdataStore |  | ||||||
| 
 |  | ||||||
| 	// get the active address and symbol
 |  | ||||||
| 	activeAddress, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_ADDRESS) |  | ||||||
| 	if err != nil { |  | ||||||
| 		logg.ErrorCtxf(ctx, "failed to read activeAddress entry with", "key", storedb.DATA_ACTIVE_ADDRESS, "error", err) |  | ||||||
| 		return res, err |  | ||||||
| 	} |  | ||||||
| 	activeSym, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_SYM) |  | ||||||
| 	if err != nil { |  | ||||||
| 		logg.ErrorCtxf(ctx, "failed to read activeSym entry with", "key", storedb.DATA_ACTIVE_SYM, "error", err) |  | ||||||
| 		return res, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	code := codeFromCtx(ctx) |  | ||||||
| 	l := gotext.NewLocale(translationDir, code) |  | ||||||
| 	l.AddDomain("default") |  | ||||||
| 
 |  | ||||||
| 	flag_incorrect_voucher, _ := h.flagManager.GetFlag("flag_incorrect_voucher") |  | ||||||
| 	flag_api_error, _ := h.flagManager.GetFlag("flag_api_error") |  | ||||||
| 
 |  | ||||||
| 	inputStr := string(input) |  | ||||||
| 	if inputStr == "0" { |  | ||||||
| 		return res, nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Get active pool address and symbol or fall back to default
 |  | ||||||
| 	var activePoolAddress []byte |  | ||||||
| 	activePoolAddress, err = userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_POOL_ADDRESS) |  | ||||||
| 	if err != nil { |  | ||||||
| 		if db.IsNotFound(err) { |  | ||||||
| 			defaultPoolAddress := config.DefaultPoolAddress() |  | ||||||
| 			// store the default as the active pool address
 |  | ||||||
| 			err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_POOL_ADDRESS, []byte(defaultPoolAddress)) |  | ||||||
| 			if err != nil { |  | ||||||
| 				logg.ErrorCtxf(ctx, "failed to write default PoolContractAdrress", "key", storedb.DATA_ACTIVE_POOL_ADDRESS, "value", defaultPoolAddress, "error", err) |  | ||||||
| 				return res, err |  | ||||||
| 			} |  | ||||||
| 			activePoolAddress = []byte(defaultPoolAddress) |  | ||||||
| 		} else { |  | ||||||
| 			logg.ErrorCtxf(ctx, "failed to read active PoolContractAdrress", "key", storedb.DATA_ACTIVE_POOL_ADDRESS, "error", err) |  | ||||||
| 			return res, err |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	var activePoolSymbol []byte |  | ||||||
| 	activePoolSymbol, err = userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_POOL_SYM) |  | ||||||
| 	if err != nil { |  | ||||||
| 		if db.IsNotFound(err) { |  | ||||||
| 			defaultPoolSym := config.DefaultPoolName() |  | ||||||
| 			// store the default as the active pool symbol
 |  | ||||||
| 			err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_POOL_SYM, []byte(defaultPoolSym)) |  | ||||||
| 			if err != nil { |  | ||||||
| 				logg.ErrorCtxf(ctx, "failed to write default Pool Symbol", "key", storedb.DATA_ACTIVE_POOL_SYM, "value", defaultPoolSym, "error", err) |  | ||||||
| 				return res, err |  | ||||||
| 			} |  | ||||||
| 			activePoolSymbol = []byte(defaultPoolSym) |  | ||||||
| 		} else { |  | ||||||
| 			logg.ErrorCtxf(ctx, "failed to read active Pool symbol", "key", storedb.DATA_ACTIVE_POOL_SYM, "error", err) |  | ||||||
| 			return res, err |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// call the api using the ActivePoolAddress and ActiveVoucherAddress to check if it is part of the pool
 |  | ||||||
| 	r, err := h.accountService.CheckTokenInPool(ctx, string(activePoolAddress), string(activeAddress)) |  | ||||||
| 	if err != nil { |  | ||||||
| 		res.FlagSet = append(res.FlagSet, flag_api_error) |  | ||||||
| 		logg.ErrorCtxf(ctx, "failed on CheckTokenInPool", "error", err) |  | ||||||
| 		return res, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	logg.InfoCtxf(ctx, "CheckTokenInPool", "response", r, "active_pool_address", string(activePoolAddress), "active_symbol_address", string(activeAddress)) |  | ||||||
| 
 |  | ||||||
| 	if !r.CanSwapFrom { |  | ||||||
| 		res.FlagSet = append(res.FlagSet, flag_incorrect_voucher) |  | ||||||
| 		res.Content = l.Get( |  | ||||||
| 			"%s is not in %s. Please update your voucher and try again.", |  | ||||||
| 			activeSym, |  | ||||||
| 			activePoolSymbol, |  | ||||||
| 		) |  | ||||||
| 		return res, nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	res.FlagReset = append(res.FlagReset, flag_incorrect_voucher) |  | ||||||
| 
 |  | ||||||
| 	// call the api using the activePoolAddress to get a list of SwapToSymbolsData
 |  | ||||||
| 	swapToList, err := h.accountService.GetPoolSwappableVouchers(ctx, string(activePoolAddress)) |  | ||||||
| 	if err != nil { |  | ||||||
| 		res.FlagSet = append(res.FlagSet, flag_api_error) |  | ||||||
| 		logg.ErrorCtxf(ctx, "failed on FetchTransactions", "error", err) |  | ||||||
| 		return res, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	logg.InfoCtxf(ctx, "GetPoolSwappableVouchers", "swapToList", swapToList) |  | ||||||
| 
 |  | ||||||
| 	// Return if there are no vouchers
 |  | ||||||
| 	if len(swapToList) == 0 { |  | ||||||
| 		return res, nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	data := store.ProcessVouchers(swapToList) |  | ||||||
| 
 |  | ||||||
| 	logg.InfoCtxf(ctx, "ProcessVouchers", "data", data) |  | ||||||
| 
 |  | ||||||
| 	// Store all swap_to tokens data
 |  | ||||||
| 	dataMap := map[storedb.DataTyp]string{ |  | ||||||
| 		storedb.DATA_POOL_TO_SYMBOLS:   data.Symbols, |  | ||||||
| 		storedb.DATA_POOL_TO_BALANCES:  data.Balances, |  | ||||||
| 		storedb.DATA_POOL_TO_DECIMALS:  data.Decimals, |  | ||||||
| 		storedb.DATA_POOL_TO_ADDRESSES: data.Addresses, |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	for key, value := range dataMap { |  | ||||||
| 		if err := userStore.WriteEntry(ctx, sessionId, key, []byte(value)); err != nil { |  | ||||||
| 			logg.ErrorCtxf(ctx, "Failed to write data entry for sessionId: %s", sessionId, "key", key, "error", err) |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	res.Content = h.ReplaceSeparatorFunc(data.Symbols) |  | ||||||
| 
 |  | ||||||
| 	return res, nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // SwapMaxLimit returns the max FROM token
 |  | ||||||
| // check if max/tokenDecimals > 0.1 for UX purposes and to prevent swapping of dust values
 |  | ||||||
| func (h *MenuHandlers) SwapMaxLimit(ctx context.Context, sym string, input []byte) (resource.Result, error) { |  | ||||||
| 	var res resource.Result |  | ||||||
| 	sessionId, ok := ctx.Value("SessionId").(string) |  | ||||||
| 	if !ok { |  | ||||||
| 		return res, fmt.Errorf("missing session") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	flag_incorrect_voucher, _ := h.flagManager.GetFlag("flag_incorrect_voucher") |  | ||||||
| 	flag_api_error, _ := h.flagManager.GetFlag("flag_api_error") |  | ||||||
| 	flag_low_swap_amount, _ := h.flagManager.GetFlag("flag_low_swap_amount") |  | ||||||
| 
 |  | ||||||
| 	res.FlagReset = append(res.FlagReset, flag_incorrect_voucher, flag_low_swap_amount) |  | ||||||
| 
 |  | ||||||
| 	inputStr := string(input) |  | ||||||
| 	if inputStr == "0" { |  | ||||||
| 		return res, nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	userStore := h.userdataStore |  | ||||||
| 	metadata, err := store.GetSwapToVoucherData(ctx, userStore, sessionId, inputStr) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return res, fmt.Errorf("failed to retrieve swap to voucher data: %v", err) |  | ||||||
| 	} |  | ||||||
| 	if metadata == nil { |  | ||||||
| 		res.FlagSet = append(res.FlagSet, flag_incorrect_voucher) |  | ||||||
| 		return res, nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	logg.InfoCtxf(ctx, "Metadata from GetSwapToVoucherData:", "metadata", metadata) |  | ||||||
| 
 |  | ||||||
| 	// Store the active swap_to data
 |  | ||||||
| 	if err := store.UpdateSwapToVoucherData(ctx, userStore, sessionId, metadata); err != nil { |  | ||||||
| 		logg.ErrorCtxf(ctx, "failed on UpdateSwapToVoucherData", "error", err) |  | ||||||
| 		return res, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	swapData, err := store.ReadSwapData(ctx, userStore, sessionId) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return res, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// call the api using the ActivePoolAddress, ActiveSwapFromAddress, ActiveSwapToAddress and PublicKey to get the swap max limit
 |  | ||||||
| 	logg.InfoCtxf(ctx, "Call GetSwapFromTokenMaxLimit with:", "ActivePoolAddress", swapData.ActivePoolAddress, "ActiveSwapFromAddress", swapData.ActiveSwapFromAddress, "ActiveSwapToAddress", swapData.ActiveSwapToAddress, "publicKey", swapData.PublicKey) |  | ||||||
| 	r, err := h.accountService.GetSwapFromTokenMaxLimit(ctx, swapData.ActivePoolAddress, swapData.ActiveSwapFromAddress, swapData.ActiveSwapToAddress, swapData.PublicKey) |  | ||||||
| 	if err != nil { |  | ||||||
| 		res.FlagSet = append(res.FlagSet, flag_api_error) |  | ||||||
| 		logg.ErrorCtxf(ctx, "failed on GetSwapFromTokenMaxLimit", "error", err) |  | ||||||
| 		return res, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Scale down the amount
 |  | ||||||
| 	maxAmountStr := store.ScaleDownBalance(r.Max, swapData.ActiveSwapFromDecimal) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return res, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	maxAmountFloat, err := strconv.ParseFloat(maxAmountStr, 64) |  | ||||||
| 	if err != nil { |  | ||||||
| 		logg.ErrorCtxf(ctx, "failed to parse maxAmountStr as float", "value", maxAmountStr, "error", err) |  | ||||||
| 		return res, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Format to 2 decimal places
 |  | ||||||
| 	maxStr := fmt.Sprintf("%.2f", maxAmountFloat) |  | ||||||
| 
 |  | ||||||
| 	if maxAmountFloat < 0.1 { |  | ||||||
| 		// return with low amount flag
 |  | ||||||
| 		res.Content = maxStr |  | ||||||
| 		res.FlagSet = append(res.FlagSet, flag_low_swap_amount) |  | ||||||
| 		return res, nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_SWAP_MAX_AMOUNT, []byte(maxStr)) |  | ||||||
| 	if err != nil { |  | ||||||
| 		logg.ErrorCtxf(ctx, "failed to write swap max amount entry with", "key", storedb.DATA_ACTIVE_SWAP_MAX_AMOUNT, "value", maxStr, "error", err) |  | ||||||
| 		return res, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	res.Content = fmt.Sprintf( |  | ||||||
| 		"Maximum: %s\n\nEnter amount of %s to swap for %s:", |  | ||||||
| 		maxStr, swapData.ActiveSwapFromSym, swapData.ActiveSwapToSym, |  | ||||||
| 	) |  | ||||||
| 
 |  | ||||||
| 	return res, nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // SwapPreview displays the swap preview and estimates
 |  | ||||||
| func (h *MenuHandlers) SwapPreview(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") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	inputStr := string(input) |  | ||||||
| 	if inputStr == "0" { |  | ||||||
| 		return res, nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	flag_invalid_amount, _ := h.flagManager.GetFlag("flag_invalid_amount") |  | ||||||
| 
 |  | ||||||
| 	code := codeFromCtx(ctx) |  | ||||||
| 	l := gotext.NewLocale(translationDir, code) |  | ||||||
| 	l.AddDomain("default") |  | ||||||
| 
 |  | ||||||
| 	userStore := h.userdataStore |  | ||||||
| 
 |  | ||||||
| 	swapData, err := store.ReadSwapPreviewData(ctx, userStore, sessionId) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return res, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	maxValue, err := strconv.ParseFloat(swapData.ActiveSwapMaxAmount, 64) |  | ||||||
| 	if err != nil { |  | ||||||
| 		logg.ErrorCtxf(ctx, "Failed to convert the swapMaxAmount to a float", "error", err) |  | ||||||
| 		return res, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	inputAmount, err := strconv.ParseFloat(inputStr, 64) |  | ||||||
| 	if err != nil || inputAmount > maxValue { |  | ||||||
| 		res.FlagSet = append(res.FlagSet, flag_invalid_amount) |  | ||||||
| 		res.Content = inputStr |  | ||||||
| 		return res, nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Format the amount to 2 decimal places
 |  | ||||||
| 	formattedAmount, err := store.TruncateDecimalString(inputStr, 2) |  | ||||||
| 	if err != nil { |  | ||||||
| 		res.FlagSet = append(res.FlagSet, flag_invalid_amount) |  | ||||||
| 		res.Content = inputStr |  | ||||||
| 		return res, nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	finalAmountStr, err := store.ParseAndScaleAmount(formattedAmount, swapData.ActiveSwapFromDecimal) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return res, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_SWAP_AMOUNT, []byte(finalAmountStr)) |  | ||||||
| 	if err != nil { |  | ||||||
| 		logg.ErrorCtxf(ctx, "failed to write swap amount entry with", "key", storedb.DATA_ACTIVE_SWAP_AMOUNT, "value", finalAmountStr, "error", err) |  | ||||||
| 		return res, err |  | ||||||
| 	} |  | ||||||
| 	// store the user's input amount in the temporary value
 |  | ||||||
| 	err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(inputStr)) |  | ||||||
| 	if err != nil { |  | ||||||
| 		logg.ErrorCtxf(ctx, "failed to write swap amount entry with", "key", storedb.DATA_ACTIVE_SWAP_AMOUNT, "value", finalAmountStr, "error", err) |  | ||||||
| 		return res, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// call the API to get the quote
 |  | ||||||
| 	r, err := h.accountService.GetPoolSwapQuote(ctx, finalAmountStr, swapData.PublicKey, swapData.ActiveSwapFromAddress, swapData.ActivePoolAddress, swapData.ActiveSwapToAddress) |  | ||||||
| 	if err != nil { |  | ||||||
| 		flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") |  | ||||||
| 		res.FlagSet = append(res.FlagSet, flag_api_error) |  | ||||||
| 		res.Content = l.Get("Your request failed. Please try again later.") |  | ||||||
| 		logg.ErrorCtxf(ctx, "failed on poolSwap", "error", err) |  | ||||||
| 		return res, nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Scale down the quoted amount
 |  | ||||||
| 	quoteAmountStr := store.ScaleDownBalance(r.OutValue, swapData.ActiveSwapToDecimal) |  | ||||||
| 	qouteAmount, err := strconv.ParseFloat(quoteAmountStr, 64) |  | ||||||
| 	if err != nil { |  | ||||||
| 		logg.ErrorCtxf(ctx, "failed to parse quoteAmountStr as float", "value", quoteAmountStr, "error", err) |  | ||||||
| 		return res, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Format to 2 decimal places
 |  | ||||||
| 	qouteStr := fmt.Sprintf("%.2f", qouteAmount) |  | ||||||
| 
 |  | ||||||
| 	res.Content = fmt.Sprintf( |  | ||||||
| 		"You will swap:\n%s %s for %s %s:", |  | ||||||
| 		inputStr, swapData.ActiveSwapFromSym, qouteStr, swapData.ActiveSwapToSym, |  | ||||||
| 	) |  | ||||||
| 
 |  | ||||||
| 	return res, nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // InitiateSwap calls the poolSwap and returns a confirmation based on the result.
 |  | ||||||
| func (h *MenuHandlers) InitiateSwap(ctx context.Context, sym string, input []byte) (resource.Result, error) { |  | ||||||
| 	var res resource.Result |  | ||||||
| 	var err error |  | ||||||
| 	sessionId, ok := ctx.Value("SessionId").(string) |  | ||||||
| 	if !ok { |  | ||||||
| 		return res, fmt.Errorf("missing session") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized") |  | ||||||
| 
 |  | ||||||
| 	code := codeFromCtx(ctx) |  | ||||||
| 	l := gotext.NewLocale(translationDir, code) |  | ||||||
| 	l.AddDomain("default") |  | ||||||
| 
 |  | ||||||
| 	userStore := h.userdataStore |  | ||||||
| 
 |  | ||||||
| 	swapData, err := store.ReadSwapPreviewData(ctx, userStore, sessionId) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return res, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	swapAmount, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_SWAP_AMOUNT) |  | ||||||
| 	if err != nil { |  | ||||||
| 		logg.ErrorCtxf(ctx, "failed to read swapAmount entry with", "key", storedb.DATA_ACTIVE_SWAP_AMOUNT, "error", err) |  | ||||||
| 		return res, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	swapAmountStr := string(swapAmount) |  | ||||||
| 
 |  | ||||||
| 	// Call the poolSwap API
 |  | ||||||
| 	r, err := h.accountService.PoolSwap(ctx, swapAmountStr, swapData.PublicKey, swapData.ActiveSwapFromAddress, swapData.ActivePoolAddress, swapData.ActiveSwapToAddress) |  | ||||||
| 	if err != nil { |  | ||||||
| 		flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") |  | ||||||
| 		res.FlagSet = append(res.FlagSet, flag_api_error) |  | ||||||
| 		res.Content = l.Get("Your request failed. Please try again later.") |  | ||||||
| 		logg.ErrorCtxf(ctx, "failed on poolSwap", "error", err) |  | ||||||
| 		return res, nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	trackingId := r.TrackingId |  | ||||||
| 	logg.InfoCtxf(ctx, "poolSwap", "trackingId", trackingId) |  | ||||||
| 
 |  | ||||||
| 	res.Content = l.Get( |  | ||||||
| 		"Your request has been sent. You will receive an SMS when your %s %s has been swapped for %s.", |  | ||||||
| 		swapData.TemporaryValue, |  | ||||||
| 		swapData.ActiveSwapFromSym, |  | ||||||
| 		swapData.ActiveSwapToSym, |  | ||||||
| 	) |  | ||||||
| 
 |  | ||||||
| 	res.FlagReset = append(res.FlagReset, flag_account_authorized) |  | ||||||
| 	return res, nil |  | ||||||
| } |  | ||||||
|  | |||||||
							
								
								
									
										427
									
								
								handlers/application/poolswap.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										427
									
								
								handlers/application/poolswap.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,427 @@ | |||||||
|  | package application | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"fmt" | ||||||
|  | 	"strconv" | ||||||
|  | 
 | ||||||
|  | 	"git.defalsify.org/vise.git/db" | ||||||
|  | 	"git.defalsify.org/vise.git/resource" | ||||||
|  | 	"git.grassecon.net/grassrootseconomics/sarafu-vise/config" | ||||||
|  | 	"git.grassecon.net/grassrootseconomics/sarafu-vise/store" | ||||||
|  | 	storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" | ||||||
|  | 	"gopkg.in/leonelquinteros/gotext.v1" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // GetPools fetches a list of 5 top pools
 | ||||||
|  | func (h *MenuHandlers) GetPools(ctx context.Context, sym string, input []byte) (resource.Result, error) { | ||||||
|  | 	var res resource.Result | ||||||
|  | 	sessionId, ok := ctx.Value("SessionId").(string) | ||||||
|  | 	if !ok { | ||||||
|  | 		return res, fmt.Errorf("missing session") | ||||||
|  | 	} | ||||||
|  | 	userStore := h.userdataStore | ||||||
|  | 
 | ||||||
|  | 	flag_api_error, _ := h.flagManager.GetFlag("flag_api_error") | ||||||
|  | 
 | ||||||
|  | 	// call the api to get a list of top 5 pools sorted by swaps
 | ||||||
|  | 	topPools, err := h.accountService.FetchTopPools(ctx) | ||||||
|  | 	if err != nil { | ||||||
|  | 		res.FlagSet = append(res.FlagSet, flag_api_error) | ||||||
|  | 		logg.ErrorCtxf(ctx, "failed on FetchTransactions", "error", err) | ||||||
|  | 		return res, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Return if there are no pools
 | ||||||
|  | 	if len(topPools) == 0 { | ||||||
|  | 		return res, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	data := store.ProcessPools(topPools) | ||||||
|  | 
 | ||||||
|  | 	// Store all Pool data
 | ||||||
|  | 	dataMap := map[storedb.DataTyp]string{ | ||||||
|  | 		storedb.DATA_POOL_NAMES:     data.PoolNames, | ||||||
|  | 		storedb.DATA_POOL_SYMBOLS:   data.PoolSymbols, | ||||||
|  | 		storedb.DATA_POOL_ADDRESSES: data.PoolContractAdrresses, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Write data entries
 | ||||||
|  | 	for key, value := range dataMap { | ||||||
|  | 		if err := userStore.WriteEntry(ctx, sessionId, key, []byte(value)); err != nil { | ||||||
|  | 			logg.ErrorCtxf(ctx, "Failed to write data entry for sessionId: %s", sessionId, "key", key, "error", err) | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	res.Content = h.ReplaceSeparatorFunc(data.PoolSymbols) | ||||||
|  | 
 | ||||||
|  | 	return res, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // LoadSwapFromList returns a list of possible vouchers to swap to
 | ||||||
|  | func (h *MenuHandlers) LoadSwapToList(ctx context.Context, sym string, input []byte) (resource.Result, error) { | ||||||
|  | 	var res resource.Result | ||||||
|  | 	sessionId, ok := ctx.Value("SessionId").(string) | ||||||
|  | 	if !ok { | ||||||
|  | 		return res, fmt.Errorf("missing session") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	userStore := h.userdataStore | ||||||
|  | 
 | ||||||
|  | 	// get the active address and symbol
 | ||||||
|  | 	activeAddress, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_ADDRESS) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logg.ErrorCtxf(ctx, "failed to read activeAddress entry with", "key", storedb.DATA_ACTIVE_ADDRESS, "error", err) | ||||||
|  | 		return res, err | ||||||
|  | 	} | ||||||
|  | 	activeSym, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_SYM) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logg.ErrorCtxf(ctx, "failed to read activeSym entry with", "key", storedb.DATA_ACTIVE_SYM, "error", err) | ||||||
|  | 		return res, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	code := codeFromCtx(ctx) | ||||||
|  | 	l := gotext.NewLocale(translationDir, code) | ||||||
|  | 	l.AddDomain("default") | ||||||
|  | 
 | ||||||
|  | 	flag_incorrect_voucher, _ := h.flagManager.GetFlag("flag_incorrect_voucher") | ||||||
|  | 	flag_api_error, _ := h.flagManager.GetFlag("flag_api_error") | ||||||
|  | 
 | ||||||
|  | 	inputStr := string(input) | ||||||
|  | 	if inputStr == "0" { | ||||||
|  | 		return res, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Get active pool address and symbol or fall back to default
 | ||||||
|  | 	var activePoolAddress []byte | ||||||
|  | 	activePoolAddress, err = userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_POOL_ADDRESS) | ||||||
|  | 	if err != nil { | ||||||
|  | 		if db.IsNotFound(err) { | ||||||
|  | 			defaultPoolAddress := config.DefaultPoolAddress() | ||||||
|  | 			// store the default as the active pool address
 | ||||||
|  | 			err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_POOL_ADDRESS, []byte(defaultPoolAddress)) | ||||||
|  | 			if err != nil { | ||||||
|  | 				logg.ErrorCtxf(ctx, "failed to write default PoolContractAdrress", "key", storedb.DATA_ACTIVE_POOL_ADDRESS, "value", defaultPoolAddress, "error", err) | ||||||
|  | 				return res, err | ||||||
|  | 			} | ||||||
|  | 			activePoolAddress = []byte(defaultPoolAddress) | ||||||
|  | 		} else { | ||||||
|  | 			logg.ErrorCtxf(ctx, "failed to read active PoolContractAdrress", "key", storedb.DATA_ACTIVE_POOL_ADDRESS, "error", err) | ||||||
|  | 			return res, err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var activePoolSymbol []byte | ||||||
|  | 	activePoolSymbol, err = userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_POOL_SYM) | ||||||
|  | 	if err != nil { | ||||||
|  | 		if db.IsNotFound(err) { | ||||||
|  | 			defaultPoolSym := config.DefaultPoolName() | ||||||
|  | 			// store the default as the active pool symbol
 | ||||||
|  | 			err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_POOL_SYM, []byte(defaultPoolSym)) | ||||||
|  | 			if err != nil { | ||||||
|  | 				logg.ErrorCtxf(ctx, "failed to write default Pool Symbol", "key", storedb.DATA_ACTIVE_POOL_SYM, "value", defaultPoolSym, "error", err) | ||||||
|  | 				return res, err | ||||||
|  | 			} | ||||||
|  | 			activePoolSymbol = []byte(defaultPoolSym) | ||||||
|  | 		} else { | ||||||
|  | 			logg.ErrorCtxf(ctx, "failed to read active Pool symbol", "key", storedb.DATA_ACTIVE_POOL_SYM, "error", err) | ||||||
|  | 			return res, err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// call the api using the ActivePoolAddress and ActiveVoucherAddress to check if it is part of the pool
 | ||||||
|  | 	r, err := h.accountService.CheckTokenInPool(ctx, string(activePoolAddress), string(activeAddress)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		res.FlagSet = append(res.FlagSet, flag_api_error) | ||||||
|  | 		logg.ErrorCtxf(ctx, "failed on CheckTokenInPool", "error", err) | ||||||
|  | 		return res, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	logg.InfoCtxf(ctx, "CheckTokenInPool", "response", r, "active_pool_address", string(activePoolAddress), "active_symbol_address", string(activeAddress)) | ||||||
|  | 
 | ||||||
|  | 	if !r.CanSwapFrom { | ||||||
|  | 		res.FlagSet = append(res.FlagSet, flag_incorrect_voucher) | ||||||
|  | 		res.Content = l.Get( | ||||||
|  | 			"%s is not in %s. Please update your voucher and try again.", | ||||||
|  | 			activeSym, | ||||||
|  | 			activePoolSymbol, | ||||||
|  | 		) | ||||||
|  | 		return res, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	res.FlagReset = append(res.FlagReset, flag_incorrect_voucher) | ||||||
|  | 
 | ||||||
|  | 	// call the api using the activePoolAddress to get a list of SwapToSymbolsData
 | ||||||
|  | 	swapToList, err := h.accountService.GetPoolSwappableVouchers(ctx, string(activePoolAddress)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		res.FlagSet = append(res.FlagSet, flag_api_error) | ||||||
|  | 		logg.ErrorCtxf(ctx, "failed on FetchTransactions", "error", err) | ||||||
|  | 		return res, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	logg.InfoCtxf(ctx, "GetPoolSwappableVouchers", "swapToList", swapToList) | ||||||
|  | 
 | ||||||
|  | 	// Return if there are no vouchers
 | ||||||
|  | 	if len(swapToList) == 0 { | ||||||
|  | 		return res, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	data := store.ProcessVouchers(swapToList) | ||||||
|  | 
 | ||||||
|  | 	logg.InfoCtxf(ctx, "ProcessVouchers", "data", data) | ||||||
|  | 
 | ||||||
|  | 	// Store all swap_to tokens data
 | ||||||
|  | 	dataMap := map[storedb.DataTyp]string{ | ||||||
|  | 		storedb.DATA_POOL_TO_SYMBOLS:   data.Symbols, | ||||||
|  | 		storedb.DATA_POOL_TO_BALANCES:  data.Balances, | ||||||
|  | 		storedb.DATA_POOL_TO_DECIMALS:  data.Decimals, | ||||||
|  | 		storedb.DATA_POOL_TO_ADDRESSES: data.Addresses, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for key, value := range dataMap { | ||||||
|  | 		if err := userStore.WriteEntry(ctx, sessionId, key, []byte(value)); err != nil { | ||||||
|  | 			logg.ErrorCtxf(ctx, "Failed to write data entry for sessionId: %s", sessionId, "key", key, "error", err) | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	res.Content = h.ReplaceSeparatorFunc(data.Symbols) | ||||||
|  | 
 | ||||||
|  | 	return res, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SwapMaxLimit returns the max FROM token
 | ||||||
|  | // check if max/tokenDecimals > 0.1 for UX purposes and to prevent swapping of dust values
 | ||||||
|  | func (h *MenuHandlers) SwapMaxLimit(ctx context.Context, sym string, input []byte) (resource.Result, error) { | ||||||
|  | 	var res resource.Result | ||||||
|  | 	sessionId, ok := ctx.Value("SessionId").(string) | ||||||
|  | 	if !ok { | ||||||
|  | 		return res, fmt.Errorf("missing session") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	flag_incorrect_voucher, _ := h.flagManager.GetFlag("flag_incorrect_voucher") | ||||||
|  | 	flag_api_error, _ := h.flagManager.GetFlag("flag_api_error") | ||||||
|  | 	flag_low_swap_amount, _ := h.flagManager.GetFlag("flag_low_swap_amount") | ||||||
|  | 
 | ||||||
|  | 	res.FlagReset = append(res.FlagReset, flag_incorrect_voucher, flag_low_swap_amount) | ||||||
|  | 
 | ||||||
|  | 	inputStr := string(input) | ||||||
|  | 	if inputStr == "0" { | ||||||
|  | 		return res, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	userStore := h.userdataStore | ||||||
|  | 	metadata, err := store.GetSwapToVoucherData(ctx, userStore, sessionId, inputStr) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return res, fmt.Errorf("failed to retrieve swap to voucher data: %v", err) | ||||||
|  | 	} | ||||||
|  | 	if metadata == nil { | ||||||
|  | 		res.FlagSet = append(res.FlagSet, flag_incorrect_voucher) | ||||||
|  | 		return res, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	logg.InfoCtxf(ctx, "Metadata from GetSwapToVoucherData:", "metadata", metadata) | ||||||
|  | 
 | ||||||
|  | 	// Store the active swap_to data
 | ||||||
|  | 	if err := store.UpdateSwapToVoucherData(ctx, userStore, sessionId, metadata); err != nil { | ||||||
|  | 		logg.ErrorCtxf(ctx, "failed on UpdateSwapToVoucherData", "error", err) | ||||||
|  | 		return res, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	swapData, err := store.ReadSwapData(ctx, userStore, sessionId) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return res, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// call the api using the ActivePoolAddress, ActiveSwapFromAddress, ActiveSwapToAddress and PublicKey to get the swap max limit
 | ||||||
|  | 	logg.InfoCtxf(ctx, "Call GetSwapFromTokenMaxLimit with:", "ActivePoolAddress", swapData.ActivePoolAddress, "ActiveSwapFromAddress", swapData.ActiveSwapFromAddress, "ActiveSwapToAddress", swapData.ActiveSwapToAddress, "publicKey", swapData.PublicKey) | ||||||
|  | 	r, err := h.accountService.GetSwapFromTokenMaxLimit(ctx, swapData.ActivePoolAddress, swapData.ActiveSwapFromAddress, swapData.ActiveSwapToAddress, swapData.PublicKey) | ||||||
|  | 	if err != nil { | ||||||
|  | 		res.FlagSet = append(res.FlagSet, flag_api_error) | ||||||
|  | 		logg.ErrorCtxf(ctx, "failed on GetSwapFromTokenMaxLimit", "error", err) | ||||||
|  | 		return res, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Scale down the amount
 | ||||||
|  | 	maxAmountStr := store.ScaleDownBalance(r.Max, swapData.ActiveSwapFromDecimal) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return res, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	maxAmountFloat, err := strconv.ParseFloat(maxAmountStr, 64) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logg.ErrorCtxf(ctx, "failed to parse maxAmountStr as float", "value", maxAmountStr, "error", err) | ||||||
|  | 		return res, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Format to 2 decimal places
 | ||||||
|  | 	maxStr := fmt.Sprintf("%.2f", maxAmountFloat) | ||||||
|  | 
 | ||||||
|  | 	if maxAmountFloat < 0.1 { | ||||||
|  | 		// return with low amount flag
 | ||||||
|  | 		res.Content = maxStr | ||||||
|  | 		res.FlagSet = append(res.FlagSet, flag_low_swap_amount) | ||||||
|  | 		return res, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_SWAP_MAX_AMOUNT, []byte(maxStr)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logg.ErrorCtxf(ctx, "failed to write swap max amount entry with", "key", storedb.DATA_ACTIVE_SWAP_MAX_AMOUNT, "value", maxStr, "error", err) | ||||||
|  | 		return res, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	res.Content = fmt.Sprintf( | ||||||
|  | 		"Maximum: %s\n\nEnter amount of %s to swap for %s:", | ||||||
|  | 		maxStr, swapData.ActiveSwapFromSym, swapData.ActiveSwapToSym, | ||||||
|  | 	) | ||||||
|  | 
 | ||||||
|  | 	return res, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SwapPreview displays the swap preview and estimates
 | ||||||
|  | func (h *MenuHandlers) SwapPreview(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") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	inputStr := string(input) | ||||||
|  | 	if inputStr == "0" { | ||||||
|  | 		return res, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	flag_invalid_amount, _ := h.flagManager.GetFlag("flag_invalid_amount") | ||||||
|  | 
 | ||||||
|  | 	code := codeFromCtx(ctx) | ||||||
|  | 	l := gotext.NewLocale(translationDir, code) | ||||||
|  | 	l.AddDomain("default") | ||||||
|  | 
 | ||||||
|  | 	userStore := h.userdataStore | ||||||
|  | 
 | ||||||
|  | 	swapData, err := store.ReadSwapPreviewData(ctx, userStore, sessionId) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return res, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	maxValue, err := strconv.ParseFloat(swapData.ActiveSwapMaxAmount, 64) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logg.ErrorCtxf(ctx, "Failed to convert the swapMaxAmount to a float", "error", err) | ||||||
|  | 		return res, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	inputAmount, err := strconv.ParseFloat(inputStr, 64) | ||||||
|  | 	if err != nil || inputAmount > maxValue { | ||||||
|  | 		res.FlagSet = append(res.FlagSet, flag_invalid_amount) | ||||||
|  | 		res.Content = inputStr | ||||||
|  | 		return res, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Format the amount to 2 decimal places
 | ||||||
|  | 	formattedAmount, err := store.TruncateDecimalString(inputStr, 2) | ||||||
|  | 	if err != nil { | ||||||
|  | 		res.FlagSet = append(res.FlagSet, flag_invalid_amount) | ||||||
|  | 		res.Content = inputStr | ||||||
|  | 		return res, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	finalAmountStr, err := store.ParseAndScaleAmount(formattedAmount, swapData.ActiveSwapFromDecimal) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return res, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_SWAP_AMOUNT, []byte(finalAmountStr)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logg.ErrorCtxf(ctx, "failed to write swap amount entry with", "key", storedb.DATA_ACTIVE_SWAP_AMOUNT, "value", finalAmountStr, "error", err) | ||||||
|  | 		return res, err | ||||||
|  | 	} | ||||||
|  | 	// store the user's input amount in the temporary value
 | ||||||
|  | 	err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(inputStr)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logg.ErrorCtxf(ctx, "failed to write swap amount entry with", "key", storedb.DATA_ACTIVE_SWAP_AMOUNT, "value", finalAmountStr, "error", err) | ||||||
|  | 		return res, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// call the API to get the quote
 | ||||||
|  | 	r, err := h.accountService.GetPoolSwapQuote(ctx, finalAmountStr, swapData.PublicKey, swapData.ActiveSwapFromAddress, swapData.ActivePoolAddress, swapData.ActiveSwapToAddress) | ||||||
|  | 	if err != nil { | ||||||
|  | 		flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") | ||||||
|  | 		res.FlagSet = append(res.FlagSet, flag_api_error) | ||||||
|  | 		res.Content = l.Get("Your request failed. Please try again later.") | ||||||
|  | 		logg.ErrorCtxf(ctx, "failed on poolSwap", "error", err) | ||||||
|  | 		return res, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Scale down the quoted amount
 | ||||||
|  | 	quoteAmountStr := store.ScaleDownBalance(r.OutValue, swapData.ActiveSwapToDecimal) | ||||||
|  | 	qouteAmount, err := strconv.ParseFloat(quoteAmountStr, 64) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logg.ErrorCtxf(ctx, "failed to parse quoteAmountStr as float", "value", quoteAmountStr, "error", err) | ||||||
|  | 		return res, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Format to 2 decimal places
 | ||||||
|  | 	qouteStr := fmt.Sprintf("%.2f", qouteAmount) | ||||||
|  | 
 | ||||||
|  | 	res.Content = fmt.Sprintf( | ||||||
|  | 		"You will swap:\n%s %s for %s %s:", | ||||||
|  | 		inputStr, swapData.ActiveSwapFromSym, qouteStr, swapData.ActiveSwapToSym, | ||||||
|  | 	) | ||||||
|  | 
 | ||||||
|  | 	return res, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // InitiateSwap calls the poolSwap and returns a confirmation based on the result.
 | ||||||
|  | func (h *MenuHandlers) InitiateSwap(ctx context.Context, sym string, input []byte) (resource.Result, error) { | ||||||
|  | 	var res resource.Result | ||||||
|  | 	var err error | ||||||
|  | 	sessionId, ok := ctx.Value("SessionId").(string) | ||||||
|  | 	if !ok { | ||||||
|  | 		return res, fmt.Errorf("missing session") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized") | ||||||
|  | 
 | ||||||
|  | 	code := codeFromCtx(ctx) | ||||||
|  | 	l := gotext.NewLocale(translationDir, code) | ||||||
|  | 	l.AddDomain("default") | ||||||
|  | 
 | ||||||
|  | 	userStore := h.userdataStore | ||||||
|  | 
 | ||||||
|  | 	swapData, err := store.ReadSwapPreviewData(ctx, userStore, sessionId) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return res, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	swapAmount, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_SWAP_AMOUNT) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logg.ErrorCtxf(ctx, "failed to read swapAmount entry with", "key", storedb.DATA_ACTIVE_SWAP_AMOUNT, "error", err) | ||||||
|  | 		return res, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	swapAmountStr := string(swapAmount) | ||||||
|  | 
 | ||||||
|  | 	// Call the poolSwap API
 | ||||||
|  | 	r, err := h.accountService.PoolSwap(ctx, swapAmountStr, swapData.PublicKey, swapData.ActiveSwapFromAddress, swapData.ActivePoolAddress, swapData.ActiveSwapToAddress) | ||||||
|  | 	if err != nil { | ||||||
|  | 		flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") | ||||||
|  | 		res.FlagSet = append(res.FlagSet, flag_api_error) | ||||||
|  | 		res.Content = l.Get("Your request failed. Please try again later.") | ||||||
|  | 		logg.ErrorCtxf(ctx, "failed on poolSwap", "error", err) | ||||||
|  | 		return res, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	trackingId := r.TrackingId | ||||||
|  | 	logg.InfoCtxf(ctx, "poolSwap", "trackingId", trackingId) | ||||||
|  | 
 | ||||||
|  | 	res.Content = l.Get( | ||||||
|  | 		"Your request has been sent. You will receive an SMS when your %s %s has been swapped for %s.", | ||||||
|  | 		swapData.TemporaryValue, | ||||||
|  | 		swapData.ActiveSwapFromSym, | ||||||
|  | 		swapData.ActiveSwapToSym, | ||||||
|  | 	) | ||||||
|  | 
 | ||||||
|  | 	res.FlagReset = append(res.FlagReset, flag_account_authorized) | ||||||
|  | 	return res, nil | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user