bavix / laravel-wallet

It's easy to work with a virtual wallet
https://bavix.github.io/laravel-wallet/
MIT License
1.12k stars 223 forks source link

Inconsitent Value #660

Closed oasin closed 1 year ago

oasin commented 1 year ago

I download the swap package

tried to exchange from wallet 1 to wallet 2

the exchange rate between wallet 1 to wallet 2 is in decimal value.

After the exchange is done, decimal values ( 0.004636) are inserted to the transfer and transaction table while wallet 2 balance will remain 0.0000

From your example try.

private array $rates = [ 'USD' => [ 'BTC' => '0.000045', ], ];

rez1dent3 commented 1 year ago

Hello. Can not understand anything. What "decimal_places" value do you have for these wallets? Need details.

oasin commented 1 year ago

8 decimal places.

oasin commented 1 year ago
        $usdwallet = $user->getWallet('usd');
        $btcWallet = $user->getWallet('btc');
        $exchange = $usdwallet->exchange($btcWallet, '100');

I want to convert 100 USD to BTC with a conversion rate of 1 USD = 0.000045 BTC

When I do this it only reflects in the Transaction table and Transfer table, perhaps $btcWallet remains 0 and no changes.

rez1dent3 commented 1 year ago

Thanks for the example. ~I'll look at it on the weekend. There's too much work right now~

Wrote a unit test, it passes: https://github.com/bavix/laravel-wallet/commit/45ffe2e0a4ed9b9d1c1843e1cd5ac846ab1f5078

    $exchange = $usdwallet->exchange($btcWallet, '100');

Also, I want to note that you are transferring not $100, but $1.

rez1dent3 commented 1 year ago

@oasin jfyi

oasin commented 1 year ago

I wrote a new Trait CanExchangeFloat

so I did this


//Get exchange rate 
        $rate = app(ExchangeServiceInterface::class)->convertTo(
                $castService->getWallet($this)->getCurrencyAttribute(),
                $castService->getWallet($to)->currency,
                1
            );

            //change value to decimal float
            $decimalPlacesValue = app(CastServiceInterface::class)->getWallet($this)->decimal_places;
            $decimalPlaces = $mathService->powTen($decimalPlacesValue);
            $rate = $mathService->round($mathService->mul($rate, $decimalPlaces, $decimalPlacesValue));
rez1dent3 commented 1 year ago

@oasin There is a mantissa problem in numerical methods. But I don't see any problems with the exchange method. I provided an example.

rez1dent3 commented 1 year ago

@oasin I don't see any problems. I'm removing the "bug" tag.

oasin commented 1 year ago

Hello @rez1dent3, did you also try the above trait? from the Test you added there is a 10000000000 value, this is unusual :(

rez1dent3 commented 1 year ago

Hello. With decimal_places=8, the integer value in the database will just be 10000000000

100 * 10^8 = 100[00_000_000]

The package stores information in integers. Now I will describe your case:

Data wallets:
USD. decimal_places=2
BTC. decimal_places=8

100$ => 100[00]
Exchange Rate USDBTC = 0.000045 

(10000 * 0.000045)/10^8 = 0.45/10^8 BTC => ~0BTC
In the database we will write the value = cast integer(0.45)

This is the expected result for the package.


Now let's take a closer look at the situation when decimal_places are the same.

Data wallets:
USD. decimal_places=8
BTC. decimal_places=8

100$ => 100[00_000_000]
Exchange Rate USDBTC = 0.000045 

(10000000000 * 0.000045)/10^8 = 450000/10^8 BTC => 0.0045BTC
In the database we will write the value = cast integer(450000)
oasin commented 1 year ago

Thanks for the explanation. this is correct