@msafe/sui-app-store 0.0.10 → 0.0.12
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/dist/index.d.mts +18 -23
- package/dist/index.d.ts +18 -23
- package/dist/index.global.js +9 -4
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +2470 -22
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2467 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -6
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,308 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
|
+
};
|
|
3
6
|
|
|
4
|
-
// src/apps/
|
|
5
|
-
import {
|
|
7
|
+
// src/apps/mpay/helper.ts
|
|
8
|
+
import { StreamEventType, TransactionType } from "@msafe/sui3-utils";
|
|
9
|
+
|
|
10
|
+
// src/apps/mpay/config/dev.json
|
|
11
|
+
var dev_exports = {};
|
|
12
|
+
__export(dev_exports, {
|
|
13
|
+
contractId: () => contractId,
|
|
14
|
+
default: () => dev_default,
|
|
15
|
+
feeObjId: () => feeObjId,
|
|
16
|
+
roleObjId: () => roleObjId,
|
|
17
|
+
status: () => status,
|
|
18
|
+
transaction: () => transaction,
|
|
19
|
+
upgradeCapObjId: () => upgradeCapObjId,
|
|
20
|
+
vaultObjId: () => vaultObjId
|
|
21
|
+
});
|
|
22
|
+
var transaction = "DiBZq4UmVVYiRL6ZJmFKYoHcxtxqrhsCXSkFyT7wUr3j";
|
|
23
|
+
var status = "success";
|
|
24
|
+
var contractId = "0x81c960dc653975fbd0072deca8afb92d322898c911622898ba1b2e3ad0c4bd8d";
|
|
25
|
+
var roleObjId = "0xc6ec0bdee0bb59a72077e9acd2f42457043cf47080b3d3fad4d39abf28bba63a";
|
|
26
|
+
var vaultObjId = "0xbc4021387fbac149119fd24e92be9e58f745774292f3a2a12e2ac6daf5363e1d";
|
|
27
|
+
var feeObjId = "0x4178f63970fe2daeb256dc5730ad172e82b3e8eb45f31b33e0daae72cd35e1e1";
|
|
28
|
+
var upgradeCapObjId = "0xe1e9aa7d222d151bfe6dd83358b0d7fdcb11260f710800cfaf7ccc1b1e245115";
|
|
29
|
+
var dev_default = {
|
|
30
|
+
transaction,
|
|
31
|
+
status,
|
|
32
|
+
contractId,
|
|
33
|
+
roleObjId,
|
|
34
|
+
vaultObjId,
|
|
35
|
+
feeObjId,
|
|
36
|
+
upgradeCapObjId
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// src/apps/mpay/config/prod.json
|
|
40
|
+
var prod_exports = {};
|
|
41
|
+
__export(prod_exports, {
|
|
42
|
+
contractId: () => contractId2,
|
|
43
|
+
default: () => prod_default,
|
|
44
|
+
feeObjId: () => feeObjId2,
|
|
45
|
+
roleObjId: () => roleObjId2,
|
|
46
|
+
status: () => status2,
|
|
47
|
+
transaction: () => transaction2,
|
|
48
|
+
upgradeCapObjId: () => upgradeCapObjId2,
|
|
49
|
+
vaultObjId: () => vaultObjId2
|
|
50
|
+
});
|
|
51
|
+
var transaction2 = "855FNDV8o8Z3fWULPnQo9qdhLJpsg7wZrkCpNyfw9KfB";
|
|
52
|
+
var status2 = "success";
|
|
53
|
+
var contractId2 = "0xc357c3985e8fb875d6b37141497af660779aa1bab0ec489b2213efd74067d1fa";
|
|
54
|
+
var roleObjId2 = "0x5ab49bdf9fd1413e328ef242b3f8d83dde791b38a0b627bfc87fb25c010d34f1";
|
|
55
|
+
var vaultObjId2 = "0xb483558770d8eb26007f193b75db40f0a45f2e36863a687625885d4de6993378";
|
|
56
|
+
var feeObjId2 = "0x48453fc4d7cde3fe35aad89e5dfb496608a6a55ea529a1c0274681a808627f94";
|
|
57
|
+
var upgradeCapObjId2 = "0x34279779a0d0d36bd5044b04830d607fa1b0ecf316548c8ac3a44151e4f1a42a";
|
|
58
|
+
var prod_default = {
|
|
59
|
+
transaction: transaction2,
|
|
60
|
+
status: status2,
|
|
61
|
+
contractId: contractId2,
|
|
62
|
+
roleObjId: roleObjId2,
|
|
63
|
+
vaultObjId: vaultObjId2,
|
|
64
|
+
feeObjId: feeObjId2,
|
|
65
|
+
upgradeCapObjId: upgradeCapObjId2
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// src/apps/mpay/common/env.ts
|
|
69
|
+
var DEV_RPC_ENDPOINT = "https://sui-testnet.blockvision.org/v1/2Sgk89ivT64MnKdcGzjmyjY2ndD";
|
|
70
|
+
var STG_RPC_ENDPOINT = "https://sui-testnet.blockvision.org/v1/2Sgk89ivT64MnKdcGzjmyjY2ndD";
|
|
71
|
+
var PREV_RPC_ENDPOINT = "https://sui-mainnet.blockvision.org/v1/2Sgk7NPvqkd7mESYkxF01yX15l7";
|
|
72
|
+
var PROD_RPC_ENDPOINT = "https://sui-mainnet.blockvision.org/v1/2Sgk7NPvqkd7mESYkxF01yX15l7";
|
|
73
|
+
var DEV_BE_API = "https://bc3p6l5unl.execute-api.us-west-1.amazonaws.com/prod";
|
|
74
|
+
var STG_BE_API = "https://rolsbkota7.execute-api.us-west-1.amazonaws.com/prod";
|
|
75
|
+
var PREV_BE_API = "https://6p6mkx33ne.execute-api.us-west-1.amazonaws.com/prod";
|
|
76
|
+
var PROD_BE_API = "https://xrae3mrjv5.execute-api.us-west-1.amazonaws.com/prod";
|
|
77
|
+
var CONTRACT_DEV = dev_exports;
|
|
78
|
+
var CONTRACT_PROD = prod_exports;
|
|
79
|
+
var ENV_CONFIG = /* @__PURE__ */ new Map([
|
|
80
|
+
[
|
|
81
|
+
"dev" /* dev */,
|
|
82
|
+
{
|
|
83
|
+
env: "dev" /* dev */,
|
|
84
|
+
rpc: {
|
|
85
|
+
url: DEV_RPC_ENDPOINT
|
|
86
|
+
},
|
|
87
|
+
backend: {
|
|
88
|
+
url: DEV_BE_API
|
|
89
|
+
},
|
|
90
|
+
contract: CONTRACT_DEV
|
|
91
|
+
}
|
|
92
|
+
],
|
|
93
|
+
[
|
|
94
|
+
"stg" /* stg */,
|
|
95
|
+
{
|
|
96
|
+
env: "stg" /* stg */,
|
|
97
|
+
rpc: {
|
|
98
|
+
url: STG_RPC_ENDPOINT
|
|
99
|
+
},
|
|
100
|
+
backend: {
|
|
101
|
+
url: STG_BE_API
|
|
102
|
+
},
|
|
103
|
+
contract: CONTRACT_DEV
|
|
104
|
+
}
|
|
105
|
+
],
|
|
106
|
+
[
|
|
107
|
+
"prev" /* prev */,
|
|
108
|
+
{
|
|
109
|
+
env: "prev" /* prev */,
|
|
110
|
+
rpc: {
|
|
111
|
+
url: PREV_RPC_ENDPOINT
|
|
112
|
+
},
|
|
113
|
+
backend: {
|
|
114
|
+
url: PREV_BE_API
|
|
115
|
+
},
|
|
116
|
+
contract: CONTRACT_PROD
|
|
117
|
+
}
|
|
118
|
+
],
|
|
119
|
+
[
|
|
120
|
+
"prod" /* prod */,
|
|
121
|
+
{
|
|
122
|
+
env: "prod" /* prod */,
|
|
123
|
+
rpc: {
|
|
124
|
+
url: PROD_RPC_ENDPOINT
|
|
125
|
+
},
|
|
126
|
+
backend: {
|
|
127
|
+
url: PROD_BE_API
|
|
128
|
+
},
|
|
129
|
+
contract: CONTRACT_PROD
|
|
130
|
+
}
|
|
131
|
+
]
|
|
132
|
+
]);
|
|
133
|
+
function getConfig(env, options) {
|
|
134
|
+
const ec = ENV_CONFIG.get(env);
|
|
135
|
+
if (!ec) {
|
|
136
|
+
throw new Error(`Env not supported: ${env}`);
|
|
137
|
+
}
|
|
138
|
+
if (options && options.rpc) {
|
|
139
|
+
ec.rpc = options.rpc;
|
|
140
|
+
}
|
|
141
|
+
if (options && options.backend) {
|
|
142
|
+
ec.backend = options.backend;
|
|
143
|
+
}
|
|
144
|
+
if (options && options.contract) {
|
|
145
|
+
ec.contract = options.contract;
|
|
146
|
+
}
|
|
147
|
+
return ec;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// src/apps/mpay/common/globals.ts
|
|
151
|
+
import { SuiClient } from "@mysten/sui.js/client";
|
|
152
|
+
|
|
153
|
+
// src/apps/mpay/error/base.ts
|
|
154
|
+
var MPayError = class extends Error {
|
|
155
|
+
mpayErrorCode;
|
|
156
|
+
context;
|
|
157
|
+
constructor(mpayErrorCode, msg, options = {}) {
|
|
158
|
+
const { cause, context } = options;
|
|
159
|
+
if (cause) {
|
|
160
|
+
super(`[MPay] ${msg}: ${cause}`);
|
|
161
|
+
} else {
|
|
162
|
+
super(`[MPay] ${msg}`);
|
|
163
|
+
}
|
|
164
|
+
this.mpayErrorCode = mpayErrorCode;
|
|
165
|
+
this.context = context;
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// src/apps/mpay/error/NoBackendError.ts
|
|
170
|
+
var NoBackendError = class extends MPayError {
|
|
171
|
+
constructor() {
|
|
172
|
+
super(11 /* NoBackend */, "Backend is not specified");
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
// src/apps/mpay/error/WalletNotConnectedError.ts
|
|
177
|
+
var WalletNotConnectedError = class extends MPayError {
|
|
178
|
+
constructor() {
|
|
179
|
+
super(1 /* walletNotConnected */, "Wallet not connected");
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
// src/apps/mpay/stream/backend.ts
|
|
184
|
+
import axios, { AxiosError } from "axios";
|
|
185
|
+
|
|
186
|
+
// src/apps/mpay/error/BackendError.ts
|
|
187
|
+
var BackendError = class extends MPayError {
|
|
188
|
+
constructor(msg, context) {
|
|
189
|
+
super(10 /* BackendError */, msg, { context });
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
// src/apps/mpay/stream/backend.ts
|
|
194
|
+
var Backend = class _Backend {
|
|
195
|
+
constructor(apiURL) {
|
|
196
|
+
this.apiURL = apiURL;
|
|
197
|
+
}
|
|
198
|
+
static parseResponseData(response) {
|
|
199
|
+
if (response instanceof AxiosError) {
|
|
200
|
+
throw new BackendError(response.response?.statusText);
|
|
201
|
+
}
|
|
202
|
+
if (response.status === 200) {
|
|
203
|
+
if (response.data.success) {
|
|
204
|
+
return response.data.data;
|
|
205
|
+
}
|
|
206
|
+
throw new BackendError(response.data.code);
|
|
207
|
+
}
|
|
208
|
+
throw new BackendError(response.status.toString());
|
|
209
|
+
}
|
|
210
|
+
async getIncomingStreams(recipient, options) {
|
|
211
|
+
const res = await axios.post(`${this.apiURL}/stream`, {
|
|
212
|
+
recipient,
|
|
213
|
+
...options
|
|
214
|
+
});
|
|
215
|
+
return _Backend.parseResponseData(res);
|
|
216
|
+
}
|
|
217
|
+
async getOutgoingStreams(sender, options) {
|
|
218
|
+
const res = await axios.post(`${this.apiURL}/stream`, {
|
|
219
|
+
sender,
|
|
220
|
+
...options
|
|
221
|
+
});
|
|
222
|
+
return _Backend.parseResponseData(res);
|
|
223
|
+
}
|
|
224
|
+
async getStreamHistory(query) {
|
|
225
|
+
const res = await axios.post(`${this.apiURL}/stream-events`, query);
|
|
226
|
+
const paginatedData = _Backend.parseResponseData(res);
|
|
227
|
+
paginatedData.data.forEach((event) => {
|
|
228
|
+
const formalizedEvent = event;
|
|
229
|
+
if (formalizedEvent.data.type === "create_stream") {
|
|
230
|
+
formalizedEvent.data.balance = BigInt(formalizedEvent.data.balance);
|
|
231
|
+
} else if (formalizedEvent.data.type === "cancel_stream") {
|
|
232
|
+
formalizedEvent.data.withdrawAmount = BigInt(formalizedEvent.data.withdrawAmount);
|
|
233
|
+
} else if (formalizedEvent.data.type === "claim" || formalizedEvent.data.type === "auto_claim") {
|
|
234
|
+
formalizedEvent.data.claimAmount = BigInt(formalizedEvent.data.claimAmount);
|
|
235
|
+
} else if (formalizedEvent.data.type === "set_auto_claim") {
|
|
236
|
+
formalizedEvent.data.enabled = !!formalizedEvent.data.enabled;
|
|
237
|
+
}
|
|
238
|
+
formalizedEvent.createdAt = new Date(formalizedEvent.createdAt);
|
|
239
|
+
return formalizedEvent;
|
|
240
|
+
});
|
|
241
|
+
return paginatedData;
|
|
242
|
+
}
|
|
243
|
+
async getAllCoinTypes(address) {
|
|
244
|
+
const res = await axios.post(`${this.apiURL}/stream-info`, { address });
|
|
245
|
+
return _Backend.parseResponseData(res);
|
|
246
|
+
}
|
|
247
|
+
async getAllRecipients(sender, options) {
|
|
248
|
+
const res = await axios.post(`${this.apiURL}/stream-info`, { sender, status: options });
|
|
249
|
+
return _Backend.parseResponseData(res);
|
|
250
|
+
}
|
|
251
|
+
async getAllSenders(recipient, options) {
|
|
252
|
+
const res = await axios.post(`${this.apiURL}/stream-info`, { recipient, status: options });
|
|
253
|
+
return _Backend.parseResponseData(res);
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
// src/apps/mpay/common/globals.ts
|
|
258
|
+
var Globals = class _Globals {
|
|
259
|
+
signer;
|
|
260
|
+
suiClient;
|
|
261
|
+
envConfig;
|
|
262
|
+
_backend;
|
|
263
|
+
constructor(envConfig) {
|
|
264
|
+
this.envConfig = envConfig;
|
|
265
|
+
this.suiClient = new SuiClient({ url: envConfig.rpc.url });
|
|
266
|
+
if (envConfig.backend) {
|
|
267
|
+
this._backend = new Backend(envConfig.backend.url);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
static new(env, options) {
|
|
271
|
+
const ec = getConfig(env, options);
|
|
272
|
+
return new _Globals(ec);
|
|
273
|
+
}
|
|
274
|
+
get walletType() {
|
|
275
|
+
if (!this.wallet) {
|
|
276
|
+
return "disconnected";
|
|
277
|
+
}
|
|
278
|
+
return this.wallet.type;
|
|
279
|
+
}
|
|
280
|
+
get backend() {
|
|
281
|
+
if (!this._backend) {
|
|
282
|
+
throw new NoBackendError();
|
|
283
|
+
}
|
|
284
|
+
return this._backend;
|
|
285
|
+
}
|
|
286
|
+
// Used for test cases
|
|
287
|
+
set backend(b) {
|
|
288
|
+
this._backend = b;
|
|
289
|
+
}
|
|
290
|
+
connectWallet(wallet) {
|
|
291
|
+
this.signer = wallet;
|
|
292
|
+
}
|
|
293
|
+
disconnect() {
|
|
294
|
+
this.signer = void 0;
|
|
295
|
+
}
|
|
296
|
+
get wallet() {
|
|
297
|
+
if (!this.signer) {
|
|
298
|
+
throw new WalletNotConnectedError();
|
|
299
|
+
}
|
|
300
|
+
return this.signer;
|
|
301
|
+
}
|
|
302
|
+
async walletAddress() {
|
|
303
|
+
return this.wallet.address();
|
|
304
|
+
}
|
|
305
|
+
};
|
|
6
306
|
|
|
7
307
|
// src/apps/msafe-core/intention.ts
|
|
8
308
|
import sortKeys from "sort-keys-recursive";
|
|
@@ -18,7 +318,2167 @@ var CoreBaseIntention = class {
|
|
|
18
318
|
}
|
|
19
319
|
};
|
|
20
320
|
|
|
321
|
+
// src/apps/mpay/stream/client.ts
|
|
322
|
+
import { normalizeStructTag as normalizeStructTag6, normalizeSuiAddress as normalizeSuiAddress3 } from "@mysten/sui.js/utils";
|
|
323
|
+
|
|
324
|
+
// src/apps/mpay/stream/helper.ts
|
|
325
|
+
import { normalizeStructTag as normalizeStructTag3, SUI_TYPE_ARG as SUI_TYPE_ARG2 } from "@mysten/sui.js/utils";
|
|
326
|
+
import { Duration } from "luxon";
|
|
327
|
+
|
|
328
|
+
// src/apps/mpay/builder/MPayBuilder.ts
|
|
329
|
+
import { TransactionBlock as TransactionBlock3 } from "@mysten/sui.js/transactions";
|
|
330
|
+
|
|
331
|
+
// src/apps/mpay/builder/CreateStreamHelper.ts
|
|
332
|
+
import { TransactionBlock } from "@mysten/sui.js/transactions";
|
|
333
|
+
import { normalizeStructTag as normalizeStructTag2, SUI_TYPE_ARG } from "@mysten/sui.js/utils";
|
|
334
|
+
|
|
335
|
+
// src/apps/mpay/builder/const.ts
|
|
336
|
+
var FEE_NUMERATOR = 50n;
|
|
337
|
+
var FEE_DENOMINATOR = 10000n;
|
|
338
|
+
var CLAIM_FEE_NUMERATOR = 25n;
|
|
339
|
+
var FLAT_FEE_SUI = 100000000n;
|
|
340
|
+
|
|
341
|
+
// src/apps/mpay/common/transaction.ts
|
|
342
|
+
var MoveObject = class {
|
|
343
|
+
constructor(object) {
|
|
344
|
+
this.object = object;
|
|
345
|
+
}
|
|
346
|
+
moveArg(txb) {
|
|
347
|
+
return txb.object(this.object);
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
var ObjectVector = class {
|
|
351
|
+
constructor(objects) {
|
|
352
|
+
this.objects = objects;
|
|
353
|
+
}
|
|
354
|
+
moveArgs(txb) {
|
|
355
|
+
return txb.makeMoveVec({ objects: this.objects.map((o) => txb.object(o)) });
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
var ResultRef = class _ResultRef {
|
|
359
|
+
constructor(result) {
|
|
360
|
+
this.result = result;
|
|
361
|
+
return new Proxy(this, {
|
|
362
|
+
set() {
|
|
363
|
+
throw new Error("The transaction result is a proxy, and does not support setting properties directly");
|
|
364
|
+
},
|
|
365
|
+
get(target, property) {
|
|
366
|
+
if (property in target) {
|
|
367
|
+
return Reflect.get(target, property);
|
|
368
|
+
}
|
|
369
|
+
const nestedResultFor = (resultIndex2) => new _ResultRef(target.result[resultIndex2]);
|
|
370
|
+
if (property === Symbol.iterator) {
|
|
371
|
+
return function* () {
|
|
372
|
+
let i = 0;
|
|
373
|
+
while (true) {
|
|
374
|
+
yield nestedResultFor(i);
|
|
375
|
+
i++;
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
if (typeof property === "symbol") {
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
const resultIndex = parseInt(property, 10);
|
|
383
|
+
if (Number.isNaN(resultIndex) || resultIndex < 0) {
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
return nestedResultFor(resultIndex);
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
moveArg() {
|
|
391
|
+
return this.result;
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
// src/apps/mpay/contract/InspectViewer.ts
|
|
396
|
+
import { normalizeSuiAddress } from "@mysten/sui.js/utils";
|
|
397
|
+
|
|
398
|
+
// src/apps/mpay/error/InvalidRpcResultError.ts
|
|
399
|
+
var InvalidRpcResultError = class extends MPayError {
|
|
400
|
+
constructor(msg, ctx) {
|
|
401
|
+
super(3 /* InvalidRpcResult */, msg, { context: ctx });
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
// src/apps/mpay/contract/InspectViewer.ts
|
|
406
|
+
var InspectViewer = class {
|
|
407
|
+
constructor(results) {
|
|
408
|
+
this.results = results;
|
|
409
|
+
}
|
|
410
|
+
callResult(index) {
|
|
411
|
+
return this.results.results[index];
|
|
412
|
+
}
|
|
413
|
+
returnValue(returned, index) {
|
|
414
|
+
return returned.returnValues[index];
|
|
415
|
+
}
|
|
416
|
+
getValue(callIndex = 0, returnIndex = 0) {
|
|
417
|
+
const callResult = this.callResult(callIndex);
|
|
418
|
+
return this.returnValue(callResult, returnIndex);
|
|
419
|
+
}
|
|
420
|
+
getAddress(callIndex = 0, returnIndex = 0) {
|
|
421
|
+
const [value, type] = this.getValue(callIndex, returnIndex);
|
|
422
|
+
if (type !== "address") {
|
|
423
|
+
throw new InvalidRpcResultError("Invalid contract return type.", {
|
|
424
|
+
ctx: {
|
|
425
|
+
expectType: "address",
|
|
426
|
+
gotType: type
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
return normalizeSuiAddress(Buffer.from(value).toString("hex"));
|
|
431
|
+
}
|
|
432
|
+
getU64(callIndex = 0, returnIndex = 0) {
|
|
433
|
+
const [value, type] = this.getValue(callIndex, returnIndex);
|
|
434
|
+
if (type !== "u64") {
|
|
435
|
+
throw new InvalidRpcResultError("Invalid contract return type.", {
|
|
436
|
+
ctx: {
|
|
437
|
+
expectType: "u64",
|
|
438
|
+
gotType: type
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
return Buffer.from(value).readBigInt64LE();
|
|
443
|
+
}
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
// src/apps/mpay/stream/metadata.ts
|
|
447
|
+
import { bcs } from "@mysten/sui.js/bcs";
|
|
448
|
+
|
|
449
|
+
// src/apps/mpay/error/InvalidInputError.ts
|
|
450
|
+
var InvalidInputError = class extends MPayError {
|
|
451
|
+
constructor(msg, fieldKey, fieldValue) {
|
|
452
|
+
super(2 /* InvalidInput */, `Invalid input: ${msg}`, {
|
|
453
|
+
context: {
|
|
454
|
+
fieldKey,
|
|
455
|
+
fieldValue
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
// src/apps/mpay/stream/metadata.ts
|
|
462
|
+
var metadataBcsType = {
|
|
463
|
+
groupId: "string",
|
|
464
|
+
name: "string"
|
|
465
|
+
};
|
|
466
|
+
var MAX_NAME_SIZE = 64;
|
|
467
|
+
function encodeMetadata(metadata) {
|
|
468
|
+
validateMetadata(metadata);
|
|
469
|
+
return bcs.ser(metadataBcsType, metadata).toString("base64");
|
|
470
|
+
}
|
|
471
|
+
function decodeMetadata(metaStr) {
|
|
472
|
+
const metadata = bcs.de(metadataBcsType, metaStr, "base64");
|
|
473
|
+
validateMetadata(metadata);
|
|
474
|
+
return metadata;
|
|
475
|
+
}
|
|
476
|
+
function validateMetadata(metadata) {
|
|
477
|
+
if (!isAsciiString(metadata.name)) {
|
|
478
|
+
throw new InvalidInputError("Invalid metadata: Name contains unknown character");
|
|
479
|
+
}
|
|
480
|
+
if (!isAsciiString(metadata.groupId)) {
|
|
481
|
+
throw new InvalidInputError("Invalid metadata: Group ID contains unknown character");
|
|
482
|
+
}
|
|
483
|
+
if (metadata.name.length > MAX_NAME_SIZE) {
|
|
484
|
+
throw new InvalidInputError("Invalid metadata: Name exceed max length 64");
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
function isAsciiString(str) {
|
|
488
|
+
const asciiPattern = /^[\x00-\x7F]+$/;
|
|
489
|
+
return asciiPattern.test(str);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// src/apps/mpay/sui/utils.ts
|
|
493
|
+
import { normalizeStructTag } from "@mysten/sui.js/utils";
|
|
494
|
+
function isSameCoinType(type1, type2) {
|
|
495
|
+
return normalizeStructTag(type1) === normalizeStructTag(type2);
|
|
496
|
+
}
|
|
497
|
+
function isSameTarget(target1, target2) {
|
|
498
|
+
return normalizeStructTag(target1) === normalizeStructTag(target2);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// src/apps/mpay/types/wallet.ts
|
|
502
|
+
var GAS_OBJECT_SPEC = "txn.gas";
|
|
503
|
+
|
|
504
|
+
// src/apps/mpay/utils/random.ts
|
|
505
|
+
function generateGroupId() {
|
|
506
|
+
return "nanoid()";
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// src/apps/mpay/builder/CreateStreamHelper.ts
|
|
510
|
+
var CreateStreamHelper = class _CreateStreamHelper {
|
|
511
|
+
constructor(globals, feeContract, streamContract) {
|
|
512
|
+
this.globals = globals;
|
|
513
|
+
this.feeContract = feeContract;
|
|
514
|
+
this.streamContract = streamContract;
|
|
515
|
+
}
|
|
516
|
+
static convertCreateStreamInfoToInternal(info) {
|
|
517
|
+
return {
|
|
518
|
+
metadata: encodeMetadata({
|
|
519
|
+
name: info.name,
|
|
520
|
+
groupId: generateGroupId()
|
|
521
|
+
}),
|
|
522
|
+
coinType: normalizeStructTag2(info.coinType),
|
|
523
|
+
recipients: info.recipients.map((recipient) => ({
|
|
524
|
+
address: recipient.address,
|
|
525
|
+
cliffAmount: recipient.cliffAmount,
|
|
526
|
+
amountPerEpoch: recipient.amountPerStep
|
|
527
|
+
})),
|
|
528
|
+
epochInterval: info.interval,
|
|
529
|
+
numberEpoch: info.steps,
|
|
530
|
+
startTime: info.startTimeMs,
|
|
531
|
+
cancelable: info.cancelable
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
async buildCreateStreamTransactionBlock(info) {
|
|
535
|
+
const txb = new TransactionBlock();
|
|
536
|
+
const paymentWithFee = this.calculateFeesInternal(info);
|
|
537
|
+
const coinReqs = this.getCreateStreamCoinRequests(info, paymentWithFee);
|
|
538
|
+
const coinResp = await this.wallet.requestCoins(coinReqs);
|
|
539
|
+
const paymentMergedObject = await this.addMergeCoins(txb, coinResp[0]);
|
|
540
|
+
let flatFeeMergedObject;
|
|
541
|
+
if (coinReqs.length > 1) {
|
|
542
|
+
flatFeeMergedObject = await this.addMergeCoins(txb, coinResp[1]);
|
|
543
|
+
} else {
|
|
544
|
+
flatFeeMergedObject = paymentMergedObject;
|
|
545
|
+
}
|
|
546
|
+
for (let i = 0; i < info.recipients.length; i++) {
|
|
547
|
+
const recipient = info.recipients[i];
|
|
548
|
+
const paymentAmount = this.amountForRecipient(recipient, info.numberEpoch);
|
|
549
|
+
const feeAmount = this.getStreamFeeLocal(paymentAmount);
|
|
550
|
+
const [paymentCoin] = txb.splitCoins(paymentMergedObject, [txb.pure(paymentAmount + feeAmount, "u64")]);
|
|
551
|
+
const [flatFeeCoin] = txb.splitCoins(flatFeeMergedObject, [txb.pure(this.flatSuiFee, "u64")]);
|
|
552
|
+
this.streamContract.createStream(txb, {
|
|
553
|
+
paymentCoin: new ResultRef(paymentCoin),
|
|
554
|
+
flatFeeCoin: new ResultRef(flatFeeCoin),
|
|
555
|
+
metadata: info.metadata,
|
|
556
|
+
recipient: recipient.address,
|
|
557
|
+
timeStart: info.startTime,
|
|
558
|
+
cliff: recipient.cliffAmount,
|
|
559
|
+
epochInterval: info.epochInterval,
|
|
560
|
+
numEpoch: info.numberEpoch,
|
|
561
|
+
amountPerEpoch: recipient.amountPerEpoch,
|
|
562
|
+
cancelable: info.cancelable,
|
|
563
|
+
coinType: info.coinType
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
return txb;
|
|
567
|
+
}
|
|
568
|
+
calculateCreateStreamFees(createInfo) {
|
|
569
|
+
const infoInternal = _CreateStreamHelper.convertCreateStreamInfoToInternal(createInfo);
|
|
570
|
+
return this.calculateFeesInternal(infoInternal);
|
|
571
|
+
}
|
|
572
|
+
feeParams() {
|
|
573
|
+
return {
|
|
574
|
+
createFeePercent: {
|
|
575
|
+
numerator: FEE_NUMERATOR,
|
|
576
|
+
denominator: FEE_DENOMINATOR
|
|
577
|
+
},
|
|
578
|
+
claimFeePercent: {
|
|
579
|
+
numerator: CLAIM_FEE_NUMERATOR,
|
|
580
|
+
denominator: FEE_DENOMINATOR
|
|
581
|
+
},
|
|
582
|
+
flatFeePerStream: FLAT_FEE_SUI
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
async addMergeCoins(txb, coins) {
|
|
586
|
+
let mergedCoin;
|
|
587
|
+
if (coins.mergedCoins && coins.mergedCoins.length) {
|
|
588
|
+
txb.mergeCoins(
|
|
589
|
+
txb.object(coins.primaryCoin),
|
|
590
|
+
coins.mergedCoins.map((coinId) => txb.object(coinId))
|
|
591
|
+
);
|
|
592
|
+
mergedCoin = txb.object(coins.primaryCoin);
|
|
593
|
+
} else if (coins.primaryCoin === GAS_OBJECT_SPEC) {
|
|
594
|
+
mergedCoin = txb.gas;
|
|
595
|
+
} else {
|
|
596
|
+
mergedCoin = txb.object(coins.primaryCoin);
|
|
597
|
+
}
|
|
598
|
+
return mergedCoin;
|
|
599
|
+
}
|
|
600
|
+
getCreateStreamCoinRequests(info, payment) {
|
|
601
|
+
const streamCoinType = info.coinType;
|
|
602
|
+
if (isSameCoinType(streamCoinType, SUI_TYPE_ARG)) {
|
|
603
|
+
return [
|
|
604
|
+
{
|
|
605
|
+
coinType: streamCoinType,
|
|
606
|
+
amount: payment.totalAmount + payment.streamFeeAmount + payment.flatFeeAmount
|
|
607
|
+
}
|
|
608
|
+
];
|
|
609
|
+
}
|
|
610
|
+
return [
|
|
611
|
+
{
|
|
612
|
+
coinType: streamCoinType,
|
|
613
|
+
amount: payment.totalAmount + payment.streamFeeAmount
|
|
614
|
+
},
|
|
615
|
+
{
|
|
616
|
+
coinType: SUI_TYPE_ARG,
|
|
617
|
+
amount: payment.flatFeeAmount
|
|
618
|
+
}
|
|
619
|
+
];
|
|
620
|
+
}
|
|
621
|
+
calculateFeesInternal(info) {
|
|
622
|
+
const streamPayment = info.recipients.reduce(
|
|
623
|
+
(sum, recipient) => {
|
|
624
|
+
const totalAmount = this.amountForRecipient(recipient, info.numberEpoch);
|
|
625
|
+
const fee = this.getStreamFeeLocal(totalAmount);
|
|
626
|
+
return {
|
|
627
|
+
totalAmount: sum.totalAmount + totalAmount,
|
|
628
|
+
streamFeeAmount: sum.streamFeeAmount + fee
|
|
629
|
+
};
|
|
630
|
+
},
|
|
631
|
+
{
|
|
632
|
+
totalAmount: 0n,
|
|
633
|
+
streamFeeAmount: 0n
|
|
634
|
+
}
|
|
635
|
+
);
|
|
636
|
+
const flatFeeAmount = BigInt(info.recipients.length) * this.flatSuiFee;
|
|
637
|
+
return {
|
|
638
|
+
flatFeeAmount,
|
|
639
|
+
...streamPayment
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
amountForRecipient(recipient, numEpoch) {
|
|
643
|
+
return recipient.amountPerEpoch * numEpoch + recipient.cliffAmount;
|
|
644
|
+
}
|
|
645
|
+
get flatSuiFee() {
|
|
646
|
+
return FLAT_FEE_SUI;
|
|
647
|
+
}
|
|
648
|
+
getStreamFeeLocal(streamAmount) {
|
|
649
|
+
return streamAmount * FEE_NUMERATOR / FEE_DENOMINATOR;
|
|
650
|
+
}
|
|
651
|
+
async getStreamFeeRemote(streamAmount) {
|
|
652
|
+
const txb = this.feeContract.streamingFee(new TransactionBlock(), streamAmount);
|
|
653
|
+
const res = await this.globals.suiClient.devInspectTransactionBlock({
|
|
654
|
+
sender: await this.globals.walletAddress(),
|
|
655
|
+
transactionBlock: txb
|
|
656
|
+
});
|
|
657
|
+
const iv = new InspectViewer(res);
|
|
658
|
+
return iv.getU64();
|
|
659
|
+
}
|
|
660
|
+
get wallet() {
|
|
661
|
+
return this.globals.wallet;
|
|
662
|
+
}
|
|
663
|
+
};
|
|
664
|
+
|
|
665
|
+
// src/apps/mpay/contract/BaseContract.ts
|
|
666
|
+
import { Transactions } from "@mysten/sui.js/transactions";
|
|
667
|
+
|
|
668
|
+
// src/apps/mpay/const.ts
|
|
669
|
+
var CLOCK_ID = "0x0000000000000000000000000000000000000000000000000000000000000006";
|
|
670
|
+
|
|
671
|
+
// src/apps/mpay/contract/BaseContract.ts
|
|
672
|
+
var BaseContract = class {
|
|
673
|
+
constructor(moduleName, config, globals) {
|
|
674
|
+
this.moduleName = moduleName;
|
|
675
|
+
this.config = config;
|
|
676
|
+
this.globals = globals;
|
|
677
|
+
}
|
|
678
|
+
addContractCall(txb, input) {
|
|
679
|
+
const target = `${this.config.contractId}::${this.moduleName}::${input.method}`;
|
|
680
|
+
txb.add(
|
|
681
|
+
Transactions.MoveCall({
|
|
682
|
+
target,
|
|
683
|
+
arguments: input.arguments.map((arg) => {
|
|
684
|
+
if (arg instanceof ObjectVector) {
|
|
685
|
+
return arg.moveArgs(txb);
|
|
686
|
+
}
|
|
687
|
+
if (arg instanceof MoveObject) {
|
|
688
|
+
return arg.moveArg(txb);
|
|
689
|
+
}
|
|
690
|
+
if (arg instanceof ResultRef) {
|
|
691
|
+
return arg.moveArg();
|
|
692
|
+
}
|
|
693
|
+
return txb.pure(arg);
|
|
694
|
+
}),
|
|
695
|
+
typeArguments: input.typeArgs
|
|
696
|
+
})
|
|
697
|
+
);
|
|
698
|
+
return txb;
|
|
699
|
+
}
|
|
700
|
+
addTransactionBlock(txb, target, callArgs = [], typeArgs = []) {
|
|
701
|
+
txb.add(
|
|
702
|
+
Transactions.MoveCall({
|
|
703
|
+
target,
|
|
704
|
+
arguments: callArgs.map((arg) => {
|
|
705
|
+
if (arg instanceof ObjectVector) {
|
|
706
|
+
return arg.moveArgs(txb);
|
|
707
|
+
}
|
|
708
|
+
if (arg instanceof MoveObject) {
|
|
709
|
+
return arg.moveArg(txb);
|
|
710
|
+
}
|
|
711
|
+
if (arg instanceof ResultRef) {
|
|
712
|
+
return arg.moveArg();
|
|
713
|
+
}
|
|
714
|
+
return txb.pure(arg);
|
|
715
|
+
}),
|
|
716
|
+
typeArguments: typeArgs
|
|
717
|
+
})
|
|
718
|
+
);
|
|
719
|
+
}
|
|
720
|
+
makeObject(object) {
|
|
721
|
+
return typeof object === "string" ? new MoveObject(object) : object;
|
|
722
|
+
}
|
|
723
|
+
vaultObject() {
|
|
724
|
+
return new MoveObject(this.config.vaultObjId);
|
|
725
|
+
}
|
|
726
|
+
roleObject() {
|
|
727
|
+
return new MoveObject(this.config.roleObjId);
|
|
728
|
+
}
|
|
729
|
+
feeObject() {
|
|
730
|
+
return new MoveObject(this.config.feeObjId);
|
|
731
|
+
}
|
|
732
|
+
clockObject() {
|
|
733
|
+
return new MoveObject(CLOCK_ID);
|
|
734
|
+
}
|
|
735
|
+
};
|
|
736
|
+
|
|
737
|
+
// src/apps/mpay/contract/FeeContract.ts
|
|
738
|
+
var FeeContract = class _FeeContract extends BaseContract {
|
|
739
|
+
constructor(config, globals) {
|
|
740
|
+
super(_FeeContract.ModuleName, config, globals);
|
|
741
|
+
this.config = config;
|
|
742
|
+
this.globals = globals;
|
|
743
|
+
}
|
|
744
|
+
static ModuleName = "fee_module";
|
|
745
|
+
static MethodName = {
|
|
746
|
+
set_streaming_fee: "set_streaming_fee",
|
|
747
|
+
set_claim_fee: "set_claim_fee",
|
|
748
|
+
set_streaming_flat_fee: "set_streaming_flat_fee",
|
|
749
|
+
streaming_flat_fee: "streaming_flat_fee",
|
|
750
|
+
streaming_fee: "streaming_fee",
|
|
751
|
+
claim_fee: "claim_fee",
|
|
752
|
+
fee_denominator: "fee_denominator"
|
|
753
|
+
};
|
|
754
|
+
setStreamingFee(txb, createFeeNumerator) {
|
|
755
|
+
const roleObject = this.roleObject();
|
|
756
|
+
const feeObject = this.feeObject();
|
|
757
|
+
return this.addContractCall(txb, {
|
|
758
|
+
method: _FeeContract.MethodName.set_streaming_fee,
|
|
759
|
+
arguments: [roleObject, feeObject, createFeeNumerator],
|
|
760
|
+
typeArgs: []
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
setStreamingFlatFee(txb, flatFee) {
|
|
764
|
+
const roleObject = this.roleObject();
|
|
765
|
+
const feeObject = this.feeObject();
|
|
766
|
+
return this.addContractCall(txb, {
|
|
767
|
+
method: _FeeContract.MethodName.set_streaming_flat_fee,
|
|
768
|
+
arguments: [roleObject, feeObject, flatFee],
|
|
769
|
+
typeArgs: []
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
setClaimFee(txb, claimFee) {
|
|
773
|
+
const roleObject = this.roleObject();
|
|
774
|
+
const feeObject = this.feeObject();
|
|
775
|
+
return this.addContractCall(txb, {
|
|
776
|
+
method: _FeeContract.MethodName.set_claim_fee,
|
|
777
|
+
arguments: [roleObject, feeObject, claimFee],
|
|
778
|
+
typeArgs: []
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
streamingFee(txb, amount) {
|
|
782
|
+
const feeObject = this.feeObject();
|
|
783
|
+
return this.addContractCall(txb, {
|
|
784
|
+
method: _FeeContract.MethodName.streaming_fee,
|
|
785
|
+
arguments: [feeObject, amount],
|
|
786
|
+
typeArgs: []
|
|
787
|
+
});
|
|
788
|
+
}
|
|
789
|
+
claimFee(txb, amount) {
|
|
790
|
+
return this.addContractCall(txb, {
|
|
791
|
+
method: _FeeContract.MethodName.claim_fee,
|
|
792
|
+
arguments: [this.feeObject(), amount],
|
|
793
|
+
typeArgs: []
|
|
794
|
+
});
|
|
795
|
+
}
|
|
796
|
+
feeDenominator(txb) {
|
|
797
|
+
return this.addContractCall(txb, {
|
|
798
|
+
method: _FeeContract.MethodName.fee_denominator,
|
|
799
|
+
arguments: [this.feeObject()],
|
|
800
|
+
typeArgs: []
|
|
801
|
+
});
|
|
802
|
+
}
|
|
803
|
+
};
|
|
804
|
+
|
|
805
|
+
// src/apps/mpay/contract/StreamContract.ts
|
|
806
|
+
var StreamContract = class _StreamContract extends BaseContract {
|
|
807
|
+
constructor(config, globals) {
|
|
808
|
+
super(_StreamContract.ModuleName, config, globals);
|
|
809
|
+
this.config = config;
|
|
810
|
+
this.globals = globals;
|
|
811
|
+
}
|
|
812
|
+
static ModuleName = "stream";
|
|
813
|
+
static MethodName = {
|
|
814
|
+
create_stream: "create_stream",
|
|
815
|
+
set_auto_claim: "set_auto_claim",
|
|
816
|
+
cancel_stream: "cancel_stream",
|
|
817
|
+
claim_stream: "claim_stream",
|
|
818
|
+
claim_stream_by_proxy: "claim_stream_by_proxy",
|
|
819
|
+
stream_current_epoch: "stream_current_epoch",
|
|
820
|
+
now_milli_seconds: "now_milli_seconds"
|
|
821
|
+
};
|
|
822
|
+
createStream(txb, input) {
|
|
823
|
+
const feeObject = this.feeObject();
|
|
824
|
+
const vaultObject = this.vaultObject();
|
|
825
|
+
const paymentCoinObject = this.makeObject(input.paymentCoin);
|
|
826
|
+
const flatFeeObject = this.makeObject(input.flatFeeCoin);
|
|
827
|
+
const clockObject = this.clockObject();
|
|
828
|
+
return this.addContractCall(txb, {
|
|
829
|
+
method: _StreamContract.MethodName.create_stream,
|
|
830
|
+
arguments: [
|
|
831
|
+
feeObject,
|
|
832
|
+
vaultObject,
|
|
833
|
+
paymentCoinObject,
|
|
834
|
+
flatFeeObject,
|
|
835
|
+
input.metadata,
|
|
836
|
+
input.recipient,
|
|
837
|
+
input.timeStart,
|
|
838
|
+
input.cliff,
|
|
839
|
+
input.epochInterval,
|
|
840
|
+
input.numEpoch,
|
|
841
|
+
input.amountPerEpoch,
|
|
842
|
+
input.cancelable,
|
|
843
|
+
clockObject
|
|
844
|
+
],
|
|
845
|
+
typeArgs: [input.coinType]
|
|
846
|
+
});
|
|
847
|
+
}
|
|
848
|
+
setAutoClaim(txb, input) {
|
|
849
|
+
const streamObject = this.makeObject(input.streamId);
|
|
850
|
+
return this.addContractCall(txb, {
|
|
851
|
+
method: _StreamContract.MethodName.set_auto_claim,
|
|
852
|
+
arguments: [streamObject, input.enabled],
|
|
853
|
+
typeArgs: [input.coinType]
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
cancelStream(txb, input) {
|
|
857
|
+
const streamObject = this.makeObject(input.streamId);
|
|
858
|
+
const clockObject = this.clockObject();
|
|
859
|
+
return this.addContractCall(txb, {
|
|
860
|
+
method: _StreamContract.MethodName.cancel_stream,
|
|
861
|
+
arguments: [streamObject, clockObject],
|
|
862
|
+
typeArgs: [input.coinType]
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
claimStream(txb, input) {
|
|
866
|
+
const streamObject = this.makeObject(input.streamId);
|
|
867
|
+
const clockObject = this.clockObject();
|
|
868
|
+
return this.addContractCall(txb, {
|
|
869
|
+
method: _StreamContract.MethodName.claim_stream,
|
|
870
|
+
arguments: [streamObject, clockObject],
|
|
871
|
+
typeArgs: [input.coinType]
|
|
872
|
+
});
|
|
873
|
+
}
|
|
874
|
+
claimStreamByProxy(txb, input) {
|
|
875
|
+
const streamObject = this.makeObject(input.streamId);
|
|
876
|
+
const vaultObject = this.vaultObject();
|
|
877
|
+
const feeObject = this.feeObject();
|
|
878
|
+
const clockObject = this.clockObject();
|
|
879
|
+
return this.addContractCall(txb, {
|
|
880
|
+
method: _StreamContract.MethodName.claim_stream_by_proxy,
|
|
881
|
+
arguments: [streamObject, vaultObject, feeObject, clockObject],
|
|
882
|
+
typeArgs: [input.coinType]
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
get createStreamTarget() {
|
|
886
|
+
return `${this.config.contractId}::${_StreamContract.ModuleName}::${_StreamContract.MethodName.create_stream}`;
|
|
887
|
+
}
|
|
888
|
+
get setAutoClaimTarget() {
|
|
889
|
+
return `${this.config.contractId}::${_StreamContract.ModuleName}::${_StreamContract.MethodName.set_auto_claim}`;
|
|
890
|
+
}
|
|
891
|
+
get cancelStreamTarget() {
|
|
892
|
+
return `${this.config.contractId}::${_StreamContract.ModuleName}::${_StreamContract.MethodName.cancel_stream}`;
|
|
893
|
+
}
|
|
894
|
+
get claimStreamTarget() {
|
|
895
|
+
return `${this.config.contractId}::${_StreamContract.ModuleName}::${_StreamContract.MethodName.claim_stream}`;
|
|
896
|
+
}
|
|
897
|
+
get claimStreamByProxyTarget() {
|
|
898
|
+
return `${this.config.contractId}::${_StreamContract.ModuleName}::${_StreamContract.MethodName.claim_stream_by_proxy}`;
|
|
899
|
+
}
|
|
900
|
+
};
|
|
901
|
+
|
|
902
|
+
// src/apps/mpay/builder/MPayBuilder.ts
|
|
903
|
+
var MPayBuilder = class {
|
|
904
|
+
constructor(globals) {
|
|
905
|
+
this.globals = globals;
|
|
906
|
+
const config = globals.envConfig.contract;
|
|
907
|
+
this.feeContract = new FeeContract(config, globals);
|
|
908
|
+
this.streamContract = new StreamContract(config, globals);
|
|
909
|
+
}
|
|
910
|
+
feeContract;
|
|
911
|
+
streamContract;
|
|
912
|
+
async createStreams(info) {
|
|
913
|
+
const infoInternal = CreateStreamHelper.convertCreateStreamInfoToInternal(info);
|
|
914
|
+
return this.createStreamHelper().buildCreateStreamTransactionBlock(infoInternal);
|
|
915
|
+
}
|
|
916
|
+
createStreamHelper() {
|
|
917
|
+
return new CreateStreamHelper(this.globals, this.feeContract, this.streamContract);
|
|
918
|
+
}
|
|
919
|
+
setAutoClaim(streamId, enabled, coinType) {
|
|
920
|
+
const txb = new TransactionBlock3();
|
|
921
|
+
return this.streamContract.setAutoClaim(txb, {
|
|
922
|
+
streamId,
|
|
923
|
+
enabled,
|
|
924
|
+
coinType
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
claimStream(streamId, coinType) {
|
|
928
|
+
const txb = new TransactionBlock3();
|
|
929
|
+
return this.streamContract.claimStream(txb, {
|
|
930
|
+
streamId,
|
|
931
|
+
coinType
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
claimStreamByProxy(streamId, coinType) {
|
|
935
|
+
const txb = new TransactionBlock3();
|
|
936
|
+
return this.streamContract.claimStreamByProxy(txb, {
|
|
937
|
+
streamId,
|
|
938
|
+
coinType
|
|
939
|
+
});
|
|
940
|
+
}
|
|
941
|
+
cancelStream(streamId, coinType) {
|
|
942
|
+
const txb = new TransactionBlock3();
|
|
943
|
+
this.streamContract.cancelStream(txb, {
|
|
944
|
+
streamId,
|
|
945
|
+
coinType
|
|
946
|
+
});
|
|
947
|
+
return txb;
|
|
948
|
+
}
|
|
949
|
+
};
|
|
950
|
+
|
|
951
|
+
// src/apps/mpay/error/TransactionFailedError.ts
|
|
952
|
+
var TransactionFailedError = class extends MPayError {
|
|
953
|
+
constructor(status3, msg) {
|
|
954
|
+
super(12 /* TransactionFailed */, `Transaction failed: ${msg}`, {
|
|
955
|
+
context: {
|
|
956
|
+
status: status3,
|
|
957
|
+
msg
|
|
958
|
+
}
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
};
|
|
962
|
+
|
|
963
|
+
// src/apps/mpay/stream/helper.ts
|
|
964
|
+
var MIN_INTERVAL_MS = 1e3;
|
|
965
|
+
var MPayHelper = class {
|
|
966
|
+
constructor(globals) {
|
|
967
|
+
this.globals = globals;
|
|
968
|
+
this.coinMetaHelper = new CoinMetaHelper(globals.suiClient);
|
|
969
|
+
this.createStreamHelper = new MPayBuilder(globals).createStreamHelper();
|
|
970
|
+
}
|
|
971
|
+
coinMetaHelper;
|
|
972
|
+
createStreamHelper;
|
|
973
|
+
getStreamIdsFromCreateStreamResponse(res) {
|
|
974
|
+
if (res.effects?.status.status !== "success") {
|
|
975
|
+
throw new TransactionFailedError(res.effects?.status.status, res.effects?.status.error);
|
|
976
|
+
}
|
|
977
|
+
return res.objectChanges.filter(
|
|
978
|
+
(change) => change.type === "created" && change.objectType.startsWith(`${this.globals.envConfig.contract.contractId}::stream::Stream`)
|
|
979
|
+
).map((change) => change.objectId);
|
|
980
|
+
}
|
|
981
|
+
calculateCreateStreamFees(info) {
|
|
982
|
+
return this.createStreamHelper.calculateCreateStreamFees(info);
|
|
983
|
+
}
|
|
984
|
+
feeParams() {
|
|
985
|
+
return this.createStreamHelper.feeParams();
|
|
986
|
+
}
|
|
987
|
+
calculateStreamAmount(input) {
|
|
988
|
+
if (input.steps === 0n) {
|
|
989
|
+
throw new InvalidInputError("Invalid stream steps: 0");
|
|
990
|
+
}
|
|
991
|
+
const cliffFraction = input.cliff ? input.cliff : {
|
|
992
|
+
numerator: 0n,
|
|
993
|
+
denominator: 100n
|
|
994
|
+
};
|
|
995
|
+
const cliffAmount = input.totalAmount * cliffFraction.numerator / cliffFraction.denominator;
|
|
996
|
+
const amountPerStep = (input.totalAmount - cliffAmount) / input.steps;
|
|
997
|
+
const realTotalAmount = amountPerStep * input.steps + cliffAmount;
|
|
998
|
+
const res = {
|
|
999
|
+
realTotalAmount,
|
|
1000
|
+
cliffAmount,
|
|
1001
|
+
amountPerStep
|
|
1002
|
+
};
|
|
1003
|
+
this.validateStreamAmount(res, input.totalAmount);
|
|
1004
|
+
return res;
|
|
1005
|
+
}
|
|
1006
|
+
calculateTimelineByInterval(input) {
|
|
1007
|
+
if (input.steps === 0n) {
|
|
1008
|
+
throw new InvalidInputError("Invalid stream steps: 0");
|
|
1009
|
+
}
|
|
1010
|
+
const timeEnd = input.timeStart.plus(input.interval.toMillis() * Number(input.steps));
|
|
1011
|
+
const res = {
|
|
1012
|
+
timeStart: input.timeStart,
|
|
1013
|
+
timeEnd,
|
|
1014
|
+
interval: input.interval,
|
|
1015
|
+
steps: input.steps
|
|
1016
|
+
};
|
|
1017
|
+
this.validateTimeline(res);
|
|
1018
|
+
return res;
|
|
1019
|
+
}
|
|
1020
|
+
calculateTimelineByTotalDuration(input) {
|
|
1021
|
+
if (input.steps === 0n) {
|
|
1022
|
+
throw new InvalidInputError("Invalid stream steps: 0");
|
|
1023
|
+
}
|
|
1024
|
+
const intervalMilli = BigInt(input.total.toMillis()) / input.steps;
|
|
1025
|
+
const timeEnd = input.timeStart.plus(Duration.fromMillis(Number(intervalMilli * input.steps)));
|
|
1026
|
+
const res = {
|
|
1027
|
+
timeStart: input.timeStart,
|
|
1028
|
+
timeEnd,
|
|
1029
|
+
interval: Duration.fromMillis(Number(intervalMilli)),
|
|
1030
|
+
steps: input.steps
|
|
1031
|
+
};
|
|
1032
|
+
this.validateTimeline(res);
|
|
1033
|
+
return res;
|
|
1034
|
+
}
|
|
1035
|
+
async getBalance(address, coinType) {
|
|
1036
|
+
const balance = await this.globals.suiClient.getBalance({
|
|
1037
|
+
owner: address,
|
|
1038
|
+
coinType
|
|
1039
|
+
});
|
|
1040
|
+
const coinMeta = await this.getCoinMeta(coinType);
|
|
1041
|
+
return {
|
|
1042
|
+
...balance,
|
|
1043
|
+
coinType: normalizeStructTag3(balance.coinType),
|
|
1044
|
+
coinMeta
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
async getAllBalance(address) {
|
|
1048
|
+
const allBalance = await this.globals.suiClient.getAllBalances({
|
|
1049
|
+
owner: address
|
|
1050
|
+
});
|
|
1051
|
+
const coinMetas = await Promise.all(allBalance.map((bal) => this.getCoinMeta(bal.coinType)));
|
|
1052
|
+
return allBalance.map((bal, i) => ({
|
|
1053
|
+
...bal,
|
|
1054
|
+
coinType: normalizeStructTag3(bal.coinType),
|
|
1055
|
+
coinMeta: coinMetas[i]
|
|
1056
|
+
}));
|
|
1057
|
+
}
|
|
1058
|
+
async getCoinMeta(coinType) {
|
|
1059
|
+
return this.coinMetaHelper.getCoinMeta(coinType);
|
|
1060
|
+
}
|
|
1061
|
+
async simulateTransactionBlock(txb) {
|
|
1062
|
+
return this.globals.suiClient.devInspectTransactionBlock({
|
|
1063
|
+
transactionBlock: txb,
|
|
1064
|
+
sender: await this.globals.wallet.address()
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1067
|
+
validateStreamAmount(val, originTotalAmount) {
|
|
1068
|
+
if (val.amountPerStep === 0n) {
|
|
1069
|
+
throw new InvalidInputError("Stream amount too small", "totalAmount", originTotalAmount);
|
|
1070
|
+
}
|
|
1071
|
+
if (val.cliffAmount > val.realTotalAmount) {
|
|
1072
|
+
throw new InvalidInputError("Invalid cliff settings");
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
validateTimeline(val) {
|
|
1076
|
+
if (val.interval.toMillis() < MIN_INTERVAL_MS) {
|
|
1077
|
+
throw new InvalidInputError("Interval shall be at least 1 second", "interval", val.interval);
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
};
|
|
1081
|
+
var CoinMetaHelper = class {
|
|
1082
|
+
constructor(suiClient) {
|
|
1083
|
+
this.suiClient = suiClient;
|
|
1084
|
+
this.coinMetaReg = /* @__PURE__ */ new Map();
|
|
1085
|
+
}
|
|
1086
|
+
coinMetaReg;
|
|
1087
|
+
async getCoinMeta(coinType) {
|
|
1088
|
+
const normalized = normalizeStructTag3(coinType || SUI_TYPE_ARG2);
|
|
1089
|
+
if (this.coinMetaReg.has(normalized)) {
|
|
1090
|
+
return this.coinMetaReg.get(normalized);
|
|
1091
|
+
}
|
|
1092
|
+
const meta = await this.queryCoinMeta(normalized);
|
|
1093
|
+
if (meta) {
|
|
1094
|
+
this.coinMetaReg.set(normalized, meta);
|
|
1095
|
+
}
|
|
1096
|
+
return meta;
|
|
1097
|
+
}
|
|
1098
|
+
async queryCoinMeta(coinType) {
|
|
1099
|
+
const res = await this.suiClient.getCoinMetadata({ coinType });
|
|
1100
|
+
return res || void 0;
|
|
1101
|
+
}
|
|
1102
|
+
};
|
|
1103
|
+
|
|
1104
|
+
// src/apps/mpay/stream/query.ts
|
|
1105
|
+
import { normalizeStructTag as normalizeStructTag5, normalizeSuiAddress as normalizeSuiAddress2 } from "@mysten/sui.js/utils";
|
|
1106
|
+
import { DateTime as DateTime4 } from "luxon";
|
|
1107
|
+
|
|
1108
|
+
// src/apps/mpay/stream/Stream.ts
|
|
1109
|
+
import { TransactionBlock as TransactionBlock4 } from "@mysten/sui.js/transactions";
|
|
1110
|
+
import { normalizeStructTag as normalizeStructTag4, parseStructTag } from "@mysten/sui.js/utils";
|
|
1111
|
+
import { DateTime as DateTime3 } from "luxon";
|
|
1112
|
+
|
|
1113
|
+
// src/apps/mpay/error/NotCreatorError.ts
|
|
1114
|
+
var NotCreatorError = class extends MPayError {
|
|
1115
|
+
constructor() {
|
|
1116
|
+
super(7 /* NotCreator */, "Connected wallet is not creator");
|
|
1117
|
+
}
|
|
1118
|
+
};
|
|
1119
|
+
|
|
1120
|
+
// src/apps/mpay/error/NotRecipientError.ts
|
|
1121
|
+
var NotRecipientError = class extends MPayError {
|
|
1122
|
+
constructor() {
|
|
1123
|
+
super(8 /* NotRecipient */, "Connected wallet is not recipient");
|
|
1124
|
+
}
|
|
1125
|
+
};
|
|
1126
|
+
|
|
1127
|
+
// src/apps/mpay/error/RpcError.ts
|
|
1128
|
+
var RpcError = class extends MPayError {
|
|
1129
|
+
constructor(msg, context) {
|
|
1130
|
+
super(6 /* RpcError */, msg, {
|
|
1131
|
+
context
|
|
1132
|
+
});
|
|
1133
|
+
}
|
|
1134
|
+
};
|
|
1135
|
+
|
|
1136
|
+
// src/apps/mpay/error/SanityError.ts
|
|
1137
|
+
var SanityError = class extends MPayError {
|
|
1138
|
+
constructor(msg, options = {}) {
|
|
1139
|
+
super(0 /* sanity */, msg, options);
|
|
1140
|
+
}
|
|
1141
|
+
};
|
|
1142
|
+
|
|
1143
|
+
// src/apps/mpay/error/StreamNotFoundError.ts
|
|
1144
|
+
var StreamNotFoundError = class extends MPayError {
|
|
1145
|
+
constructor(streamId) {
|
|
1146
|
+
super(5 /* StreamNotFound */, "Stream not found", {
|
|
1147
|
+
context: {
|
|
1148
|
+
streamId
|
|
1149
|
+
}
|
|
1150
|
+
});
|
|
1151
|
+
}
|
|
1152
|
+
};
|
|
1153
|
+
|
|
1154
|
+
// src/apps/mpay/utils/utils.ts
|
|
1155
|
+
import { DateTime as DateTime2, Duration as Duration2 } from "luxon";
|
|
1156
|
+
var MAX_U64 = (1n << 64n) - 1n;
|
|
1157
|
+
var TIME_ROUND_UNIT = 1e3;
|
|
1158
|
+
function roundDateTime(date) {
|
|
1159
|
+
let dateMs;
|
|
1160
|
+
if (typeof date === "number") {
|
|
1161
|
+
dateMs = date;
|
|
1162
|
+
} else if (typeof date === "bigint") {
|
|
1163
|
+
dateMs = Number(date);
|
|
1164
|
+
} else {
|
|
1165
|
+
dateMs = date.toMillis();
|
|
1166
|
+
}
|
|
1167
|
+
const roundMs = Math.round(dateMs / TIME_ROUND_UNIT);
|
|
1168
|
+
return DateTime2.fromMillis(roundMs * TIME_ROUND_UNIT);
|
|
1169
|
+
}
|
|
1170
|
+
function roundDuration(duration) {
|
|
1171
|
+
let durationMs;
|
|
1172
|
+
if (typeof duration === "number") {
|
|
1173
|
+
durationMs = duration;
|
|
1174
|
+
} else if (typeof duration === "bigint") {
|
|
1175
|
+
durationMs = Number(duration);
|
|
1176
|
+
} else {
|
|
1177
|
+
durationMs = duration.toMillis();
|
|
1178
|
+
}
|
|
1179
|
+
const roundMs = Math.round(durationMs / TIME_ROUND_UNIT);
|
|
1180
|
+
return Duration2.fromMillis(roundMs * TIME_ROUND_UNIT);
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
// src/apps/mpay/stream/Stream.ts
|
|
1184
|
+
var Stream = class _Stream {
|
|
1185
|
+
constructor(globals, streamId, rawData) {
|
|
1186
|
+
this.globals = globals;
|
|
1187
|
+
this.streamId = streamId;
|
|
1188
|
+
this.rawData = rawData;
|
|
1189
|
+
this.streamContract = new StreamContract(globals.envConfig.contract, globals);
|
|
1190
|
+
}
|
|
1191
|
+
streamContract;
|
|
1192
|
+
type = "Stream";
|
|
1193
|
+
static async new(globals, streamId) {
|
|
1194
|
+
const rawData = await _Stream.fetchStreamData(globals, streamId);
|
|
1195
|
+
return new _Stream(globals, streamId, rawData);
|
|
1196
|
+
}
|
|
1197
|
+
static fromObjectData(globals, streamId, data) {
|
|
1198
|
+
const rawData = _Stream.parseRawStreamData(streamId, data);
|
|
1199
|
+
return new _Stream(globals, streamId, rawData);
|
|
1200
|
+
}
|
|
1201
|
+
get info() {
|
|
1202
|
+
return {
|
|
1203
|
+
name: this.name,
|
|
1204
|
+
creator: this.creator,
|
|
1205
|
+
coinType: this.coinType,
|
|
1206
|
+
totalAmount: this.totalAmount,
|
|
1207
|
+
start: this.timeStart,
|
|
1208
|
+
end: this.timeEnd,
|
|
1209
|
+
cancelable: this.cancelable,
|
|
1210
|
+
cliffAmount: this.cliff,
|
|
1211
|
+
duration: this.duration,
|
|
1212
|
+
interval: this.interval,
|
|
1213
|
+
steps: this.totalSteps,
|
|
1214
|
+
nextReleaseDate: this.nextReleaseDate,
|
|
1215
|
+
nextReleaseAmount: this.nextReleaseAmount,
|
|
1216
|
+
groupId: this.groupId,
|
|
1217
|
+
streamId: this.streamId,
|
|
1218
|
+
recipient: this.recipient,
|
|
1219
|
+
progress: this.progress,
|
|
1220
|
+
autoClaim: this.autoClaim
|
|
1221
|
+
};
|
|
1222
|
+
}
|
|
1223
|
+
get groupCommonInfo() {
|
|
1224
|
+
return {
|
|
1225
|
+
name: this.name,
|
|
1226
|
+
groupId: this.groupId,
|
|
1227
|
+
creator: this.creator,
|
|
1228
|
+
start: this.timeStart,
|
|
1229
|
+
interval: this.interval,
|
|
1230
|
+
steps: this.totalSteps,
|
|
1231
|
+
cancelable: this.cancelable
|
|
1232
|
+
};
|
|
1233
|
+
}
|
|
1234
|
+
async refresh() {
|
|
1235
|
+
this.rawData = await _Stream.fetchStreamData(this.globals, this.streamId);
|
|
1236
|
+
}
|
|
1237
|
+
refreshWithData(data) {
|
|
1238
|
+
if (data.data?.objectId !== this.streamId) {
|
|
1239
|
+
throw new SanityError("Object Id does not align");
|
|
1240
|
+
}
|
|
1241
|
+
this.rawData = _Stream.parseRawStreamData(this.streamId, data);
|
|
1242
|
+
}
|
|
1243
|
+
async historyEvents(pagination) {
|
|
1244
|
+
return this.globals.backend.getStreamHistory({
|
|
1245
|
+
streamId: this.streamId,
|
|
1246
|
+
pagination
|
|
1247
|
+
});
|
|
1248
|
+
}
|
|
1249
|
+
async cancel() {
|
|
1250
|
+
if (await this.globals.walletAddress() !== this.creator) {
|
|
1251
|
+
throw new NotCreatorError();
|
|
1252
|
+
}
|
|
1253
|
+
const txb = new TransactionBlock4();
|
|
1254
|
+
this.streamContract.cancelStream(txb, {
|
|
1255
|
+
streamId: this.streamId,
|
|
1256
|
+
coinType: this.coinType
|
|
1257
|
+
});
|
|
1258
|
+
return txb;
|
|
1259
|
+
}
|
|
1260
|
+
async claim() {
|
|
1261
|
+
if (await this.globals.walletAddress() !== this.recipient) {
|
|
1262
|
+
throw new NotRecipientError();
|
|
1263
|
+
}
|
|
1264
|
+
const txb = new TransactionBlock4();
|
|
1265
|
+
this.streamContract.claimStream(txb, {
|
|
1266
|
+
streamId: this.streamId,
|
|
1267
|
+
coinType: this.coinType
|
|
1268
|
+
});
|
|
1269
|
+
return txb;
|
|
1270
|
+
}
|
|
1271
|
+
async setAutoClaim(enabled) {
|
|
1272
|
+
if (await this.globals.walletAddress() !== this.recipient) {
|
|
1273
|
+
throw new NotRecipientError();
|
|
1274
|
+
}
|
|
1275
|
+
const txb = new TransactionBlock4();
|
|
1276
|
+
this.streamContract.setAutoClaim(txb, {
|
|
1277
|
+
streamId: this.streamId,
|
|
1278
|
+
coinType: this.coinType,
|
|
1279
|
+
enabled
|
|
1280
|
+
});
|
|
1281
|
+
return txb;
|
|
1282
|
+
}
|
|
1283
|
+
async claimByProxy() {
|
|
1284
|
+
const txb = new TransactionBlock4();
|
|
1285
|
+
this.streamContract.claimStreamByProxy(txb, {
|
|
1286
|
+
streamId: this.streamId,
|
|
1287
|
+
coinType: this.coinType
|
|
1288
|
+
});
|
|
1289
|
+
return txb;
|
|
1290
|
+
}
|
|
1291
|
+
get wallet() {
|
|
1292
|
+
return this.globals.wallet;
|
|
1293
|
+
}
|
|
1294
|
+
get client() {
|
|
1295
|
+
return this.globals.suiClient;
|
|
1296
|
+
}
|
|
1297
|
+
get coinType() {
|
|
1298
|
+
return normalizeStructTag4(this.rawData.coinType);
|
|
1299
|
+
}
|
|
1300
|
+
get progress() {
|
|
1301
|
+
return {
|
|
1302
|
+
status: this.streamStatus,
|
|
1303
|
+
total: this.totalAmount,
|
|
1304
|
+
streamed: this.streamedAmount,
|
|
1305
|
+
claimed: this.claimedAmount,
|
|
1306
|
+
claimable: this.claimable,
|
|
1307
|
+
canceled: this.canceledAmount
|
|
1308
|
+
};
|
|
1309
|
+
}
|
|
1310
|
+
get balance() {
|
|
1311
|
+
return this.rawData.balance;
|
|
1312
|
+
}
|
|
1313
|
+
get autoClaim() {
|
|
1314
|
+
return this.rawData.autoClaim;
|
|
1315
|
+
}
|
|
1316
|
+
get amountPerEpoch() {
|
|
1317
|
+
return this.rawData.config.amountPerEpoch;
|
|
1318
|
+
}
|
|
1319
|
+
get cancelable() {
|
|
1320
|
+
return this.rawData.config.cancelable;
|
|
1321
|
+
}
|
|
1322
|
+
get cliff() {
|
|
1323
|
+
return this.rawData.config.cliff;
|
|
1324
|
+
}
|
|
1325
|
+
get creator() {
|
|
1326
|
+
return this.rawData.config.creator;
|
|
1327
|
+
}
|
|
1328
|
+
get interval() {
|
|
1329
|
+
return roundDuration(this.rawData.config.epochInterval);
|
|
1330
|
+
}
|
|
1331
|
+
get groupId() {
|
|
1332
|
+
const { metadata } = this.rawData.config;
|
|
1333
|
+
const md = decodeMetadata(metadata);
|
|
1334
|
+
return md.groupId;
|
|
1335
|
+
}
|
|
1336
|
+
get name() {
|
|
1337
|
+
const { metadata } = this.rawData.config;
|
|
1338
|
+
const md = decodeMetadata(metadata);
|
|
1339
|
+
return md.name;
|
|
1340
|
+
}
|
|
1341
|
+
get recipient() {
|
|
1342
|
+
return this.rawData.config.recipient;
|
|
1343
|
+
}
|
|
1344
|
+
get timeStart() {
|
|
1345
|
+
return roundDateTime(this.rawData.config.timeStart);
|
|
1346
|
+
}
|
|
1347
|
+
get duration() {
|
|
1348
|
+
const rawConfig = this.rawData.config;
|
|
1349
|
+
const duration = rawConfig.epochInterval * rawConfig.totalEpoch;
|
|
1350
|
+
return roundDuration(duration);
|
|
1351
|
+
}
|
|
1352
|
+
get timeEnd() {
|
|
1353
|
+
return this.timeStart.plus(this.duration);
|
|
1354
|
+
}
|
|
1355
|
+
get totalSteps() {
|
|
1356
|
+
return this.rawData.config.totalEpoch;
|
|
1357
|
+
}
|
|
1358
|
+
get claimable() {
|
|
1359
|
+
return this.streamedAmount - this.claimedAmount;
|
|
1360
|
+
}
|
|
1361
|
+
get nextReleaseDate() {
|
|
1362
|
+
if (this.currentEpoch === -1n) {
|
|
1363
|
+
return this.timeStart;
|
|
1364
|
+
}
|
|
1365
|
+
if (this.currentEpoch >= this.totalSteps || this.isCanceled) {
|
|
1366
|
+
return null;
|
|
1367
|
+
}
|
|
1368
|
+
return roundDateTime((this.currentEpoch + 1n) * this.rawData.config.epochInterval + this.rawData.config.timeStart);
|
|
1369
|
+
}
|
|
1370
|
+
get nextReleaseAmount() {
|
|
1371
|
+
if (this.currentEpoch === -1n) {
|
|
1372
|
+
return this.cliff;
|
|
1373
|
+
}
|
|
1374
|
+
if (this.currentEpoch >= this.totalSteps || this.isCanceled) {
|
|
1375
|
+
return null;
|
|
1376
|
+
}
|
|
1377
|
+
return this.amountPerEpoch;
|
|
1378
|
+
}
|
|
1379
|
+
get streamStatus() {
|
|
1380
|
+
const rawStatus = this.rawData.status.status;
|
|
1381
|
+
if (rawStatus === 16 /* CANCELED */) {
|
|
1382
|
+
return "CANCELED" /* CANCELED */;
|
|
1383
|
+
}
|
|
1384
|
+
if (rawStatus === 17 /* CANCELED_COMPLETED */) {
|
|
1385
|
+
return "SETTLED" /* SETTLED */;
|
|
1386
|
+
}
|
|
1387
|
+
if (rawStatus === 1 /* COMPLETED */) {
|
|
1388
|
+
return "COMPLETED" /* COMPLETED */;
|
|
1389
|
+
}
|
|
1390
|
+
if (this.currentEpoch >= this.totalSteps) {
|
|
1391
|
+
return "STREAMED" /* STREAMED */;
|
|
1392
|
+
}
|
|
1393
|
+
return "STREAMING" /* STREAMING */;
|
|
1394
|
+
}
|
|
1395
|
+
get streamedAmount() {
|
|
1396
|
+
if (this.currentEpoch === -1n) {
|
|
1397
|
+
return 0n;
|
|
1398
|
+
}
|
|
1399
|
+
if (this.isCanceled) {
|
|
1400
|
+
return this.rawData.status.epochCanceled * this.amountPerEpoch + this.cliff;
|
|
1401
|
+
}
|
|
1402
|
+
return this.currentEpoch * this.amountPerEpoch + this.cliff;
|
|
1403
|
+
}
|
|
1404
|
+
get claimedAmount() {
|
|
1405
|
+
if (this.rawData.status.epochClaimed === MAX_U64) {
|
|
1406
|
+
return 0n;
|
|
1407
|
+
}
|
|
1408
|
+
return this.rawData.status.epochClaimed * this.amountPerEpoch + this.cliff;
|
|
1409
|
+
}
|
|
1410
|
+
get currentEpoch() {
|
|
1411
|
+
const timeNowMs = DateTime3.now().toMillis();
|
|
1412
|
+
const timeStartMs = this.timeStart.toMillis();
|
|
1413
|
+
if (timeNowMs < timeStartMs) {
|
|
1414
|
+
return -1n;
|
|
1415
|
+
}
|
|
1416
|
+
const epoch = Math.floor((timeNowMs - timeStartMs) / Number(this.rawData.config.epochInterval));
|
|
1417
|
+
return BigInt(epoch) > Number(this.rawData.config.totalEpoch) ? this.rawData.config.totalEpoch : BigInt(epoch);
|
|
1418
|
+
}
|
|
1419
|
+
get totalAmount() {
|
|
1420
|
+
const rawConfig = this.rawData.config;
|
|
1421
|
+
return rawConfig.amountPerEpoch * rawConfig.totalEpoch + rawConfig.cliff;
|
|
1422
|
+
}
|
|
1423
|
+
get isCanceled() {
|
|
1424
|
+
const rawStatus = this.rawData.status.status;
|
|
1425
|
+
return rawStatus === 16 /* CANCELED */ || rawStatus === 17 /* CANCELED_COMPLETED */;
|
|
1426
|
+
}
|
|
1427
|
+
get canceledAmount() {
|
|
1428
|
+
return this.isCanceled ? this.totalAmount - this.streamedAmount : 0n;
|
|
1429
|
+
}
|
|
1430
|
+
static async fetchStreamData(globals, streamId) {
|
|
1431
|
+
const res = await globals.suiClient.getObject({
|
|
1432
|
+
id: streamId,
|
|
1433
|
+
options: {
|
|
1434
|
+
showContent: true,
|
|
1435
|
+
showType: true
|
|
1436
|
+
}
|
|
1437
|
+
});
|
|
1438
|
+
return _Stream.parseRawStreamData(streamId, res);
|
|
1439
|
+
}
|
|
1440
|
+
static parseRawStreamData(streamId, res) {
|
|
1441
|
+
if (res.error) {
|
|
1442
|
+
if (res.error.code === "notExists") {
|
|
1443
|
+
throw new StreamNotFoundError(streamId);
|
|
1444
|
+
}
|
|
1445
|
+
throw new RpcError(`get stream data: ${res.error.code}`, {
|
|
1446
|
+
streamId,
|
|
1447
|
+
...res.error
|
|
1448
|
+
});
|
|
1449
|
+
}
|
|
1450
|
+
const content = res.data.content;
|
|
1451
|
+
if (content.dataType !== "moveObject") {
|
|
1452
|
+
throw new RpcError("Unexpected object type", {
|
|
1453
|
+
gotType: content.dataType
|
|
1454
|
+
});
|
|
1455
|
+
}
|
|
1456
|
+
const { typeParams } = parseStructTag(content.type);
|
|
1457
|
+
const coinType = normalizeStructTag4(typeParams[0]);
|
|
1458
|
+
const dataFields = content.fields;
|
|
1459
|
+
const config = dataFields.config.fields;
|
|
1460
|
+
const status3 = dataFields.status.fields;
|
|
1461
|
+
return {
|
|
1462
|
+
coinType,
|
|
1463
|
+
autoClaim: dataFields.auto_claim,
|
|
1464
|
+
balance: BigInt(dataFields.balance.fields.balance),
|
|
1465
|
+
config: {
|
|
1466
|
+
amountPerEpoch: BigInt(config.amount_per_epoch),
|
|
1467
|
+
cancelable: config.cancelable,
|
|
1468
|
+
cliff: BigInt(config.cliff),
|
|
1469
|
+
creator: config.creator,
|
|
1470
|
+
epochInterval: BigInt(config.epoch_interval),
|
|
1471
|
+
metadata: config.metadata,
|
|
1472
|
+
recipient: config.recipient,
|
|
1473
|
+
timeStart: BigInt(config.time_start),
|
|
1474
|
+
totalEpoch: BigInt(config.total_epoch)
|
|
1475
|
+
},
|
|
1476
|
+
status: {
|
|
1477
|
+
status: status3.status,
|
|
1478
|
+
epochCanceled: BigInt(status3.epoch_canceled),
|
|
1479
|
+
epochClaimed: BigInt(status3.epoch_claimed)
|
|
1480
|
+
}
|
|
1481
|
+
};
|
|
1482
|
+
}
|
|
1483
|
+
};
|
|
1484
|
+
|
|
1485
|
+
// src/apps/mpay/error/InvalidStreamGroupError.ts
|
|
1486
|
+
var InvalidStreamGroupError = class extends MPayError {
|
|
1487
|
+
constructor(msg, context) {
|
|
1488
|
+
super(9 /* InvalidStreamGroup */, `Invalid stream group: ${msg}`, { context });
|
|
1489
|
+
}
|
|
1490
|
+
};
|
|
1491
|
+
|
|
1492
|
+
// src/apps/mpay/sui/iterator/iterator.ts
|
|
1493
|
+
async function getAllFromIterator(it) {
|
|
1494
|
+
const res = [];
|
|
1495
|
+
while (await it.hasNext()) {
|
|
1496
|
+
const val = await it.next();
|
|
1497
|
+
res.push(val);
|
|
1498
|
+
}
|
|
1499
|
+
if (res && Array.isArray(res[0])) {
|
|
1500
|
+
return res.flat(1);
|
|
1501
|
+
}
|
|
1502
|
+
return res;
|
|
1503
|
+
}
|
|
1504
|
+
var PagedIterator = class {
|
|
1505
|
+
constructor(requester) {
|
|
1506
|
+
this.requester = requester;
|
|
1507
|
+
this.curPage = void 0;
|
|
1508
|
+
this.init = true;
|
|
1509
|
+
}
|
|
1510
|
+
curPage;
|
|
1511
|
+
init;
|
|
1512
|
+
async hasNext() {
|
|
1513
|
+
if (this.init) {
|
|
1514
|
+
if (!this.curPage) {
|
|
1515
|
+
this.curPage = await this.requester.doNextRequest();
|
|
1516
|
+
}
|
|
1517
|
+
return !!this.curPage.data?.length || this.curPage.hasNext;
|
|
1518
|
+
}
|
|
1519
|
+
if (!this.curPage) {
|
|
1520
|
+
throw new Error("invalid implementation of iterator");
|
|
1521
|
+
}
|
|
1522
|
+
return this.curPage.hasNext;
|
|
1523
|
+
}
|
|
1524
|
+
async next() {
|
|
1525
|
+
if (this.init) {
|
|
1526
|
+
this.init = false;
|
|
1527
|
+
if (!this.curPage) {
|
|
1528
|
+
this.curPage = await this.requester.doNextRequest();
|
|
1529
|
+
}
|
|
1530
|
+
return this.curPage.data;
|
|
1531
|
+
}
|
|
1532
|
+
this.curPage = await this.requester.doNextRequest();
|
|
1533
|
+
return this.curPage.data;
|
|
1534
|
+
}
|
|
1535
|
+
};
|
|
1536
|
+
var EntryIterator = class {
|
|
1537
|
+
constructor(requester) {
|
|
1538
|
+
this.requester = requester;
|
|
1539
|
+
this.pager = new PagedIterator(requester);
|
|
1540
|
+
this.curData = [];
|
|
1541
|
+
this.cursor = 0;
|
|
1542
|
+
}
|
|
1543
|
+
cursor;
|
|
1544
|
+
pager;
|
|
1545
|
+
curData;
|
|
1546
|
+
async hasNext() {
|
|
1547
|
+
if (this.cursor < this.curData.length - 1) {
|
|
1548
|
+
return true;
|
|
1549
|
+
}
|
|
1550
|
+
return this.pager.hasNext();
|
|
1551
|
+
}
|
|
1552
|
+
async next() {
|
|
1553
|
+
this.cursor += 1;
|
|
1554
|
+
while (this.cursor >= this.curData.length) {
|
|
1555
|
+
if (!await this.pager.hasNext()) {
|
|
1556
|
+
throw new Error("not more data");
|
|
1557
|
+
} else {
|
|
1558
|
+
this.curData = await this.pager.next();
|
|
1559
|
+
this.cursor = 0;
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
return this.curData[this.cursor];
|
|
1563
|
+
}
|
|
1564
|
+
};
|
|
1565
|
+
|
|
1566
|
+
// src/apps/mpay/sui/iterator/object.ts
|
|
1567
|
+
var REQUEST_PAGE_SIZE = 25;
|
|
1568
|
+
async function getObjectsById(suiClient, ids, options) {
|
|
1569
|
+
const oidIter = new ListOidIterator(ids);
|
|
1570
|
+
const iter = new ObjectBatchIterator(suiClient, oidIter, options);
|
|
1571
|
+
return await getAllFromIterator(iter);
|
|
1572
|
+
}
|
|
1573
|
+
var ListOidIterator = class {
|
|
1574
|
+
constructor(ids) {
|
|
1575
|
+
this.ids = ids;
|
|
1576
|
+
this.cursor = -1;
|
|
1577
|
+
}
|
|
1578
|
+
cursor;
|
|
1579
|
+
async hasNext() {
|
|
1580
|
+
return this.cursor < this.ids.length - 1;
|
|
1581
|
+
}
|
|
1582
|
+
async next() {
|
|
1583
|
+
this.cursor += 1;
|
|
1584
|
+
if (this.cursor >= this.ids.length) {
|
|
1585
|
+
throw new Error("invalid iterator implementation");
|
|
1586
|
+
}
|
|
1587
|
+
return this.ids[this.cursor];
|
|
1588
|
+
}
|
|
1589
|
+
};
|
|
1590
|
+
var ObjectBatchIterator = class extends EntryIterator {
|
|
1591
|
+
constructor(suiClient, idIter, options) {
|
|
1592
|
+
super(new ObjectBatchRequester(suiClient, idIter, options));
|
|
1593
|
+
this.suiClient = suiClient;
|
|
1594
|
+
this.idIter = idIter;
|
|
1595
|
+
this.options = options;
|
|
1596
|
+
}
|
|
1597
|
+
};
|
|
1598
|
+
var ObjectBatchRequester = class {
|
|
1599
|
+
constructor(suiClient, stringIter, options) {
|
|
1600
|
+
this.suiClient = suiClient;
|
|
1601
|
+
this.stringIter = stringIter;
|
|
1602
|
+
this.options = options;
|
|
1603
|
+
this.filter = options?.filter;
|
|
1604
|
+
this.pageSize = options?.pageSize || REQUEST_PAGE_SIZE;
|
|
1605
|
+
this.objectOptions = options?.objectOptions || {
|
|
1606
|
+
showType: true,
|
|
1607
|
+
showContent: true
|
|
1608
|
+
};
|
|
1609
|
+
}
|
|
1610
|
+
filter;
|
|
1611
|
+
pageSize;
|
|
1612
|
+
objectOptions;
|
|
1613
|
+
async doNextRequest() {
|
|
1614
|
+
const requestPage = [];
|
|
1615
|
+
while (requestPage.length < this.pageSize) {
|
|
1616
|
+
const hasNext = await this.stringIter.hasNext();
|
|
1617
|
+
if (!hasNext) {
|
|
1618
|
+
break;
|
|
1619
|
+
}
|
|
1620
|
+
const objId = await this.stringIter.next();
|
|
1621
|
+
if (objId) {
|
|
1622
|
+
requestPage.push(objId);
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
const res = await this.suiClient.multiGetObjects({
|
|
1626
|
+
ids: requestPage,
|
|
1627
|
+
options: this.objectOptions
|
|
1628
|
+
});
|
|
1629
|
+
let filtered;
|
|
1630
|
+
if (this.filter) {
|
|
1631
|
+
const { filter } = this;
|
|
1632
|
+
filtered = res.filter((r) => filter?.(r));
|
|
1633
|
+
} else {
|
|
1634
|
+
filtered = res;
|
|
1635
|
+
}
|
|
1636
|
+
return {
|
|
1637
|
+
data: filtered,
|
|
1638
|
+
hasNext: await this.stringIter.hasNext()
|
|
1639
|
+
};
|
|
1640
|
+
}
|
|
1641
|
+
};
|
|
1642
|
+
|
|
1643
|
+
// src/apps/mpay/stream/StreamGroup.ts
|
|
1644
|
+
var StreamGroup = class _StreamGroup {
|
|
1645
|
+
constructor(globals, streams) {
|
|
1646
|
+
this.globals = globals;
|
|
1647
|
+
this.streams = streams;
|
|
1648
|
+
if (streams.length === 0) {
|
|
1649
|
+
throw new InvalidStreamGroupError("stream size 0");
|
|
1650
|
+
}
|
|
1651
|
+
const gids = streams.map((st) => st.groupId);
|
|
1652
|
+
const set = new Set(gids);
|
|
1653
|
+
if (set.size !== 1) {
|
|
1654
|
+
throw new InvalidInputError("Stream does not have same group ID");
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
type = "StreamGroup";
|
|
1658
|
+
static async new(globals, ids) {
|
|
1659
|
+
const streamObjs = await getObjectsById(globals.suiClient, ids);
|
|
1660
|
+
streamObjs.forEach((obj) => {
|
|
1661
|
+
if (!obj) {
|
|
1662
|
+
throw new SanityError("stream group object data undefined");
|
|
1663
|
+
}
|
|
1664
|
+
});
|
|
1665
|
+
return _StreamGroup.newFromObjectResponse(globals, ids, streamObjs);
|
|
1666
|
+
}
|
|
1667
|
+
static async newFromObjectResponse(globals, ids, responses) {
|
|
1668
|
+
const streams = await _StreamGroup.parseGroupStreams(globals, ids, responses);
|
|
1669
|
+
return new _StreamGroup(globals, streams);
|
|
1670
|
+
}
|
|
1671
|
+
static checkStreamGroup(streams) {
|
|
1672
|
+
const commonInfos = streams.map((stream) => stream.groupCommonInfo);
|
|
1673
|
+
const expInfo = commonInfos[0];
|
|
1674
|
+
let isEqual = true;
|
|
1675
|
+
commonInfos.forEach((info) => {
|
|
1676
|
+
if (!isEqualStreamGroupCommonInfo(expInfo, info)) {
|
|
1677
|
+
isEqual = false;
|
|
1678
|
+
}
|
|
1679
|
+
});
|
|
1680
|
+
return isEqual;
|
|
1681
|
+
}
|
|
1682
|
+
async refresh() {
|
|
1683
|
+
const streamObjs = await getObjectsById(
|
|
1684
|
+
this.globals.suiClient,
|
|
1685
|
+
this.streams.map((stream) => stream.streamId)
|
|
1686
|
+
);
|
|
1687
|
+
this.streams.forEach((stream, i) => {
|
|
1688
|
+
stream.refreshWithData(streamObjs[i]);
|
|
1689
|
+
});
|
|
1690
|
+
}
|
|
1691
|
+
get groupId() {
|
|
1692
|
+
return this.streams[0].groupId;
|
|
1693
|
+
}
|
|
1694
|
+
get creator() {
|
|
1695
|
+
return this.streams[0].creator;
|
|
1696
|
+
}
|
|
1697
|
+
get info() {
|
|
1698
|
+
return {
|
|
1699
|
+
groupId: this.groupId,
|
|
1700
|
+
streamIds: this.streams.map((st) => st.streamId),
|
|
1701
|
+
progress: this.progress,
|
|
1702
|
+
name: this.streams[0].name,
|
|
1703
|
+
creator: this.creator,
|
|
1704
|
+
coinType: this.streams[0].coinType,
|
|
1705
|
+
totalAmount: this.streams.reduce((sum, st) => sum + st.totalAmount, 0n),
|
|
1706
|
+
start: this.streams[0].timeStart,
|
|
1707
|
+
end: this.streams[0].timeEnd,
|
|
1708
|
+
cancelable: this.streams[0].cancelable,
|
|
1709
|
+
cliffAmount: this.streams.reduce((sum, st) => sum + st.cliff, 0n),
|
|
1710
|
+
duration: this.streams[0].duration,
|
|
1711
|
+
interval: this.streams[0].interval,
|
|
1712
|
+
steps: this.streams[0].totalSteps,
|
|
1713
|
+
nextReleaseAmount: this.streams.reduce((sum, st) => {
|
|
1714
|
+
if (st.nextReleaseAmount === null) {
|
|
1715
|
+
return sum;
|
|
1716
|
+
}
|
|
1717
|
+
return sum + st.nextReleaseAmount;
|
|
1718
|
+
}, 0n),
|
|
1719
|
+
nextReleaseDate: this.streams[0].nextReleaseDate
|
|
1720
|
+
};
|
|
1721
|
+
}
|
|
1722
|
+
get progress() {
|
|
1723
|
+
return {
|
|
1724
|
+
total: this.streams.reduce((sum, st) => sum + st.totalAmount, 0n),
|
|
1725
|
+
streamed: this.streams.reduce((sum, st) => sum + st.streamedAmount, 0n),
|
|
1726
|
+
claimed: this.streams.reduce((sum, st) => sum + st.claimedAmount, 0n),
|
|
1727
|
+
claimable: this.streams.reduce((sum, st) => sum + st.claimable, 0n),
|
|
1728
|
+
canceled: this.streams.reduce((sum, st) => sum + st.canceledAmount, 0n)
|
|
1729
|
+
};
|
|
1730
|
+
}
|
|
1731
|
+
async historyEvents(pagination) {
|
|
1732
|
+
return this.globals.backend.getStreamHistory({
|
|
1733
|
+
groupId: this.groupId,
|
|
1734
|
+
pagination
|
|
1735
|
+
});
|
|
1736
|
+
}
|
|
1737
|
+
static async parseGroupStreams(globals, ids, responses) {
|
|
1738
|
+
const streams = responses.map((obj, i) => Stream.fromObjectData(globals, ids[i], obj)).filter((stream) => !!stream);
|
|
1739
|
+
if (new Set(streams.map((st) => st.groupId)).size !== 1) {
|
|
1740
|
+
throw new InvalidStreamGroupError("Not same group ID");
|
|
1741
|
+
}
|
|
1742
|
+
if (!this.checkStreamGroup(streams)) {
|
|
1743
|
+
throw new InvalidStreamGroupError("Not same stream settings");
|
|
1744
|
+
}
|
|
1745
|
+
return streams;
|
|
1746
|
+
}
|
|
1747
|
+
};
|
|
1748
|
+
function isEqualStreamGroupCommonInfo(info1, info2) {
|
|
1749
|
+
return info1.name === info2.name && info1.groupId === info2.groupId && info1.creator === info2.creator && info1.start.toMillis() === info2.start.toMillis() && info1.interval.toMillis() === info2.interval.toMillis() && info1.steps === info2.steps && info1.cancelable === info2.cancelable;
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
// src/apps/mpay/stream/query.ts
|
|
1753
|
+
var PagedStreamListIterator = class _PagedStreamListIterator {
|
|
1754
|
+
constructor(it, pageSize) {
|
|
1755
|
+
this.it = it;
|
|
1756
|
+
this.pageSize = pageSize;
|
|
1757
|
+
}
|
|
1758
|
+
static async newIncoming(input) {
|
|
1759
|
+
const it = await StreamListIterator.newIncoming(input);
|
|
1760
|
+
return new _PagedStreamListIterator(it, input.pageSize);
|
|
1761
|
+
}
|
|
1762
|
+
static async newOutgoing(input) {
|
|
1763
|
+
const it = await StreamListIterator.newOutgoing(input);
|
|
1764
|
+
return new _PagedStreamListIterator(it, input.pageSize);
|
|
1765
|
+
}
|
|
1766
|
+
async hasNext() {
|
|
1767
|
+
return this.it.hasNext();
|
|
1768
|
+
}
|
|
1769
|
+
async next() {
|
|
1770
|
+
const res = [];
|
|
1771
|
+
while (res.length < this.pageSize && await this.it.hasNext()) {
|
|
1772
|
+
res.push(await this.it.next());
|
|
1773
|
+
}
|
|
1774
|
+
return res;
|
|
1775
|
+
}
|
|
1776
|
+
};
|
|
1777
|
+
var StreamListIterator = class _StreamListIterator {
|
|
1778
|
+
constructor(requester) {
|
|
1779
|
+
this.requester = requester;
|
|
1780
|
+
}
|
|
1781
|
+
cachedNext;
|
|
1782
|
+
static async newIncoming(input) {
|
|
1783
|
+
const requester = await StreamListRequester.newIncomingQuery(input);
|
|
1784
|
+
return new _StreamListIterator(requester);
|
|
1785
|
+
}
|
|
1786
|
+
static async newOutgoing(input) {
|
|
1787
|
+
const requester = await StreamListRequester.newOutgoingQuery(input);
|
|
1788
|
+
return new _StreamListIterator(requester);
|
|
1789
|
+
}
|
|
1790
|
+
async hasNext() {
|
|
1791
|
+
if (this.cachedNext === void 0) {
|
|
1792
|
+
this.cachedNext = await this.requester.doNextRequest();
|
|
1793
|
+
}
|
|
1794
|
+
return this.cachedNext !== null;
|
|
1795
|
+
}
|
|
1796
|
+
async next() {
|
|
1797
|
+
if (this.cachedNext === void 0) {
|
|
1798
|
+
const res2 = await this.requester.doNextRequest();
|
|
1799
|
+
if (res2 === null) {
|
|
1800
|
+
throw new SanityError("No more results");
|
|
1801
|
+
}
|
|
1802
|
+
return res2;
|
|
1803
|
+
}
|
|
1804
|
+
const res = this.cachedNext;
|
|
1805
|
+
this.cachedNext = void 0;
|
|
1806
|
+
if (res === null) {
|
|
1807
|
+
throw new SanityError("No more results");
|
|
1808
|
+
}
|
|
1809
|
+
return res;
|
|
1810
|
+
}
|
|
1811
|
+
};
|
|
1812
|
+
var StreamListRequester = class _StreamListRequester {
|
|
1813
|
+
constructor(globals, recipient, groupRefs, query) {
|
|
1814
|
+
this.globals = globals;
|
|
1815
|
+
this.recipient = recipient;
|
|
1816
|
+
this.groupRefs = groupRefs;
|
|
1817
|
+
this.query = query;
|
|
1818
|
+
this.current = 0;
|
|
1819
|
+
const oidIter = new ListOidIterator(groupRefs.flat().map((ref) => ref.streamId));
|
|
1820
|
+
this.objectIter = new ObjectBatchIterator(globals.suiClient, oidIter);
|
|
1821
|
+
}
|
|
1822
|
+
current = 0;
|
|
1823
|
+
objectIter;
|
|
1824
|
+
static async newIncomingQuery(input) {
|
|
1825
|
+
const backendQuery = convertToIncomingBackendQuery(input.query);
|
|
1826
|
+
const recipient = await input.globals.walletAddress();
|
|
1827
|
+
const refs = await input.globals.backend.getIncomingStreams(recipient, backendQuery);
|
|
1828
|
+
const filtered = refs.filter((ref) => normalizeSuiAddress2(ref.recipient) === normalizeSuiAddress2(recipient));
|
|
1829
|
+
const groupedRefs = groupAndSortRefs(filtered);
|
|
1830
|
+
return new _StreamListRequester(input.globals, recipient, groupedRefs, input.query);
|
|
1831
|
+
}
|
|
1832
|
+
static async newOutgoingQuery(input) {
|
|
1833
|
+
const backendQuery = convertToOutgoingBackendQuery(input.query);
|
|
1834
|
+
const sender = await input.globals.walletAddress();
|
|
1835
|
+
const refs = await input.globals.backend.getOutgoingStreams(sender, backendQuery);
|
|
1836
|
+
const groupedRefs = groupAndSortRefs(refs);
|
|
1837
|
+
return new _StreamListRequester(input.globals, sender, groupedRefs, input.query);
|
|
1838
|
+
}
|
|
1839
|
+
async doNextRequest() {
|
|
1840
|
+
if (this.current >= this.groupRefs.length) {
|
|
1841
|
+
return null;
|
|
1842
|
+
}
|
|
1843
|
+
const stRefs = this.groupRefs[this.current];
|
|
1844
|
+
if (stRefs.length === 1) {
|
|
1845
|
+
const stream = await getStreamFromIterator(this.globals, stRefs[0].streamId, this.objectIter);
|
|
1846
|
+
this.current++;
|
|
1847
|
+
return isStreamOfQuery(stream, this.query) ? stream : this.doNextRequest();
|
|
1848
|
+
}
|
|
1849
|
+
if (stRefs.length > 1) {
|
|
1850
|
+
const sg = await getStreamGroupFromIterator(
|
|
1851
|
+
this.globals,
|
|
1852
|
+
stRefs.map((ref) => ref.streamId),
|
|
1853
|
+
this.objectIter
|
|
1854
|
+
);
|
|
1855
|
+
this.current++;
|
|
1856
|
+
return isStreamGroupOfQuery(sg, this.query) ? sg : this.doNextRequest();
|
|
1857
|
+
}
|
|
1858
|
+
throw new SanityError("Stream group with no stream");
|
|
1859
|
+
}
|
|
1860
|
+
};
|
|
1861
|
+
function groupAndSortRefs(refs) {
|
|
1862
|
+
const m = /* @__PURE__ */ new Map();
|
|
1863
|
+
refs.forEach((ref) => {
|
|
1864
|
+
const groupList = m.get(ref.groupId);
|
|
1865
|
+
if (groupList) {
|
|
1866
|
+
groupList.push(ref);
|
|
1867
|
+
m.set(ref.groupId, groupList);
|
|
1868
|
+
} else {
|
|
1869
|
+
m.set(ref.groupId, [ref]);
|
|
1870
|
+
}
|
|
1871
|
+
});
|
|
1872
|
+
return Array.from(m.values()).sort(
|
|
1873
|
+
(gl1, gl2) => DateTime4.fromISO(gl2[0].createDate).toMillis() - DateTime4.fromISO(gl1[0].createDate).toMillis()
|
|
1874
|
+
);
|
|
1875
|
+
}
|
|
1876
|
+
function isStreamOfQuery(stream, query) {
|
|
1877
|
+
if (query === void 0) {
|
|
1878
|
+
return true;
|
|
1879
|
+
}
|
|
1880
|
+
const isStatus = isStreamOfStatus(stream, query.status);
|
|
1881
|
+
if (query && "claimable" in query && query.claimable !== void 0) {
|
|
1882
|
+
const isClaimable = query.claimable ? stream.progress.claimable !== 0n : stream.progress.claimable === 0n;
|
|
1883
|
+
return isStatus && isClaimable;
|
|
1884
|
+
}
|
|
1885
|
+
return isStatus;
|
|
1886
|
+
}
|
|
1887
|
+
function isStreamOfStatus(stream, filter) {
|
|
1888
|
+
if (filter === void 0) {
|
|
1889
|
+
return true;
|
|
1890
|
+
}
|
|
1891
|
+
if (!Array.isArray(filter)) {
|
|
1892
|
+
return stream.progress.status === filter;
|
|
1893
|
+
}
|
|
1894
|
+
return filter.includes(stream.progress.status);
|
|
1895
|
+
}
|
|
1896
|
+
function isStreamGroupOfQuery(sg, query) {
|
|
1897
|
+
if (!query) {
|
|
1898
|
+
return true;
|
|
1899
|
+
}
|
|
1900
|
+
let isStatus = false;
|
|
1901
|
+
sg.streams.forEach((stream) => {
|
|
1902
|
+
if (isStreamOfQuery(stream, query)) {
|
|
1903
|
+
isStatus = true;
|
|
1904
|
+
}
|
|
1905
|
+
});
|
|
1906
|
+
return isStatus;
|
|
1907
|
+
}
|
|
1908
|
+
async function getStreamFromIterator(globals, streamId, it) {
|
|
1909
|
+
const data = await getStreamObjectResponseFromIter(it, streamId);
|
|
1910
|
+
return Stream.fromObjectData(globals, streamId, data);
|
|
1911
|
+
}
|
|
1912
|
+
async function getStreamGroupFromIterator(globals, streamIds, it) {
|
|
1913
|
+
const objResponses = [];
|
|
1914
|
+
while (objResponses.length < streamIds.length) {
|
|
1915
|
+
const data = await getStreamObjectResponseFromIter(it, streamIds[objResponses.length]);
|
|
1916
|
+
objResponses.push(data);
|
|
1917
|
+
}
|
|
1918
|
+
return StreamGroup.newFromObjectResponse(globals, streamIds, objResponses);
|
|
1919
|
+
}
|
|
1920
|
+
async function getStreamObjectResponseFromIter(it, streamId) {
|
|
1921
|
+
if (!await it.hasNext()) {
|
|
1922
|
+
throw new SanityError("object iterator has been consumed");
|
|
1923
|
+
}
|
|
1924
|
+
const data = await it.next();
|
|
1925
|
+
if (!data || data.error || data.data === void 0 || data.data === null) {
|
|
1926
|
+
throw new SanityError(`object iterator undefined response`, {
|
|
1927
|
+
cause: data?.error
|
|
1928
|
+
});
|
|
1929
|
+
}
|
|
1930
|
+
if (data?.data?.objectId !== streamId) {
|
|
1931
|
+
throw new SanityError("stream id not aligned");
|
|
1932
|
+
}
|
|
1933
|
+
return data;
|
|
1934
|
+
}
|
|
1935
|
+
function convertToIncomingBackendQuery(query) {
|
|
1936
|
+
return {
|
|
1937
|
+
status: convertStreamStatus(query?.status),
|
|
1938
|
+
coinType: normalizeCoinTypeFilter(query?.coinType),
|
|
1939
|
+
sender: normalizeAddressFilter(query?.sender)
|
|
1940
|
+
};
|
|
1941
|
+
}
|
|
1942
|
+
function convertToOutgoingBackendQuery(query) {
|
|
1943
|
+
return {
|
|
1944
|
+
status: convertStreamStatus(query?.status),
|
|
1945
|
+
coinType: normalizeCoinTypeFilter(query?.coinType),
|
|
1946
|
+
recipient: normalizeAddressFilter(query?.recipient)
|
|
1947
|
+
};
|
|
1948
|
+
}
|
|
1949
|
+
function convertStreamStatus(status3) {
|
|
1950
|
+
if (status3 === void 0 || status3.length === 0) {
|
|
1951
|
+
return "all";
|
|
1952
|
+
}
|
|
1953
|
+
if (!Array.isArray(status3)) {
|
|
1954
|
+
return convertStreamStatusSingle(status3);
|
|
1955
|
+
}
|
|
1956
|
+
return status3.reduce((res, st) => {
|
|
1957
|
+
const sts = convertStreamStatus(st);
|
|
1958
|
+
if (!res) {
|
|
1959
|
+
return sts;
|
|
1960
|
+
}
|
|
1961
|
+
if (res === sts) {
|
|
1962
|
+
return sts;
|
|
1963
|
+
}
|
|
1964
|
+
return "all";
|
|
1965
|
+
}, void 0);
|
|
1966
|
+
}
|
|
1967
|
+
function convertStreamStatusSingle(status3) {
|
|
1968
|
+
switch (status3) {
|
|
1969
|
+
case "STREAMING":
|
|
1970
|
+
case "STREAMED":
|
|
1971
|
+
case "CANCELED":
|
|
1972
|
+
return "active";
|
|
1973
|
+
case "COMPLETED":
|
|
1974
|
+
case "SETTLED":
|
|
1975
|
+
return "inactive";
|
|
1976
|
+
default:
|
|
1977
|
+
throw new InvalidInputError("Unknown stream filtered status");
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
function normalizeCoinTypeFilter(coinType) {
|
|
1981
|
+
if (!coinType) {
|
|
1982
|
+
return void 0;
|
|
1983
|
+
}
|
|
1984
|
+
if (!Array.isArray(coinType)) {
|
|
1985
|
+
return normalizeStructTag5(coinType);
|
|
1986
|
+
}
|
|
1987
|
+
return coinType.length !== 0 ? coinType.map((ct) => normalizeStructTag5(ct)) : void 0;
|
|
1988
|
+
}
|
|
1989
|
+
function normalizeAddressFilter(address) {
|
|
1990
|
+
if (!address) {
|
|
1991
|
+
return void 0;
|
|
1992
|
+
}
|
|
1993
|
+
if (!Array.isArray(address)) {
|
|
1994
|
+
return normalizeSuiAddress2(address);
|
|
1995
|
+
}
|
|
1996
|
+
return address.length !== 0 ? address.map((addr) => normalizeSuiAddress2(addr)) : void 0;
|
|
1997
|
+
}
|
|
1998
|
+
|
|
1999
|
+
// src/apps/mpay/stream/client.ts
|
|
2000
|
+
var MSafeAccountAdapter = class {
|
|
2001
|
+
constructor(msafe) {
|
|
2002
|
+
this.msafe = msafe;
|
|
2003
|
+
}
|
|
2004
|
+
get type() {
|
|
2005
|
+
return "msafe" /* msafe */;
|
|
2006
|
+
}
|
|
2007
|
+
async address() {
|
|
2008
|
+
return this.msafe.address();
|
|
2009
|
+
}
|
|
2010
|
+
async requestCoins(reqs) {
|
|
2011
|
+
return this.msafe.requestCoins(reqs);
|
|
2012
|
+
}
|
|
2013
|
+
};
|
|
2014
|
+
var MPayClient = class {
|
|
2015
|
+
globals;
|
|
2016
|
+
helper;
|
|
2017
|
+
constructor(env, options) {
|
|
2018
|
+
this.globals = Globals.new(env, options);
|
|
2019
|
+
this.helper = new MPayHelper(this.globals);
|
|
2020
|
+
}
|
|
2021
|
+
connectMSafeAccount(msafe) {
|
|
2022
|
+
const adapter = new MSafeAccountAdapter(msafe);
|
|
2023
|
+
this.globals.connectWallet(adapter);
|
|
2024
|
+
}
|
|
2025
|
+
async createStream(info) {
|
|
2026
|
+
return this.builder().createStreams(info);
|
|
2027
|
+
}
|
|
2028
|
+
async getStream(streamId) {
|
|
2029
|
+
return Stream.new(this.globals, streamId);
|
|
2030
|
+
}
|
|
2031
|
+
async getIncomingStreams(query, pageSize = 10) {
|
|
2032
|
+
return PagedStreamListIterator.newIncoming({
|
|
2033
|
+
globals: this.globals,
|
|
2034
|
+
query,
|
|
2035
|
+
pageSize
|
|
2036
|
+
});
|
|
2037
|
+
}
|
|
2038
|
+
async getOutgoingStreams(query, pageSize = 10) {
|
|
2039
|
+
return PagedStreamListIterator.newOutgoing({
|
|
2040
|
+
globals: this.globals,
|
|
2041
|
+
query,
|
|
2042
|
+
pageSize
|
|
2043
|
+
});
|
|
2044
|
+
}
|
|
2045
|
+
async getCoinTypesForStreamFilter() {
|
|
2046
|
+
const address = await this.wallet.address();
|
|
2047
|
+
const coinTypes = await this.globals.backend.getAllCoinTypes(address);
|
|
2048
|
+
return coinTypes.map((coinType) => normalizeStructTag6(coinType));
|
|
2049
|
+
}
|
|
2050
|
+
async getRecipientsForStreamFilter(options) {
|
|
2051
|
+
const address = await this.wallet.address();
|
|
2052
|
+
const recipients = await this.globals.backend.getAllRecipients(address, options);
|
|
2053
|
+
return recipients.map((recipient) => normalizeSuiAddress3(recipient));
|
|
2054
|
+
}
|
|
2055
|
+
async getCreatorsForStreamFilter(options) {
|
|
2056
|
+
const address = await this.wallet.address();
|
|
2057
|
+
const creators = await this.globals.backend.getAllSenders(address, options);
|
|
2058
|
+
return creators.map((creator) => normalizeSuiAddress3(creator));
|
|
2059
|
+
}
|
|
2060
|
+
get wallet() {
|
|
2061
|
+
return this.globals.wallet;
|
|
2062
|
+
}
|
|
2063
|
+
builder() {
|
|
2064
|
+
return new MPayBuilder(this.globals);
|
|
2065
|
+
}
|
|
2066
|
+
};
|
|
2067
|
+
|
|
2068
|
+
// src/apps/mpay/create-stream.ts
|
|
2069
|
+
var CreateStreamIntention = class _CreateStreamIntention extends CoreBaseIntention {
|
|
2070
|
+
constructor(data) {
|
|
2071
|
+
super(data);
|
|
2072
|
+
this.data = data;
|
|
2073
|
+
}
|
|
2074
|
+
txType;
|
|
2075
|
+
txSubType;
|
|
2076
|
+
async build(input) {
|
|
2077
|
+
const { network } = input;
|
|
2078
|
+
const mpayClient = new MPayClient(network === "sui:mainnet" ? "prod" /* prod */ : "dev" /* dev */);
|
|
2079
|
+
const txb = await mpayClient.createStream(this.data);
|
|
2080
|
+
return txb;
|
|
2081
|
+
}
|
|
2082
|
+
static fromData(data) {
|
|
2083
|
+
return new _CreateStreamIntention(data);
|
|
2084
|
+
}
|
|
2085
|
+
};
|
|
2086
|
+
|
|
2087
|
+
// src/apps/mpay/decoder/create.ts
|
|
2088
|
+
import { normalizeStructTag as normalizeStructTag8, SUI_TYPE_ARG as SUI_TYPE_ARG3 } from "@mysten/sui.js/utils";
|
|
2089
|
+
|
|
2090
|
+
// src/apps/mpay/decoder/moveCall.ts
|
|
2091
|
+
import { bcs as bcs2 } from "@mysten/sui.js/bcs";
|
|
2092
|
+
import { normalizeStructTag as normalizeStructTag7, normalizeSuiAddress as normalizeSuiAddress4 } from "@mysten/sui.js/utils";
|
|
2093
|
+
var MoveCallHelper = class _MoveCallHelper {
|
|
2094
|
+
constructor(moveCall, txb) {
|
|
2095
|
+
this.moveCall = moveCall;
|
|
2096
|
+
this.txb = txb;
|
|
2097
|
+
}
|
|
2098
|
+
decodeSharedObjectId(argIndex) {
|
|
2099
|
+
const input = this.getInputParam(argIndex);
|
|
2100
|
+
return _MoveCallHelper.getSharedObjectId(input);
|
|
2101
|
+
}
|
|
2102
|
+
decodeOwnedObjectId(argIndex) {
|
|
2103
|
+
const input = this.getInputParam(argIndex);
|
|
2104
|
+
return _MoveCallHelper.getOwnedObjectId(input);
|
|
2105
|
+
}
|
|
2106
|
+
decodeInputU64(argIndex) {
|
|
2107
|
+
const strVal = this.decodePureArg(argIndex, "u64");
|
|
2108
|
+
return BigInt(strVal);
|
|
2109
|
+
}
|
|
2110
|
+
decodeInputAddress(argIndex) {
|
|
2111
|
+
const input = this.decodePureArg(argIndex, "address");
|
|
2112
|
+
return normalizeSuiAddress4(input);
|
|
2113
|
+
}
|
|
2114
|
+
decodeInputString(argIndex) {
|
|
2115
|
+
return this.decodePureArg(argIndex, "string");
|
|
2116
|
+
}
|
|
2117
|
+
decodeInputBool(argIndex) {
|
|
2118
|
+
return this.decodePureArg(argIndex, "bool");
|
|
2119
|
+
}
|
|
2120
|
+
decodePureArg(argIndex, bcsType) {
|
|
2121
|
+
const input = this.getInputParam(argIndex);
|
|
2122
|
+
return _MoveCallHelper.getPureInputValue(input, bcsType);
|
|
2123
|
+
}
|
|
2124
|
+
getInputParam(argIndex) {
|
|
2125
|
+
const arg = this.moveCall.arguments[argIndex];
|
|
2126
|
+
if (arg.kind !== "Input") {
|
|
2127
|
+
throw new Error("not input type");
|
|
2128
|
+
}
|
|
2129
|
+
return this.txb.blockData.inputs[arg.index];
|
|
2130
|
+
}
|
|
2131
|
+
static getPureInputValue(input, bcsType) {
|
|
2132
|
+
if (input.type !== "pure") {
|
|
2133
|
+
throw new Error("not pure argument");
|
|
2134
|
+
}
|
|
2135
|
+
if (typeof input.value === "object" && "Pure" in input.value) {
|
|
2136
|
+
const bcsNums = input.value.Pure;
|
|
2137
|
+
return bcs2.de(bcsType, new Uint8Array(bcsNums));
|
|
2138
|
+
}
|
|
2139
|
+
return input.value;
|
|
2140
|
+
}
|
|
2141
|
+
static getOwnedObjectId(input) {
|
|
2142
|
+
if (input.type !== "object") {
|
|
2143
|
+
throw new Error(`not object argument: ${JSON.stringify(input)}`);
|
|
2144
|
+
}
|
|
2145
|
+
if (typeof input.value === "object") {
|
|
2146
|
+
if (!("Object" in input.value) || !("ImmOrOwned" in input.value.Object)) {
|
|
2147
|
+
throw new Error("not ImmOrOwned");
|
|
2148
|
+
}
|
|
2149
|
+
return normalizeSuiAddress4(input.value.Object.ImmOrOwned.objectId);
|
|
2150
|
+
}
|
|
2151
|
+
return normalizeSuiAddress4(input.value);
|
|
2152
|
+
}
|
|
2153
|
+
static getSharedObjectId(input) {
|
|
2154
|
+
if (input.type !== "object") {
|
|
2155
|
+
throw new Error(`not object argument: ${JSON.stringify(input)}`);
|
|
2156
|
+
}
|
|
2157
|
+
if (typeof input.value !== "object") {
|
|
2158
|
+
return normalizeSuiAddress4(input.value);
|
|
2159
|
+
}
|
|
2160
|
+
if (!("Object" in input.value) || !("Shared" in input.value.Object)) {
|
|
2161
|
+
throw new Error("not Shared");
|
|
2162
|
+
}
|
|
2163
|
+
return normalizeSuiAddress4(input.value.Object.Shared.objectId);
|
|
2164
|
+
}
|
|
2165
|
+
static getPureInput(input, bcsType) {
|
|
2166
|
+
if (input.type !== "pure") {
|
|
2167
|
+
throw new Error("not pure argument");
|
|
2168
|
+
}
|
|
2169
|
+
if (typeof input.value !== "object") {
|
|
2170
|
+
return input.value;
|
|
2171
|
+
}
|
|
2172
|
+
if (!("Pure" in input.value)) {
|
|
2173
|
+
throw new Error("Pure not in value");
|
|
2174
|
+
}
|
|
2175
|
+
const bcsVal = input.value.Pure;
|
|
2176
|
+
return bcs2.de(bcsType, new Uint8Array(bcsVal));
|
|
2177
|
+
}
|
|
2178
|
+
typeArg(index) {
|
|
2179
|
+
return normalizeStructTag7(this.moveCall.typeArguments[index]);
|
|
2180
|
+
}
|
|
2181
|
+
txArg(index) {
|
|
2182
|
+
return this.moveCall.arguments[index];
|
|
2183
|
+
}
|
|
2184
|
+
};
|
|
2185
|
+
|
|
2186
|
+
// src/apps/mpay/decoder/create.ts
|
|
2187
|
+
var CreateStreamDecodeHelper = class {
|
|
2188
|
+
constructor(globals, txb) {
|
|
2189
|
+
this.globals = globals;
|
|
2190
|
+
this.txb = txb;
|
|
2191
|
+
}
|
|
2192
|
+
decode() {
|
|
2193
|
+
const streamInfo = this.decodeCreateStreamInfo();
|
|
2194
|
+
const fees = this.createStreamHelper().calculateCreateStreamFees(streamInfo);
|
|
2195
|
+
const coinMerges = this.getCoinMerges();
|
|
2196
|
+
return {
|
|
2197
|
+
type: "CreateStream" /* CREATE_STREAM */,
|
|
2198
|
+
info: streamInfo,
|
|
2199
|
+
fees,
|
|
2200
|
+
coinMerges
|
|
2201
|
+
};
|
|
2202
|
+
}
|
|
2203
|
+
decodeCreateStreamInfo() {
|
|
2204
|
+
const moveCalls = this.createStreamTransactions();
|
|
2205
|
+
const infos = moveCalls.map((moveCall) => this.getCreationInfoFromMoveCall(moveCall));
|
|
2206
|
+
return this.aggregateGroupStreamInfo(infos);
|
|
2207
|
+
}
|
|
2208
|
+
createStreamTransactions() {
|
|
2209
|
+
const txs = this.transactions.filter(
|
|
2210
|
+
(tx) => tx.kind === "MoveCall" && isSameTarget(tx.target, this.contract.createStreamTarget)
|
|
2211
|
+
);
|
|
2212
|
+
if (txs.length === 0) {
|
|
2213
|
+
throw new SanityError("No create stream transactions");
|
|
2214
|
+
}
|
|
2215
|
+
return txs.map((tx) => new MoveCallHelper(tx, this.txb));
|
|
2216
|
+
}
|
|
2217
|
+
getCreationInfoFromMoveCall(moveCall) {
|
|
2218
|
+
const metadata = moveCall.decodeInputString(4);
|
|
2219
|
+
const { name, groupId } = decodeMetadata(metadata);
|
|
2220
|
+
const recipient = moveCall.decodeInputAddress(5);
|
|
2221
|
+
const timeStart = moveCall.decodeInputU64(6);
|
|
2222
|
+
const cliff = moveCall.decodeInputU64(7);
|
|
2223
|
+
const epochInterval = moveCall.decodeInputU64(8);
|
|
2224
|
+
const totalEpoch = moveCall.decodeInputU64(9);
|
|
2225
|
+
const amountPerEpoch = moveCall.decodeInputU64(10);
|
|
2226
|
+
const cancelable = moveCall.decodeInputBool(11);
|
|
2227
|
+
const coinType = moveCall.typeArg(0);
|
|
2228
|
+
return {
|
|
2229
|
+
name,
|
|
2230
|
+
groupId,
|
|
2231
|
+
recipient,
|
|
2232
|
+
timeStart,
|
|
2233
|
+
cliff,
|
|
2234
|
+
epochInterval,
|
|
2235
|
+
totalEpoch,
|
|
2236
|
+
amountPerEpoch,
|
|
2237
|
+
cancelable,
|
|
2238
|
+
coinType
|
|
2239
|
+
};
|
|
2240
|
+
}
|
|
2241
|
+
aggregateGroupStreamInfo(infos) {
|
|
2242
|
+
const commonInfoSet = new Set(
|
|
2243
|
+
infos.map(
|
|
2244
|
+
(info) => JSON.stringify({
|
|
2245
|
+
name: info.name,
|
|
2246
|
+
groupId: info.groupId,
|
|
2247
|
+
timeStart: String(info.timeStart),
|
|
2248
|
+
epochInterval: String(info.epochInterval),
|
|
2249
|
+
totalEpoch: String(info.totalEpoch),
|
|
2250
|
+
cancelable: info.cancelable,
|
|
2251
|
+
coinType: info.coinType
|
|
2252
|
+
})
|
|
2253
|
+
)
|
|
2254
|
+
);
|
|
2255
|
+
if (commonInfoSet.size !== 1) {
|
|
2256
|
+
throw new InvalidInputError("Stream group not have common info");
|
|
2257
|
+
}
|
|
2258
|
+
const recipients = infos.map((info) => ({
|
|
2259
|
+
address: info.recipient,
|
|
2260
|
+
amountPerStep: info.amountPerEpoch,
|
|
2261
|
+
cliffAmount: info.cliff
|
|
2262
|
+
}));
|
|
2263
|
+
return {
|
|
2264
|
+
name: infos[0].name,
|
|
2265
|
+
coinType: infos[0].coinType,
|
|
2266
|
+
recipients,
|
|
2267
|
+
interval: infos[0].epochInterval,
|
|
2268
|
+
steps: infos[0].totalEpoch,
|
|
2269
|
+
startTimeMs: infos[0].timeStart,
|
|
2270
|
+
cancelable: infos[0].cancelable
|
|
2271
|
+
};
|
|
2272
|
+
}
|
|
2273
|
+
getCoinMerges() {
|
|
2274
|
+
const createStreamTx = this.createStreamTransactions()[0];
|
|
2275
|
+
return this.getCoinMergeForCreateStream(createStreamTx);
|
|
2276
|
+
}
|
|
2277
|
+
getCoinMergeForCreateStream(moveCall) {
|
|
2278
|
+
const coinType = moveCall.typeArg(0);
|
|
2279
|
+
const paymentCoin = moveCall.txArg(2);
|
|
2280
|
+
const paymentCoinMerge = this.getCoinMergeFromNestedResult(paymentCoin, coinType, moveCall);
|
|
2281
|
+
if (coinType === normalizeStructTag8(SUI_TYPE_ARG3)) {
|
|
2282
|
+
return [paymentCoinMerge];
|
|
2283
|
+
}
|
|
2284
|
+
const flatFeeCoin = moveCall.txArg(3);
|
|
2285
|
+
const flatCoinMerge = this.getCoinMergeFromNestedResult(flatFeeCoin, normalizeStructTag8(SUI_TYPE_ARG3), moveCall);
|
|
2286
|
+
return [paymentCoinMerge, flatCoinMerge];
|
|
2287
|
+
}
|
|
2288
|
+
getCoinMergeFromNestedResult(coinArg, coinType, moveCall) {
|
|
2289
|
+
if (coinArg.kind === "GasCoin") {
|
|
2290
|
+
return {
|
|
2291
|
+
primary: "GAS",
|
|
2292
|
+
coinType
|
|
2293
|
+
};
|
|
2294
|
+
}
|
|
2295
|
+
if (coinArg.kind === "Input") {
|
|
2296
|
+
const arg = this.getInputArg(coinArg);
|
|
2297
|
+
const objectId = MoveCallHelper.getOwnedObjectId(arg);
|
|
2298
|
+
const mergeTx = this.transactions.find((tx) => {
|
|
2299
|
+
if (tx.kind !== "MergeCoins") {
|
|
2300
|
+
return false;
|
|
2301
|
+
}
|
|
2302
|
+
if (tx.destination.kind !== "Input") {
|
|
2303
|
+
throw new Error("merge coin destination not Input type");
|
|
2304
|
+
}
|
|
2305
|
+
const primaryCoinInput = this.getInputArg(tx.destination);
|
|
2306
|
+
return MoveCallHelper.getOwnedObjectId(primaryCoinInput) === objectId;
|
|
2307
|
+
});
|
|
2308
|
+
if (!mergeTx) {
|
|
2309
|
+
return {
|
|
2310
|
+
primary: objectId,
|
|
2311
|
+
coinType
|
|
2312
|
+
};
|
|
2313
|
+
}
|
|
2314
|
+
return {
|
|
2315
|
+
primary: objectId,
|
|
2316
|
+
merged: mergeTx.sources.map((sourceArg) => {
|
|
2317
|
+
const sourceInputArg = this.getInputArg(sourceArg);
|
|
2318
|
+
return MoveCallHelper.getOwnedObjectId(sourceInputArg);
|
|
2319
|
+
}),
|
|
2320
|
+
coinType
|
|
2321
|
+
};
|
|
2322
|
+
}
|
|
2323
|
+
if (coinArg.kind === "NestedResult") {
|
|
2324
|
+
const parentTx = this.transactions[coinArg.index];
|
|
2325
|
+
if (parentTx.kind !== "SplitCoins") {
|
|
2326
|
+
throw new InvalidInputError(`Transaction type not expected. Expect SplitCoins, got ${parentTx.kind}`);
|
|
2327
|
+
}
|
|
2328
|
+
return this.getCoinMergeFromNestedResult(parentTx.coin, coinType, moveCall);
|
|
2329
|
+
}
|
|
2330
|
+
if (coinArg.kind === "Result") {
|
|
2331
|
+
throw new Error("Result type not expected for coin inputs");
|
|
2332
|
+
}
|
|
2333
|
+
throw new Error(`Unknown argument kind`);
|
|
2334
|
+
}
|
|
2335
|
+
mergeCoinTransactions() {
|
|
2336
|
+
return this.transactions.filter((tx) => tx.kind === "MergeCoins");
|
|
2337
|
+
}
|
|
2338
|
+
get transactions() {
|
|
2339
|
+
return this.txb.blockData.transactions;
|
|
2340
|
+
}
|
|
2341
|
+
get contract() {
|
|
2342
|
+
return new StreamContract(this.globals.envConfig.contract, this.globals);
|
|
2343
|
+
}
|
|
2344
|
+
get feeContract() {
|
|
2345
|
+
return new FeeContract(this.globals.envConfig.contract, this.globals);
|
|
2346
|
+
}
|
|
2347
|
+
createStreamHelper() {
|
|
2348
|
+
return new CreateStreamHelper(this.globals, this.feeContract, this.contract);
|
|
2349
|
+
}
|
|
2350
|
+
getInputArg(arg) {
|
|
2351
|
+
if (arg.kind !== "Input") {
|
|
2352
|
+
throw new Error("not input type");
|
|
2353
|
+
}
|
|
2354
|
+
return "value" in arg ? arg : this.txb.blockData.inputs[arg.index];
|
|
2355
|
+
}
|
|
2356
|
+
};
|
|
2357
|
+
|
|
2358
|
+
// src/apps/mpay/decoder/decoder.ts
|
|
2359
|
+
var DecodeHelper = class {
|
|
2360
|
+
constructor(globals, txb) {
|
|
2361
|
+
this.globals = globals;
|
|
2362
|
+
this.txb = txb;
|
|
2363
|
+
this.contract = new StreamContract(globals.envConfig.contract, globals);
|
|
2364
|
+
}
|
|
2365
|
+
contract;
|
|
2366
|
+
decode() {
|
|
2367
|
+
if (this.isCreateStreamTransaction()) {
|
|
2368
|
+
return this.decodeCreateStreamTransaction();
|
|
2369
|
+
}
|
|
2370
|
+
if (this.isClaimByProxyTransaction()) {
|
|
2371
|
+
return this.decodeClaimByProxyTransaction();
|
|
2372
|
+
}
|
|
2373
|
+
if (this.isSetAutoClaimTransaction()) {
|
|
2374
|
+
return this.decodeSetAutoClaimTransaction();
|
|
2375
|
+
}
|
|
2376
|
+
if (this.isCancelStreamTransaction()) {
|
|
2377
|
+
return this.decodeCancelStreamTransaction();
|
|
2378
|
+
}
|
|
2379
|
+
if (this.isClaimStreamTransaction()) {
|
|
2380
|
+
return this.decodeClaimTransaction();
|
|
2381
|
+
}
|
|
2382
|
+
return void 0;
|
|
2383
|
+
}
|
|
2384
|
+
get transactions() {
|
|
2385
|
+
return this.txb.blockData.transactions;
|
|
2386
|
+
}
|
|
2387
|
+
isCreateStreamTransaction() {
|
|
2388
|
+
const createStreamIndex = this.transactions.findIndex(
|
|
2389
|
+
(tx) => tx.kind === "MoveCall" && isSameTarget(tx.target, this.contract.createStreamTarget)
|
|
2390
|
+
);
|
|
2391
|
+
return createStreamIndex !== -1;
|
|
2392
|
+
}
|
|
2393
|
+
isSetAutoClaimTransaction() {
|
|
2394
|
+
return this.transactions.length === 1 && this.transactions[0].kind === "MoveCall" && isSameTarget(this.transactions[0].target, this.contract.setAutoClaimTarget);
|
|
2395
|
+
}
|
|
2396
|
+
isCancelStreamTransaction() {
|
|
2397
|
+
return this.transactions.length === 1 && this.transactions[0].kind === "MoveCall" && isSameTarget(this.transactions[0].target, this.contract.cancelStreamTarget);
|
|
2398
|
+
}
|
|
2399
|
+
isClaimStreamTransaction() {
|
|
2400
|
+
return this.transactions.length === 1 && this.transactions[0].kind === "MoveCall" && isSameTarget(this.transactions[0].target, this.contract.claimStreamTarget);
|
|
2401
|
+
}
|
|
2402
|
+
isClaimByProxyTransaction() {
|
|
2403
|
+
return this.transactions.length === 1 && this.transactions[0].kind === "MoveCall" && isSameTarget(this.transactions[0].target, this.contract.claimStreamByProxyTarget);
|
|
2404
|
+
}
|
|
2405
|
+
decodeCreateStreamTransaction() {
|
|
2406
|
+
const helper = new CreateStreamDecodeHelper(this.globals, this.txb);
|
|
2407
|
+
return helper.decode();
|
|
2408
|
+
}
|
|
2409
|
+
decodeSetAutoClaimTransaction() {
|
|
2410
|
+
const streamId = this.helper.decodeSharedObjectId(0);
|
|
2411
|
+
const enabled = this.helper.decodeInputBool(1);
|
|
2412
|
+
return {
|
|
2413
|
+
type: "SetAutoClaim" /* SET_AUTO_CLAIM */,
|
|
2414
|
+
streamId,
|
|
2415
|
+
enabled
|
|
2416
|
+
};
|
|
2417
|
+
}
|
|
2418
|
+
decodeClaimTransaction() {
|
|
2419
|
+
const streamId = this.helper.decodeSharedObjectId(0);
|
|
2420
|
+
return {
|
|
2421
|
+
type: "Claim" /* CLAIM */,
|
|
2422
|
+
streamId
|
|
2423
|
+
};
|
|
2424
|
+
}
|
|
2425
|
+
decodeClaimByProxyTransaction() {
|
|
2426
|
+
const streamId = this.helper.decodeSharedObjectId(0);
|
|
2427
|
+
return {
|
|
2428
|
+
type: "ClaimByProxy" /* CLAIM_BY_PROXY */,
|
|
2429
|
+
streamId
|
|
2430
|
+
};
|
|
2431
|
+
}
|
|
2432
|
+
decodeCancelStreamTransaction() {
|
|
2433
|
+
const streamId = this.helper.decodeSharedObjectId(0);
|
|
2434
|
+
return {
|
|
2435
|
+
type: "Cancel" /* CANCEL */,
|
|
2436
|
+
streamId
|
|
2437
|
+
};
|
|
2438
|
+
}
|
|
2439
|
+
get helper() {
|
|
2440
|
+
const moveCall = this.transactions[0];
|
|
2441
|
+
return new MoveCallHelper(moveCall, this.txb);
|
|
2442
|
+
}
|
|
2443
|
+
};
|
|
2444
|
+
|
|
2445
|
+
// src/apps/mpay/helper.ts
|
|
2446
|
+
var MPayAppHelper = class {
|
|
2447
|
+
application = "mpay";
|
|
2448
|
+
async deserialize(input) {
|
|
2449
|
+
const { chain, transactionBlock } = input;
|
|
2450
|
+
const globals = Globals.new(chain === "sui:mainnet" ? "prod" /* prod */ : "dev" /* dev */);
|
|
2451
|
+
const decoder = new DecodeHelper(globals, transactionBlock);
|
|
2452
|
+
const result = decoder.decode();
|
|
2453
|
+
console.log("\u{1F680} ~ MPayHelper ~ deserialize ~ input:", input, result);
|
|
2454
|
+
if (result.type === "CreateStream" /* CREATE_STREAM */) {
|
|
2455
|
+
return {
|
|
2456
|
+
txType: TransactionType.Other,
|
|
2457
|
+
txSubType: StreamEventType.Create,
|
|
2458
|
+
intentionData: result.info
|
|
2459
|
+
};
|
|
2460
|
+
}
|
|
2461
|
+
throw new Error(`Unknown transaction type: ${result.type}`);
|
|
2462
|
+
}
|
|
2463
|
+
async build(input) {
|
|
2464
|
+
const { network, intentionData, suiClient, account } = input;
|
|
2465
|
+
let intention;
|
|
2466
|
+
switch (input.txSubType) {
|
|
2467
|
+
case StreamEventType.Create:
|
|
2468
|
+
intention = CreateStreamIntention.fromData(intentionData);
|
|
2469
|
+
break;
|
|
2470
|
+
default:
|
|
2471
|
+
throw new Error("not implemented");
|
|
2472
|
+
}
|
|
2473
|
+
return intention.build({ network, suiClient, account });
|
|
2474
|
+
}
|
|
2475
|
+
};
|
|
2476
|
+
|
|
2477
|
+
// src/apps/msafe-core/helper.ts
|
|
2478
|
+
import { TransactionDefaultApplication, TransactionSubTypes } from "@msafe/sui3-utils";
|
|
2479
|
+
|
|
21
2480
|
// src/apps/msafe-core/coin-transfer.ts
|
|
2481
|
+
import { buildCoinTransferTxb } from "@msafe/sui3-utils";
|
|
22
2482
|
var CoinTransferIntention = class _CoinTransferIntention extends CoreBaseIntention {
|
|
23
2483
|
constructor(data) {
|
|
24
2484
|
super(data);
|
|
@@ -55,7 +2515,7 @@ var ObjectTransferIntention = class _ObjectTransferIntention extends CoreBaseInt
|
|
|
55
2515
|
|
|
56
2516
|
// src/apps/msafe-core/plain-payload.ts
|
|
57
2517
|
import { isSameAddress } from "@msafe/sui3-utils";
|
|
58
|
-
import { TransactionBlock } from "@mysten/sui.js/transactions";
|
|
2518
|
+
import { TransactionBlock as TransactionBlock5 } from "@mysten/sui.js/transactions";
|
|
59
2519
|
var PlainPayloadIntention = class _PlainPayloadIntention extends CoreBaseIntention {
|
|
60
2520
|
constructor(data) {
|
|
61
2521
|
super(data);
|
|
@@ -65,7 +2525,7 @@ var PlainPayloadIntention = class _PlainPayloadIntention extends CoreBaseIntenti
|
|
|
65
2525
|
txSubType;
|
|
66
2526
|
async build(input) {
|
|
67
2527
|
const { account } = input;
|
|
68
|
-
const tb =
|
|
2528
|
+
const tb = TransactionBlock5.from(this.data.content);
|
|
69
2529
|
if (!isSameAddress(tb.blockData.sender, account.address)) {
|
|
70
2530
|
throw new Error("Invalid sender address");
|
|
71
2531
|
}
|
|
@@ -118,16 +2578,10 @@ var MSafeApps = class {
|
|
|
118
2578
|
}
|
|
119
2579
|
return app;
|
|
120
2580
|
}
|
|
121
|
-
deserialize(appName, input) {
|
|
122
|
-
return this.getAppHelper(appName).deserialize(input);
|
|
123
|
-
}
|
|
124
|
-
build(appName, input) {
|
|
125
|
-
return this.getAppHelper(appName).build(input);
|
|
126
|
-
}
|
|
127
2581
|
};
|
|
128
2582
|
|
|
129
2583
|
// src/index.ts
|
|
130
|
-
var appHelpers = new MSafeApps([new CoreHelper()]);
|
|
2584
|
+
var appHelpers = new MSafeApps([new CoreHelper(), new MPayAppHelper()]);
|
|
131
2585
|
export {
|
|
132
2586
|
appHelpers
|
|
133
2587
|
};
|