suidouble 1.14.2-1 → 1.14.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/SuiCoin.js +86 -15
- package/lib/SuiPackage.js +1 -1
- package/package.json +3 -3
- package/test/coins.test.js +92 -7
package/lib/SuiCoin.js
CHANGED
|
@@ -25,7 +25,6 @@ import { Commands, Transaction } from '@mysten/sui/transactions';
|
|
|
25
25
|
*
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
|
-
|
|
29
28
|
/** Coin metadata object */
|
|
30
29
|
export default class SuiCoin {
|
|
31
30
|
|
|
@@ -63,38 +62,86 @@ export default class SuiCoin {
|
|
|
63
62
|
|
|
64
63
|
/**
|
|
65
64
|
* Normalize amount based on .decimals. Pass a string with a dot ('5.22', '0.0005') to convert it to units. No worries about loading metadata first.
|
|
66
|
-
* @param {String|Number|
|
|
67
|
-
* @returns {
|
|
65
|
+
* @param {String|Number|bigint} amount
|
|
66
|
+
* @returns {Promise.<bigint>}
|
|
68
67
|
*/
|
|
69
68
|
async lazyNormalizeAmount(amount) {
|
|
70
69
|
await this.getMetadata();
|
|
71
70
|
return this.normalizeAmount(amount);
|
|
72
71
|
}
|
|
73
72
|
|
|
74
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Get readable representation of amount value (system one, bigint or converted from bigint, NOT the '1.99' etc)
|
|
75
|
+
* based on coin decimals metadata ( so it expects metadata to be loaded or set).
|
|
76
|
+
*
|
|
77
|
+
* @param {Object} params - format parameters
|
|
78
|
+
* @param {boolean} params.withAbbr - append K, M, B, T for large amounts. Suiet-style
|
|
79
|
+
* @param {boolean|string} params.separateThousands - separate thousands, by ',' or by specific delimeter
|
|
80
|
+
*
|
|
81
|
+
* @returns {string}
|
|
82
|
+
*/
|
|
83
|
+
amountToString(amount, options = {}) {
|
|
75
84
|
if (!this.decimals) {
|
|
76
85
|
throw new Error('Please load coin metadata first');
|
|
77
86
|
}
|
|
78
87
|
|
|
88
|
+
const withAbbr = !!options.withAbbr;
|
|
89
|
+
const separateThousands = options.separateThousands;
|
|
90
|
+
|
|
79
91
|
const str = (''+BigInt(amount)).padStart(this.decimals + 1,'0');
|
|
80
92
|
const ind = str.length - this.decimals;
|
|
81
93
|
let asFloatString = str.substring(0, ind) + '.' + str.substring(ind);
|
|
82
94
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (asFloatString.substring(i, i+1) === '0' && asFloatString.substring(i-1, i) !== '.') {
|
|
88
|
-
asFloatString = asFloatString.substring(0, i);
|
|
89
|
-
} else {
|
|
90
|
-
haveNotMetNoZero = true;
|
|
95
|
+
if (asFloatString.includes('.')) {
|
|
96
|
+
asFloatString = asFloatString.replace(/(\.\d*?)0+$/, '$1').replace(/\.$/, '');
|
|
97
|
+
if (!asFloatString.includes('.')) {
|
|
98
|
+
asFloatString = '' + asFloatString + '.0';
|
|
91
99
|
}
|
|
92
|
-
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (withAbbr) {
|
|
103
|
+
const asBig = BigInt(Math.floor(Number(asFloatString)));
|
|
104
|
+
|
|
105
|
+
if (asBig > 1000n) {
|
|
106
|
+
if (asBig < 1000000n) return this.formatWithAbbr(asBig, 1000n, 'K');
|
|
107
|
+
if (asBig >= 1000000n && asBig < 1000000000n) return this.formatWithAbbr(asBig, 1000000n, 'M');
|
|
108
|
+
if (asBig >= 1000000000n && asBig < 1000000000000n) return this.formatWithAbbr(asBig, 1000000000n, 'B');
|
|
109
|
+
if (asBig >= 1000000000000n) return this.formatWithAbbr(asBig, 1000000000000n, 'T');
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (separateThousands) {
|
|
114
|
+
// asFloatString has '.' anyway ( see above )
|
|
115
|
+
const [integerPart, decimalPart] = asFloatString.split('.'); // Split into integer and decimal parts
|
|
116
|
+
const separator = (typeof separateThousands === 'string') ? separateThousands : ',';
|
|
117
|
+
const formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, separator);
|
|
118
|
+
asFloatString = '' + formattedInteger + '.' + decimalPart;
|
|
93
119
|
}
|
|
94
120
|
|
|
95
121
|
return asFloatString;
|
|
96
122
|
}
|
|
97
123
|
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Format large amounts
|
|
127
|
+
*
|
|
128
|
+
* thanks @bruceeewong and @suiet
|
|
129
|
+
*
|
|
130
|
+
* @param {bigint} amount
|
|
131
|
+
* @param {bigint} measureUnit
|
|
132
|
+
* @param {string} abbrSymbol
|
|
133
|
+
*
|
|
134
|
+
* @returns {string}
|
|
135
|
+
*/
|
|
136
|
+
formatWithAbbr(amount, measureUnit, abbrSymbol) {
|
|
137
|
+
let showAmount = (''+(Number(amount) / Number(measureUnit / 1000n)));
|
|
138
|
+
showAmount = showAmount.padEnd(4, '0');
|
|
139
|
+
|
|
140
|
+
const result = Intl.NumberFormat('en-US').format(Number(showAmount));
|
|
141
|
+
return result.replace(',', '.') + abbrSymbol;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
|
|
98
145
|
get suiMaster() {
|
|
99
146
|
return this._suiCoins.suiMaster;
|
|
100
147
|
}
|
|
@@ -150,6 +197,7 @@ export default class SuiCoin {
|
|
|
150
197
|
/**
|
|
151
198
|
* set predefined coin metadata so it will not be fetched from RPC
|
|
152
199
|
* @param {CoinMeta} meta
|
|
200
|
+
*
|
|
153
201
|
* @returns {boolean} if processed ok
|
|
154
202
|
*/
|
|
155
203
|
setMetadata(meta) {
|
|
@@ -162,11 +210,25 @@ export default class SuiCoin {
|
|
|
162
210
|
return false;
|
|
163
211
|
}
|
|
164
212
|
|
|
213
|
+
/**
|
|
214
|
+
* Load coin metadata from the blockchain. As a good pattern, it's better to have metadata hard-coded or cached
|
|
215
|
+
* and set via suiMaster.suiCoins.setCoinMetas(...)
|
|
216
|
+
*
|
|
217
|
+
* @returns {Promise.<boolean>}
|
|
218
|
+
*/
|
|
165
219
|
async getMetadata() {
|
|
166
220
|
if (this._metadata) {
|
|
167
221
|
return this._metadata;
|
|
168
222
|
}
|
|
169
223
|
|
|
224
|
+
if (this.__getMetadataPromise) {
|
|
225
|
+
return await this.__getMetadataPromise();
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// be sure it asyncs in 1 thread
|
|
229
|
+
this.__getMetadataResolver = null;
|
|
230
|
+
this.__getMetadataPromise = new Promise((res)=>{ this.__getMetadataResolver = res; });
|
|
231
|
+
|
|
170
232
|
let result = null;
|
|
171
233
|
try {
|
|
172
234
|
result = await this.suiMaster.client.getCoinMetadata({
|
|
@@ -183,9 +245,17 @@ export default class SuiCoin {
|
|
|
183
245
|
this._exists = true;
|
|
184
246
|
}
|
|
185
247
|
|
|
186
|
-
|
|
248
|
+
this.__getMetadataResolver(true);
|
|
249
|
+
|
|
250
|
+
return true;
|
|
187
251
|
}
|
|
188
252
|
|
|
253
|
+
/**
|
|
254
|
+
* Get coin balance of the wallet
|
|
255
|
+
* @param {string} owner
|
|
256
|
+
*
|
|
257
|
+
* @returns {Promise.<bigint>}
|
|
258
|
+
*/
|
|
189
259
|
async getBalance(owner) {
|
|
190
260
|
const coins = [];
|
|
191
261
|
let result = null;
|
|
@@ -218,7 +288,8 @@ export default class SuiCoin {
|
|
|
218
288
|
* @param {string} owner - address of the owner
|
|
219
289
|
* @param {BigInt|string} amount - amount of coin. BigIng or String to be normalized via Coin decimals, "0.05" for 0.05 sui
|
|
220
290
|
* @param {boolean} addEmptyCoins - attach coins == 0 to the list
|
|
221
|
-
*
|
|
291
|
+
*
|
|
292
|
+
* @returns {Promise.<TransactionObjectArgument>}
|
|
222
293
|
*/
|
|
223
294
|
async coinOfAmountToTxCoin(txb, owner, amount, addEmptyCoins = false) {
|
|
224
295
|
const normalizedAmount = await this.lazyNormalizeAmount(amount);
|
package/lib/SuiPackage.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "suidouble",
|
|
3
|
-
"version": "1.14.
|
|
3
|
+
"version": "1.14.3",
|
|
4
4
|
"description": "Set of provider, package and object classes for javascript representation of Sui Move smart contracts. Use same code for publishing, upgrading, integration testing, interaction with smart contracts and integration in browser web3 dapps",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
"author": "suidouble (https://github.com/suidouble)",
|
|
23
23
|
"license": "Apache-2.0",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@mysten/sui": "^1.14.
|
|
26
|
-
"@polymedia/coinmeta": "^0.0.
|
|
25
|
+
"@mysten/sui": "^1.14.3",
|
|
26
|
+
"@polymedia/coinmeta": "^0.0.17",
|
|
27
27
|
"@wallet-standard/core": "^1.0.3",
|
|
28
28
|
"websocket": "^1.0.35"
|
|
29
29
|
},
|
package/test/coins.test.js
CHANGED
|
@@ -35,13 +35,6 @@ test('type is normalized for SUI', async t => {
|
|
|
35
35
|
const suiCoin5 = suiMaster.suiCoins.get('2::sui::SUI');
|
|
36
36
|
const suiCoin6 = suiMaster.suiCoins.get('0000000000000000000000000000000000000000000000000000000000000002::sui::SUI');
|
|
37
37
|
|
|
38
|
-
console.log(suiCoin1.coinType);
|
|
39
|
-
console.log(suiCoin2.coinType);
|
|
40
|
-
console.log(suiCoin3.coinType);
|
|
41
|
-
console.log(suiCoin4.coinType);
|
|
42
|
-
console.log(suiCoin5.coinType);
|
|
43
|
-
console.log(suiCoin6.coinType);
|
|
44
|
-
|
|
45
38
|
t.ok(suiCoin1.coinType == suiCoin2.coinType);
|
|
46
39
|
t.ok(suiCoin1.coinType == suiCoin3.coinType);
|
|
47
40
|
t.ok(suiCoin1.coinType == suiCoin4.coinType);
|
|
@@ -69,6 +62,9 @@ test('string representation works ok', async t => {
|
|
|
69
62
|
const toDisplay2 = suiCoin.amountToString(1); // 1 mist
|
|
70
63
|
t.equal(toDisplay2, '0.000000001');
|
|
71
64
|
|
|
65
|
+
const toDisplay1000 = suiCoin.amountToString(1000); // 1000 mist
|
|
66
|
+
t.equal(toDisplay1000, '0.000001');
|
|
67
|
+
|
|
72
68
|
const toDisplay3 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(1000) + BigInt(1)); // 1000 SUI + 1 mist
|
|
73
69
|
t.equal(toDisplay3, '1000.000000001');
|
|
74
70
|
|
|
@@ -76,6 +72,95 @@ test('string representation works ok', async t => {
|
|
|
76
72
|
t.equal(toDisplay4, '999.999999999');
|
|
77
73
|
});
|
|
78
74
|
|
|
75
|
+
|
|
76
|
+
test('string representation (withAbbr) works ok', async t => {
|
|
77
|
+
const suiCoin = suiMaster.suiCoins.get('sui');
|
|
78
|
+
await suiCoin.getMetadata();
|
|
79
|
+
|
|
80
|
+
// it should dispaly the same on the low amounts:
|
|
81
|
+
|
|
82
|
+
const toDisplay1 = suiCoin.amountToString(suiMaster.MIST_PER_SUI, {withAbbr: true});
|
|
83
|
+
t.equal(toDisplay1, '1.0');
|
|
84
|
+
|
|
85
|
+
const toDisplay2 = suiCoin.amountToString(1, {withAbbr: true}); // 1 mist
|
|
86
|
+
t.equal(toDisplay2, '0.000000001');
|
|
87
|
+
|
|
88
|
+
const toDisplay1000 = suiCoin.amountToString(1000, {withAbbr: true}); // 1000 mist
|
|
89
|
+
t.equal(toDisplay1000, '0.000001');
|
|
90
|
+
|
|
91
|
+
const toDisplay3 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(1000) + BigInt(1), {withAbbr: true}); // 1000 SUI + 1 mist
|
|
92
|
+
t.equal(toDisplay3, '1000.000000001');
|
|
93
|
+
|
|
94
|
+
const toDisplay4 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(1000) - BigInt(1), {withAbbr: true}); // 1000 SUI - 1 mist
|
|
95
|
+
t.equal(toDisplay4, '999.999999999');
|
|
96
|
+
|
|
97
|
+
// things are getting interesting starting from '1001.0'
|
|
98
|
+
|
|
99
|
+
const toDisplayK1 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(1001) + BigInt(1), {withAbbr: true}); // 1000 SUI + 1 mist
|
|
100
|
+
t.equal(toDisplayK1, '1.001K');
|
|
101
|
+
const toDisplayK2 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(2000), {withAbbr: true});
|
|
102
|
+
t.equal(toDisplayK2, '2.000K');
|
|
103
|
+
const toDisplayK3 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(999900), {withAbbr: true});
|
|
104
|
+
t.equal(toDisplayK3, '999.900K');
|
|
105
|
+
|
|
106
|
+
const toDisplayM1 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(1000000) + BigInt(1), {withAbbr: true}); // 1000 SUI + 1 mist
|
|
107
|
+
t.equal(toDisplayM1, '1.000M');
|
|
108
|
+
const toDisplayM2 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(2000000) + BigInt(900), {withAbbr: true}); // 1000 SUI + 1 mist
|
|
109
|
+
t.equal(toDisplayM2, '2.000M');
|
|
110
|
+
|
|
111
|
+
const toDisplayB1 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(1000000000) + BigInt(1), {withAbbr: true}); // 1000 SUI + 1 mist
|
|
112
|
+
t.equal(toDisplayB1, '1.000B');
|
|
113
|
+
|
|
114
|
+
const toDisplayT1 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(1000000000000) + BigInt(1), {withAbbr: true}); // 1000 SUI + 1 mist
|
|
115
|
+
t.equal(toDisplayT1, '1.000T');
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
test('string representation (separateThousands) works ok', async t => {
|
|
120
|
+
const suiCoin = suiMaster.suiCoins.get('sui');
|
|
121
|
+
await suiCoin.getMetadata();
|
|
122
|
+
|
|
123
|
+
// it should dispaly the same on the low amounts:
|
|
124
|
+
|
|
125
|
+
const toDisplay1 = suiCoin.amountToString(suiMaster.MIST_PER_SUI, {separateThousands: true});
|
|
126
|
+
t.equal(toDisplay1, '1.0');
|
|
127
|
+
|
|
128
|
+
const toDisplay2 = suiCoin.amountToString(1, {separateThousands: true}); // 1 mist
|
|
129
|
+
t.equal(toDisplay2, '0.000000001');
|
|
130
|
+
|
|
131
|
+
const toDisplay1000 = suiCoin.amountToString(1000, {separateThousands: true}); // 1000 mist
|
|
132
|
+
t.equal(toDisplay1000, '0.000001');
|
|
133
|
+
|
|
134
|
+
const toDisplay3 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(1000) + BigInt(1), {separateThousands: true}); // 1000 SUI + 1 mist
|
|
135
|
+
t.equal(toDisplay3, '1,000.000000001');
|
|
136
|
+
|
|
137
|
+
const toDisplay4 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(1000) - BigInt(1), {separateThousands: true}); // 1000 SUI - 1 mist
|
|
138
|
+
t.equal(toDisplay4, '999.999999999');
|
|
139
|
+
|
|
140
|
+
// things are getting interesting starting from '1001.0'
|
|
141
|
+
|
|
142
|
+
const toDisplayK1 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(1001) + BigInt(1), {separateThousands: true});
|
|
143
|
+
t.equal(toDisplayK1, '1,001.000000001');
|
|
144
|
+
const toDisplayK2 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(2000), {separateThousands: true});
|
|
145
|
+
t.equal(toDisplayK2, '2,000.0');
|
|
146
|
+
const toDisplayK3 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(999900), {separateThousands: true});
|
|
147
|
+
t.equal(toDisplayK3, '999,900.0');
|
|
148
|
+
|
|
149
|
+
const toDisplayM1 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(1000000) + BigInt(1), {separateThousands: true});
|
|
150
|
+
t.equal(toDisplayM1, '1,000,000.000000001');
|
|
151
|
+
const toDisplayM2 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(2000000) + BigInt(900), {separateThousands: true});
|
|
152
|
+
t.equal(toDisplayM2, '2,000,000.0000009');
|
|
153
|
+
|
|
154
|
+
const toDisplayB1 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(1000000000) + BigInt(1), {separateThousands: true});
|
|
155
|
+
t.equal(toDisplayB1, '1,000,000,000.000000001');
|
|
156
|
+
|
|
157
|
+
const toDisplayT1 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(1000000000000) + BigInt(1), {separateThousands: true});
|
|
158
|
+
t.equal(toDisplayT1, '1,000,000,000,000.000000001');
|
|
159
|
+
|
|
160
|
+
const toDisplayT1q = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(1000000000000) + BigInt(1), {separateThousands: ' '});
|
|
161
|
+
t.equal(toDisplayT1q, '1 000 000 000 000.000000001');
|
|
162
|
+
});
|
|
163
|
+
|
|
79
164
|
test('you have no SUI on the fresh node', async t => {
|
|
80
165
|
const suiCoin = suiMaster.suiCoins.get('sui');
|
|
81
166
|
const balance = await suiCoin.getBalance(suiMaster.address);
|