@stellar-expert/contract-wasm-interface-parser 1.1.0 → 2.0.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.
package/README.md CHANGED
@@ -10,15 +10,109 @@ npm i @stellar-expert/contract-wasm-interface-parser
10
10
 
11
11
  ## Usage
12
12
 
13
+ Download WASM contract code and call `parseContractMetadata()` function to obtain a parsed contract interface.
14
+
13
15
  ```js
14
16
  parseContractMetadata(Buffer.from(/*binary wasm code*/))
15
- /*{
16
- rustVersion: '1.76.0',
17
- sdkVersion: '20.0.0',
18
- functions: [],
19
- enums: [],
20
- structs: [],
21
- unions: [],
22
- errors: []
23
- }*/
17
+ ```
18
+
19
+ Example output:
20
+
21
+ ```json
22
+ {
23
+ "unions": [
24
+ {
25
+ "name": "Asset",
26
+ "cases": {
27
+ "Stellar": [
28
+ "address"
29
+ ],
30
+ "Other": [
31
+ "symbol"
32
+ ]
33
+ }
34
+ }
35
+ ],
36
+ "structs": [
37
+ {
38
+ "name": "TickerAsset",
39
+ "fields": [
40
+ {
41
+ "name": "asset",
42
+ "type": "Asset",
43
+ "doc": "Short ticker name of the asset"
44
+ },
45
+ {
46
+ "name": "source",
47
+ "type": "string",
48
+ "doc": "Data provider ID"
49
+ }
50
+ ]
51
+ }
52
+ ],
53
+ "errors": [
54
+ {
55
+ "name": "Error",
56
+ "cases": [
57
+ {
58
+ "name": "AlreadyInitialized",
59
+ "value": 0
60
+ },
61
+ {
62
+ "name": "Unauthorized",
63
+ "value": 1
64
+ }
65
+ ]
66
+ }
67
+ ],
68
+ "enums": [
69
+ {
70
+ "name": "SubscriptionStatus",
71
+ "cases": {
72
+ "Active": 0,
73
+ "Suspended": 1,
74
+ "Cancelled": 2
75
+ }
76
+ }
77
+ ],
78
+ "functions": [
79
+ {
80
+ "name": "config",
81
+ "inputs": [
82
+ {
83
+ "name": "config",
84
+ "type": "ConfigData"
85
+ "doc": "New configuration data"
86
+ }
87
+ ],
88
+ "outputs": [],
89
+ "doc": "Update contract confirguration"
90
+ },
91
+ {
92
+ "name": "set_fee",
93
+ "inputs": [
94
+ {
95
+ "name": "fee",
96
+ "type": "u64"
97
+ }
98
+ ],
99
+ "outputs": []
100
+ },
101
+ {
102
+ "name": "get_subscription",
103
+ "inputs": [
104
+ {
105
+ "name": "subscription_id",
106
+ "type": "u64"
107
+ }
108
+ ],
109
+ "outputs": [
110
+ "Subscription"
111
+ ]
112
+ }
113
+ ],
114
+ "interfaceVersion": "85899345920",
115
+ "rustVersion": "1.74.0",
116
+ "sdkVersion": "20.5.0#9e2c3022b4355b224a7a814e13ba51761eeb14bb"
117
+ }
24
118
  ```
@@ -0,0 +1,20 @@
1
+ module.exports = {
2
+ presets: [
3
+ [
4
+ '@babel/preset-env',
5
+ {
6
+ corejs: '3.34',
7
+ useBuiltIns: 'entry',
8
+ //modules: false,
9
+ targets: {
10
+ browsers: [
11
+ '> 1%',
12
+ 'not dead',
13
+ 'not op_mini all'
14
+ ],
15
+ node: '18'
16
+ }
17
+ }
18
+ ]
19
+ ]
20
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stellar-expert/contract-wasm-interface-parser",
3
- "version": "1.1.0",
3
+ "version": "2.0.1",
4
4
  "description": "Contract interface metadata parser for binary WASM",
5
5
  "main": "index.js",
6
6
  "module": "./index.js",
@@ -11,6 +11,14 @@
11
11
  "author": "orbitlens <orbit@stellar.expert>",
12
12
  "license": "MIT",
13
13
  "peerDependencies": {
14
- "@stellar/stellar-base": ">=11"
14
+ "@stellar/stellar-base": ">=12"
15
+ },
16
+ "devDependencies": {
17
+ "@babel/core": "^7.24.8",
18
+ "@babel/preset-env": "^7.24.8",
19
+ "babel-loader": "^9.1.3",
20
+ "jest": "^29.7.0",
21
+ "webpack": "^5.93.0",
22
+ "webpack-cli": "^5.1.4"
15
23
  }
16
24
  }
@@ -16,100 +16,153 @@ export function parseContractMeta(meta) {
16
16
  }
17
17
 
18
18
  export function parseSpec(entries) {
19
- const res = {}
19
+ return new SpecParser().parse(entries)
20
+ }
21
+
22
+
23
+ class SpecParser {
24
+ constructor() {
25
+ this.res = {}
26
+ }
20
27
 
21
- function addSpec(key, descriptor) {
22
- let spec = res[key]
28
+ /**
29
+ * @type {{}}
30
+ */
31
+ res
32
+
33
+ addSpec(key, descriptor, doc) {
34
+ let spec = this.res[key]
23
35
  if (spec === undefined) {
24
- spec = res[key] = []
36
+ spec = this.res[key] = []
25
37
  }
26
- spec.push(descriptor)
38
+ spec.push(this.withDocs(descriptor, doc))
27
39
  }
28
40
 
29
- for (const spec of entries) {
30
- const value = spec.value()
31
- switch (spec._arm) {
32
- case 'functionV0':
33
- addSpec('functions', {
34
- name: value.name().toString(),
35
- inputs: value.inputs().map(parseParameter),
36
- outputs: value.outputs().map(parseParameterType)
37
- })
38
- break
39
- case 'udtStructV0':
40
- addSpec('structs', {
41
- name: parseStructName(value),
42
- fields: value.fields().map(parseParameter)
43
- })
44
- break
45
- case 'udtUnionV0':
46
- addSpec('unions', {
47
- name: parseStructName(value),
48
- cases: value.cases().reduce((agg, c) => {
49
- const value = c.value()
50
- agg[value.name().toString()] = value.type ? value.type().map(parseParameterType) : []
51
- return agg
52
- }, {})
53
- })
54
- break
55
- case 'udtEnumV0':
56
- addSpec('enums', {
57
- name: parseStructName(value),
58
- cases: value.cases().reduce((agg, c) => {
59
- const value = c.value()
60
- agg[value.name().toString()] = value.value()
61
- return agg
62
- }, {})
63
- })
64
- break
65
- case 'udtErrorEnumV0':
66
- addSpec('errors', {
67
- name: parseStructName(value),
68
- cases: value.cases().map(c => ({
69
- name: c.name().toString(),
70
- value: c.value()
71
- }))
72
- })
73
- break
41
+ parse(entries) {
42
+ for (const spec of entries) {
43
+ const value = spec.value()
44
+ const {_attributes: attr} = value
45
+ switch (spec._arm) {
46
+ case 'functionV0':
47
+ this.addSpec('functions', this.parseFunction(attr), attr.doc)
48
+ break
49
+ case 'udtStructV0':
50
+ this.addSpec('structs', this.parseStruct(attr), attr.doc)
51
+ break
52
+ case 'udtUnionV0':
53
+ this.addSpec('unions', this.parseUnion(attr), attr.doc)
54
+ break
55
+ case 'udtEnumV0':
56
+ this.addSpec('enums', this.parseEnum(attr), attr.doc)
57
+ break
58
+ case 'udtErrorEnumV0':
59
+ this.addSpec('errors', this.parseError(attr), attr.doc)
60
+ break
61
+ default:
62
+ console.log('Unknown spec type: ' + spec._arm)
63
+ break
64
+ }
74
65
  }
66
+ return this.res
75
67
  }
76
- return res
77
- }
78
68
 
79
- function parseStructName(value) {
80
- let structName = value.name().toString()
81
- const lib = value.lib()
82
- if (lib.length) {
83
- structName += ':' + lib.toString()
69
+ parseFunction(attr) {
70
+ return {
71
+ name: attr.name.toString(),
72
+ inputs: attr.inputs.map(i => this.parseParameter(i)),
73
+ outputs: attr.outputs.map(o => this.parseParameterType(o))
74
+ }
84
75
  }
85
- return structName
86
- }
87
76
 
88
- function parseParameterType(type) {
89
- const typeName = type.switch().name
90
- switch (typeName) {
91
- case 'scSpecTypeOption':
92
- return `option<${parseParameterType(type.value().valueType())}>`
93
- case 'scSpecTypeBytesN':
94
- return `bytesn<${type.value().n()}>`
95
- case 'scSpecTypeVec':
96
- return `vec<${parseParameterType(type.value().elementType())}>`
97
- case 'scSpecTypeMap':
98
- return `map<${parseParameterType(type.value().keyType())},${parseParameterType(type.value().valueType())}>`
99
- case 'scSpecTypeResult':
100
- return `result<${parseParameterType(type.value().okType())},${parseParameterType(type.value().errorType())}>`
101
- case 'scSpecTypeTuple':
102
- return `tuple<${type.value().valueTypes().map(parseParameterType).join()}>`
103
- case 'scSpecTypeUdt':
104
- return type.value().name()
105
- default:
106
- return typeName.replace('scSpecType', '').toLowerCase()
77
+ parseStruct(attr) {
78
+ return {
79
+ name: this.parseStructName(attr),
80
+ fields: attr.fields.map(f => this.parseParameter(f))
81
+ }
82
+ }
83
+
84
+ parseUnion(attr) {
85
+ return {
86
+ name: this.parseStructName(attr),
87
+ cases: attr.cases.reduce((agg, c) => {
88
+ const value = c.value()
89
+ agg[value.name().toString()] = value.type ?
90
+ value.type().map(t => this.parseParameterType(t)) :
91
+ []
92
+ return agg
93
+ }, {})
94
+ }
95
+ }
96
+
97
+ parseEnum(attr) {
98
+ return {
99
+ name: this.parseStructName(attr),
100
+ cases: attr.cases.reduce((agg, c) => {
101
+ const value = c.value()
102
+ if (value.name) {
103
+ agg[value.name().toString()] = value.value()
104
+ } else {
105
+ agg[c._attributes.name] = value
106
+ }
107
+ return agg
108
+ }, {})
109
+ }
110
+ }
111
+
112
+ parseError(attr) {
113
+ return {
114
+ name: this.parseStructName(attr),
115
+ cases: attr.cases.map(c => ({
116
+ name: c.name().toString(),
117
+ value: c.value()
118
+ }))
119
+ }
107
120
  }
108
- }
109
121
 
110
- function parseParameter(param) {
111
- return {
112
- name: param.name().toString(),
113
- type: parseParameterType(param.type())
122
+ parseParameterType(type) {
123
+ const typeName = type.switch().name
124
+ switch (typeName) {
125
+ case 'scSpecTypeOption':
126
+ return `option<${this.parseParameterType(type.value().valueType())}>`
127
+ case 'scSpecTypeBytesN':
128
+ return `bytesn<${type.value().n()}>`
129
+ case 'scSpecTypeVec':
130
+ return `vec<${this.parseParameterType(type.value().elementType())}>`
131
+ case 'scSpecTypeMap':
132
+ return `map<${this.parseParameterType(type.value().keyType())},${this.parseParameterType(type.value().valueType())}>`
133
+ case 'scSpecTypeResult':
134
+ return `result<${this.parseParameterType(type.value().okType())},${this.parseParameterType(type.value().errorType())}>`
135
+ case 'scSpecTypeTuple':
136
+ return `tuple<${type.value().valueTypes().map(this.parseParameterType).join()}>`
137
+ case 'scSpecTypeUdt':
138
+ return type.value().name().toString()
139
+ default:
140
+ return typeName.replace('scSpecType', '').toLowerCase()
141
+ }
114
142
  }
115
- }
143
+
144
+ parseStructName(value) {
145
+ let structName = value.name.toString()
146
+ if (value.lib.length) {
147
+ structName += ':' + value.lib.toString()
148
+ }
149
+ return structName
150
+ }
151
+
152
+ parseParameter(param) {
153
+ const {_attributes: attr} = param
154
+ const res = {
155
+ name: attr.name.toString(),
156
+ type: this.parseParameterType(attr.type)
157
+ }
158
+ return this.withDocs(res, attr.doc)
159
+ }
160
+
161
+ withDocs(descriptor, doc) {
162
+ if (doc?.length) {
163
+ descriptor.doc = doc.toString()
164
+ }
165
+ return descriptor
166
+ }
167
+ }
168
+