suidouble 1.14.2-1 → 1.14.3-1
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 +94 -15
- package/lib/SuiPackage.js +1 -1
- package/package.json +3 -3
- package/test/coins.test.js +108 -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,94 @@ 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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
95
|
+
if (asFloatString.includes('.')) {
|
|
96
|
+
asFloatString = asFloatString.replace(/(\.\d*?)0+$/, '$1').replace(/\.$/, '');
|
|
97
|
+
if (!asFloatString.includes('.')) {
|
|
98
|
+
asFloatString = '' + asFloatString + '.0';
|
|
99
|
+
}
|
|
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', separateThousands);
|
|
107
|
+
if (asBig >= 1000000n && asBig < 1000000000n) return this.formatWithAbbr(asBig, 1000000n, 'M', separateThousands);
|
|
108
|
+
if (asBig >= 1000000000n && asBig < 1000000000000n) return this.formatWithAbbr(asBig, 1000000000n, 'B', separateThousands);
|
|
109
|
+
if (asBig >= 1000000000000n) return this.formatWithAbbr(asBig, 1000000000000n, 'T', separateThousands);
|
|
91
110
|
}
|
|
92
|
-
|
|
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, separateThousands = false) {
|
|
137
|
+
let showAmount = (''+Math.floor(Number(amount) / Number(measureUnit / 1000n)));
|
|
138
|
+
showAmount = showAmount.padEnd(4, '0');
|
|
139
|
+
|
|
140
|
+
const result = Intl.NumberFormat('en-US').format(Number(showAmount));
|
|
141
|
+
|
|
142
|
+
let separator = '';
|
|
143
|
+
if (separateThousands) {
|
|
144
|
+
separator = (typeof separateThousands === 'string') ? separateThousands : ',';
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const pcs = result.split(',');
|
|
148
|
+
const lastPc = pcs.pop();
|
|
149
|
+
return pcs.join( separator ) + '.' + lastPc + abbrSymbol;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
|
|
98
153
|
get suiMaster() {
|
|
99
154
|
return this._suiCoins.suiMaster;
|
|
100
155
|
}
|
|
@@ -150,6 +205,7 @@ export default class SuiCoin {
|
|
|
150
205
|
/**
|
|
151
206
|
* set predefined coin metadata so it will not be fetched from RPC
|
|
152
207
|
* @param {CoinMeta} meta
|
|
208
|
+
*
|
|
153
209
|
* @returns {boolean} if processed ok
|
|
154
210
|
*/
|
|
155
211
|
setMetadata(meta) {
|
|
@@ -162,11 +218,25 @@ export default class SuiCoin {
|
|
|
162
218
|
return false;
|
|
163
219
|
}
|
|
164
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Load coin metadata from the blockchain. As a good pattern, it's better to have metadata hard-coded or cached
|
|
223
|
+
* and set via suiMaster.suiCoins.setCoinMetas(...)
|
|
224
|
+
*
|
|
225
|
+
* @returns {Promise.<boolean>}
|
|
226
|
+
*/
|
|
165
227
|
async getMetadata() {
|
|
166
228
|
if (this._metadata) {
|
|
167
229
|
return this._metadata;
|
|
168
230
|
}
|
|
169
231
|
|
|
232
|
+
if (this.__getMetadataPromise) {
|
|
233
|
+
return await this.__getMetadataPromise();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// be sure it asyncs in 1 thread
|
|
237
|
+
this.__getMetadataResolver = null;
|
|
238
|
+
this.__getMetadataPromise = new Promise((res)=>{ this.__getMetadataResolver = res; });
|
|
239
|
+
|
|
170
240
|
let result = null;
|
|
171
241
|
try {
|
|
172
242
|
result = await this.suiMaster.client.getCoinMetadata({
|
|
@@ -183,9 +253,17 @@ export default class SuiCoin {
|
|
|
183
253
|
this._exists = true;
|
|
184
254
|
}
|
|
185
255
|
|
|
186
|
-
|
|
256
|
+
this.__getMetadataResolver(true);
|
|
257
|
+
|
|
258
|
+
return true;
|
|
187
259
|
}
|
|
188
260
|
|
|
261
|
+
/**
|
|
262
|
+
* Get coin balance of the wallet
|
|
263
|
+
* @param {string} owner
|
|
264
|
+
*
|
|
265
|
+
* @returns {Promise.<bigint>}
|
|
266
|
+
*/
|
|
189
267
|
async getBalance(owner) {
|
|
190
268
|
const coins = [];
|
|
191
269
|
let result = null;
|
|
@@ -218,7 +296,8 @@ export default class SuiCoin {
|
|
|
218
296
|
* @param {string} owner - address of the owner
|
|
219
297
|
* @param {BigInt|string} amount - amount of coin. BigIng or String to be normalized via Coin decimals, "0.05" for 0.05 sui
|
|
220
298
|
* @param {boolean} addEmptyCoins - attach coins == 0 to the list
|
|
221
|
-
*
|
|
299
|
+
*
|
|
300
|
+
* @returns {Promise.<TransactionObjectArgument>}
|
|
222
301
|
*/
|
|
223
302
|
async coinOfAmountToTxCoin(txb, owner, amount, addEmptyCoins = false) {
|
|
224
303
|
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-1",
|
|
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,111 @@ 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 toDisplayM2spec = suiCoin.amountToString(148518424765531477n, {withAbbr: true}); // 1000 SUI + 1 mist
|
|
112
|
+
t.equal(toDisplayM2spec, '148.518M');
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
const toDisplayB1 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(1000000000) + BigInt(1), {withAbbr: true}); // 1000 SUI + 1 mist
|
|
116
|
+
t.equal(toDisplayB1, '1.000B');
|
|
117
|
+
|
|
118
|
+
const toDisplayB2spec = suiCoin.amountToString(148518424765531477000n, {withAbbr: true}); // 1000 SUI + 1 mist
|
|
119
|
+
t.equal(toDisplayB2spec, '148.518B');
|
|
120
|
+
|
|
121
|
+
const toDisplayT1 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(1000000000000) + BigInt(1), {withAbbr: true}); // 1000 SUI + 1 mist
|
|
122
|
+
t.equal(toDisplayT1, '1.000T');
|
|
123
|
+
|
|
124
|
+
const toDisplayT2spec = suiCoin.amountToString(148518424765531477000000n, {withAbbr: true}); // 1000 SUI + 1 mist
|
|
125
|
+
t.equal(toDisplayT2spec, '148.518T');
|
|
126
|
+
|
|
127
|
+
const toDisplayT20spec = suiCoin.amountToString(148518424765531477000000000n, {withAbbr: true}); // 1000 SUI + 1 mist
|
|
128
|
+
t.equal(toDisplayT20spec, '148518.424T');
|
|
129
|
+
|
|
130
|
+
const toDisplayT20spec2 = suiCoin.amountToString(148518424765531477000000000n, {withAbbr: true, separateThousands: true}); // 1000 SUI + 1 mist
|
|
131
|
+
t.equal(toDisplayT20spec2, '148,518.424T');
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
test('string representation (separateThousands) works ok', async t => {
|
|
136
|
+
const suiCoin = suiMaster.suiCoins.get('sui');
|
|
137
|
+
await suiCoin.getMetadata();
|
|
138
|
+
|
|
139
|
+
// it should dispaly the same on the low amounts:
|
|
140
|
+
|
|
141
|
+
const toDisplay1 = suiCoin.amountToString(suiMaster.MIST_PER_SUI, {separateThousands: true});
|
|
142
|
+
t.equal(toDisplay1, '1.0');
|
|
143
|
+
|
|
144
|
+
const toDisplay2 = suiCoin.amountToString(1, {separateThousands: true}); // 1 mist
|
|
145
|
+
t.equal(toDisplay2, '0.000000001');
|
|
146
|
+
|
|
147
|
+
const toDisplay1000 = suiCoin.amountToString(1000, {separateThousands: true}); // 1000 mist
|
|
148
|
+
t.equal(toDisplay1000, '0.000001');
|
|
149
|
+
|
|
150
|
+
const toDisplay3 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(1000) + BigInt(1), {separateThousands: true}); // 1000 SUI + 1 mist
|
|
151
|
+
t.equal(toDisplay3, '1,000.000000001');
|
|
152
|
+
|
|
153
|
+
const toDisplay4 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(1000) - BigInt(1), {separateThousands: true}); // 1000 SUI - 1 mist
|
|
154
|
+
t.equal(toDisplay4, '999.999999999');
|
|
155
|
+
|
|
156
|
+
// things are getting interesting starting from '1001.0'
|
|
157
|
+
|
|
158
|
+
const toDisplayK1 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(1001) + BigInt(1), {separateThousands: true});
|
|
159
|
+
t.equal(toDisplayK1, '1,001.000000001');
|
|
160
|
+
const toDisplayK2 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(2000), {separateThousands: true});
|
|
161
|
+
t.equal(toDisplayK2, '2,000.0');
|
|
162
|
+
const toDisplayK3 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(999900), {separateThousands: true});
|
|
163
|
+
t.equal(toDisplayK3, '999,900.0');
|
|
164
|
+
|
|
165
|
+
const toDisplayM1 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(1000000) + BigInt(1), {separateThousands: true});
|
|
166
|
+
t.equal(toDisplayM1, '1,000,000.000000001');
|
|
167
|
+
const toDisplayM2 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(2000000) + BigInt(900), {separateThousands: true});
|
|
168
|
+
t.equal(toDisplayM2, '2,000,000.0000009');
|
|
169
|
+
|
|
170
|
+
const toDisplayB1 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(1000000000) + BigInt(1), {separateThousands: true});
|
|
171
|
+
t.equal(toDisplayB1, '1,000,000,000.000000001');
|
|
172
|
+
|
|
173
|
+
const toDisplayT1 = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(1000000000000) + BigInt(1), {separateThousands: true});
|
|
174
|
+
t.equal(toDisplayT1, '1,000,000,000,000.000000001');
|
|
175
|
+
|
|
176
|
+
const toDisplayT1q = suiCoin.amountToString(suiMaster.MIST_PER_SUI * BigInt(1000000000000) + BigInt(1), {separateThousands: ' '});
|
|
177
|
+
t.equal(toDisplayT1q, '1 000 000 000 000.000000001');
|
|
178
|
+
});
|
|
179
|
+
|
|
79
180
|
test('you have no SUI on the fresh node', async t => {
|
|
80
181
|
const suiCoin = suiMaster.suiCoins.get('sui');
|
|
81
182
|
const balance = await suiCoin.getBalance(suiMaster.address);
|