@stellar-expert/contract-wasm-interface-parser 2.0.1 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,97 +20,254 @@ Example output:
20
20
 
21
21
  ```json
22
22
  {
23
- "unions": [
24
- {
25
- "name": "Asset",
23
+ "enums": {
24
+ "SubscriptionStatus": {
26
25
  "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",
26
+ "Active": {
59
27
  "value": 0
60
28
  },
61
- {
62
- "name": "Unauthorized",
29
+ "Cancelled": {
30
+ "value": 2
31
+ },
32
+ "Suspended": {
63
33
  "value": 1
64
34
  }
65
- ]
66
- }
67
- ],
68
- "enums": [
69
- {
70
- "name": "SubscriptionStatus",
71
- "cases": {
72
- "Active": 0,
73
- "Suspended": 1,
74
- "Cancelled": 2
75
35
  }
76
36
  }
77
- ],
78
- "functions": [
79
- {
80
- "name": "config",
81
- "inputs": [
82
- {
83
- "name": "config",
37
+ },
38
+ "errors": {
39
+ "AlreadyInitialized": {
40
+ "value": 0
41
+ },
42
+ "InvalidAmount": {
43
+ "value": 4
44
+ },
45
+ "InvalidHeartbeat": {
46
+ "value": 5
47
+ },
48
+ "InvalidSubscriptionStatusError": {
49
+ "value": 8
50
+ },
51
+ "InvalidThreshold": {
52
+ "value": 6
53
+ },
54
+ "NotInitialized": {
55
+ "value": 3
56
+ },
57
+ "SubscriptionNotFound": {
58
+ "value": 2
59
+ },
60
+ "Unauthorized": {
61
+ "value": 1
62
+ },
63
+ "WebhookTooLong": {
64
+ "value": 7
65
+ }
66
+ },
67
+ "functions": {
68
+ "admin": {
69
+ "inputs": {},
70
+ "outputs": [
71
+ "option<address>"
72
+ ]
73
+ },
74
+ "cancel": {
75
+ "inputs": {
76
+ "subscription_id": {
77
+ "type": "u64"
78
+ }
79
+ },
80
+ "outputs": []
81
+ },
82
+ "charge": {
83
+ "inputs": {
84
+ "subscription_ids": {
85
+ "type": "vec<u64>"
86
+ }
87
+ },
88
+ "outputs": []
89
+ },
90
+ "config": {
91
+ "inputs": {
92
+ "config": {
84
93
  "type": "ConfigData"
85
- "doc": "New configuration data"
86
94
  }
87
- ],
88
- "outputs": [],
89
- "doc": "Update contract confirguration"
90
- },
91
- {
92
- "name": "set_fee",
93
- "inputs": [
94
- {
95
- "name": "fee",
95
+ },
96
+ "outputs": []
97
+ },
98
+ "create_subscription": {
99
+ "inputs": {
100
+ "amount": {
101
+ "type": "u64"
102
+ },
103
+ "new_subscription": {
104
+ "type": "CreateSubscription"
105
+ }
106
+ },
107
+ "outputs": [
108
+ "tuple<u64,Subscription>"
109
+ ]
110
+ },
111
+ "deposit": {
112
+ "inputs": {
113
+ "amount": {
114
+ "type": "u64"
115
+ },
116
+ "from": {
117
+ "type": "address"
118
+ },
119
+ "subscription_id": {
96
120
  "type": "u64"
97
121
  }
98
- ],
122
+ },
99
123
  "outputs": []
100
124
  },
101
- {
102
- "name": "get_subscription",
103
- "inputs": [
104
- {
105
- "name": "subscription_id",
125
+ "fee": {
126
+ "inputs": {},
127
+ "outputs": [
128
+ "u64"
129
+ ]
130
+ },
131
+ "get_subscription": {
132
+ "inputs": {
133
+ "subscription_id": {
106
134
  "type": "u64"
107
135
  }
108
- ],
136
+ },
109
137
  "outputs": [
110
138
  "Subscription"
111
139
  ]
140
+ },
141
+ "set_fee": {
142
+ "inputs": {
143
+ "fee": {
144
+ "type": "u64"
145
+ }
146
+ },
147
+ "outputs": []
148
+ },
149
+ "token": {
150
+ "inputs": {},
151
+ "outputs": [
152
+ "address"
153
+ ]
154
+ },
155
+ "trigger": {
156
+ "inputs": {
157
+ "timestamp": {
158
+ "type": "u64"
159
+ },
160
+ "trigger_hash": {
161
+ "type": "bytesn<32>"
162
+ }
163
+ },
164
+ "outputs": []
165
+ },
166
+ "update_contract": {
167
+ "inputs": {
168
+ "wasm_hash": {
169
+ "type": "bytesn<32>"
170
+ }
171
+ },
172
+ "outputs": []
173
+ },
174
+ "version": {
175
+ "inputs": {},
176
+ "outputs": [
177
+ "u32"
178
+ ]
179
+ }
180
+ },
181
+ "structs": {
182
+ "ConfigData": {
183
+ "fields": {
184
+ "admin": {
185
+ "type": "address"
186
+ },
187
+ "fee": {
188
+ "type": "u64"
189
+ },
190
+ "token": {
191
+ "type": "address"
192
+ }
193
+ }
194
+ },
195
+ "CreateSubscription": {
196
+ "fields": {
197
+ "asset1": {
198
+ "type": "TickerAsset"
199
+ },
200
+ "asset2": {
201
+ "type": "TickerAsset"
202
+ },
203
+ "heartbeat": {
204
+ "type": "u32"
205
+ },
206
+ "owner": {
207
+ "type": "address"
208
+ },
209
+ "threshold": {
210
+ "type": "u32"
211
+ },
212
+ "webhook": {
213
+ "type": "bytes"
214
+ }
215
+ }
216
+ },
217
+ "Subscription": {
218
+ "fields": {
219
+ "asset1": {
220
+ "type": "TickerAsset"
221
+ },
222
+ "asset2": {
223
+ "type": "TickerAsset"
224
+ },
225
+ "balance": {
226
+ "type": "u64"
227
+ },
228
+ "heartbeat": {
229
+ "type": "u32"
230
+ },
231
+ "last_charge": {
232
+ "type": "u64"
233
+ },
234
+ "owner": {
235
+ "type": "address"
236
+ },
237
+ "status": {
238
+ "type": "SubscriptionStatus"
239
+ },
240
+ "threshold": {
241
+ "type": "u32"
242
+ },
243
+ "webhook": {
244
+ "type": "bytes"
245
+ }
246
+ }
247
+ },
248
+ "TickerAsset": {
249
+ "fields": {
250
+ "asset": {
251
+ "type": "Asset"
252
+ },
253
+ "source": {
254
+ "type": "string"
255
+ }
256
+ }
257
+ }
258
+ },
259
+ "unions": {
260
+ "Asset": {
261
+ "cases": {
262
+ "Other": [
263
+ "symbol"
264
+ ],
265
+ "Stellar": [
266
+ "address"
267
+ ]
268
+ }
112
269
  }
113
- ],
270
+ },
114
271
  "interfaceVersion": "85899345920",
115
272
  "rustVersion": "1.74.0",
116
273
  "sdkVersion": "20.5.0#9e2c3022b4355b224a7a814e13ba51761eeb14bb"
package/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import {xdr} from '@stellar/stellar-base'
2
- import {XdrReader} from './src/xdr-reader'
2
+ import {parseSectionEntriesXdr} from './src/xdr-reader'
3
3
  import {WasmSectionReader} from './src/wasm-section-reader'
4
4
  import {parseContractMeta, parseSpec} from './src/xdr-spec-parser'
5
5
 
6
6
  /**
7
7
  * Parse contract metadata from WASM sections
8
8
  * @param {Buffer} rawWasm
9
- * @return {{}}
9
+ * @return {ParsedWasmMeta}
10
10
  */
11
11
  export function parseContractMetadata(rawWasm) {
12
12
  const wasmSectionReader = new WasmSectionReader(rawWasm)
@@ -18,21 +18,24 @@ export function parseContractMetadata(rawWasm) {
18
18
  res.interfaceVersion = xdr.ScEnvMetaEntry.fromXDR(section.contents).value().toString()
19
19
  break
20
20
  case 'contractmetav0':
21
- Object.assign(res, parseContractMeta(parseEntries(section.contents, xdr.ScMetaEntry)))
21
+ Object.assign(res, parseContractMeta(parseSectionEntriesXdr(section.contents, xdr.ScMetaEntry)))
22
22
  break
23
23
  case 'contractspecv0':
24
- Object.assign(res, parseSpec(parseEntries(section.contents, xdr.ScSpecEntry)))
24
+ Object.assign(res, parseSpec(parseSectionEntriesXdr(section.contents, xdr.ScSpecEntry)))
25
25
  break
26
26
  }
27
27
  }
28
28
  return res
29
29
  }
30
30
 
31
- function parseEntries(buffer, xdrContract) {
32
- const reader = new XdrReader(buffer)
33
- const entries = []
34
- while (!reader.eof) {
35
- entries.push(xdrContract.read(reader))
36
- }
37
- return entries
38
- }
31
+ /**
32
+ * @typedef {{}} ParsedWasmMeta
33
+ * @property {{}} functions
34
+ * @property {{}} [errors]
35
+ * @property {{}} [enums]
36
+ * @property {{}} [structs]
37
+ * @property {{}} [unions]
38
+ * @property {string} rustVersion
39
+ * @property {string} sdkVersion
40
+ * @property {string} interfaceVersion
41
+ */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stellar-expert/contract-wasm-interface-parser",
3
- "version": "2.0.1",
3
+ "version": "3.1.0",
4
4
  "description": "Contract interface metadata parser for binary WASM",
5
5
  "main": "index.js",
6
6
  "module": "./index.js",
@@ -8,6 +8,9 @@
8
8
  "type": "git",
9
9
  "url": "git+https://github.com/stellar-expert/contract-wasm-interface-parser.git"
10
10
  },
11
+ "scripts": {
12
+ "test": "jest"
13
+ },
11
14
  "author": "orbitlens <orbit@stellar.expert>",
12
15
  "license": "MIT",
13
16
  "peerDependencies": {
package/src/xdr-reader.js CHANGED
@@ -1,4 +1,19 @@
1
- export class XdrReader {
1
+ /**
2
+ *
3
+ * @param {Buffer} buffer
4
+ * @param {{read: function}} xdrContract
5
+ * @return {{}[]}
6
+ */
7
+ export function parseSectionEntriesXdr(buffer, xdrContract) {
8
+ const reader = new XdrReader(buffer)
9
+ const entries = []
10
+ while (!reader.eof) {
11
+ entries.push(xdrContract.read(reader))
12
+ }
13
+ return entries
14
+ }
15
+
16
+ class XdrReader {
2
17
  /**
3
18
  * @constructor
4
19
  * @param {Buffer} source - Buffer containing serialized data
@@ -30,12 +30,13 @@ class SpecParser {
30
30
  */
31
31
  res
32
32
 
33
- addSpec(key, descriptor, doc) {
33
+ addSpec(key, attr, parser) {
34
+ //this.parseFunction(attr), attr.doc
34
35
  let spec = this.res[key]
35
36
  if (spec === undefined) {
36
- spec = this.res[key] = []
37
+ spec = this.res[key] = {}
37
38
  }
38
- spec.push(this.withDocs(descriptor, doc))
39
+ parser.call(this, attr, spec)
39
40
  }
40
41
 
41
42
  parse(entries) {
@@ -44,19 +45,19 @@ class SpecParser {
44
45
  const {_attributes: attr} = value
45
46
  switch (spec._arm) {
46
47
  case 'functionV0':
47
- this.addSpec('functions', this.parseFunction(attr), attr.doc)
48
+ this.addSpec('functions', attr, this.parseFunction)
48
49
  break
49
50
  case 'udtStructV0':
50
- this.addSpec('structs', this.parseStruct(attr), attr.doc)
51
+ this.addSpec('structs', attr, this.parseStruct)
51
52
  break
52
53
  case 'udtUnionV0':
53
- this.addSpec('unions', this.parseUnion(attr), attr.doc)
54
+ this.addSpec('unions', attr, this.parseUnion)
54
55
  break
55
56
  case 'udtEnumV0':
56
- this.addSpec('enums', this.parseEnum(attr), attr.doc)
57
+ this.addSpec('enums', attr, this.parseEnum)
57
58
  break
58
59
  case 'udtErrorEnumV0':
59
- this.addSpec('errors', this.parseError(attr), attr.doc)
60
+ this.addSpec('errors', attr, this.parseError)
60
61
  break
61
62
  default:
62
63
  console.log('Unknown spec type: ' + spec._arm)
@@ -66,57 +67,51 @@ class SpecParser {
66
67
  return this.res
67
68
  }
68
69
 
69
- parseFunction(attr) {
70
- return {
71
- name: attr.name.toString(),
72
- inputs: attr.inputs.map(i => this.parseParameter(i)),
70
+ parseFunction(attr, into) {
71
+ const inputs = {}
72
+ attr.inputs.forEach(i => this.parseParameter(i, inputs))
73
+ into[attr.name.toString()] = this.withDocs({
74
+ inputs,
73
75
  outputs: attr.outputs.map(o => this.parseParameterType(o))
74
- }
76
+ }, attr)
75
77
  }
76
78
 
77
- parseStruct(attr) {
78
- return {
79
- name: this.parseStructName(attr),
80
- fields: attr.fields.map(f => this.parseParameter(f))
81
- }
79
+ parseStruct(attr, into) {
80
+ const fields = {}
81
+ attr.fields.forEach(f => this.parseParameter(f, fields))
82
+ into[this.parseStructName(attr)] = this.withDocs({fields}, attr)
82
83
  }
83
84
 
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
- }
85
+ parseUnion(attr, into) {
86
+ const cases = {}
87
+ attr.cases.forEach(c => {
88
+ const value = c.value()
89
+ cases[value.name().toString()] = value.type ?
90
+ value.type().map(t => this.parseParameterType(t)) :
91
+ []
92
+ })
93
+ into[this.parseStructName(attr)] = this.withDocs({cases}, attr)
95
94
  }
96
95
 
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
- }
96
+ parseEnum(attr, into) {
97
+ const cases = {}
98
+ attr.cases.forEach(c => {
99
+ const value = c.value()
100
+ if (value.name) {
101
+ cases[value.name().toString()] = value.value()
102
+ } else {
103
+ const attr = c._attributes
104
+ cases[attr.name.toString()] = this.withDocs({value}, attr)
105
+ }
106
+ })
107
+ into[this.parseStructName(attr)] = this.withDocs({cases}, attr)
110
108
  }
111
109
 
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
- }
110
+ parseError(attr, into) {
111
+ attr.cases.forEach(c => {
112
+ const attr = c._attributes
113
+ into[attr.name.toString()] = this.withDocs({value: attr.value}, attr)
114
+ })
120
115
  }
121
116
 
122
117
  parseParameterType(type) {
@@ -149,18 +144,14 @@ class SpecParser {
149
144
  return structName
150
145
  }
151
146
 
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)
147
+ parseParameter(param, into) {
148
+ const attr = param._attributes
149
+ into[attr.name.toString()] = this.withDocs({type: this.parseParameterType(attr.type)}, attr)
159
150
  }
160
151
 
161
- withDocs(descriptor, doc) {
162
- if (doc?.length) {
163
- descriptor.doc = doc.toString()
152
+ withDocs(descriptor, attr) {
153
+ if (attr.doc?.length) {
154
+ descriptor.doc = attr.doc.toString()
164
155
  }
165
156
  return descriptor
166
157
  }