Skip to content

Commit a5592f8

Browse files
authored
fix: decimals precision (#22)
* fix: decimals errors * fix: decimals * test: add some numbers to test
1 parent 57af68a commit a5592f8

4 files changed

Lines changed: 799 additions & 31 deletions

File tree

packages/sdk/src/mintlayer-connect-sdk.ts

Lines changed: 44 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ function stringToUint8Array(str: string): Uint8Array {
6666
return new TextEncoder().encode(str);
6767
}
6868

69-
function atomsToDecimal(atoms: string | number, decimals: number): string {
69+
export function atomsToDecimal(atoms: string | number, decimals: number): string {
7070
const atomsStr = atoms.toString();
7171
const atomsLength = atomsStr.length;
7272

@@ -87,6 +87,13 @@ function atomsToDecimal(atoms: string | number, decimals: number): string {
8787
return fractionalPart === '' ? integerPart : `${integerPart}.${fractionalPart}`;
8888
}
8989

90+
export function decimalsToAtoms(value: string | number, decimals: number): bigint {
91+
const [intPart, fracPart = ""] = value.toString().split(".");
92+
const paddedFrac = (fracPart + "0".repeat(decimals)).slice(0, decimals);
93+
const full = intPart + paddedFrac;
94+
return BigInt(full);
95+
}
96+
9097
type Address = {
9198
[key: string]: {
9299
receiving: string[];
@@ -1355,12 +1362,12 @@ class Client {
13551362
fee = token_change_authority_fee(block_height, this.network === 'mainnet' ? Network.Mainnet : Network.Testnet);
13561363
return BigInt(fee.atoms());
13571364
case 'ChangeMetadataUri':
1358-
return BigInt(50 * Math.pow(10, 11));
1365+
return decimalsToAtoms(50, 11);
13591366
case 'FreezeToken':
13601367
fee = token_freeze_fee(block_height, this.network === 'mainnet' ? Network.Mainnet : Network.Testnet);
13611368
return BigInt(fee.atoms());
13621369
case 'UnfreezeToken':
1363-
return BigInt(50 * Math.pow(10, 11));
1370+
return decimalsToAtoms(50, 11);
13641371
case 'DataDeposit':
13651372
fee = data_deposit_fee(block_height, this.network === 'mainnet' ? Network.Mainnet : Network.Testnet);
13661373
return BigInt(fee.atoms());
@@ -1396,13 +1403,13 @@ class Client {
13961403
const { token_id, token_details } = params;
13971404

13981405
if (token_details) {
1399-
input_amount_token_req += BigInt(params.amount! * Math.pow(10, token_details.number_of_decimals));
1406+
input_amount_token_req += decimalsToAtoms(params.amount!,token_details.number_of_decimals);
14001407
send_token = {
14011408
token_id,
14021409
number_of_decimals: token_details.number_of_decimals,
14031410
};
14041411
} else {
1405-
input_amount_coin_req += BigInt(params.amount! * Math.pow(10, 11));
1412+
input_amount_coin_req += decimalsToAtoms(params.amount!, 11);
14061413
}
14071414

14081415
outputs.push({
@@ -1418,13 +1425,13 @@ class Client {
14181425
? {
14191426
amount: {
14201427
decimal: params.amount!.toString(),
1421-
atoms: (params.amount! * Math.pow(10, token_details.number_of_decimals)).toString(),
1428+
atoms: decimalsToAtoms(params.amount!, token_details.number_of_decimals).toString(),
14221429
},
14231430
}
14241431
: {
14251432
amount: {
14261433
decimal: params.amount!.toString(),
1427-
atoms: (params.amount! * Math.pow(10, 11)).toString(),
1434+
atoms: decimalsToAtoms(params.amount!, 11).toString(),
14281435
},
14291436
}),
14301437
},
@@ -1435,13 +1442,13 @@ class Client {
14351442
const { token_id, token_details } = params;
14361443

14371444
if (token_details) {
1438-
input_amount_token_req += BigInt(params.amount! * Math.pow(10, token_details.number_of_decimals));
1445+
input_amount_token_req += decimalsToAtoms(params.amount!, token_details.number_of_decimals);
14391446
send_token = {
14401447
token_id,
14411448
number_of_decimals: token_details.number_of_decimals,
14421449
};
14431450
} else {
1444-
input_amount_coin_req += BigInt(params.amount! * Math.pow(10, 11));
1451+
input_amount_coin_req += decimalsToAtoms(params.amount!,11);
14451452
}
14461453

14471454
outputs.push({
@@ -1455,7 +1462,7 @@ class Client {
14551462
}),
14561463
amount: {
14571464
decimal: params.amount!.toString(),
1458-
atoms: (params.amount! * Math.pow(10, 11)).toString(),
1465+
atoms: decimalsToAtoms(params.amount!, 11).toString(),
14591466
},
14601467
},
14611468
});
@@ -1472,7 +1479,7 @@ class Client {
14721479
total_supply = {
14731480
type: 'Fixed',
14741481
amount: {
1475-
atoms: (params.supply_amount! * Math.pow(10, params.number_of_decimals!)).toString(),
1482+
atoms: decimalsToAtoms(params.supply_amount!, params.number_of_decimals!).toString(),
14761483
decimal: params.supply_amount!.toString(),
14771484
},
14781485
};
@@ -1538,7 +1545,7 @@ class Client {
15381545

15391546
if (type === 'MintToken') {
15401547
const amount = {
1541-
atoms: (params.amount! * Math.pow(10, params.token_details!.number_of_decimals)).toString(),
1548+
atoms: decimalsToAtoms(params.amount!, params.token_details!.number_of_decimals).toString(),
15421549
decimal: params.amount!.toString(),
15431550
};
15441551

@@ -1573,7 +1580,7 @@ class Client {
15731580
const token_id = params.token_id;
15741581
const token_details = params.token_details;
15751582

1576-
input_amount_token_req += BigInt(params.amount! * Math.pow(10, token_details!.number_of_decimals));
1583+
input_amount_token_req += decimalsToAtoms(params.amount!, token_details!.number_of_decimals);
15771584
send_token = {
15781585
token_id,
15791586
number_of_decimals: token_details!.number_of_decimals,
@@ -1693,8 +1700,8 @@ class Client {
16931700
if (type === 'DelegateStaking') {
16941701
const { delegation_id, amount } = params;
16951702

1696-
const amount_atoms = amount! * Math.pow(10, 11);
1697-
input_amount_coin_req += BigInt(amount! * Math.pow(10, 11));
1703+
const amount_atoms = decimalsToAtoms(amount!, 11);
1704+
input_amount_coin_req += decimalsToAtoms(amount!, 11);
16981705

16991706
outputs.push({
17001707
type: 'DelegateStaking',
@@ -1709,7 +1716,7 @@ class Client {
17091716
if (type === 'DelegationWithdraw') {
17101717
const { delegation_id, amount, delegation_details } = params;
17111718

1712-
const amount_atoms = amount! * Math.pow(10, 11);
1719+
const amount_atoms = decimalsToAtoms(amount!, 11);
17131720

17141721
inputs.push({
17151722
input: {
@@ -1753,9 +1760,9 @@ class Client {
17531760
} = params;
17541761

17551762
if (give_token === 'Coin') {
1756-
input_amount_coin_req += BigInt(give_amount! * Math.pow(10, 11));
1763+
input_amount_coin_req += decimalsToAtoms(give_amount!, 11);
17571764
} else if (give_token_details) {
1758-
input_amount_token_req += BigInt(give_amount! * Math.pow(10, give_token_details.number_of_decimals));
1765+
input_amount_token_req += decimalsToAtoms(give_amount!, give_token_details.number_of_decimals);
17591766
send_token = {
17601767
token_id: give_token,
17611768
number_of_decimals: give_token_details.number_of_decimals,
@@ -1770,27 +1777,27 @@ class Client {
17701777
ask_currency: ask_token === 'Coin' ? { type: 'Coin' } : { token_id: ask_token, type: 'TokenV1' },
17711778
ask_balance: {
17721779
atoms: ask_token_details
1773-
? (ask_amount! * Math.pow(10, ask_token_details.number_of_decimals)).toString()
1774-
: (ask_amount! * Math.pow(10, 11)).toString(),
1780+
? decimalsToAtoms(ask_amount!, ask_token_details.number_of_decimals).toString()
1781+
: decimalsToAtoms(ask_amount!, 11).toString(),
17751782
decimal: ask_amount!.toString(),
17761783
},
17771784
initially_asked: {
17781785
atoms: ask_token_details
1779-
? (ask_amount! * Math.pow(10, ask_token_details.number_of_decimals)).toString()
1780-
: (ask_amount! * Math.pow(10, 11)).toString(),
1786+
? decimalsToAtoms(ask_amount!, ask_token_details.number_of_decimals).toString()
1787+
: decimalsToAtoms(ask_amount!, 11).toString(),
17811788
decimal: ask_amount!.toString(),
17821789
},
17831790
give_currency: give_token === 'Coin' ? { type: 'Coin' } : { token_id: give_token, type: 'TokenV1' },
17841791
give_balance: {
17851792
atoms: give_token_details
1786-
? (give_amount! * Math.pow(10, give_token_details.number_of_decimals)).toString()
1787-
: (give_amount! * Math.pow(10, 11)).toString(),
1793+
? decimalsToAtoms(give_amount!, give_token_details.number_of_decimals).toString()
1794+
: decimalsToAtoms(give_amount!, 11).toString(),
17881795
decimal: give_amount!.toString(),
17891796
},
17901797
initially_given: {
17911798
atoms: give_token_details
1792-
? (give_amount! * Math.pow(10, give_token_details.number_of_decimals)).toString()
1793-
: (give_amount! * Math.pow(10, 11)).toString(),
1799+
? decimalsToAtoms(give_amount!, give_token_details.number_of_decimals).toString()
1800+
: decimalsToAtoms(give_amount!, 11).toString(),
17941801
decimal: give_amount!.toString(),
17951802
},
17961803
});
@@ -1860,8 +1867,8 @@ class Client {
18601867
const give_amount = amount; // Amount to fill in the order. Give _to_ order as counterpart of ask
18611868
const give_amount_atoms =
18621869
order_details.ask_currency.type === 'Token'
1863-
? give_amount! * Math.pow(10, ask_token_details!.number_of_decimals)
1864-
: give_amount! * Math.pow(10, 11); // Coin decimal
1870+
? decimalsToAtoms(give_amount!, ask_token_details!.number_of_decimals)
1871+
: decimalsToAtoms(give_amount!, 11); // Coin decimal
18651872
if (order_details.ask_currency.type === 'Coin') {
18661873
input_amount_coin_req += BigInt(give_amount_atoms);
18671874
} else if (ask_token_details) {
@@ -1872,9 +1879,15 @@ class Client {
18721879
};
18731880
}
18741881

1882+
const asked = BigInt(order_details.initially_asked.atoms);
1883+
const given = BigInt(order_details.initially_given.atoms);
1884+
1885+
const give_atoms = BigInt(give_amount_atoms);
1886+
const ask_amount_atoms_bigint = (give_atoms * given) / asked;
1887+
18751888
const rate = parseInt(order_details.initially_asked.atoms) / parseInt(order_details.initially_given.atoms);
18761889

1877-
const ask_amount_atoms = Math.floor(give_amount_atoms / rate);
1890+
const ask_amount_atoms = ask_amount_atoms_bigint.toString();
18781891
const ask_amount =
18791892
order_details.give_currency.type === 'Token'
18801893
? atomsToDecimal(ask_amount_atoms, give_token_details!.number_of_decimals)
@@ -1993,7 +2006,7 @@ class Client {
19932006
type: 'Coin',
19942007
amount: {
19952008
atoms: changeAmountCoin.toString(),
1996-
decimal: (Number(changeAmountCoin) / 1e11).toString(),
2009+
decimal: atomsToDecimal(changeAmountCoin.toString(), 11).toString(),
19972010
},
19982011
},
19992012
destination: currentAddress.change[0],
@@ -2009,7 +2022,7 @@ class Client {
20092022
token_id: send_token.token_id,
20102023
amount: {
20112024
atoms: changeAmountToken.toString(),
2012-
decimal: (Number(changeAmountToken) / Math.pow(10, decimals)).toString(),
2025+
decimal: atomsToDecimal(changeAmountToken.toString(), decimals).toString(),
20132026
},
20142027
},
20152028
destination: currentAddress.change[0],

0 commit comments

Comments
 (0)