suidouble 0.0.31 → 0.0.33

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/index.js CHANGED
@@ -8,4 +8,5 @@ module.exports = {
8
8
  SuiInBrowser,
9
9
  SuiTestScenario,
10
10
  SuiLocalTestValidator,
11
+ MIST_PER_SUI: SuiMaster.MIST_PER_SUI,
11
12
  };
package/lib/SuiMaster.js CHANGED
@@ -3,6 +3,10 @@ const SuiCommonMethods = require('./SuiCommonMethods.js');
3
3
  const SuiPackage = require('./SuiPackage.js');
4
4
  const SuiPseudoRandomAddress = require('./SuiPseudoRandomAddress.js');
5
5
  const SuiMemoryObjectStorage = require('./SuiMemoryObjectStorage.js');
6
+ const SuiPaginatedResponse = require('./SuiPaginatedResponse.js');
7
+ const SuiObject = require('./SuiObject.js');
8
+ const SuiTransaction = require('./SuiTransaction.js');
9
+ const SuiEvent = require('./SuiEvent.js');
6
10
 
7
11
  class SuiMaster extends SuiCommonMethods {
8
12
  constructor(params = {}) {
@@ -104,6 +108,25 @@ class SuiMaster extends SuiCommonMethods {
104
108
  return BigInt(sui.MIST_PER_SUI);
105
109
  }
106
110
 
111
+ /**
112
+ * Referencing it here to get rid of circullar dependency. So you can always call SuiObject contructor if you have instance of SuiMaster
113
+ */
114
+ get SuiObject() {
115
+ return SuiObject;
116
+ }
117
+ /**
118
+ * Referencing it here to get rid of circullar dependency. So you can always call SuiTransaction contructor if you have instance of SuiMaster
119
+ */
120
+ get SuiTransaction() {
121
+ return SuiTransaction;
122
+ }
123
+ /**
124
+ * Referencing it here to get rid of circullar dependency. So you can always call SuiEvent contructor if you have instance of SuiMaster
125
+ */
126
+ get SuiEvent() {
127
+ return SuiEvent;
128
+ }
129
+
107
130
  get objectStorage() {
108
131
  return this._objectStorage;
109
132
  }
@@ -234,8 +257,68 @@ class SuiMaster extends SuiCommonMethods {
234
257
  this.log('balance of', coinType, 'is', ret);
235
258
  return ret;
236
259
  }
237
- };
238
260
 
261
+ // export type TransactionFilter =
262
+ // | { FromOrToAddress: { addr: string } }
263
+ // | { Checkpoint: string }
264
+ // | { FromAndToAddress: { from: string; to: string } }
265
+ // | { TransactionKind: string }
266
+ // | {
267
+ // MoveFunction: {
268
+ // package: ObjectId;
269
+ // module: string | null;
270
+ // function: string | null;
271
+ // };
272
+ // }
273
+ // | { InputObject: ObjectId }
274
+ // | { ChangedObject: ObjectId }
275
+ // | { FromAddress: SuiAddress }
276
+ // | { ToAddress: SuiAddress };
277
+
278
+
279
+ // /* Whether to show transaction input data. Default to be false. */
280
+ // showInput: optional(boolean()),
281
+ // /* Whether to show transaction effects. Default to be false. */
282
+ // showEffects: optional(boolean()),
283
+ // /* Whether to show transaction events. Default to be false. */
284
+ // showEvents: optional(boolean()),
285
+ // /* Whether to show object changes. Default to be false. */
286
+ // showObjectChanges: optional(boolean()),
287
+ // /* Whether to show coin balance changes. Default to be false. */
288
+ // showBalanceChanges: optional(boolean()),
289
+ async fetchTransactions(params = {}) {
290
+ const filter = {};
291
+ if (params.fromOrToAddress) {
292
+ filter.FromOrToAddress = { addr: params.fromOrToAddress };
293
+ }
294
+
295
+ const queryParams = {
296
+ descending_order: false,
297
+ query: filter,
298
+ options: {
299
+ showInput: true,
300
+ showEffects: true,
301
+ showEvents: true,
302
+ showObjectChanges: true,
303
+ showBalanceChanges: true,
304
+ },
305
+ limit: params.limit || 50,
306
+ };
307
+ const paginatedResponse = new SuiPaginatedResponse({
308
+ debug: this._debug,
309
+ suiMaster: this,
310
+ params: queryParams,
311
+ method: 'queryTransactionBlocks',
312
+ order: params.order,
313
+ });
314
+
315
+ await paginatedResponse.fetch();
316
+
317
+ return paginatedResponse;
318
+ }
319
+
320
+ };
239
321
 
322
+ SuiMaster.MIST_PER_SUI = BigInt(sui.MIST_PER_SUI);
240
323
 
241
324
  module.exports = SuiMaster;
package/lib/SuiObject.js CHANGED
@@ -238,6 +238,38 @@ class SuiObject extends SuiCommonMethods {
238
238
  }
239
239
  }
240
240
 
241
+ /**
242
+ * Replace data with another suiObject data if it's version is newer compared to this one
243
+ * @param {SuiObject} suiObject
244
+ */
245
+ replaceWithSuiObjectIfNeeded(suiObject) {
246
+ if (!suiObject || !suiObject.version || !suiObject.id) {
247
+ return false;
248
+ }
249
+
250
+ if (!this.idEquals(suiObject.id)) {
251
+ // should be the same id
252
+ return false;
253
+ }
254
+
255
+ if (!this.version || suiObject.version > this.version) {
256
+ this._type = suiObject.type;
257
+ this._owner = suiObject._owner;
258
+ this._fields = suiObject._fields;
259
+ this._display = suiObject._display;
260
+
261
+ this._version = suiObject.version;
262
+
263
+ if (suiObject.isDeleted) {
264
+ this.markAsDeleted();
265
+ }
266
+
267
+ return true;
268
+ }
269
+
270
+ return false;
271
+ }
272
+
241
273
  /**
242
274
  * Try to fill local object properties with values from ( showObjectChanges = true ) rpc response
243
275
  * @param {Object} objectChange
@@ -152,99 +152,59 @@ class SuiPackageModule extends SuiCommonMethods {
152
152
  showDisplay: true,
153
153
  },
154
154
  });
155
+ const suiTransaction = new this._suiMaster.SuiTransaction({
156
+ suiMaster: this._suiMaster,
157
+ debug: this._debug,
158
+ data: result,
159
+ });
155
160
 
156
- let status = null;
157
- if (result && result.effects && result.effects.status && result.effects.status.status) {
158
- status = result.effects.status.status;
159
- }
161
+ const status = suiTransaction.status;
160
162
 
161
163
  const listCreated = [];
162
164
  const listMutated = [];
163
165
  const listDeleted = [];
164
166
 
165
- for (const objectChange of result.objectChanges) {
166
- if (objectChange.objectId) {
167
- if (this.objectStorage.byAddress(objectChange.objectId)) {
168
- this.objectStorage.byAddress(objectChange.objectId).tryToFillDataFromObjectChange(objectChange);
169
- } else {
170
- const obj = new SuiObject({
171
- suiMaster: this._suiMaster,
172
- debug: this._debug,
173
- objectChange: objectChange,
174
- });
175
-
176
- if (obj.address) {
177
- this.objectStorage.push(obj);
178
-
179
- this.emit('added', obj);
180
- }
181
- }
167
+ for (const obj of suiTransaction.results.objects) {
168
+ if (this.objectStorage.byAddress(obj.id)) {
169
+ this.objectStorage.byAddress(obj.id).replaceWithSuiObjectIfNeeded(obj);
170
+ } else {
171
+ this.objectStorage.push(obj);
172
+ this.emit('added', obj);
182
173
  }
183
174
  }
184
175
 
185
- // Mark objects as deleted so we don't fetch them
186
- if (result.effects && result.effects.deleted && result.effects.deleted.length) {
187
- for (const effect of result.effects.deleted) {
188
- // if (effect.reference && effect.reference.objectId) {
189
- // if (this._objects[effect.reference.objectId]) {
190
- // this.log('object is deleted', effect.reference.objectId);
191
- // this._objects[effect.reference.objectId].markAsDeleted();
192
- // }
193
- // }
194
- if (effect.objectId) {
195
- if (this.objectStorage.byAddress(effect.objectId)) {
196
- this.log('object is deleted', effect.objectId);
197
- this.objectStorage.byAddress(effect.objectId).markAsDeleted();
198
- this.emit('deleted', this.objectStorage.byAddress(effect.objectId));
199
-
200
- listDeleted.push(this.objectStorage.byAddress(effect.objectId));
201
- }
202
- }
176
+ for (const obj of suiTransaction.results.deleted) {
177
+ if (this.objectStorage.byAddress(obj.id)) {
178
+ this.objectStorage.byAddress(obj.id).markAsDeleted();
179
+ listDeleted.push(this.objectStorage.byAddress(obj.id));
180
+ this.emit('deleted', this.objectStorage.byAddress(obj.id));
203
181
  }
204
182
  }
205
183
 
206
184
  await this.fetchObjects();
207
185
 
208
- // Emit events based on result.effects
209
- if (result.effects) {
210
- const events = ['created', 'mutated']; // events names are the same as properties in result.effects
211
-
212
- for (const eventName of events) {
213
- if (result.effects[eventName] && result.effects[eventName].length) {
214
- for (const effect of result.effects[eventName]) {
215
- if (effect.reference && effect.reference.objectId) {
216
- if (this.objectStorage.byAddress(effect.reference.objectId)) {
217
- this.emit(eventName, this.objectStorage.byAddress(effect.reference.objectId));
218
-
219
- if (eventName === 'created') {
220
- listCreated.push(this.objectStorage.byAddress(effect.reference.objectId));
221
- } else if (eventName === 'mutated') {
222
- listMutated.push(this.objectStorage.byAddress(effect.reference.objectId));
223
- }
224
- }
225
- }
226
- }
227
- }
186
+ for (const obj of suiTransaction.results.created) {
187
+ if (this.objectStorage.byAddress(obj.id)) {
188
+ listCreated.push(this.objectStorage.byAddress(obj.id)); // it's probably the same instance as it's just created. @todo: check
189
+ this.emit('created', this.objectStorage.byAddress(obj.id));
190
+ } else {
191
+ throw new Error('something is wrong!');
228
192
  }
229
193
  }
230
194
 
231
- if (result.events && result.events.length) {
232
- for (const event of result.events) {
233
- const eventType = event.type;
234
- const eventTypeName = eventType.split(':').pop(); // last name, without package and module names
235
-
236
- // const eventData = event.parsedJson;
237
-
238
- const suiEvent = new SuiEvent({
239
- suiMaster: this._suiMaster,
240
- debug: this._debug,
241
- data: event,
242
- });
243
-
244
- this.emit(eventTypeName, suiEvent);
195
+ for (const obj of suiTransaction.results.mutated) {
196
+ if (this.objectStorage.byAddress(obj.id)) {
197
+ listMutated.push(this.objectStorage.byAddress(obj.id)); // it may be a different entity, updated via .replaceWithSuiObjectIfNeeded above
198
+ this.emit('mutated', this.objectStorage.byAddress(obj.id));
199
+ } else {
200
+ throw new Error('something is wrong!');
245
201
  }
246
202
  }
247
203
 
204
+ for (const suiEvent of suiTransaction.events) {
205
+ this.emit(suiEvent.typeName, suiEvent);
206
+ }
207
+
248
208
  return {
249
209
  created: listCreated,
250
210
  mutated: listMutated,
@@ -1,6 +1,7 @@
1
1
  const sui = require('@mysten/sui.js');
2
2
  const SuiCommonMethods = require('./SuiCommonMethods.js');
3
3
  const SuiEvent = require('./SuiEvent.js');
4
+ const SuiTransaction = require('./SuiTransaction.js');
4
5
 
5
6
  class SuiPaginatedResponse extends SuiCommonMethods {
6
7
  constructor(params = {}) {
@@ -83,6 +84,9 @@ class SuiPaginatedResponse extends SuiCommonMethods {
83
84
  if (this._method === 'queryEvents') {
84
85
  // convert data to SuiEvent instances
85
86
  this._data = response.data.map((raw)=>(new SuiEvent({data: raw, suiMaster: this._suiMaster, debug: this._debug})));
87
+ } else if (this._method === 'queryTransactionBlocks') {
88
+ // convert data to SuiEvent instances
89
+ this._data = response.data.map((raw)=>(new SuiTransaction({data: raw, suiMaster: this._suiMaster, debug: this._debug})));
86
90
  } else {
87
91
  this._data = response.data;
88
92
  }
@@ -0,0 +1,152 @@
1
+ const SuiCommonMethods = require('./SuiCommonMethods.js');
2
+
3
+ class SuiTransaction extends SuiCommonMethods {
4
+ constructor(params = {}) {
5
+ super(params);
6
+
7
+ this._debug = !!params.debug;
8
+ this._suiMaster = params.suiMaster;
9
+ if (!this._suiMaster) {
10
+ throw new Error('suiMaster is requried for suiPackage');
11
+ }
12
+
13
+ this._data = params.data || {};
14
+
15
+ this._results = null;
16
+ this._events = null;
17
+ }
18
+
19
+ get data() {
20
+ return this._data;
21
+ }
22
+
23
+ get status() {
24
+ let status = null;
25
+ if (this.data && this.data.effects && this.data.effects.status && this.data.effects.status.status) {
26
+ status = this.data.effects.status.status;
27
+ }
28
+ return status;
29
+ }
30
+
31
+ isSuccessful() {
32
+ if (this.data && this.data.effects && this.data.effects.status && this.data.effects.status.status) {
33
+ if (this.data.effects.status.status == 'success') {
34
+ return true;
35
+ }
36
+ }
37
+
38
+ return false;
39
+ }
40
+
41
+ get events() {
42
+ if (this._events) {
43
+ return this._events;
44
+ }
45
+
46
+ const events = [];
47
+
48
+ if (this.data.events && this.data.events.length) {
49
+ for (const event of this.data.events) {
50
+ const suiEvent = new this._suiMaster.SuiEvent({
51
+ suiMaster: this._suiMaster,
52
+ debug: this._debug,
53
+ data: event,
54
+ });
55
+
56
+ events.push(suiEvent);
57
+ }
58
+ }
59
+
60
+ this._events = events;
61
+ return this._events;
62
+ }
63
+
64
+ get results() {
65
+ if (this._results) {
66
+ return this._results;
67
+ }
68
+
69
+ const objects = {};
70
+
71
+ const listCreated = [];
72
+ const listMutated = [];
73
+ const listDeleted = [];
74
+
75
+ if (this.data.objectChanges) {
76
+ for (const objectChange of this.data.objectChanges) {
77
+ if (objectChange.objectId) {
78
+ if (objects[objectChange.objectId]) {
79
+
80
+ } else {
81
+ const obj = new this._suiMaster.SuiObject({
82
+ suiMaster: this._suiMaster,
83
+ debug: this._debug,
84
+ objectChange: objectChange,
85
+ });
86
+ if (obj.address) {
87
+ objects[obj.address] = obj;
88
+ }
89
+ }
90
+ }
91
+ }
92
+ }
93
+
94
+ if (this.data.effects) {
95
+ const events = ['created', 'mutated']; // events names are the same as properties in result.effects
96
+
97
+ for (const eventName of events) {
98
+ if ( this.data.effects[eventName] && this.data.effects[eventName].length) {
99
+ for (const effect of this.data.effects[eventName]) {
100
+ if (effect.reference && effect.reference.objectId) {
101
+ if (objects[effect.reference.objectId]) {
102
+ if (eventName === 'created') {
103
+ listCreated.push(objects[effect.reference.objectId]);
104
+ } else if (eventName === 'mutated') {
105
+ listMutated.push(objects[effect.reference.objectId]);
106
+ }
107
+ }
108
+ }
109
+ }
110
+ }
111
+ }
112
+
113
+ if (this.data.effects.deleted) {
114
+ for (const effect of this.data.effects.deleted) {
115
+ if (effect.objectId) {
116
+ if (objects[effect.objectId]) {
117
+
118
+ } else {
119
+ const obj = new this._suiMaster.SuiObject({
120
+ suiMaster: this._suiMaster,
121
+ debug: this._debug,
122
+ objectChange: effect,
123
+ });
124
+ objects[effect.objectId] = obj;
125
+ }
126
+ objects[effect.objectId].markAsDeleted();
127
+ listDeleted.push(objects[effect.objectId]);
128
+ }
129
+ }
130
+ }
131
+ }
132
+
133
+ this._results = {
134
+ created: listCreated,
135
+ mutated: listMutated,
136
+ deleted: listDeleted,
137
+ objects: Object.values(objects),
138
+ };
139
+
140
+ return this._results;
141
+ }
142
+
143
+ get timestampMs() {
144
+ if (this.data.timestampMs) {
145
+ return parseInt(this.data.timestampMs, 10);
146
+ } else {
147
+ return null;
148
+ }
149
+ }
150
+ };
151
+
152
+ module.exports = SuiTransaction;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "suidouble",
3
- "version": "0.0.31",
3
+ "version": "0.0.33",
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": {
@@ -3,7 +3,7 @@
3
3
  const t = require('tap');
4
4
  const { test } = t;
5
5
 
6
- const { SuiMaster } = require('..');
6
+ const { SuiMaster, MIST_PER_SUI } = require('..');
7
7
 
8
8
  test('initialization', async t => {
9
9
  t.plan(2);
@@ -62,6 +62,10 @@ test('SuiMaster has MIST_PER_SUI property available as BigInt', async t => {
62
62
 
63
63
  t.equal(typeof suiMaster.MIST_PER_SUI, 'bigint');
64
64
  t.ok(suiMaster.MIST_PER_SUI > BigInt(0));
65
+
66
+
67
+ t.equal(suiMaster.MIST_PER_SUI, SuiMaster.MIST_PER_SUI);
68
+ t.equal(suiMaster.MIST_PER_SUI, MIST_PER_SUI); // available as global library export too
65
69
  });
66
70
 
67
71
  test('connecting to different chains', async t => {
@@ -84,4 +88,22 @@ test('connecting to different chains', async t => {
84
88
  await suiMaster4.initialize();
85
89
 
86
90
  t.equal(suiMaster4.connectedChain, 'sui:localnet');
87
- });
91
+ });
92
+
93
+ // test('get transactions', async t => {
94
+ // const suiMaster = new SuiMaster({provider: 'main', as: 'somebody'});
95
+ // await suiMaster.initialize();
96
+
97
+ // const paginatedResponse = await suiMaster.fetchTransactions({
98
+ // fromOrToAddress: '0xffc5bc3732f201892df5d2839b86957abcf42dfe66dc79383fe107f6548bc2bf',
99
+ // });
100
+
101
+ // await paginatedResponse.forEach((suiTransaction)=>{
102
+ // // console.log(suiTransaction.results);
103
+ // const objects = suiTransaction.results.objects;
104
+ // for (const o of objects) {
105
+ // // console.log(o.id, o.typeName, o.version);
106
+ // }
107
+ // }, 10);
108
+
109
+ // });
@@ -15,6 +15,8 @@ let contractAddressV2 = null;
15
15
 
16
16
  let chatShopObjectId = null;
17
17
 
18
+ let chatResponseToDelete = null;
19
+
18
20
  test('spawn local test node', async t => {
19
21
  suiLocalTestValidator = await SuiLocalTestValidator.launch({ testFallbackEnabled: true });
20
22
  t.ok(suiLocalTestValidator.active);
@@ -230,6 +232,8 @@ test('execute contract methods', async t => {
230
232
  moveCallResult2.created.forEach((obj)=>{
231
233
  if (obj.typeName == 'ChatResponse') {
232
234
  responseText = obj.fields.text;
235
+
236
+ chatResponseToDelete = obj.id; // ChatResponse is moved to be owned by author, so we can store id to try burn_response later
233
237
  }
234
238
  });
235
239
  // messageTextAsBytes = [].slice.call(new TextEncoder().encode(messageText)); // regular array with utf data
@@ -275,6 +279,7 @@ test('testing paginatedResponse', async t => {
275
279
  t.ok(loopsInForEach >= 60); // it's 60 in move code, but let's keep chat flexible
276
280
  });
277
281
 
282
+
278
283
  test('testing move call with coins', async t => {
279
284
  const balanceWas = await suiMaster.getBalance();
280
285
 
@@ -317,6 +322,20 @@ test('testing move call with coins', async t => {
317
322
  t.ok( balanceNow <= (balanceWas - 400000000000n) );
318
323
  });
319
324
 
325
+ test('testing move call deleting object', async t => {
326
+
327
+ console.error('chatResponseToDelete', chatResponseToDelete);
328
+
329
+ const moveCallResult = await contract.moveCall('suidouble_chat', 'burn_response', [chatResponseToDelete]);
330
+
331
+ // there're at least some object created
332
+ t.ok(moveCallResult.deleted.length > 0);
333
+
334
+ t.equal(moveCallResult.deleted[0].id, chatResponseToDelete);
335
+
336
+ t.ok(moveCallResult.deleted[0].isDeleted);
337
+ });
338
+
320
339
  test('stops local test node', async t => {
321
340
  await SuiLocalTestValidator.stop();
322
341
  });
@@ -201,6 +201,12 @@ module suidouble_chat::suidouble_chat {
201
201
 
202
202
  transfer::transfer(chat_response, tx_context::sender(ctx));
203
203
  }
204
+
205
+ /// Permanently delete `ChatResponse`
206
+ public entry fun burn_response(chat_response: ChatResponse, _: &mut TxContext) {
207
+ let ChatResponse { id, chat_top_message_id: _, author: _, text: _, metadata: _, seq_n: _ } = chat_response;
208
+ object::delete(id)
209
+ }
204
210
 
205
211
 
206
212
  // /// Mint (post) a ChatResponse object