Skip to content

Commit

Permalink
Wallet provide tokens value as a float without floating point roundin…
Browse files Browse the repository at this point in the history
…g point penelty. (#381)
  • Loading branch information
bartossh authored Mar 5, 2024
1 parent 52c2018 commit 3316617
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 29 deletions.
42 changes: 14 additions & 28 deletions src/cmd/wallet/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,6 @@ const (
actionReadAddress
)

const (
currency = "PRIMUS"
suplementaryCurrency = "SECUNDUS"
)

const pauseDuration = time.Second * 2

const usage = `Wallet CLI tool allows to create a new Wallet or act on the local Wallet by using keys from different formats and transforming them between formats.
Expand Down Expand Up @@ -274,13 +269,6 @@ func runTransactionOps(cfg fileoperations.Config, nodeURL string) error {
return fmt.Errorf("cannot read wallet %s", cfg.WalletPath)
}

pterm.Info.Printf(
"Please note that %s [ %s ] = 1 [ %s ]\n",
spice.GetSientific(spice.MaxAmoutnPerSupplementaryCurrency),
suplementaryCurrency, currency,
)
fmt.Println("")

options := []string{"Send tokens", "Check balance", "Read Transactions", "Quit"}

for {
Expand All @@ -289,35 +277,33 @@ func runTransactionOps(cfg fileoperations.Config, nodeURL string) error {
switch selectedOption {
case "Send tokens":
receiver, _ := pterm.DefaultInteractiveTextInput.Show("Provide receiver public wallet address")
spiceStr, _ := pterm.DefaultInteractiveTextInput.Show(fmt.Sprintf("Provide [ %s ] amount", currency))
spiceVal, err := strconv.Atoi(spiceStr)
if err != nil || spiceVal < 0 {
printError(fmt.Errorf("token [ %s ] can only be provided as a positive integer", currency))
subject, _ := pterm.DefaultInteractiveTextInput.Show("Provide the subject")
if subject == "" {
printError(errors.New("subject cannot be empty"))
continue
}
suplStr, _ := pterm.DefaultInteractiveTextInput.Show(fmt.Sprintf("Provide [ %s ] amount", suplementaryCurrency))
suplVal, err := strconv.Atoi(suplStr)
if err != nil || suplVal < 0 {
printError(fmt.Errorf("token [ %s ] can only be provided as a positive integer", suplementaryCurrency))
value, _ := pterm.DefaultInteractiveTextInput.Show("Provide amount of tokans")
v, err := strconv.ParseFloat(value, 64)
if err != nil {
printError(err)
continue
}
subject, _ := pterm.DefaultInteractiveTextInput.Show("Transfer subject")
if subject == "" {
printError(errors.New("subject cannot be empty"))
if v == 0.0 {
printError(errors.New("transfer value canot be 0"))
continue
}
melange := spice.FromFloat(v)
result, _ := pterm.DefaultInteractiveConfirm.Show(
fmt.Sprintf(
"Are you sure you want to transfer [ %v %s ][ %v %s ] to [ %s ].\n",
spiceVal, currency, suplVal, suplementaryCurrency, receiver,
"Are you sure you want to transfer [ %s ] tokans to [ %s ].\n",
melange.String(), receiver,
),
)
pterm.Println()
if !result {
printWarning("Transaction has been rejected.")
continue
}
melange := spice.New(uint64(spiceVal), uint64(suplVal))
spinnerInfo, _ := pterm.DefaultSpinner.Start("Sending transaction ...")
time.Sleep(pauseDuration)
if err := c.ProposeTransaction(ctx, receiver, subject, melange, []byte{}); err != nil {
Expand Down Expand Up @@ -366,12 +352,12 @@ func runTransactionOps(cfg fileoperations.Config, nodeURL string) error {
continue
}
tableData := pterm.TableData{
{"Subject", "From", "To", "Transfer", "Data Length", "Time"},
{"Subject", "From", "To", "Transfer", "Time"},
}
for _, trx := range transactions {
tableData = append(tableData, []string{
trx.Subject, trx.IssuerAddress, trx.ReceiverAddress,
trx.Spice.String(), fmt.Sprintf("%v", len(trx.Data)), trx.CreatedAt.UTC().Format("2006-01-02T15:04:05"),
trx.Spice.String(), trx.CreatedAt.UTC().Format("2006-01-02T15:04:05"),
})
}

Expand Down
38 changes: 37 additions & 1 deletion src/spice/spice.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"math"
"strconv"
"strings"

msgpackv2 "github.com/shamaton/msgpack/v2"
Expand All @@ -24,6 +25,32 @@ var (
ErrNoSufficientFounds = errors.New("no sufficient founds to process transaction")
)

func convertFloatToInt(d float64) (int, int) {
intPart := int(d)

parts := strings.SplitN(fmt.Sprintf("%v", d), ".", 2)
if len(parts) < 2 {
return intPart, 0
}
p := parts[1]

var isPassedLeading bool
var buf strings.Builder
for i := 0; i < 18; i++ {
if i >= len(p) {
buf.WriteRune('0')
continue
}
if p[i] != '0' || isPassedLeading {
buf.WriteByte(p[i])
isPassedLeading = true
}
}

fractionalPart, _ := strconv.Atoi(buf.String())
return intPart, fractionalPart
}

func GetSientific(v uint64) string {
var zeros int
for v%10 == 0 {
Expand All @@ -40,7 +67,7 @@ type Melange struct {
SupplementaryCurrency uint64 `yaml:"supplementary_currency" msgpack:"supplementary_currency"`
}

// New creates new spice Melange from given currency and supplementary currency values.
// New creates a new spice Melange from given currency and supplementary currency values.
func New(currency, supplementaryCurrency uint64) Melange {
if supplementaryCurrency >= MaxAmoutnPerSupplementaryCurrency {
currency += 1
Expand All @@ -52,6 +79,15 @@ func New(currency, supplementaryCurrency uint64) Melange {
}
}

// From float crates a new spice Melange from floating point number.
func FromFloat(n float64) Melange {
if n <= 0.0 {
return Melange{}
}
cur, supl := convertFloatToInt(n)
return New(uint64(cur), uint64(supl))
}

// Supply supplies spice of the given amount from the source to the entity.
func (m *Melange) Supply(amount Melange) error {
mCp := m.Clone()
Expand Down
34 changes: 34 additions & 0 deletions src/spice/spice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,37 @@ func TestPrintGetScientific(t *testing.T) {
})
}
}

func TestFromFloat(t *testing.T) {
cases := []struct {
expected string
given float64
}{
{"1.0", 1.0},
{"1.1", 1.1},
{"10.1", 10.10},
{"100.1", 100.1},
{"1234.1", 1234.1},
{"0.111", 0.111},
{"1.123", 1.123},
{"1.999", 1.999},
{"1.9", 1.9000000},
{"1.9", 1.900000000000000000000},
{"1.009", 1.009},
{"1.0123", 1.0123},
{"1.000001001001", 1.000001001001},
{"1.000001001001", 1.00000100100100000},
{"1.009012301", 1.009012301},
{"10101.009012301", 10101.009012301},
{"11101.009012301", 11101.009012301},
{"22202.00901", 22202.00901},
}

for _, c := range cases {
t.Run(fmt.Sprintf("from float test case %v", c), func(t *testing.T) {
s := FromFloat(c.given)
fmt.Printf("%v %s, %s\n", c.given, c.expected, s.String())
assert.Equal(t, s.String(), c.expected)
})
}
}

0 comments on commit 3316617

Please sign in to comment.