suidouble 1.0.4 → 1.6.0

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
@@ -16,4 +16,5 @@ module.exports = {
16
16
  Transaction: Transaction,
17
17
  Commands: Commands,
18
18
  SuiUtils: SuiUtils,
19
+ txInput: SuiUtils.txInput,
19
20
  };
package/lib/SuiCoin.js CHANGED
@@ -1,4 +1,4 @@
1
- const { Commands } = require('@mysten/sui/transactions');
1
+ const { Commands, Transaction } = require('@mysten/sui/transactions');
2
2
  const { bcs } = require('@mysten/sui/bcs');
3
3
  // console.log(bcs);
4
4
 
@@ -102,6 +102,15 @@ class SuiCoin {
102
102
  return '0x'+this._coinType;
103
103
  }
104
104
 
105
+ /**
106
+ * Move type for the Coin object of this coin type
107
+ *
108
+ * @type {string}
109
+ */
110
+ get coinObjectType() {
111
+ return '0x2::coin::Coin<'+this.coinType+'>';
112
+ }
113
+
105
114
  get decimals() {
106
115
  if (this.metadata) {
107
116
  return this.metadata.decimals;
@@ -202,6 +211,15 @@ class SuiCoin {
202
211
  return totalAmount;
203
212
  }
204
213
 
214
+ /**
215
+ * Returns TransactionObjectArgument with Coin of amount to be used in tranasctions
216
+ *
217
+ * @param {import('@mysten/sui/transactions').Transaction} txb - Native SUI SDK Transaction
218
+ * @param {string} owner - address of the owner
219
+ * @param {BigInt|string} amount - amount of coin. BigIng or String to be normalized via Coin decimals, "0.05" for 0.05 sui
220
+ * @param {boolean} addEmptyCoins - attach coins == 0 to the list
221
+ * @returns {import('@mysten/sui/transactions').TransactionObjectArgument}
222
+ */
205
223
  async coinOfAmountToTxCoin(txb, owner, amount, addEmptyCoins = false) {
206
224
  const normalizedAmount = await this.lazyNormalizeAmount(amount);
207
225
 
@@ -215,12 +233,6 @@ class SuiCoin {
215
233
  if (coinIds.length == 1) {
216
234
  // only one coin object enough to cover the expense
217
235
  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
236
  const coinInput = txb.add(Commands.SplitCoins(txb.gas, [txb.pure.u64(expectedAmountAsBigInt)]));
225
237
  return coinInput;
226
238
  } 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,6 +1,7 @@
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
 
@@ -8,6 +9,23 @@ const WebSocketClient = require('websocket').w3cwebsocket;
8
9
 
9
10
  class SuiUtils extends SuiCommonMethods {
10
11
 
12
+ /**
13
+ * Attacha the parameter input into transaction, to be used for moveCall
14
+ * accepts an Inputs.Pure (result of .pureInput) or type + value directly
15
+ *
16
+ * @param {Transaction} tx
17
+ * @param {Inputs.Pure | String} typeOrInput
18
+ * @param {any | undefined} value
19
+ * @returns Argument
20
+ */
21
+ static txInput(tx, typeOrInput, value = null) {
22
+ if (typeOrInput && typeOrInput.Pure && typeOrInput.Pure.bytes) {
23
+ return tx.pure(this.pureInputToBytes(typeOrInput));
24
+ } else {
25
+ return tx.pure(this.pureInputToBytes(this.pureInput(typeOrInput, value)));
26
+ }
27
+ }
28
+
11
29
  /**
12
30
  * Returns and Inputs.Pure for a given type
13
31
  * to be used as moveCall parameters
@@ -58,6 +76,14 @@ class SuiUtils extends SuiCommonMethods {
58
76
  }
59
77
  }
60
78
 
79
+ /**
80
+ * Convert sui's PureInput into bcs serialized bytes
81
+ * @param {Inputs.Pure} pureInput
82
+ */
83
+ static pureInputToBytes(pureInput) {
84
+ return fromB64(pureInput.Pure.bytes);
85
+ }
86
+
61
87
  /**
62
88
  * Wrapper for sui's utils normalizeSuiAddress
63
89
  * Perform the following operations:
@@ -128,7 +154,7 @@ class SuiUtils extends SuiCommonMethods {
128
154
  client = SuiUtils.suiClientFor('mainnet');
129
155
  providerName = 'sui:mainnet';
130
156
  } else {
131
- if (clientParam && clientParam.constructor && clientParam.constructor.name && clientParam.constructor.name == 'SuiClient') {
157
+ if (clientParam && clientParam.constructor && (clientParam.endpoint || clientParam.transport)) {
132
158
  client = clientParam;
133
159
  let url = '';
134
160
  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",
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(