@typemove/move 2.0.0 → 2.0.1-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/esm/abstract-move-coder.d.ts +30 -0
  2. package/dist/esm/abstract-move-coder.d.ts.map +1 -0
  3. package/dist/esm/abstract-move-coder.js +308 -0
  4. package/dist/esm/abstract-move-coder.js.map +1 -0
  5. package/dist/esm/account.d.ts +16 -0
  6. package/dist/esm/account.d.ts.map +1 -0
  7. package/dist/esm/account.js +71 -0
  8. package/dist/esm/account.js.map +1 -0
  9. package/dist/esm/chain-adapter.d.ts +13 -0
  10. package/dist/esm/chain-adapter.d.ts.map +1 -0
  11. package/dist/esm/chain-adapter.js +3 -0
  12. package/dist/esm/chain-adapter.js.map +1 -0
  13. package/dist/esm/codegen/abstract-codegen.d.ts +50 -0
  14. package/dist/esm/codegen/abstract-codegen.d.ts.map +1 -0
  15. package/dist/esm/codegen/abstract-codegen.js +463 -0
  16. package/dist/esm/codegen/abstract-codegen.js.map +1 -0
  17. package/dist/esm/codegen/index.d.ts +2 -0
  18. package/dist/esm/codegen/index.d.ts.map +1 -0
  19. package/dist/esm/codegen/index.js +2 -0
  20. package/dist/esm/codegen/index.js.map +1 -0
  21. package/dist/esm/index.d.ts +7 -0
  22. package/dist/esm/index.d.ts.map +1 -0
  23. package/dist/esm/index.js +7 -0
  24. package/dist/esm/index.js.map +1 -0
  25. package/dist/esm/internal-models.d.ts +46 -0
  26. package/dist/esm/internal-models.d.ts.map +1 -0
  27. package/dist/esm/internal-models.js +7 -0
  28. package/dist/esm/internal-models.js.map +1 -0
  29. package/dist/esm/types.d.ts +52 -0
  30. package/dist/esm/types.d.ts.map +1 -0
  31. package/dist/esm/types.js +317 -0
  32. package/dist/esm/types.js.map +1 -0
  33. package/dist/esm/utils.d.ts +17 -0
  34. package/dist/esm/utils.d.ts.map +1 -0
  35. package/dist/esm/utils.js +127 -0
  36. package/dist/esm/utils.js.map +1 -0
  37. package/package.json +5 -5
  38. package/src/abstract-move-coder.ts +347 -0
  39. package/src/account.ts +81 -0
  40. package/src/chain-adapter.ts +26 -0
  41. package/src/codegen/abstract-codegen.ts +574 -0
  42. package/src/codegen/index.ts +1 -0
  43. package/src/index.ts +6 -0
  44. package/src/internal-models.ts +52 -0
  45. package/src/types.ts +362 -0
  46. package/src/utils.ts +144 -0
@@ -0,0 +1,347 @@
1
+ import { accountTypeString, moduleQname, SPLITTER, VECTOR_STR } from './utils.js'
2
+ import { DecodedStruct, matchType, parseMoveType, TypeDescriptor } from './types.js'
3
+ import { InternalMoveEnum, InternalMoveFunction, InternalMoveModule, InternalMoveStruct } from './internal-models.js'
4
+ // import { bytesToBigInt } from '../utils/index.js'
5
+ import { ChainAdapter } from './chain-adapter.js'
6
+
7
+ export abstract class AbstractMoveCoder<ModuleType, StructType> {
8
+ protected moduleMapping = new Map<string, InternalMoveModule>()
9
+ protected accounts = new Set<string>()
10
+ private typeMapping = new Map<string, InternalMoveStruct>()
11
+ private enumMapping = new Map<string, InternalMoveEnum>()
12
+
13
+ private funcMapping = new Map<string, InternalMoveFunction>()
14
+ // network: string
15
+ adapter: ChainAdapter<ModuleType, StructType>
16
+
17
+ protected constructor(adapter: ChainAdapter<ModuleType, StructType>) {
18
+ this.adapter = adapter
19
+ }
20
+
21
+ contains(account: string, name: string) {
22
+ return this.moduleMapping.has(moduleQname({ address: account, name }))
23
+ }
24
+
25
+ abstract load(module: ModuleType, address: string): InternalMoveModule
26
+
27
+ protected loadInternal(module: InternalMoveModule, address: string) {
28
+ const account = module.address
29
+ const declareAccount = accountTypeString(address)
30
+
31
+ this._loadInternal(module, account)
32
+ if (account !== declareAccount) {
33
+ this._loadInternal(module, declareAccount)
34
+ }
35
+ }
36
+
37
+ private _loadInternal(module: InternalMoveModule, account: string) {
38
+ if (this.contains(account, module.name)) {
39
+ return
40
+ }
41
+ this.moduleMapping.set(moduleQname({ address: account, name: module.name }), module)
42
+ for (const enumType of module.enums) {
43
+ const key = [account, module.name, enumType.name].join(SPLITTER)
44
+ this.enumMapping.set(key, enumType)
45
+ }
46
+
47
+ for (const struct of module.structs) {
48
+ // TODO move to util
49
+ const key = [account, module.name, struct.name].join(SPLITTER)
50
+ this.typeMapping.set(key, struct)
51
+ }
52
+
53
+ for (const func of module.exposedFunctions) {
54
+ // if (!func.isEntry) {
55
+ // continue
56
+ // }
57
+ const key = [account, module.name, func.name].join(SPLITTER)
58
+ this.funcMapping.set(key, func)
59
+ }
60
+ }
61
+
62
+ protected decodeBigInt(data: any): bigint {
63
+ if (Array.isArray(data)) {
64
+ throw new Error('data is in byte array')
65
+ // Only sui function need this, strange
66
+ // const bytes = data as number[]
67
+ // return bytesToBigInt(new Uint8Array(bytes.slice().reverse()))
68
+ }
69
+
70
+ return BigInt(data)
71
+ }
72
+
73
+ private requestMap = new Map<string, Promise<void>>()
74
+
75
+ async getMoveStruct(type: string): Promise<InternalMoveStruct> {
76
+ const [account_, module, typeName] = type.split(SPLITTER)
77
+ const account = accountTypeString(account_)
78
+ type = [account, module, typeName].join(SPLITTER)
79
+
80
+ let struct = this.typeMapping.get(type)
81
+ if (struct) {
82
+ return struct
83
+ }
84
+ if (this.accounts.has(account)) {
85
+ throw new Error('Failed to load struct ' + type + ' for imported account')
86
+ }
87
+ let resp = this.requestMap.get(account)
88
+ if (!resp) {
89
+ resp = this.adapter.fetchModules(account).then((modules) => {
90
+ for (const m of modules) {
91
+ this.load(m, account)
92
+ }
93
+ })
94
+ this.requestMap.set(account, resp)
95
+ }
96
+ await resp
97
+ struct = this.typeMapping.get(type)
98
+ if (struct) {
99
+ return struct
100
+ }
101
+ throw new Error('Failed to load function ' + type + ' type are not imported anywhere')
102
+ }
103
+
104
+ async maybeGetMoveEnum(type: string): Promise<InternalMoveEnum | undefined> {
105
+ const [account_, module, typeName] = type.split(SPLITTER)
106
+ const account = accountTypeString(account_)
107
+ type = [account, module, typeName].join(SPLITTER)
108
+
109
+ let enumType = this.enumMapping.get(type)
110
+ if (enumType) {
111
+ return enumType
112
+ }
113
+ if (this.accounts.has(account)) {
114
+ return undefined
115
+ }
116
+ let resp = this.requestMap.get(account)
117
+ if (!resp) {
118
+ resp = this.adapter.fetchModules(account).then((modules) => {
119
+ for (const m of modules) {
120
+ this.load(m, account)
121
+ }
122
+ })
123
+ this.requestMap.set(account, resp)
124
+ }
125
+ await resp
126
+ enumType = this.enumMapping.get(type)
127
+ if (enumType) {
128
+ return enumType
129
+ }
130
+ return undefined
131
+ }
132
+
133
+ async getMoveFunction(type: string): Promise<InternalMoveFunction> {
134
+ const [account_, module, typeName] = type.split(SPLITTER)
135
+ const account = accountTypeString(account_)
136
+ type = [account, module, typeName].join(SPLITTER)
137
+
138
+ let func = this.funcMapping.get(type)
139
+ if (func) {
140
+ return func
141
+ }
142
+ if (this.accounts.has(account)) {
143
+ throw new Error('Failed to load function ' + type + ' for imported account')
144
+ }
145
+ let resp = this.requestMap.get(account)
146
+ if (!resp) {
147
+ resp = this.adapter
148
+ .fetchModules(account)
149
+ .then((modules) => {
150
+ for (const m of modules) {
151
+ this.load(m, account)
152
+ }
153
+ })
154
+ .catch((e) => {
155
+ this.requestMap.delete(account)
156
+ })
157
+ this.requestMap.set(account, resp)
158
+ }
159
+ await resp
160
+ func = this.funcMapping.get(type)
161
+ if (func) {
162
+ return func
163
+ }
164
+ throw new Error('Failed to load function ' + type + ' type are not imported anywhere')
165
+ }
166
+
167
+ protected async decode<T>(data: any, type: TypeDescriptor<T>): Promise<T> {
168
+ // process simple type
169
+ if (type.reference) {
170
+ return data
171
+ }
172
+ switch (type.qname) {
173
+ case 'signer': // TODO check this, aptos only
174
+ case 'address':
175
+ case 'Address':
176
+ case '0x1::string::String':
177
+ case 'bool':
178
+ case 'Bool':
179
+ case 'u8':
180
+ case 'U8':
181
+ case 'u16':
182
+ case 'U16':
183
+ case 'u32':
184
+ case 'U32':
185
+ return data
186
+ case 'u64':
187
+ case 'U64':
188
+ case 'u128':
189
+ case 'U128':
190
+ case 'u256':
191
+ case 'U256':
192
+ return this.decodeBigInt(data) as any
193
+ }
194
+
195
+ // process vector
196
+ if (type.qname.toLowerCase() === VECTOR_STR) {
197
+ // vector<u8> as hex string
198
+ if (type.typeArgs[0].qname === 'u8' || type.typeArgs[0].qname === 'U8') {
199
+ return data
200
+ }
201
+
202
+ const res = []
203
+ for (const entry of data) {
204
+ res.push(await this.decode(entry, type.typeArgs[0]))
205
+ }
206
+ return res as any
207
+ }
208
+
209
+ // try enum type first
210
+ const enumType = await this.maybeGetMoveEnum(type.qname)
211
+ if (enumType) {
212
+ return data
213
+ }
214
+
215
+ // Process complex type
216
+ const struct = await this.getMoveStruct(type.qname)
217
+
218
+ const typeCtx = new Map<string, TypeDescriptor>()
219
+ for (const [idx, typeArg] of type.typeArgs.entries()) {
220
+ typeCtx.set('T' + idx, typeArg)
221
+ }
222
+
223
+ const typedData: any = {}
224
+
225
+ for (const field of struct.fields) {
226
+ let filedType = field.type
227
+ filedType = filedType.applyTypeArgs(typeCtx)
228
+ const fieldValue = this.adapter.getData(data)[field.name]
229
+ const value = await this.decode(fieldValue, filedType)
230
+ typedData[field.name] = value
231
+ }
232
+ return typedData
233
+ }
234
+
235
+ async decodeArray(entries: any[], types: TypeDescriptor[], strict = true): Promise<any[]> {
236
+ const entriesDecoded: any[] = []
237
+ for (const [idx, arg] of entries.entries()) {
238
+ // TODO consider apply payload.type_arguments, but this might be hard since we don't code gen for them
239
+ const argType = types[idx]
240
+ try {
241
+ if (!strict && arg === undefined) {
242
+ entriesDecoded.push(arg)
243
+ } else {
244
+ entriesDecoded.push(await this.decode(arg, argType))
245
+ }
246
+ } catch (e) {
247
+ throw Error('Decoding error for ' + JSON.stringify(arg) + 'using type' + argType + String(e))
248
+ }
249
+ }
250
+ return entriesDecoded
251
+ }
252
+
253
+ public encode(data: any): any {
254
+ if (data === undefined || data === null) {
255
+ return undefined
256
+ }
257
+ if (typeof data === 'bigint') {
258
+ return data.toString()
259
+ }
260
+ if (Array.isArray(data)) {
261
+ return this.encodeArray(data)
262
+ }
263
+ for (const [key, value] of Object.entries(data)) {
264
+ if (!value) {
265
+ continue
266
+ }
267
+ if (typeof value === 'bigint') {
268
+ data[key] = value.toString()
269
+ }
270
+ }
271
+ return data
272
+ }
273
+
274
+ encodeArray(entriesDecoded: any[]): any[] {
275
+ const entries: any[] = []
276
+ for (const [idx, arg] of entriesDecoded.entries()) {
277
+ entries.push(this.encode(arg))
278
+ }
279
+ return entries
280
+ }
281
+
282
+ async decodeCallResult(res: any[], func: string): Promise<any[]> {
283
+ const f = await this.getMoveFunction(func)
284
+ return this.decodeArray(res, f.return)
285
+ }
286
+
287
+ async filterAndDecodeStruct<T, ST extends StructType>(
288
+ typeMatcher: TypeDescriptor<T>,
289
+ structsWithTags: ST[]
290
+ ): Promise<DecodedStruct<ST, T>[]> {
291
+ if (!structsWithTags) {
292
+ return [] as any
293
+ }
294
+ // const typeMatcherDescriptor = parseMoveType(typeMatcher)
295
+ const results: DecodedStruct<ST, T>[] = []
296
+ for (const resource of structsWithTags) {
297
+ const resourceType = this.adapter.getType(resource)
298
+ const resourceTypeDescriptor = parseMoveType(resourceType)
299
+ if (!matchType(typeMatcher, resourceTypeDescriptor)) {
300
+ continue
301
+ }
302
+
303
+ const result = await this.decodedStruct<T, ST>(resource)
304
+ if (result) {
305
+ results.push(result)
306
+ } else {
307
+ console.error('decoding error')
308
+ }
309
+ }
310
+ return results
311
+ }
312
+
313
+ protected async decodedStruct<T, ST extends StructType>(typeStruct: ST): Promise<DecodedStruct<ST, T> | undefined> {
314
+ const typeDescriptor = parseMoveType(this.adapter.getType(typeStruct))
315
+ const typeArguments = typeDescriptor.typeArgs.map((t) => t.getSignature())
316
+
317
+ let dataTyped = undefined
318
+ try {
319
+ dataTyped = await this.decode(typeStruct, typeDescriptor)
320
+ } catch (e) {
321
+ throw Error('Decoding error for struct' + JSON.stringify(typeStruct) + String(e))
322
+ // return undefined
323
+ }
324
+ return {
325
+ ...typeStruct,
326
+ data_decoded: dataTyped,
327
+ type_arguments: typeArguments
328
+ }
329
+ }
330
+
331
+ public async decodeType<T, ST>(typeStruct: ST, type: TypeDescriptor<T>): Promise<T | undefined> {
332
+ if (typeStruct === null || typeStruct == undefined) {
333
+ return typeStruct as any
334
+ }
335
+ if (typeof typeStruct === 'object') {
336
+ if ('type' in typeStruct) {
337
+ const typeInStruct = parseMoveType((typeStruct.type as any).toString() || '')
338
+ if (!matchType(type, typeInStruct)) {
339
+ return undefined
340
+ }
341
+ type = typeInStruct
342
+ }
343
+ }
344
+
345
+ return await this.decode(typeStruct, type)
346
+ }
347
+ }
package/src/account.ts ADDED
@@ -0,0 +1,81 @@
1
+ import { moduleQname, moduleQnameForType } from './utils.js'
2
+ import { InternalMoveModule } from './internal-models.js'
3
+
4
+ export class AccountModulesImportInfo {
5
+ // account to module
6
+ imports: Map<string, Set<string>>
7
+ account: string
8
+ moduleName: string
9
+
10
+ constructor(account: string, tsModuleName: string) {
11
+ this.account = account
12
+ this.moduleName = tsModuleName
13
+ this.imports = new Map<string, Set<string>>()
14
+ }
15
+
16
+ addImport(account: string, module: string) {
17
+ if (account === this.account) {
18
+ return
19
+ }
20
+ let accountModules = this.imports.get(account)
21
+ if (!accountModules) {
22
+ accountModules = new Set<string>()
23
+ this.imports.set(account, accountModules)
24
+ }
25
+ accountModules.add(module)
26
+ }
27
+ }
28
+
29
+ export class AccountRegister {
30
+ accountImports = new Map<string, AccountModulesImportInfo>()
31
+ pendingAccounts = new Set<string>()
32
+
33
+ register(module: InternalMoveModule, tsModuleName: string): AccountModulesImportInfo {
34
+ const currentModuleFqn = moduleQname(module)
35
+
36
+ let accountModuleImports = this.accountImports.get(module.address)
37
+ if (!accountModuleImports) {
38
+ accountModuleImports = new AccountModulesImportInfo(module.address, tsModuleName)
39
+ this.accountImports.set(module.address, accountModuleImports)
40
+ // the account has already be processed, delete pending task
41
+ this.pendingAccounts.delete(module.address)
42
+ }
43
+
44
+ this.registerStruct(module, accountModuleImports)
45
+ this.registerFunctions(module, accountModuleImports)
46
+
47
+ this.accountImports.set(currentModuleFqn, accountModuleImports)
48
+ return accountModuleImports
49
+ }
50
+
51
+ private registerFunctions(module: InternalMoveModule, accountModuleImports: AccountModulesImportInfo): void {
52
+ for (const func of module.exposedFunctions) {
53
+ // if (!func.isEntry) {
54
+ // continue
55
+ // }
56
+ for (const param of func.params.concat(func.return)) {
57
+ for (const type of param.dependedTypes()) {
58
+ const [account, module] = moduleQnameForType(type)
59
+ accountModuleImports.addImport(account, module)
60
+ if (!this.accountImports.has(account)) {
61
+ this.pendingAccounts.add(account)
62
+ }
63
+ }
64
+ }
65
+ }
66
+ }
67
+
68
+ private registerStruct(module: InternalMoveModule, accountModuleImports: AccountModulesImportInfo): void {
69
+ for (const struct of module.structs) {
70
+ for (const field of struct.fields) {
71
+ for (const type of field.type.dependedTypes()) {
72
+ const [account, module] = moduleQnameForType(type)
73
+ accountModuleImports.addImport(account, module)
74
+ if (!this.accountImports.has(account)) {
75
+ this.pendingAccounts.add(account)
76
+ }
77
+ }
78
+ }
79
+ }
80
+ }
81
+ }
@@ -0,0 +1,26 @@
1
+ import { InternalMoveModule, InternalMoveStruct } from './internal-models.js'
2
+ import { TypeDescriptor } from './types.js'
3
+
4
+ export abstract class ChainAdapter<ModuleType, StructType> {
5
+ // endpoint: string
6
+ //
7
+ // constructor(endpoint: string) {
8
+ // this.endpoint = endpoint
9
+ // }
10
+ abstract getChainId(): Promise<string>
11
+
12
+ abstract fetchModule(account: string, module: string): Promise<ModuleType>
13
+
14
+ abstract fetchModules(account: string): Promise<ModuleType[]>
15
+ abstract toInternalModules(modules: ModuleType[]): InternalMoveModule[]
16
+
17
+ // Get all structs that represent Events
18
+ abstract getAllEventStructs(module: InternalMoveModule[]): Map<string, InternalMoveStruct>
19
+
20
+ // Get the parameters that actually have arguments in runtime
21
+ // Aptos first signer and Sui's last TxContext are no use
22
+ abstract getMeaningfulFunctionParams(params: TypeDescriptor[]): TypeDescriptor[]
23
+
24
+ abstract getType(base: StructType): string
25
+ abstract getData<T>(base: StructType): any
26
+ }