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 CHANGED
@@ -168,7 +168,9 @@ while (events.hasNextPage) {
168
168
 
169
169
  ##### subscribing to events
170
170
 
171
- You can subscribe to Sui's contract events on package's module level. No types-etc filters for now ( @todo? )
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 block yourself:
297
+ If you need more flexebility, there's always an option to construct the transaction yourself:
296
298
 
297
299
  ```javascript
298
- const { TransactionBlock, Transactions } = require('suidobule'); // this exposes classes from the "@mysten/sui.js", so you don't have to import them separately
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 txb = new TransactionBlock();
301
- txb.moveCall({
302
+ const tx = new Transaction();
303
+ tx.moveCall({
302
304
  target: `package_id::module_id::method_name`,
303
305
  arguments: [
304
- txb.pure(contract.arg('u256', something)),
305
- txb.object(someid),
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: txb});
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];
@@ -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
- // const { spawn } = require('child_process');
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
- const params = [];
77
- if (this._epochDuration) {
78
- params.push('--epoch-duration-ms');
79
- params.push(this._epochDuration);
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.__readyLaunchedPromise;
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 TransactionBlock() {
114
- return TransactionBlock;
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
- tx.pure(this.arg('u8', UpgradePolicyCOMPATIBLE)),
456
- tx.pure(this.arg('vector<u8>', this._builtDigest)),
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({
@@ -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({ objects: [txCoinToSend]}));
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
- * or:
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.constructor.name && clientParam.constructor.name == 'SuiClient') {
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.4",
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 -j=1 ./test/*.test.js",
8
- "coverage": "tap -j=1 ./test/*.test.js"
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.4",
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": "^16.3.4"
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
  }
@@ -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], tx.pure('0x1d20dcdb2bca4f508ea9613994683eb4e76e9c4ed371169677c1be02aaf0b12a')); // send it anywhere
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
- test('subscribe to module events', async t => {
156
- const module = await contract.getModule('suidouble_chat');
157
- await module.subscribeEvents();
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
- let gotEventChatTopMessageCreated = false;
160
- let gotEventChatResponseCreated = false;
160
+ // let gotEventChatTopMessageCreated = false;
161
+ // let gotEventChatResponseCreated = false;
161
162
 
162
- module.addEventListener('ChatTopMessageCreated', (event)=>{
163
- gotEventChatTopMessageCreated = event;
164
- });
165
- module.addEventListener('ChatResponseCreated', (event)=>{
166
- gotEventChatResponseCreated = event.detail; // .detail is reference to event itself. To support CustomEvent pattern
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
- await contract.moveCall('suidouble_chat', 'post', [chatShopObjectId, contract.arg('string', 'the message'), contract.arg('string', 'metadata')]);
170
- await new Promise((res)=>setTimeout(res, 300)); // got events without timeout, but just to be sure.
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
- t.ok(gotEventChatTopMessageCreated);
173
- t.ok(gotEventChatResponseCreated);
173
+ // t.ok(gotEventChatTopMessageCreated);
174
+ // t.ok(gotEventChatResponseCreated);
174
175
 
175
- // just some checks that events have data by contract's architecture
176
- t.ok(gotEventChatResponseCreated.parsedJson.top_message_id == gotEventChatTopMessageCreated.parsedJson.id);
177
- t.ok(gotEventChatTopMessageCreated.parsedJson.top_response_id == gotEventChatResponseCreated.parsedJson.id);
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
- // unsubscribing from events, to close websocket
180
- await module.unsubscribeEvents();
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);
@@ -21,6 +21,6 @@ dependencies = [
21
21
  ]
22
22
 
23
23
  [move.toolchain-version]
24
- compiler-version = "1.25.1"
24
+ compiler-version = "1.30.1"
25
25
  edition = "2024.beta"
26
26
  flavor = "sui"
@@ -22,6 +22,6 @@ dependencies = [
22
22
  ]
23
23
 
24
24
  [move.toolchain-version]
25
- compiler-version = "1.25.1"
26
- edition = "legacy"
25
+ compiler-version = "1.30.1"
26
+ edition = "2024.beta"
27
27
  flavor = "sui"
@@ -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(