suidouble 1.0.4 → 1.6.0-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/README.md +12 -9
- package/index.js +3 -0
- package/lib/SuiCoin.js +27 -8
- package/lib/SuiCoins.js +6 -0
- package/lib/SuiInBrowser.js +4 -0
- package/lib/SuiInBrowserAdapter.js +22 -0
- package/lib/SuiLocalTestValidator.js +64 -31
- package/lib/SuiMaster.js +7 -6
- package/lib/SuiPackage.js +2 -2
- package/lib/SuiPackageModule.js +19 -6
- package/lib/SuiUtils.js +34 -11
- package/package.json +10 -9
- package/test/coins.test.js +1 -1
- package/test/sui_master_onlocal.test.js +38 -24
- package/test/test_move_contracts/different_types/Move.lock +1 -1
- package/test/test_move_contracts/suidouble_chat/Move.lock +2 -2
- package/test/test_move_contracts/suidouble_chat/sources/suidouble_chat.move +13 -1
package/README.md
CHANGED
|
@@ -168,7 +168,9 @@ while (events.hasNextPage) {
|
|
|
168
168
|
|
|
169
169
|
##### subscribing to events
|
|
170
170
|
|
|
171
|
-
|
|
171
|
+
*** Subscribe to Events is deprecated in Sui SDK *** You should plan to use different architecture in your application.
|
|
172
|
+
|
|
173
|
+
You can subscribe to Sui's contract events on package's module level.
|
|
172
174
|
|
|
173
175
|
```javascript
|
|
174
176
|
const module = await contract.getModule('suidouble_chat');
|
|
@@ -228,7 +230,7 @@ arguments.push(contract.arg('u128', 5555));
|
|
|
228
230
|
arguments.push(contract.arg('u256', 6666));
|
|
229
231
|
arguments.push(contract.arg('address', '0xd9a95d7cc137f71dd7766f02791536453062a7509e9f461620cc4f583b09134c'));
|
|
230
232
|
arguments.push(contract.arg('string', 'some utf-8 💧string'));
|
|
231
|
-
arguments.push(contract.arg('vector<u8>', 222)); // works for other vectors with primitive contents, e.g. u128, bool etc
|
|
233
|
+
arguments.push(contract.arg('vector<u8>', [222,111,211])); // works for other vectors with primitive contents, e.g. u128, bool etc
|
|
232
234
|
```
|
|
233
235
|
|
|
234
236
|
Take a look at unit test covering all types arguments [here](test/different_types_args.test.js)
|
|
@@ -292,20 +294,21 @@ Don't forget to test transactions sending real money on devnet/testnet first!
|
|
|
292
294
|
|
|
293
295
|
##### composing transaction block yourself
|
|
294
296
|
|
|
295
|
-
If you need more flexebility, there's always an option to construct the transaction
|
|
297
|
+
If you need more flexebility, there's always an option to construct the transaction yourself:
|
|
296
298
|
|
|
297
299
|
```javascript
|
|
298
|
-
const {
|
|
300
|
+
const { Transaction, txInput } = require('suidobule'); // this exposes classes from the "@mysten/sui.js", so you don't have to import them separately
|
|
299
301
|
|
|
300
|
-
const
|
|
301
|
-
|
|
302
|
+
const tx = new Transaction();
|
|
303
|
+
tx.moveCall({
|
|
302
304
|
target: `package_id::module_id::method_name`,
|
|
303
305
|
arguments: [
|
|
304
|
-
|
|
305
|
-
|
|
306
|
+
txInput(tx, 'u256', some_value),
|
|
307
|
+
txInput(tx, 'vector<bool>', some_array),
|
|
308
|
+
tx.object('0xc060006111016b8a020ad5b33834984a437aaa7d3c74c18e09a95d48aceab08c'), // object ids are ok t
|
|
306
309
|
],
|
|
307
310
|
});
|
|
308
|
-
const moveCallResult = await contract.moveCall('suidouble_chat', 'post_pay', {tx:
|
|
311
|
+
const moveCallResult = await contract.moveCall('suidouble_chat', 'post_pay', {tx: tx});
|
|
309
312
|
```
|
|
310
313
|
|
|
311
314
|
|
package/index.js
CHANGED
|
@@ -5,6 +5,7 @@ const SuiObject = require('./lib/SuiObject.js');
|
|
|
5
5
|
const SuiUtils = require('./lib/SuiUtils.js');
|
|
6
6
|
const SuiLocalTestValidator = require('./lib/SuiLocalTestValidator.js');
|
|
7
7
|
const { Transaction, Commands } = require('@mysten/sui/transactions');
|
|
8
|
+
const { bcs } = require('@mysten/sui/bcs');
|
|
8
9
|
|
|
9
10
|
module.exports = {
|
|
10
11
|
SuiMaster,
|
|
@@ -16,4 +17,6 @@ module.exports = {
|
|
|
16
17
|
Transaction: Transaction,
|
|
17
18
|
Commands: Commands,
|
|
18
19
|
SuiUtils: SuiUtils,
|
|
20
|
+
txInput: SuiUtils.txInput,
|
|
21
|
+
bcs,
|
|
19
22
|
};
|
package/lib/SuiCoin.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
const { Commands } = require('@mysten/sui/transactions');
|
|
1
|
+
const { Commands, Transaction, TransactionObjectArgument } = require('@mysten/sui/transactions');
|
|
2
2
|
const { bcs } = require('@mysten/sui/bcs');
|
|
3
|
-
// console.log(bcs);
|
|
4
3
|
|
|
5
4
|
|
|
6
5
|
const safeList = {
|
|
@@ -25,7 +24,15 @@ const safeList = {
|
|
|
25
24
|
},
|
|
26
25
|
};
|
|
27
26
|
|
|
27
|
+
/** Coin metadata object */
|
|
28
28
|
class SuiCoin {
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* SuiCoin constructor
|
|
32
|
+
* @param {Object} params - Initialization parameters
|
|
33
|
+
* @param {string} params.coinType - sui object type for a coin, without Coin<...>, only the inside type
|
|
34
|
+
* @param {SuiCoins} params.suiCoins - instance of SuiCoins
|
|
35
|
+
*/
|
|
29
36
|
constructor(params = {}) {
|
|
30
37
|
this._coinType = params.coinType;
|
|
31
38
|
this._suiCoins = params.suiCoins;
|
|
@@ -102,6 +109,15 @@ class SuiCoin {
|
|
|
102
109
|
return '0x'+this._coinType;
|
|
103
110
|
}
|
|
104
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Move type for the Coin object of this coin type
|
|
114
|
+
*
|
|
115
|
+
* @type {string}
|
|
116
|
+
*/
|
|
117
|
+
get coinObjectType() {
|
|
118
|
+
return '0x2::coin::Coin<'+this.coinType+'>';
|
|
119
|
+
}
|
|
120
|
+
|
|
105
121
|
get decimals() {
|
|
106
122
|
if (this.metadata) {
|
|
107
123
|
return this.metadata.decimals;
|
|
@@ -202,6 +218,15 @@ class SuiCoin {
|
|
|
202
218
|
return totalAmount;
|
|
203
219
|
}
|
|
204
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Returns TransactionObjectArgument with Coin of amount to be used in tranasctions
|
|
223
|
+
*
|
|
224
|
+
* @param {Transaction} txb - Native SUI SDK Transaction
|
|
225
|
+
* @param {string} owner - address of the owner
|
|
226
|
+
* @param {BigInt|string} amount - amount of coin. BigIng or String to be normalized via Coin decimals, "0.05" for 0.05 sui
|
|
227
|
+
* @param {boolean} addEmptyCoins - attach coins == 0 to the list
|
|
228
|
+
* @returns {TransactionObjectArgument}
|
|
229
|
+
*/
|
|
205
230
|
async coinOfAmountToTxCoin(txb, owner, amount, addEmptyCoins = false) {
|
|
206
231
|
const normalizedAmount = await this.lazyNormalizeAmount(amount);
|
|
207
232
|
|
|
@@ -215,12 +240,6 @@ class SuiCoin {
|
|
|
215
240
|
if (coinIds.length == 1) {
|
|
216
241
|
// only one coin object enough to cover the expense
|
|
217
242
|
if (this.isSUI()) {
|
|
218
|
-
// console.log(txb.gas);
|
|
219
|
-
// console.log(bcs);
|
|
220
|
-
// console.log(txb.pure(bcs.vector(bcs.u64).serialize([expectedAmountAsBigInt])));
|
|
221
|
-
// console.log(txb.pure.u64(expectedAmountAsBigInt));
|
|
222
|
-
// txb.pure(bcs.vector(bcs.u64).serialize(['0x123']))
|
|
223
|
-
|
|
224
243
|
const coinInput = txb.add(Commands.SplitCoins(txb.gas, [txb.pure.u64(expectedAmountAsBigInt)]));
|
|
225
244
|
return coinInput;
|
|
226
245
|
} else {
|
package/lib/SuiCoins.js
CHANGED
|
@@ -97,6 +97,12 @@ class SuiCoins extends SuiCommonMethods {
|
|
|
97
97
|
return coinType;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Return instance of SuiCoin of specific type
|
|
102
|
+
*
|
|
103
|
+
* @param {string} coinType - MoveType, or 'SUI' as helper
|
|
104
|
+
* @returns {SuiCoin}
|
|
105
|
+
*/
|
|
100
106
|
get(coinType) {
|
|
101
107
|
const normalizedCoinType = this.normalizeCoinType(coinType);
|
|
102
108
|
let suiCoin = this._coins[normalizedCoinType];
|
package/lib/SuiInBrowser.js
CHANGED
|
@@ -42,6 +42,10 @@ class SuiInBrowser extends SuiCommonMethods {
|
|
|
42
42
|
return await this._activeAdapter.signAndExecuteTransactionBlock(params);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
async signAndExecuteTransaction(params) {
|
|
46
|
+
return await this._activeAdapter.signAndExecuteTransaction(params);
|
|
47
|
+
}
|
|
48
|
+
|
|
45
49
|
get client() {
|
|
46
50
|
return this._client;
|
|
47
51
|
}
|
|
@@ -8,6 +8,8 @@ const Feature = {
|
|
|
8
8
|
EVENTS: 'standard:events',
|
|
9
9
|
SUI_SIGN_AND_EXECUTE_TX_BLOCK: 'sui:signAndExecuteTransactionBlock',
|
|
10
10
|
SUI_SIGN_TX_BLOCK: 'sui:signTransactionBlock',
|
|
11
|
+
SUI_SIGN_AND_EXECUTE_TX: 'sui:signAndExecuteTransaction',
|
|
12
|
+
SUI_SIGN_TX: 'sui:signTransaction',
|
|
11
13
|
SUI_SIGN_MESSAGE: 'sui:signMessage'
|
|
12
14
|
};
|
|
13
15
|
|
|
@@ -30,10 +32,30 @@ class SuiInBrowserAdapter extends SuiCommonMethods {
|
|
|
30
32
|
this._isConnected = false;
|
|
31
33
|
}
|
|
32
34
|
|
|
35
|
+
async signAndExecuteTransaction(params) {
|
|
36
|
+
if (this.hasFeature(Feature.SUI_SIGN_AND_EXECUTE_TX)) {
|
|
37
|
+
return await this.getFeature(Feature.SUI_SIGN_AND_EXECUTE_TX).signAndExecuteTransaction(params);
|
|
38
|
+
} else {
|
|
39
|
+
// outdated wallet?
|
|
40
|
+
params.transactionBlock = params.transaction;
|
|
41
|
+
return await this.getFeature(Feature.SUI_SIGN_AND_EXECUTE_TX_BLOCK).signAndExecuteTransactionBlock(params);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
33
45
|
async signAndExecuteTransactionBlock(params) {
|
|
34
46
|
return await this.getFeature(Feature.SUI_SIGN_AND_EXECUTE_TX_BLOCK).signAndExecuteTransactionBlock(params);
|
|
35
47
|
}
|
|
36
48
|
|
|
49
|
+
async signTransactionBlock(params) {
|
|
50
|
+
if (this.hasFeature(Feature.SUI_SIGN_TX)) {
|
|
51
|
+
return await this.getFeature(Feature.SUI_SIGN_TX).signTransaction(params);
|
|
52
|
+
} else {
|
|
53
|
+
// outdated wallet?
|
|
54
|
+
params.transactionBlock = params.transaction;
|
|
55
|
+
return await this.getFeature(Feature.SUI_SIGN_TX_BLOCK).signTransactionBlock(params);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
37
59
|
async signTransactionBlock(params) {
|
|
38
60
|
return await this.getFeature(Feature.SUI_SIGN_TX_BLOCK).signTransactionBlock(params);
|
|
39
61
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
const net = require("net");
|
|
2
2
|
const SuiCliCommands = require('./SuiCliCommands.js');
|
|
3
3
|
const SuiCommonMethods = require('./SuiCommonMethods.js');
|
|
4
|
-
// const { JsonRpcProvider, localnetConnection, devnetConnection } = require('@mysten/sui.js');
|
|
5
4
|
|
|
6
5
|
const { SuiClient, getFullnodeUrl, SuiHTTPTransport } = require('@mysten/sui/client');
|
|
7
6
|
const SuiUtils = require('./SuiUtils.js');
|
|
@@ -65,6 +64,51 @@ class SuiLocalTestValidator extends SuiCommonMethods {
|
|
|
65
64
|
}
|
|
66
65
|
}
|
|
67
66
|
|
|
67
|
+
async isPortThere(port) {
|
|
68
|
+
const Socket = net.Socket;
|
|
69
|
+
const socket = new Socket();
|
|
70
|
+
|
|
71
|
+
let __waitPortPromiseResolver = null;
|
|
72
|
+
const __waitPortPromise = new Promise((res)=>{ __waitPortPromiseResolver = res; });
|
|
73
|
+
|
|
74
|
+
setTimeout(()=>{
|
|
75
|
+
socket.destroy();
|
|
76
|
+
__waitPortPromiseResolver(false);
|
|
77
|
+
}, 3000);
|
|
78
|
+
socket.on("connect", () => {
|
|
79
|
+
__waitPortPromiseResolver(true);
|
|
80
|
+
});
|
|
81
|
+
socket.on("error", () =>
|
|
82
|
+
{
|
|
83
|
+
__waitPortPromiseResolver(false);
|
|
84
|
+
});
|
|
85
|
+
socket.on("timeout", () => {
|
|
86
|
+
__waitPortPromiseResolver(false);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
socket.connect(port, "0.0.0.0");
|
|
90
|
+
|
|
91
|
+
const portIsThere = await __waitPortPromise;
|
|
92
|
+
socket.destroy();
|
|
93
|
+
|
|
94
|
+
return portIsThere;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async waitForPort(port, timeout) {
|
|
98
|
+
this.log('waiting for port', port);
|
|
99
|
+
const startedCheckingAt = (new Date()).getTime();
|
|
100
|
+
let portIsThere = false;
|
|
101
|
+
do {
|
|
102
|
+
portIsThere = await this.isPortThere(port);
|
|
103
|
+
this.log('checking for port', port, 'is there:', portIsThere);
|
|
104
|
+
if (!portIsThere) {
|
|
105
|
+
await new Promise((res)=>setTimeout(res, 500));
|
|
106
|
+
}
|
|
107
|
+
} while (!portIsThere && (startedCheckingAt + timeout) > ((new Date()).getTime()));
|
|
108
|
+
|
|
109
|
+
return portIsThere;
|
|
110
|
+
}
|
|
111
|
+
|
|
68
112
|
async launch() {
|
|
69
113
|
if (this._active) {
|
|
70
114
|
return this;
|
|
@@ -73,12 +117,22 @@ class SuiLocalTestValidator extends SuiCommonMethods {
|
|
|
73
117
|
this.log('launching sui-test-validator ...');
|
|
74
118
|
|
|
75
119
|
try {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
params
|
|
79
|
-
|
|
120
|
+
try {
|
|
121
|
+
// try sui-test-validator
|
|
122
|
+
const params = [];
|
|
123
|
+
if (this._epochDuration) {
|
|
124
|
+
params.push('--epoch-duration-ms');
|
|
125
|
+
params.push(this._epochDuration);
|
|
126
|
+
}
|
|
127
|
+
this._child = await SuiCliCommands.spawn('sui-test-validator', params, { RUST_LOG: 'consensus=off' });
|
|
128
|
+
} catch (e) {
|
|
129
|
+
this.log('can not launch sui-test-validator. Trying to run "sui start"...');
|
|
130
|
+
const params = [];
|
|
131
|
+
params.push('start');
|
|
132
|
+
params.push('--with-faucet');
|
|
133
|
+
params.push('--force-regenesis');
|
|
134
|
+
this._child = await SuiCliCommands.spawn('sui', params, { RUST_LOG: 'off,sui_node=info' });
|
|
80
135
|
}
|
|
81
|
-
this._child = await SuiCliCommands.spawn('sui-test-validator', params, { RUST_LOG: 'consensus=off' });
|
|
82
136
|
} catch (e) {
|
|
83
137
|
if (this._testFallbackEnabled) {
|
|
84
138
|
// can't start local node. Let's switch to sui:dev
|
|
@@ -93,29 +147,6 @@ class SuiLocalTestValidator extends SuiCommonMethods {
|
|
|
93
147
|
throw e;
|
|
94
148
|
}
|
|
95
149
|
}
|
|
96
|
-
|
|
97
|
-
this.__readyLaunchedPromiseResolver = null;
|
|
98
|
-
this.__readyLaunchedPromise = new Promise((res)=>{
|
|
99
|
-
this.__readyLaunchedPromiseResolver = res;
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
this._child.stdout.on('data', (data) => {
|
|
103
|
-
this.log(`stdout:\n${data}`);
|
|
104
|
-
if ((`${data}`).indexOf('Fullnode RPC URL') !== -1) {
|
|
105
|
-
this._active = true;
|
|
106
|
-
|
|
107
|
-
this.log('sui-test-validator launched');
|
|
108
|
-
this.__readyLaunchedPromiseResolver();
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
this._child.stderr.on('data', (data) => {
|
|
113
|
-
this.log(`stderr: ${data}`);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
this._child.on('error', (error) => {
|
|
117
|
-
this.log(`error: ${error.message}`);
|
|
118
|
-
});
|
|
119
150
|
|
|
120
151
|
this._child.on('close', (code) => {
|
|
121
152
|
this._active = false;
|
|
@@ -131,7 +162,9 @@ class SuiLocalTestValidator extends SuiCommonMethods {
|
|
|
131
162
|
process.on('SIGINT', cleanExit); // catch ctrl-c
|
|
132
163
|
process.on('SIGTERM', cleanExit); // catch kill
|
|
133
164
|
|
|
134
|
-
await this.
|
|
165
|
+
this._active = await this.waitForPort(9123, 30000);
|
|
166
|
+
|
|
167
|
+
// await this.__readyLaunchedPromise;
|
|
135
168
|
|
|
136
169
|
return this;
|
|
137
170
|
}
|
package/lib/SuiMaster.js
CHANGED
|
@@ -102,6 +102,11 @@ class SuiMaster extends SuiCommonMethods {
|
|
|
102
102
|
return SuiUtils;
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Instance of SuiCoins class connected to this SuiMaster
|
|
107
|
+
*
|
|
108
|
+
* @type {SuiCoins}
|
|
109
|
+
*/
|
|
105
110
|
get suiCoins() {
|
|
106
111
|
return this._suiCoins;
|
|
107
112
|
}
|
|
@@ -110,12 +115,8 @@ class SuiMaster extends SuiCommonMethods {
|
|
|
110
115
|
return BigInt(MIST_PER_SUI);
|
|
111
116
|
}
|
|
112
117
|
|
|
113
|
-
get
|
|
114
|
-
return
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
get Transactions() {
|
|
118
|
-
return Transactions;
|
|
118
|
+
get Transaction() {
|
|
119
|
+
return Transaction;
|
|
119
120
|
}
|
|
120
121
|
|
|
121
122
|
get Commands() {
|
package/lib/SuiPackage.js
CHANGED
|
@@ -452,8 +452,8 @@ class SuiPackage extends SuiObject {
|
|
|
452
452
|
|
|
453
453
|
const authorizeUpgradeArguments = [
|
|
454
454
|
cap,
|
|
455
|
-
|
|
456
|
-
|
|
455
|
+
this._suiMaster.utils.txInput(tx, 'u8', UpgradePolicyCOMPATIBLE),
|
|
456
|
+
this._suiMaster.utils.txInput(tx, 'vector<u8>', this._builtDigest),
|
|
457
457
|
];
|
|
458
458
|
|
|
459
459
|
const ticket = tx.moveCall({
|
package/lib/SuiPackageModule.js
CHANGED
|
@@ -7,8 +7,18 @@ const SuiEvent = require('./SuiEvent.js');
|
|
|
7
7
|
|
|
8
8
|
const { Transaction } = require('@mysten/sui/transactions');
|
|
9
9
|
const { normalizeSuiAddress } = require('@mysten/sui/utils');
|
|
10
|
+
const SuiMaster = require('./SuiMaster.js');
|
|
11
|
+
const SuiPackage = require('./SuiPackage.js');
|
|
10
12
|
|
|
11
13
|
class SuiPackageModule extends SuiCommonMethods {
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* SuiPackageModule constructor
|
|
17
|
+
* @param {Object} params - Initialization parameters
|
|
18
|
+
* @param {SuiPackage} params.package - instance of SuiPackage this module is part of
|
|
19
|
+
* @param {SuiMaster} params.suiMaster - instance of SuiMaster
|
|
20
|
+
* @param {string} params.moduleName - name of the Move module
|
|
21
|
+
*/
|
|
12
22
|
constructor(params = {}) {
|
|
13
23
|
super(params);
|
|
14
24
|
|
|
@@ -16,6 +26,7 @@ class SuiPackageModule extends SuiCommonMethods {
|
|
|
16
26
|
if (!this._package) {
|
|
17
27
|
throw new Error('package is required for SuiPackageModule');
|
|
18
28
|
}
|
|
29
|
+
|
|
19
30
|
this._suiMaster = params.suiMaster;
|
|
20
31
|
if (!this._suiMaster) {
|
|
21
32
|
throw new Error('suiMaster is requried for SuiPackageModule');
|
|
@@ -25,9 +36,6 @@ class SuiPackageModule extends SuiCommonMethods {
|
|
|
25
36
|
throw new Error('moduleName is required for SuiPackageModule');
|
|
26
37
|
}
|
|
27
38
|
|
|
28
|
-
// this._objects = {};
|
|
29
|
-
// this._objectsArray = [];
|
|
30
|
-
|
|
31
39
|
// we need to get very first version's address of this package to use for types, so we are doing this in separate call
|
|
32
40
|
this._checkedOnChain = false;
|
|
33
41
|
this._normalizedMoveModule = {};
|
|
@@ -154,10 +162,15 @@ class SuiPackageModule extends SuiCommonMethods {
|
|
|
154
162
|
// vector<Coin<SUI>>
|
|
155
163
|
const ownerAddress = this._suiMaster.address;
|
|
156
164
|
|
|
157
|
-
const suiCoin = await this._suiMaster.suiCoins.get(param.type);
|
|
158
|
-
const txCoinToSend = await suiCoin.coinOfAmountToTxCoin(tx, ownerAddress, param.amount);
|
|
165
|
+
const suiCoin = await this._suiMaster.suiCoins.get(param[0].type);
|
|
166
|
+
const txCoinToSend = await suiCoin.coinOfAmountToTxCoin(tx, ownerAddress, param[0].amount);
|
|
159
167
|
|
|
160
|
-
callArgs.push(tx.makeMoveVec({
|
|
168
|
+
callArgs.push(tx.makeMoveVec({ type: suiCoin.coinObjectType, elements: [txCoinToSend]}));
|
|
169
|
+
} else if (typeof param === 'string' && param.indexOf('0x') === 0) {
|
|
170
|
+
callArgs.push(tx.object(param));
|
|
171
|
+
} else if (param && param.Pure && param.Pure.bytes) {
|
|
172
|
+
// already Pure
|
|
173
|
+
callArgs.push(this._suiMaster.utils.txInput(tx, param));
|
|
161
174
|
} else {
|
|
162
175
|
callArgs.push(tx.pure(param));
|
|
163
176
|
}
|
package/lib/SuiUtils.js
CHANGED
|
@@ -1,13 +1,32 @@
|
|
|
1
1
|
const SuiCommonMethods = require('./SuiCommonMethods.js');
|
|
2
|
-
const { Inputs } = require('@mysten/sui/transactions');
|
|
2
|
+
const { Inputs, Transaction, Argument } = require('@mysten/sui/transactions');
|
|
3
3
|
const { bcs } = require('@mysten/sui/bcs');
|
|
4
|
+
const { fromB64 } = require('@mysten/bcs');
|
|
4
5
|
const { SuiClient, getFullnodeUrl, SuiHTTPTransport } = require('@mysten/sui/client');
|
|
5
6
|
const { normalizeSuiAddress } = require('@mysten/sui/utils');
|
|
6
7
|
|
|
7
8
|
const WebSocketClient = require('websocket').w3cwebsocket;
|
|
8
9
|
|
|
10
|
+
/** Helpful methods using in different places of suidouble */
|
|
9
11
|
class SuiUtils extends SuiCommonMethods {
|
|
10
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Attach the parameter input into transaction, to be used for moveCall
|
|
15
|
+
* accepts an Inputs.Pure (result of .pureInput) or type + value directly
|
|
16
|
+
*
|
|
17
|
+
* @param {Transaction} tx
|
|
18
|
+
* @param {string | Inputs.Pure} typeOrInput
|
|
19
|
+
* @param {?Argument} value
|
|
20
|
+
* @returns Argument
|
|
21
|
+
*/
|
|
22
|
+
static txInput(tx, typeOrInput, value = null) {
|
|
23
|
+
if (typeOrInput && typeOrInput.Pure && typeOrInput.Pure.bytes) {
|
|
24
|
+
return tx.pure(SuiUtils.pureInputToBytes(typeOrInput));
|
|
25
|
+
} else {
|
|
26
|
+
return tx.pure(SuiUtils.pureInputToBytes(SuiUtils.pureInput(typeOrInput, value)));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
11
30
|
/**
|
|
12
31
|
* Returns and Inputs.Pure for a given type
|
|
13
32
|
* to be used as moveCall parameters
|
|
@@ -19,13 +38,7 @@ class SuiUtils extends SuiCommonMethods {
|
|
|
19
38
|
* SuiUtils.pureInput('string', 'metadata')
|
|
20
39
|
* ]);
|
|
21
40
|
*
|
|
22
|
-
*
|
|
23
|
-
* wrapped in tx.pure if you are going to construct tx yourself:
|
|
24
|
-
* const tx = new Transaction();
|
|
25
|
-
* tx.moveCall({ target: `x.x.x`, arguments: [
|
|
26
|
-
* tx.pure(SuiUtils.pureInput('u8',22)),
|
|
27
|
-
* tx.pure(SuiUtils.pureInput('string','test')),
|
|
28
|
-
* ] });
|
|
41
|
+
* if you are going to construct tx yourself, you'd better use SuiUtils.txInput static method
|
|
29
42
|
*
|
|
30
43
|
* @param {string} type
|
|
31
44
|
* @param {value} value
|
|
@@ -58,24 +71,34 @@ class SuiUtils extends SuiCommonMethods {
|
|
|
58
71
|
}
|
|
59
72
|
}
|
|
60
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Convert sui's PureInput into bcs serialized bytes
|
|
76
|
+
* @param {Inputs.Pure} pureInput
|
|
77
|
+
*/
|
|
78
|
+
static pureInputToBytes(pureInput) {
|
|
79
|
+
return fromB64(pureInput.Pure.bytes);
|
|
80
|
+
}
|
|
81
|
+
|
|
61
82
|
/**
|
|
62
83
|
* Wrapper for sui's utils normalizeSuiAddress
|
|
63
84
|
* Perform the following operations:
|
|
85
|
+
* <pre>
|
|
64
86
|
* 1. Make the address lower case
|
|
65
87
|
* 2. Prepend `0x` if the string does not start with `0x`.
|
|
66
88
|
* 3. Add more zeros if the length of the address(excluding `0x`) is less than `SUI_ADDRESS_LENGTH`
|
|
89
|
+
* </pre>
|
|
67
90
|
*
|
|
68
91
|
* @param {string} address
|
|
69
92
|
* @returns string
|
|
70
93
|
*/
|
|
71
|
-
normalizeSuiAddress(address) {
|
|
94
|
+
static normalizeSuiAddress(address) {
|
|
72
95
|
return normalizeSuiAddress(address);
|
|
73
96
|
}
|
|
74
97
|
|
|
75
98
|
/**
|
|
76
99
|
* As SUI removed websocket dependency for a node, we'll have it here as constructor wrapper
|
|
77
100
|
* returning native WebSocket in browser and websocket's w3cwebsocket in node
|
|
78
|
-
* @returns
|
|
101
|
+
* @returns WebSocketClient
|
|
79
102
|
*/
|
|
80
103
|
static WebSocketConstructor() {
|
|
81
104
|
return WebSocketClient;
|
|
@@ -128,7 +151,7 @@ class SuiUtils extends SuiCommonMethods {
|
|
|
128
151
|
client = SuiUtils.suiClientFor('mainnet');
|
|
129
152
|
providerName = 'sui:mainnet';
|
|
130
153
|
} else {
|
|
131
|
-
if (clientParam && clientParam.constructor && clientParam.
|
|
154
|
+
if (clientParam && clientParam.constructor && (clientParam.endpoint || clientParam.transport)) {
|
|
132
155
|
client = clientParam;
|
|
133
156
|
let url = '';
|
|
134
157
|
if (clientParam.endpoint) {
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "suidouble",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.6.0-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
|
"scripts": {
|
|
7
|
-
"test": "tap -
|
|
8
|
-
"coverage": "tap -
|
|
7
|
+
"test": "tap -j1 -t120 ./test/*.test.js",
|
|
8
|
+
"coverage": "tap -j1 -t120 ./test/*.test.js"
|
|
9
9
|
},
|
|
10
10
|
"keywords": [
|
|
11
11
|
"sui",
|
|
@@ -21,17 +21,18 @@
|
|
|
21
21
|
"author": "Jeka Kiselyov <jeka911@gmail.com> (https://github.com/jeka-kiselyov)",
|
|
22
22
|
"license": "Apache-2.0",
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@mysten/sui": "^1.0
|
|
24
|
+
"@mysten/sui": "^1.6.0",
|
|
25
25
|
"@wallet-standard/core": "^1.0.3",
|
|
26
26
|
"websocket": "^1.0.35"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"tap": "^
|
|
29
|
+
"tap": "^21.0.1"
|
|
30
|
+
},
|
|
31
|
+
"browser": {
|
|
32
|
+
"child_process": false,
|
|
33
|
+
"fs": false,
|
|
34
|
+
"path": false
|
|
30
35
|
},
|
|
31
36
|
"tap": {
|
|
32
|
-
"branches": 90,
|
|
33
|
-
"lines": 90,
|
|
34
|
-
"functions": 90,
|
|
35
|
-
"statements": 90
|
|
36
37
|
}
|
|
37
38
|
}
|
package/test/coins.test.js
CHANGED
|
@@ -89,7 +89,7 @@ test('getting coin objects for a transaction', async t => {
|
|
|
89
89
|
|
|
90
90
|
const tx = new Transaction();
|
|
91
91
|
const coinInput = await suiCoin.coinOfAmountToTxCoin(tx, suiMaster.address, suiMaster.MIST_PER_SUI); // pick 1 SUI
|
|
92
|
-
tx.transferObjects([coinInput],
|
|
92
|
+
tx.transferObjects([coinInput], '0x1d20dcdb2bca4f508ea9613994683eb4e76e9c4ed371169677c1be02aaf0b12a'); // send it anywhere
|
|
93
93
|
|
|
94
94
|
const result = await suiMaster.signAndExecuteTransaction({
|
|
95
95
|
transaction: tx,
|
|
@@ -152,33 +152,36 @@ test('can find a package on the blockchain by expected module name (in owned)',
|
|
|
152
152
|
t.equal(contract.version, 2);
|
|
153
153
|
});
|
|
154
154
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
155
|
+
// Event websocket subscriptions are going to be deprecated.
|
|
156
|
+
// test('subscribe to module events', async t => {
|
|
157
|
+
// const module = await contract.getModule('suidouble_chat');
|
|
158
|
+
// await module.subscribeEvents();
|
|
158
159
|
|
|
159
|
-
|
|
160
|
-
|
|
160
|
+
// let gotEventChatTopMessageCreated = false;
|
|
161
|
+
// let gotEventChatResponseCreated = false;
|
|
161
162
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
163
|
+
// module.addEventListener('ChatTopMessageCreated', (event)=>{
|
|
164
|
+
// gotEventChatTopMessageCreated = event;
|
|
165
|
+
// });
|
|
166
|
+
// module.addEventListener('ChatResponseCreated', (event)=>{
|
|
167
|
+
// gotEventChatResponseCreated = event.detail; // .detail is reference to event itself. To support CustomEvent pattern
|
|
168
|
+
// });
|
|
168
169
|
|
|
169
|
-
|
|
170
|
-
|
|
170
|
+
// await contract.moveCall('suidouble_chat', 'post', [chatShopObjectId, contract.arg('string', 'the message'), contract.arg('string', 'metadata')]);
|
|
171
|
+
// await new Promise((res)=>setTimeout(res, 300)); // got events without timeout, but just to be sure.
|
|
171
172
|
|
|
172
|
-
|
|
173
|
-
|
|
173
|
+
// t.ok(gotEventChatTopMessageCreated);
|
|
174
|
+
// t.ok(gotEventChatResponseCreated);
|
|
174
175
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
176
|
+
// // just some checks that events have data by contract's architecture
|
|
177
|
+
// t.ok(gotEventChatResponseCreated.parsedJson.top_message_id == gotEventChatTopMessageCreated.parsedJson.id);
|
|
178
|
+
// t.ok(gotEventChatTopMessageCreated.parsedJson.top_response_id == gotEventChatResponseCreated.parsedJson.id);
|
|
178
179
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
180
|
+
// // unsubscribing from events, to close websocket
|
|
181
|
+
// await module.unsubscribeEvents();
|
|
182
|
+
|
|
183
|
+
// t.end();
|
|
184
|
+
// });
|
|
182
185
|
|
|
183
186
|
test('execute contract methods', async t => {
|
|
184
187
|
const moveCallResult = await contract.moveCall('suidouble_chat', 'post', [chatShopObjectId, contract.arg('string', 'the message'), contract.arg('string', 'metadata')]);
|
|
@@ -346,9 +349,7 @@ test('testing move call with coins', async t => {
|
|
|
346
349
|
|
|
347
350
|
t.ok(foundChatTopMessage);
|
|
348
351
|
t.ok(foundChatResponse);
|
|
349
|
-
|
|
350
|
-
// messageTextAsBytes = [].slice.call(new TextEncoder().encode(messageText)); // regular array with utf data
|
|
351
|
-
// suidouble_chat contract store text a bytes (easier to work with unicode things), let's convert it back to js string
|
|
352
|
+
|
|
352
353
|
foundText = new TextDecoder().decode(new Uint8Array(foundText));
|
|
353
354
|
|
|
354
355
|
t.equal(foundText, longMessageYouCanNotPostForFree);
|
|
@@ -358,6 +359,19 @@ test('testing move call with coins', async t => {
|
|
|
358
359
|
t.ok( balanceNow <= (balanceWas - 400000000000n) );
|
|
359
360
|
});
|
|
360
361
|
|
|
362
|
+
test('testing move call with vector<Coin<..>>', async t => {
|
|
363
|
+
const balanceWas = await suiMaster.getBalance();
|
|
364
|
+
const longMessageYouCanNotPostForFree = ('message ').padEnd(500, 'test');
|
|
365
|
+
|
|
366
|
+
// you can pass vector of coin, wrapping it's definition in array
|
|
367
|
+
const moveCallResult = await contract.moveCall('suidouble_chat', 'post_pay_with_coin_vector', [chatShopObjectId, [{type: 'SUI', amount: 400000000000n}], contract.arg('string', longMessageYouCanNotPostForFree), contract.arg('string', 'metadata')]);
|
|
368
|
+
// it's the wrapper over the same move function we've already tested, so lets keep the unit simple:
|
|
369
|
+
t.ok(moveCallResult.created.length > 0);
|
|
370
|
+
|
|
371
|
+
const balanceNow = await suiMaster.getBalance();
|
|
372
|
+
t.ok( balanceNow <= (balanceWas - 400000000000n) ); // vector<Coin<SUI>> paid
|
|
373
|
+
});
|
|
374
|
+
|
|
361
375
|
test('testing move call deleting object', async t => {
|
|
362
376
|
|
|
363
377
|
console.error('chatResponseToDelete', chatResponseToDelete);
|
|
@@ -3,7 +3,7 @@ module suidouble_chat::suidouble_chat {
|
|
|
3
3
|
use sui::object::{Self, UID, ID};
|
|
4
4
|
use sui::transfer;
|
|
5
5
|
use sui::tx_context::{Self, TxContext};
|
|
6
|
-
use std::vector::length;
|
|
6
|
+
use std::vector::{Self, length};
|
|
7
7
|
|
|
8
8
|
use sui::dynamic_object_field::{Self};
|
|
9
9
|
|
|
@@ -12,6 +12,7 @@ module suidouble_chat::suidouble_chat {
|
|
|
12
12
|
use sui::balance::{Self, Balance};
|
|
13
13
|
|
|
14
14
|
use std::debug;
|
|
15
|
+
use sui::pay;
|
|
15
16
|
|
|
16
17
|
use sui::event::emit;
|
|
17
18
|
|
|
@@ -168,6 +169,17 @@ module suidouble_chat::suidouble_chat {
|
|
|
168
169
|
transfer::share_object(chat_top_message);
|
|
169
170
|
}
|
|
170
171
|
|
|
172
|
+
public entry fun post_pay_with_coin_vector(
|
|
173
|
+
chat_shop: &mut ChatShop,
|
|
174
|
+
coins: vector<Coin<SUI>>,
|
|
175
|
+
text: vector<u8>,
|
|
176
|
+
metadata: vector<u8>,
|
|
177
|
+
ctx: &mut TxContext
|
|
178
|
+
) {
|
|
179
|
+
let base = vector::pop_back(&mut coins);
|
|
180
|
+
pay::join_vec(&mut base, coins);
|
|
181
|
+
post_pay(chat_shop, base, text, metadata, ctx);
|
|
182
|
+
}
|
|
171
183
|
|
|
172
184
|
/// Mint (post) a ChatResponse object
|
|
173
185
|
public entry fun reply(
|