suidouble 2.5.0 → 2.16.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.
Files changed (55) hide show
  1. package/.claude/settings.local.json +7 -0
  2. package/README.md +222 -131
  3. package/index.js +0 -2
  4. package/lib/SuiCliCommands.js +18 -25
  5. package/lib/SuiCoin.js +79 -137
  6. package/lib/SuiCoins.js +41 -29
  7. package/lib/SuiCommonMethods.js +40 -3
  8. package/lib/SuiEvent.js +54 -6
  9. package/lib/SuiInBrowser.js +143 -15
  10. package/lib/SuiInBrowserAdapter.js +164 -37
  11. package/lib/SuiLocalTestValidator.js +76 -14
  12. package/lib/SuiMaster.js +335 -139
  13. package/lib/SuiMemoryObjectStorage.js +66 -73
  14. package/lib/SuiObject.js +128 -153
  15. package/lib/SuiPackage.js +292 -187
  16. package/lib/SuiPackageModule.js +176 -221
  17. package/lib/SuiPaginatedResponse.js +288 -25
  18. package/lib/SuiPseudoRandomAddress.js +29 -2
  19. package/lib/SuiTransaction.js +115 -70
  20. package/lib/SuiUtils.js +179 -127
  21. package/package.json +29 -13
  22. package/test/build_modules.test.js +41 -0
  23. package/test/coins.test.js +17 -16
  24. package/test/custom_transaction.test.js +167 -0
  25. package/test/event_listeners.test.js +171 -0
  26. package/test/failed_transaction.test.js +184 -0
  27. package/test/name_service.test.js +28 -0
  28. package/test/owned_objects.test.js +148 -0
  29. package/test/rpc.test.js +3 -6
  30. package/test/sui_in_browser.test.js +2 -2
  31. package/test/sui_master_basic.test.js +4 -5
  32. package/test/sui_master_onlocal.test.js +84 -22
  33. package/test/sui_object_properties.test.js +85 -0
  34. package/tsconfig.json +15 -0
  35. package/types/index.d.ts +15 -0
  36. package/types/lib/SuiCliCommands.d.ts +6 -0
  37. package/types/lib/SuiCoin.d.ts +183 -0
  38. package/types/lib/SuiCoins.d.ts +93 -0
  39. package/types/lib/SuiCommonMethods.d.ts +37 -0
  40. package/types/lib/SuiEvent.d.ts +95 -0
  41. package/types/lib/SuiInBrowser.d.ts +189 -0
  42. package/types/lib/SuiInBrowserAdapter.d.ts +167 -0
  43. package/types/lib/SuiLocalTestValidator.d.ts +92 -0
  44. package/types/lib/SuiMaster.d.ts +333 -0
  45. package/types/lib/SuiMemoryObjectStorage.d.ts +96 -0
  46. package/types/lib/SuiObject.d.ts +135 -0
  47. package/types/lib/SuiPackage.d.ts +233 -0
  48. package/types/lib/SuiPackageModule.d.ts +139 -0
  49. package/types/lib/SuiPaginatedResponse.d.ts +148 -0
  50. package/types/lib/SuiPseudoRandomAddress.d.ts +33 -0
  51. package/types/lib/SuiTransaction.d.ts +92 -0
  52. package/types/lib/SuiUtils.d.ts +152 -0
  53. package/types/lib/data/icons.d.ts +12 -0
  54. package/lib/SuiTestScenario.js +0 -169
  55. package/test/sui_test_scenario.test.js +0 -61
@@ -2,8 +2,14 @@ import SuiCommonMethods from './SuiCommonMethods.js';
2
2
  import SuiObject from './SuiObject.js';
3
3
 
4
4
  /**
5
- * Class to work with SuiObject's in bulk
6
- *
5
+ * @typedef {import("./SuiMaster.js").default} SuiMaster
6
+ */
7
+
8
+ /**
9
+ * In-memory registry of `SuiObject` instances keyed by normalized address. One instance is
10
+ * created per connected chain (see `instanceOf`). Used by `SuiPackageModule` and friends to
11
+ * deduplicate object references across moveCall results and queries.
12
+ *
7
13
  * Sample usage:
8
14
  * ```
9
15
  * suiMemoryObjectStorage.push(id);
@@ -17,26 +23,41 @@ export default class SuiMemoryObjectStorage extends SuiCommonMethods {
17
23
  * SuiMemoryObjectStorage constructor
18
24
  * @param {Object} params - Initialization parameters
19
25
  * @param {SuiMaster} params.suiMaster - instance of SuiMaster
26
+ * @param {boolean} [params.debug]
20
27
  */
21
- constructor(params = {}) {
28
+ constructor(params) {
22
29
  super(params);
23
30
 
31
+ /** @type {SuiMaster} */
24
32
  this._suiMaster = params.suiMaster;
25
33
 
26
34
  /** @type {Object.<string, SuiObject>} */
27
35
  this._objects = {};
28
36
  }
29
37
 
38
+ /** @returns {SuiObject[]} all stored SuiObjects, in insertion order */
30
39
  asArray() {
31
40
  return Object.values(this._objects);
32
41
  }
33
42
 
43
+ /**
44
+ * Find the most-recently-pushed object whose `typeName` (short type name, e.g. "ChatTopMessage")
45
+ * matches `typeName`. Ordering is by each object's `constructedAt` timestamp.
46
+ *
47
+ * @param {string} typeName
48
+ * @returns {?SuiObject}
49
+ */
34
50
  findMostRecentByTypeName(typeName) {
35
51
  return this.findMostRecent((object) => {
36
52
  return (object.typeName == typeName);
37
53
  });
38
54
  }
39
55
 
56
+ /**
57
+ * Return the first stored object for which `filterFunction` returns truthy.
58
+ * @param {(obj: SuiObject) => boolean} filterFunction
59
+ * @returns {?SuiObject}
60
+ */
40
61
  find(filterFunction) {
41
62
  for (const id in this._objects) {
42
63
  if (filterFunction(this._objects[id])) {
@@ -47,6 +68,11 @@ export default class SuiMemoryObjectStorage extends SuiCommonMethods {
47
68
  return null;
48
69
  }
49
70
 
71
+ /**
72
+ * Return the most-recently-constructed object (by `constructedAt`) that matches `filterFunction`.
73
+ * @param {(obj: SuiObject) => boolean} filterFunction
74
+ * @returns {?SuiObject}
75
+ */
50
76
  findMostRecent(filterFunction) {
51
77
  let mostRecentDate = null;
52
78
  let mostRecentObject = null;
@@ -64,22 +90,26 @@ export default class SuiMemoryObjectStorage extends SuiCommonMethods {
64
90
  }
65
91
 
66
92
  /**
67
- * @param {SuiObject | string} suiObjectOrId
68
- *
69
- * @returns {SuiObject | null}
93
+ * Store a SuiObject, or wrap a raw `0x…` id in a new SuiObject and store it.
94
+ * If an object with the same address is already stored, it is returned as-is (no replacement).
95
+ *
96
+ * @param {SuiObject | string} suiObjectOrId - a SuiObject instance, or a `0x…` id string
97
+ * @returns {?SuiObject} the stored instance, or null if input didn't look like either
70
98
  */
71
99
  push(suiObjectOrId) {
72
- if (suiObjectOrId && suiObjectOrId.address) {
73
- const /** @type {SuiObject} */ obj = suiObjectOrId;
100
+ const a = /** @type {any} */ (suiObjectOrId);
101
+ if (a && a.address) {
102
+ const obj = /** @type {SuiObject} */ (a);
74
103
  this._objects[obj.address] = obj;
75
104
 
76
105
  return obj;
77
- } else if (suiObjectOrId && (''+suiObjectOrId).indexOf('0x') === 0) {
78
- if (this._objects[suiObjectOrId]) {
79
- return this._objects[suiObjectOrId];
106
+ } else if (a && (''+a).indexOf('0x') === 0) {
107
+ const id = /** @type {string} */ (a);
108
+ if (this._objects[id]) {
109
+ return this._objects[id];
80
110
  }
81
111
 
82
- const obj = new SuiObject({id: suiObjectOrId, suiMaster: this._suiMaster});
112
+ const obj = new SuiObject({id, suiMaster: this._suiMaster});
83
113
  this._objects[obj.address] = obj;
84
114
 
85
115
  return obj;
@@ -88,6 +118,11 @@ export default class SuiMemoryObjectStorage extends SuiCommonMethods {
88
118
  return null;
89
119
  }
90
120
 
121
+ /**
122
+ * Lookup by address. The address must already be in its normalized form (as produced by SuiObject).
123
+ * @param {string} address
124
+ * @returns {?SuiObject}
125
+ */
91
126
  byAddress(address) {
92
127
  if (this._objects[address]) {
93
128
  return this._objects[address];
@@ -95,78 +130,36 @@ export default class SuiMemoryObjectStorage extends SuiCommonMethods {
95
130
  return null;
96
131
  }
97
132
 
133
+ /**
134
+ * Refresh every non-deleted stored SuiObject's fields from chain.
135
+ * Delegates to `SuiMaster.getObjects(...)` which mutates the passed-in instances in place.
136
+ *
137
+ * @returns {Promise<SuiObject[]>}
138
+ */
98
139
  async fetchObjects() {
99
- const objectsToFetch = this.asArray(); //Object.values(this._objects);
140
+ const objectsToFetch = this.asArray().filter((o) => !o.isDeleted);
141
+ if (!objectsToFetch.length) return [];
100
142
 
101
- const objectIds = [];
102
- for (const object of objectsToFetch) {
103
- if (!object.isDeleted && objectIds.indexOf(object.address) === -1) {
104
- objectIds.push(object.address);
105
- }
106
- }
107
-
108
- this.log('querying details about', objectIds.length, 'objects');
109
- this.log(objectIds);
110
-
111
- let results = [];
112
- const maxCountToFetch = 50;
113
- for (let i = 0; i < objectIds.length; i += maxCountToFetch) {
114
- const objectIdsSlice = objectIds.slice(i, i + maxCountToFetch);
115
-
116
- let resultsSlice = [];
117
- let consoleWarnMessage = null;
118
- try {
119
- const originalConsoleWarn = console.warn;
120
- console.warn = (e)=>{
121
- consoleWarnMessage = e;
122
- };
123
- resultsSlice = await this._suiMaster._client.multiGetObjects({
124
- ids: objectIdsSlice,
125
- options: { showType: true, showContent: true, showOwner: true, showDisplay: true, },
126
- });
127
- console.warn = originalConsoleWarn;
128
- } catch(e) {
129
- console.error(e);
130
- }
143
+ this.log('querying details about', objectsToFetch.length, 'objects');
144
+ await this._suiMaster.getObjects(objectsToFetch);
131
145
 
132
- if (consoleWarnMessage) {
133
- this.log('got', resultsSlice.length, 'objects but with warning (ok, but probably it is different client vs rpc versions)');
134
- } else {
135
- this.log('got', resultsSlice.length, 'objects');
136
- }
137
-
138
- if (resultsSlice && resultsSlice.length) {
139
- results = results.concat(resultsSlice);
140
- }
141
- }
142
-
143
- for (const object of objectsToFetch) {
144
- const foundInResults = results.find(element => object.idEquals(element?.data?.objectId));
145
- if (foundInResults) {
146
- object.tryToFillDataFromObjectChange(foundInResults);
147
- // this.log('got updates for object', object.address, object.fields);
148
- } else {
149
- // object is removed?
150
- const foundInRemoved = results.find(element => (element?.error?.code == 'deleted' && object.idEquals(element?.error?.object_id)));
151
- if (foundInRemoved) {
152
- object.markAsDeleted();
153
- } else {
154
- this.log('not found in results', object);
155
- }
156
- }
157
- }
146
+ return objectsToFetch;
158
147
  }
159
148
 
160
149
  static _instances = {};
161
150
 
162
151
  /**
163
- * @param {string} validatorId - just a string for single instance identifier
164
- * @param {Object} params - Initialization parameters
152
+ * Return (and lazily create) a shared SuiMemoryObjectStorage keyed by `validatorId`.
153
+ * Typically `validatorId` is the connected chain name (`sui:mainnet`, `sui:localnet`, …) so that
154
+ * objects from different chains stay isolated.
155
+ *
156
+ * @param {string} validatorId - identifier for the singleton slot (chain name by convention)
157
+ * @param {Object} params - Initialization parameters used only on first creation for that slot
165
158
  * @param {SuiMaster} params.suiMaster - instance of SuiMaster
166
- *
159
+ * @param {boolean} [params.debug]
167
160
  * @returns {SuiMemoryObjectStorage}
168
161
  */
169
- static instanceOf(validatorId, params = {}) {
162
+ static instanceOf(validatorId, params) {
170
163
  if (SuiMemoryObjectStorage._instances[validatorId]) {
171
164
  return SuiMemoryObjectStorage._instances[validatorId];
172
165
  }
package/lib/SuiObject.js CHANGED
@@ -2,6 +2,9 @@ import SuiCommonMethods from './SuiCommonMethods.js';
2
2
  import SuiPaginatedResponse from './SuiPaginatedResponse.js';
3
3
  import { normalizeSuiAddress } from './SuiUtils.js';
4
4
 
5
+ /**
6
+ * @import { SuiClientTypes } from "@mysten/sui/client"
7
+ */
5
8
  /**
6
9
  * @typedef {import("./SuiMaster.js").default} SuiMaster
7
10
  */
@@ -12,23 +15,27 @@ export default class SuiObject extends SuiCommonMethods {
12
15
  *
13
16
  * @param {Object} params - parameters
14
17
  * @param {SuiMaster} params.suiMaster - instance of SuiMaster
18
+ * @param {SuiClientTypes.Object} [params.raw] - raw data from api
15
19
  * @param {?string} [params.id] - ID or address on the sui blockchain
20
+ * @param {string|number} [params.version] - object version
21
+ * @param {?string} [params.type] - fully-qualified Move type string
22
+ * @param {boolean} [params.debug]
16
23
  */
17
- constructor(params = {}) {
24
+ constructor(params) {
18
25
  super(params);
19
26
 
20
27
  /** @type {SuiMaster} */
21
28
  this._suiMaster = params.suiMaster;
22
29
  if (!this._suiMaster) {
23
- throw new Error('suiMaster is requried for suiPackage');
30
+ throw new Error('suiMaster is required for SuiObject');
24
31
  }
25
32
 
26
- /** @type {string} */
33
+ /** @type {?string} */
27
34
  this._id = params.id || null;
28
- this._version = params.version || null;
29
-
35
+ /** @type {?number} */
36
+ this._version = params.version != null ? Number(params.version) : null;
30
37
 
31
- /** @type {string} */
38
+ /** @type {?string} */
32
39
  this._type = params.type || null;
33
40
 
34
41
  this._fields = {}; // on-chain fields on the object
@@ -41,42 +48,84 @@ export default class SuiObject extends SuiCommonMethods {
41
48
 
42
49
  this._localProperties = {}; // object to store some local data for you to help with your local calculations, no interaction with blockchain
43
50
 
44
- // this._ownerAddress = null;
45
-
46
51
  this._isDeleted = false;
47
52
 
48
- if (params.objectChange) {
49
- this.tryToFillDataFromObjectChange(params.objectChange);
53
+ if (params.raw) {
54
+ this.fillDataFromApi(params.raw);
50
55
  }
51
56
 
52
57
  this._constructedAt = new Date(); // just a helpful data so we can sort later when trying to find most recent item in different modules
53
58
  }
54
59
 
60
+ /**
61
+ * Fill local properties from raw SuiClientTypes.Object api response
62
+ * @param {SuiClientTypes.Object} raw
63
+ */
64
+ fillDataFromApi(raw) {
65
+ if (!raw) {
66
+ return;
67
+ }
68
+
69
+ if (raw.objectId && !this._id) {
70
+ this._id = raw.objectId;
71
+ }
72
+ if (raw.version !== undefined && raw.version !== null) {
73
+ this._version = Number(raw.version);
74
+ }
75
+ if (raw.type) {
76
+ this._type = raw.type;
77
+ }
78
+ if (raw.owner) {
79
+ this._owner = raw.owner;
80
+ }
81
+
82
+ if (raw.json && typeof raw.json === 'object') {
83
+ this._fields = raw.json;
84
+ }
85
+
86
+ if (raw.display && raw.display.output) {
87
+ this._display = raw.display.output;
88
+ }
89
+ }
90
+
91
+ /** @returns {Date} timestamp when this JS object was instantiated (useful for sorting by recency) */
55
92
  get constructedAt() {
56
93
  return this._constructedAt;
57
94
  }
58
95
 
96
+ /**
97
+ * Compare two Sui object IDs after normalisation.
98
+ * @param {string} id1
99
+ * @param {string} id2
100
+ * @returns {boolean}
101
+ */
59
102
  static idsEqual(id1, id2) {
60
103
  return (normalizeSuiAddress(id1) === normalizeSuiAddress(id2));
61
104
  }
62
105
 
106
+ /** @returns {boolean} true if this object has been marked deleted */
63
107
  get isDeleted() {
64
108
  return this._isDeleted;
65
109
  }
66
110
 
111
+ /** @returns {boolean} true if the object is shared (owned by the network) */
67
112
  get isShared() {
68
- return (this._owner && this._owner.Shared);
113
+ return !!(this._owner && (this._owner.Shared || this._owner.$kind === 'Shared'));
69
114
  }
70
115
 
116
+ /** @returns {boolean} true if the object is immutable (frozen) */
71
117
  get isImmutable() {
72
- return (this._owner && this._owner == 'Immutable');
118
+ return !!(this._owner && (this._owner === 'Immutable' || this._owner.$kind === 'Immutable'));
73
119
  }
74
120
 
121
+ /**
122
+ * Check whether this object is address-owned by the given address or SuiObject.
123
+ * @param {string | SuiObject} addressOrSuiObject
124
+ * @returns {boolean}
125
+ */
75
126
  isOwnedBy(addressOrSuiObject) {
76
- let toId = addressOrSuiObject;
77
- if (toId.id) {
78
- toId = toId.id;
79
- }
127
+ const a = /** @type {any} */ (addressOrSuiObject);
128
+ const toId = a.id ?? a;
80
129
 
81
130
  if (this._owner && this._owner.AddressOwner && this._owner.AddressOwner == toId) {
82
131
  return true;
@@ -85,30 +134,39 @@ export default class SuiObject extends SuiCommonMethods {
85
134
  return false;
86
135
  }
87
136
 
137
+ /** Mark this object as deleted on-chain and set `isDeleted` to true. */
88
138
  markAsDeleted() {
89
139
  this._isDeleted = true;
90
140
  }
91
141
 
142
+ /** @returns {?string} raw object id as stored (not normalised) */
92
143
  get id() {
93
144
  return this._id;
94
145
  }
95
146
 
147
+ /** @returns {?string} fully-qualified Move type string, e.g. `'0x2::coin::Coin<0x2::sui::SUI>'` */
96
148
  get type() {
97
149
  return this._type;
98
150
  }
99
151
 
100
152
  /**
101
- * In module type name, without package and module prefix and without <T..> suffix
153
+ * Short type name last `::` segment without `<T…>` suffix.
154
+ * @returns {?string} e.g. `'ChatTopMessage'`
102
155
  */
103
156
  get typeName() {
104
157
  return this._type ? (''+this._type).split('<')[0].split('::').pop() : null;
105
158
  }
106
159
 
160
+ /**
161
+ * Check whether this object's normalised address equals `toId`.
162
+ * @param {string} toId
163
+ * @returns {boolean}
164
+ */
107
165
  idEquals(toId) {
108
166
  if (!toId) {
109
167
  return false;
110
168
  }
111
-
169
+
112
170
  const thisAddress = this.address;
113
171
  if (thisAddress && thisAddress === normalizeSuiAddress(toId)) {
114
172
  return true;
@@ -116,6 +174,10 @@ export default class SuiObject extends SuiCommonMethods {
116
174
  return false;
117
175
  }
118
176
 
177
+ /**
178
+ * Normalised 0x-padded Sui address, or null if the id is invalid.
179
+ * @returns {?string}
180
+ */
119
181
  get address() {
120
182
  try {
121
183
  return normalizeSuiAddress(this._id);
@@ -124,99 +186,49 @@ export default class SuiObject extends SuiCommonMethods {
124
186
  }
125
187
  }
126
188
 
189
+ /** @returns {Object} on-chain Move struct fields (populated by `fillDataFromApi` or `fetchFields`) */
127
190
  get fields() {
128
191
  return this._fields;
129
192
  }
130
193
 
194
+ /** @returns {Object} Display template rendered output (populated by `fillDataFromApi` or `fetchFields`) */
131
195
  get display() {
132
196
  return this._display;
133
197
  }
134
198
 
199
+ /** @returns {Object} local-only property bag — never sent to chain, for caller convenience */
135
200
  get localProperties() {
136
201
  return this._localProperties;
137
202
  }
138
203
 
204
+ /** @returns {?number} object version (lamport timestamp), or null before `fetchFields` */
139
205
  get version() {
140
206
  return this._version;
141
207
  }
142
208
 
143
209
  /**
144
- * Try to get past version of an object from blockchain.
145
- * Non-cacheable
146
- * Note from SUI docs, there's no garantee past version is available on nodes, so may return null even if you expect v to be there
147
- * @param {Number} v
148
- * @returns SuiObject
210
+ * Fetch transactions that interacted with this object, via GraphQL.
211
+ *
212
+ * @param {Object} [params]
213
+ * @param {number} [params.limit=10]
214
+ * @param {string} [params.order]
215
+ * @returns {Promise<SuiPaginatedResponse>}
149
216
  */
150
- async getPastObject(v = null) {
151
- if (!v) {
152
- v = this._version - BigInt(1);
153
- }
154
- v = Number(v);
155
-
156
- const result = await this._suiMaster._client.tryGetPastObject({
157
- version: (v),
158
- id: this.address,
159
- options: {
160
- showType: true,
161
- showContent: true,
162
- showOwner: true,
163
- showDisplay: true,
164
- "showPreviousTransaction": true,
165
- "showBcs": false,
166
- "showStorageRebate": true
167
- },
168
- });
169
-
170
- if (result && result.details && result.details.objectId) {
171
- const pastObject = new SuiObject({
172
- suiMaster: this._suiMaster,
173
- debug: this._debug,
174
- objectChange: result.details,
175
- });
176
-
177
- return pastObject;
178
- }
179
-
180
- return null;
181
- }
182
-
183
- async queryTransactionBlocks(params = {}) {
184
- // @todo: InputObject / ChangedObject ? make separate function or a param here?
185
- const queryParams = {
186
- filter: {
187
- InputObject: this.address,
188
- },
217
+ async fetchTransactions(params = {}) {
218
+ return await this._suiMaster.fetchTransactions({
219
+ affectedObject: this.address,
189
220
  limit: params.limit || 10,
190
- options: {
191
- /* Whether to show transaction input data. Default to be false. */
192
- showInput: true,
193
- /* Whether to show transaction effects. Default to be false. */
194
- showEffects: true,
195
- /* Whether to show transaction events. Default to be false. */
196
- showEvents: true,
197
- /* Whether to show object changes. Default to be false. */
198
- showObjectChanges: true,
199
- /* Whether to show coin balance changes. Default to be false. */
200
- showBalanceChanges: true,
201
- showContent: true,
202
- showOwner: true,
203
- showDisplay: true,
204
- },
205
- };
206
-
207
- const paginatedResponse = new SuiPaginatedResponse({
208
- debug: this._debug,
209
- suiMaster: this._suiMaster,
210
- params: queryParams,
211
- method: 'queryTransactionBlocks',
212
221
  order: params.order,
213
222
  });
214
-
215
- await paginatedResponse.fetch();
216
-
217
- return paginatedResponse;
218
223
  }
219
224
 
225
+ /**
226
+ * Fetch dynamic fields owned by this object, paginated.
227
+ * @param {Object} [params]
228
+ * @param {number} [params.limit=50]
229
+ * @param {string} [params.order]
230
+ * @returns {Promise<SuiPaginatedResponse>}
231
+ */
220
232
  async getDynamicFields(params = {}) {
221
233
  const queryParams = {
222
234
  parentId: this.address,
@@ -227,7 +239,7 @@ export default class SuiObject extends SuiCommonMethods {
227
239
  debug: this._debug,
228
240
  suiMaster: this._suiMaster,
229
241
  params: queryParams,
230
- method: 'getDynamicFields',
242
+ method: 'listDynamicFields',
231
243
  order: params.order,
232
244
  });
233
245
 
@@ -236,22 +248,17 @@ export default class SuiObject extends SuiCommonMethods {
236
248
  return paginatedResponse;
237
249
  }
238
250
 
251
+ /**
252
+ * Fetch full field data for this object from chain and merge via `replaceWithSuiObjectIfNeeded`.
253
+ * Populates `fields`, `display`, `type`, and `version` if not already filled.
254
+ * @returns {Promise<this>}
255
+ */
239
256
  async fetchFields() {
240
- const result = await this._suiMaster._client.getObject({
241
- id: this.address, // normalized id
242
- options: {
243
- showType: true,
244
- showContent: true,
245
- showOwner: true,
246
- showDisplay: true,
247
- "showPreviousTransaction": true,
248
- "showBcs": false,
249
- "showStorageRebate": true
250
- },
251
- });
252
- if (result && result.data) {
253
- this.tryToFillDataFromObjectChange(result.data);
257
+ const fetched = await this._suiMaster.getObject(this.address);
258
+ if (fetched) {
259
+ this.replaceWithSuiObjectIfNeeded(fetched);
254
260
  }
261
+ return this;
255
262
  }
256
263
 
257
264
  /**
@@ -283,61 +290,29 @@ export default class SuiObject extends SuiCommonMethods {
283
290
  return true;
284
291
  }
285
292
 
286
- return false;
287
- }
288
-
289
- /**
290
- * Try to fill local object properties with values from ( showObjectChanges = true ) rpc response
291
- * @param {Object} objectChange
292
- */
293
- tryToFillDataFromObjectChange(objectChange) {
294
- if (!objectChange.objectId && objectChange.data && objectChange.data.objectId) {
295
- objectChange = objectChange.data;
296
- }
297
-
298
- if (objectChange.type && objectChange.type == 'deleted') {
299
- this.markAsDeleted();
300
- }
301
-
302
- // basic fields. Available both in getObject and in results of .moveCall
303
- if (objectChange.objectId) {
304
- if (!this._id) {
305
- this._id = objectChange.objectId;
306
- } else if (!this.idEquals(objectChange.objectId)) {
307
- throw new Error('Trying to fill from different object');
308
- }
309
- if (objectChange.type && !this._type) {
310
- this._type = objectChange.type;
311
- }
312
- }
313
- if (objectChange.version) {
314
- this._version = BigInt(objectChange.version);
293
+ // same or older version — still fill any locally-empty slots
294
+ let filled = false;
295
+ if (!this._type && suiObject.type) {
296
+ this._type = suiObject.type;
297
+ filled = true;
315
298
  }
316
- if (objectChange.objectType) {
317
- this._type = `${objectChange.objectType}`;
299
+ if (!this._owner && suiObject._owner) {
300
+ this._owner = suiObject._owner;
301
+ filled = true;
318
302
  }
319
-
320
- // extra fields. Possible to get them from separate call to getObject or multiGetObjects
321
- // .content
322
- if (objectChange?.content?.fields) {
323
- for (const key in objectChange?.content?.fields) {
324
- if (key !== 'id') {
325
- this._fields[key] = objectChange.content.fields[key];
326
- }
327
- }
303
+ if ((!this._fields || Object.keys(this._fields).length === 0) && suiObject._fields) {
304
+ this._fields = suiObject._fields;
305
+ filled = true;
328
306
  }
329
-
330
- // .display
331
- if (objectChange?.display?.data) {
332
- for (const key in objectChange?.display?.data) {
333
- this._display[key] = objectChange.display.data[key];
334
- }
307
+ if ((!this._display || Object.keys(this._display).length === 0) && suiObject._display) {
308
+ this._display = suiObject._display;
309
+ filled = true;
335
310
  }
336
-
337
- // .owner
338
- if (objectChange.owner) {
339
- this._owner = objectChange.owner;
311
+ if (!this._version && suiObject.version) {
312
+ this._version = suiObject.version;
313
+ filled = true;
340
314
  }
341
315
 
316
+ return filled;
342
317
  }
343
318
  };