suidouble 0.0.3

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.
@@ -0,0 +1,199 @@
1
+ const sui = require('@mysten/sui.js');
2
+ const SuiCommonMethods = require('./SuiCommonMethods.js');
3
+ const SuiPackage = require('./SuiPackage.js');
4
+ const SuiPseudoRandomAddress = require('./SuiPseudoRandomAddress.js');
5
+ const SuiMemoryObjectStorage = require('./SuiMemoryObjectStorage.js');
6
+
7
+ class SuiMaster extends SuiCommonMethods {
8
+ constructor(params = {}) {
9
+ super(params);
10
+
11
+ // quick value to differenciate instances (if there're few) in logs
12
+ SuiMaster.instancesCount++;
13
+ this._instanceN = SuiMaster.instancesCount;
14
+
15
+ this._signer = null;
16
+ this._keypair = null;
17
+
18
+ if (params.signer) {
19
+ this._signer = params.signer;
20
+ } else if (params.keypair) {
21
+ this._keypair = params.keypair;
22
+ } else if (params.phrase) {
23
+ this._keypair = sui.Ed25519Keypair.deriveKeypair(params.phrase);
24
+
25
+ this.log('goint to use keypair of', this._keypair.getPublicKey().toSuiAddress());
26
+ } else if (params.as) {
27
+ // generate pseudo-random keypair
28
+ this._keypair = SuiPseudoRandomAddress.stringToKeyPair(params.as);
29
+
30
+ this.log('goint to use keypair of', this._keypair.getPublicKey().toSuiAddress());
31
+ }
32
+
33
+ this._provider = null;
34
+ this._providerName = null;
35
+ if (params.provider) {
36
+ if (params.provider == 'local' || (params.provider.constructor && params.provider.constructor.name && params.provider.constructor.name == 'SuiLocalTestValidator')) {
37
+ this._provider = new sui.JsonRpcProvider(sui.localnetConnection);
38
+ this._providerName = 'local';
39
+ } else if (params.provider == 'test' || params.provider == 'testnet') {
40
+ this._provider = new sui.JsonRpcProvider(sui.testnetConnection);
41
+ this._providerName = 'test';
42
+ } else if (params.provider == 'dev' || params.provider == 'devnet') {
43
+ this._provider = new sui.JsonRpcProvider(sui.devnetConnection);
44
+ this._providerName = 'dev';
45
+ } else {
46
+ if (params.provider && params.provider.connection && params.provider.connection.fullnode) {
47
+ this._provider = params.provider;
48
+ this._providerName = params.provider.connection.fullnode;
49
+ }
50
+ }
51
+ }
52
+
53
+ if (!this._provider) {
54
+ throw new Error('Can not do anything without provider. Set params.provider at least to `local`');
55
+ }
56
+
57
+ // we are differient single instances of object storage by provider name (so we can separate like devnet-testnet entities if needed)
58
+ this._objectStorage = SuiMemoryObjectStorage.instanceOf(this._providerName, {
59
+ debug: this._debug,
60
+ });
61
+
62
+ this._initialized = false;
63
+
64
+ this._address = null;
65
+
66
+ this._packages = {};
67
+ }
68
+
69
+ get objectStorage() {
70
+ return this._objectStorage;
71
+ }
72
+
73
+ get instanceN() {
74
+ return this._instanceN;
75
+ }
76
+
77
+ static instancesCount = 0;
78
+
79
+ get provider() {
80
+ return this._provider;
81
+ }
82
+
83
+ get address() {
84
+ return this._address;
85
+ }
86
+
87
+ get signer() {
88
+ return this._signer;
89
+ }
90
+
91
+ package(params = {}) {
92
+ return this.addPackage(params);
93
+ }
94
+
95
+ addPackage(params = {}) {
96
+ if (params.id && this._packages[params.id]) {
97
+ return this._packages[params.id];
98
+ }
99
+ const suiPackage = new SuiPackage({
100
+ ...params,
101
+ debug: this._debug,
102
+ suiMaster: this,
103
+ });
104
+
105
+ if (params.id) {
106
+ this._packages[params.id] = suiPackage;
107
+ }
108
+
109
+ return suiPackage;
110
+ }
111
+
112
+ async getProvider() {
113
+ await this.initialize();
114
+ return this._provider;
115
+ }
116
+
117
+ async initialize() {
118
+ if (this._initialized) {
119
+ return true;
120
+ }
121
+
122
+ this.log('initializing...');
123
+
124
+ this._initialized = true;
125
+
126
+ // this._keypair = sui.Ed25519Keypair.deriveKeypair(this._phrase);
127
+ if (!this._signer && this._keypair) { // we may optionally go without signer, to work in read-only mode
128
+ this._signer = new sui.RawSigner(this._keypair, this._provider);
129
+ }
130
+
131
+ // const publicKey = this._keypair.getPublicKey();
132
+ // this._address = publicKey.toSuiAddress();
133
+ if (this._signer) {
134
+ this._address = await this._signer.getAddress();
135
+ // console.log(this._signer);
136
+ // console.log(this._providerName);
137
+ this.log('initialized. connected as', this._address);
138
+ } else {
139
+ this.log('initialized in read-only mode.');
140
+ }
141
+
142
+
143
+ return true;
144
+ }
145
+
146
+ async requestSuiFromFaucet() {
147
+ await this.initialize();
148
+
149
+ this.log('requesting sui from faucet...');
150
+
151
+ let res = null;
152
+ try {
153
+ res = await this._provider.requestSuiFromFaucet(this._address);
154
+ } catch (e) {
155
+ this.log('error', e);
156
+ res = null;
157
+ }
158
+
159
+ let amount = BigInt(0);
160
+ let objectsCount = 0;
161
+
162
+ if (res && res.transferredGasObjects) {
163
+ for (let transferredGasObject of res.transferredGasObjects) {
164
+ amount += BigInt(transferredGasObject.amount);
165
+ objectsCount++;
166
+ }
167
+ }
168
+
169
+ this.log('got from faucet', amount, 'MIST in', objectsCount, 'objects');
170
+
171
+ return amount;
172
+ }
173
+
174
+ async getBalance(coinType = '0x2::sui::SUI') {
175
+ await this.initialize();
176
+
177
+ this.log('requesting balance of coin', coinType, '...');
178
+
179
+ let res = null;
180
+ try {
181
+ res = await this._provider.getBalance({owner: this._address, coinType});
182
+ } catch (e) {
183
+ this.log('error', e);
184
+ res = null;
185
+ }
186
+
187
+ let ret = BigInt(0);
188
+ if (res && res.totalBalance) {
189
+ ret = BigInt(res.totalBalance);
190
+ }
191
+
192
+ this.log('balance of', coinType, 'is', ret);
193
+ return ret;
194
+ }
195
+ };
196
+
197
+
198
+
199
+ module.exports = SuiMaster;
@@ -0,0 +1,69 @@
1
+ const SuiCommonMethods = require('./SuiCommonMethods.js');
2
+
3
+ class SuiMemoryObjectStorage extends SuiCommonMethods {
4
+ constructor(params = {}) {
5
+ super(params);
6
+
7
+ this._objects = {};
8
+ }
9
+
10
+ asArray() {
11
+ return Object.values(this._objects);
12
+ }
13
+
14
+ find(filterFunction) {
15
+ for (const id in this._objects) {
16
+ if (filterFunction(this._objects[id])) {
17
+ return this._objects[id];
18
+ }
19
+ }
20
+
21
+ return null;
22
+ }
23
+
24
+ findMostRecent(filterFunction) {
25
+ let mostRecentDate = null;
26
+ let mostRecentObject = null;
27
+
28
+ for (const id in this._objects) {
29
+ if (filterFunction(this._objects[id])) {
30
+ if (!mostRecentDate || (mostRecentDate.getTime() <= this._objects[id].constructedAt.getTime())) {
31
+ mostRecentDate = this._objects[id].constructedAt;
32
+ mostRecentObject = this._objects[id];
33
+ }
34
+ }
35
+ }
36
+
37
+ return mostRecentObject;
38
+ }
39
+
40
+ push(object) {
41
+ if (object.address) {
42
+ this._objects[object.address] = object;
43
+
44
+ return true;
45
+ }
46
+
47
+ return false;
48
+ }
49
+
50
+ byAddress(address) {
51
+ if (this._objects[address]) {
52
+ return this._objects[address];
53
+ }
54
+ return null;
55
+ }
56
+
57
+ static _instances = {};
58
+
59
+ static instanceOf(validatorId, params = {}) {
60
+ if (SuiMemoryObjectStorage._instances[validatorId]) {
61
+ return SuiMemoryObjectStorage._instances[validatorId];
62
+ }
63
+
64
+ SuiMemoryObjectStorage._instances[validatorId] = new SuiMemoryObjectStorage(params);
65
+ return SuiMemoryObjectStorage._instances[validatorId];
66
+ }
67
+ };
68
+
69
+ module.exports = SuiMemoryObjectStorage;
@@ -0,0 +1,211 @@
1
+ const sui = require('@mysten/sui.js');
2
+ const SuiCommonMethods = require('./SuiCommonMethods.js');
3
+
4
+ class SuiObject extends SuiCommonMethods {
5
+ constructor(params = {}) {
6
+ super(params);
7
+
8
+ this._suiMaster = params.suiMaster;
9
+ if (!this._suiMaster) {
10
+ throw new Error('suiMaster is requried for suiPackage');
11
+ }
12
+
13
+ this._id = params.id || null;
14
+ this._version = params.version || null;
15
+ this._type = params.type || null;
16
+
17
+ this._fields = {}; // on-chain fields on the object
18
+ //
19
+
20
+ this._display = {}; // https://examples.sui.io/basics/display.html
21
+ // https://docs.sui.io/devnet/build/sui-object-display
22
+
23
+ this._owner = null; // Going to store it in the same format as in rpc responses
24
+
25
+ this._localProperties = {}; // object to store some local data for you to help with your local calculations, no interaction with blockchain
26
+
27
+ // this._ownerAddress = null;
28
+
29
+ this._isDeleted = false;
30
+
31
+ if (params.objectChange) {
32
+ this.tryToFillDataFromObjectChange(params.objectChange);
33
+ }
34
+
35
+ this._constructedAt = new Date(); // just a helpful data so we can sort later when trying to find most recent item in different modules
36
+ }
37
+
38
+ get constructedAt() {
39
+ return this._constructedAt;
40
+ }
41
+
42
+ static idsEqual(id1, id2) {
43
+ return (sui.normalizeSuiAddress(id1) === sui.normalizeSuiAddress(id2));
44
+ }
45
+
46
+ get isDeleted() {
47
+ return this._isDeleted;
48
+ }
49
+
50
+ get isShared() {
51
+ return (this._owner && this._owner.Shared);
52
+ }
53
+
54
+ get isImmutable() {
55
+ return (this._owner && this._owner == 'Immutable');
56
+ }
57
+
58
+ isOwnedBy(addressOrSuiObject) {
59
+ let toId = addressOrSuiObject;
60
+ if (toId.id) {
61
+ toId = toId.id;
62
+ }
63
+
64
+ if (this._owner && this._owner.AddressOwner && this._owner.AddressOwner == toId) {
65
+ return true;
66
+ }
67
+
68
+ return false;
69
+ }
70
+
71
+ markAsDeleted() {
72
+ this._isDeleted = true;
73
+ }
74
+
75
+ get id() {
76
+ return this._id;
77
+ }
78
+
79
+ get type() {
80
+ return this._type;
81
+ }
82
+
83
+ /**
84
+ * In module type name, without package and module prefix
85
+ */
86
+ get typeName() {
87
+ return this._type ? this._type.split('::').pop() : null;
88
+ }
89
+
90
+ idEquals(toId) {
91
+ if (!toId) {
92
+ return false;
93
+ }
94
+
95
+ const thisAddress = this.address;
96
+ if (thisAddress && thisAddress === sui.normalizeSuiAddress(toId)) {
97
+ return true;
98
+ }
99
+ return false;
100
+ }
101
+
102
+ get address() {
103
+ try {
104
+ return sui.normalizeSuiAddress(this._id);
105
+ } catch (e) {
106
+ return null;
107
+ }
108
+ }
109
+
110
+ get fields() {
111
+ return this._fields;
112
+ }
113
+
114
+ get display() {
115
+ return this._display;
116
+ }
117
+
118
+ get localProperties() {
119
+ return this._localProperties;
120
+ }
121
+
122
+ async getDynamicFields() {
123
+ const result = await this._suiMaster._provider.getDynamicFields({
124
+ parentId: this.address, // normalized id
125
+ options: {
126
+ showType: true,
127
+ showContent: true,
128
+ showOwner: true,
129
+ showDisplay: true,
130
+ "showPreviousTransaction": true,
131
+ "showBcs": false,
132
+ "showStorageRebate": true
133
+ },
134
+ });
135
+ }
136
+
137
+ async fetchFields() {
138
+ const result = await this._suiMaster._provider.getObject({
139
+ id: this.address, // normalized id
140
+ options: {
141
+ showType: true,
142
+ showContent: true,
143
+ showOwner: true,
144
+ showDisplay: true,
145
+ "showPreviousTransaction": true,
146
+ "showBcs": false,
147
+ "showStorageRebate": true
148
+ },
149
+ });
150
+ if (result && result.data) {
151
+ this.tryToFillDataFromObjectChange(result.data);
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Try to fill local object properties with values from ( showObjectChanges = true ) rpc response
157
+ * @param {Object} objectChange
158
+ */
159
+ tryToFillDataFromObjectChange(objectChange) {
160
+ if (!objectChange.objectId && objectChange.data && objectChange.data.objectId) {
161
+ objectChange = objectChange.data;
162
+ }
163
+
164
+ if (objectChange.type && objectChange.type == 'deleted') {
165
+ this.markAsDeleted();
166
+ }
167
+
168
+ // basic fields. Available both in getObject and in results of .moveCall
169
+ if (objectChange.objectId) {
170
+ if (!this._id) {
171
+ this._id = objectChange.objectId;
172
+ } else if (!this.idEquals(objectChange.objectId)) {
173
+ throw new Error('Trying to fill from different object');
174
+ }
175
+ if (objectChange.type && !this._type) {
176
+ this._type = objectChange.type;
177
+ }
178
+ }
179
+ if (objectChange.version) {
180
+ this._version = BigInt(objectChange.version);
181
+ }
182
+ if (objectChange.objectType) {
183
+ this._type = `${objectChange.objectType}`;
184
+ }
185
+
186
+ // extra fields. Possible to get them from separate call to getObject or multiGetObjects
187
+ // .content
188
+ if (objectChange?.content?.fields) {
189
+ for (const key in objectChange?.content?.fields) {
190
+ if (key !== 'id') {
191
+ this._fields[key] = objectChange.content.fields[key];
192
+ }
193
+ }
194
+ }
195
+
196
+ // .display
197
+ if (objectChange?.display?.data) {
198
+ for (const key in objectChange?.display?.data) {
199
+ this._display[key] = objectChange.display.data[key];
200
+ }
201
+ }
202
+
203
+ // .owner
204
+ if (objectChange.owner) {
205
+ this._owner = objectChange.owner;
206
+ }
207
+
208
+ }
209
+ };
210
+
211
+ module.exports = SuiObject;