@aeternity/aepp-sdk 8.2.0 → 10.0.0-beta.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 (145) hide show
  1. package/README.md +16 -9
  2. package/dist/aepp-sdk.browser-script.js +1 -1
  3. package/dist/aepp-sdk.browser-script.js.LICENSE.txt +0 -9
  4. package/dist/aepp-sdk.browser-script.js.map +1 -1
  5. package/dist/aepp-sdk.browser.js +1 -1
  6. package/dist/aepp-sdk.browser.js.map +1 -1
  7. package/dist/aepp-sdk.js +1 -1
  8. package/dist/aepp-sdk.js.map +1 -1
  9. package/es/account/base.js +33 -119
  10. package/es/account/base.js.map +1 -1
  11. package/es/account/memory.js +17 -19
  12. package/es/account/memory.js.map +1 -1
  13. package/es/account/multiple.js +75 -154
  14. package/es/account/multiple.js.map +1 -1
  15. package/es/ae/aens.js +164 -599
  16. package/es/ae/aens.js.map +1 -1
  17. package/es/ae/contract.js +108 -916
  18. package/es/ae/contract.js.map +1 -1
  19. package/es/ae/index.js +89 -250
  20. package/es/ae/index.js.map +1 -1
  21. package/es/ae/oracle.js +132 -500
  22. package/es/ae/oracle.js.map +1 -1
  23. package/es/chain/index.js +4 -23
  24. package/es/chain/index.js.map +1 -1
  25. package/es/chain/node.js +292 -1018
  26. package/es/chain/node.js.map +1 -1
  27. package/es/channel/handlers.js +597 -1086
  28. package/es/channel/handlers.js.map +1 -1
  29. package/es/channel/index.js +203 -451
  30. package/es/channel/index.js.map +1 -1
  31. package/es/channel/internal.js +129 -301
  32. package/es/channel/internal.js.map +1 -1
  33. package/es/contract/aci/index.js +319 -491
  34. package/es/contract/aci/index.js.map +1 -1
  35. package/es/contract/aci/transformation.js +35 -711
  36. package/es/contract/aci/transformation.js.map +1 -1
  37. package/es/contract/compiler.js +129 -203
  38. package/es/contract/compiler.js.map +1 -1
  39. package/es/contract/ga/helpers.js +17 -122
  40. package/es/contract/ga/helpers.js.map +1 -1
  41. package/es/contract/ga/index.js +102 -247
  42. package/es/contract/ga/index.js.map +1 -1
  43. package/es/contract/index.js +1 -1
  44. package/es/contract/index.js.map +1 -1
  45. package/es/index.js +2 -3
  46. package/es/index.js.map +1 -1
  47. package/es/node-pool/index.js +54 -73
  48. package/es/node-pool/index.js.map +1 -1
  49. package/es/node.js +56 -157
  50. package/es/node.js.map +1 -1
  51. package/es/other.d.ts +1 -1
  52. package/es/tx/builder/helpers.js +49 -89
  53. package/es/tx/builder/helpers.js.map +1 -1
  54. package/es/tx/builder/index.js +205 -303
  55. package/es/tx/builder/index.js.map +1 -1
  56. package/es/tx/builder/schema.js +585 -573
  57. package/es/tx/builder/schema.js.map +1 -1
  58. package/es/tx/index.js +1 -1
  59. package/es/tx/index.js.map +1 -1
  60. package/es/tx/tx-object.js +105 -135
  61. package/es/tx/tx-object.js.map +1 -1
  62. package/es/tx/tx.js +810 -1586
  63. package/es/tx/tx.js.map +1 -1
  64. package/es/tx/validator.js +191 -426
  65. package/es/tx/validator.js.map +1 -1
  66. package/es/utils/aepp-wallet-communication/connection/browser-runtime.js +17 -21
  67. package/es/utils/aepp-wallet-communication/connection/browser-runtime.js.map +1 -1
  68. package/es/utils/aepp-wallet-communication/connection/browser-window-message.js +38 -74
  69. package/es/utils/aepp-wallet-communication/connection/browser-window-message.js.map +1 -1
  70. package/es/utils/aepp-wallet-communication/content-script-bridge.js +14 -15
  71. package/es/utils/aepp-wallet-communication/content-script-bridge.js.map +1 -1
  72. package/es/utils/aepp-wallet-communication/helpers.js +60 -105
  73. package/es/utils/aepp-wallet-communication/helpers.js.map +1 -1
  74. package/es/utils/aepp-wallet-communication/rpc/aepp-rpc.js +179 -510
  75. package/es/utils/aepp-wallet-communication/rpc/aepp-rpc.js.map +1 -1
  76. package/es/utils/aepp-wallet-communication/rpc/rpc-client.js +70 -89
  77. package/es/utils/aepp-wallet-communication/rpc/rpc-client.js.map +1 -1
  78. package/es/utils/aepp-wallet-communication/rpc/wallet-rpc.js +354 -603
  79. package/es/utils/aepp-wallet-communication/rpc/wallet-rpc.js.map +1 -1
  80. package/es/utils/aepp-wallet-communication/schema.js +43 -39
  81. package/es/utils/aepp-wallet-communication/schema.js.map +1 -1
  82. package/es/utils/aepp-wallet-communication/wallet-detector.js +32 -58
  83. package/es/utils/aepp-wallet-communication/wallet-detector.js.map +1 -1
  84. package/es/utils/amount-formatter.js +41 -61
  85. package/es/utils/amount-formatter.js.map +1 -1
  86. package/es/utils/async-init.js +28 -64
  87. package/es/utils/async-init.js.map +1 -1
  88. package/es/utils/bignumber.js +3 -11
  89. package/es/utils/bignumber.js.map +1 -1
  90. package/es/utils/bytes.js +5 -9
  91. package/es/utils/bytes.js.map +1 -1
  92. package/es/utils/crypto.js +49 -75
  93. package/es/utils/crypto.js.map +1 -1
  94. package/es/utils/hd-wallet.js +45 -81
  95. package/es/utils/hd-wallet.js.map +1 -1
  96. package/es/utils/json-big.js +16 -49
  97. package/es/utils/json-big.js.map +1 -1
  98. package/es/utils/keystore.js +81 -246
  99. package/es/utils/keystore.js.map +1 -1
  100. package/es/utils/mptree.js +88 -134
  101. package/es/utils/mptree.js.map +1 -1
  102. package/es/utils/other.js +10 -60
  103. package/es/utils/other.js.map +1 -1
  104. package/es/utils/semver-satisfies.js +9 -28
  105. package/es/utils/semver-satisfies.js.map +1 -1
  106. package/es/utils/string.js +4 -13
  107. package/es/utils/string.js.map +1 -1
  108. package/es/utils/swagger.js +85 -218
  109. package/es/utils/swagger.js.map +1 -1
  110. package/package.json +52 -43
  111. package/src/account/base.js +8 -9
  112. package/src/account/multiple.js +20 -16
  113. package/src/ae/aens.js +25 -21
  114. package/src/ae/contract.js +65 -246
  115. package/src/ae/index.js +31 -7
  116. package/src/ae/oracle.js +21 -17
  117. package/src/chain/index.js +2 -12
  118. package/src/chain/node.js +26 -29
  119. package/src/channel/handlers.js +0 -1
  120. package/src/channel/index.js +4 -5
  121. package/src/contract/aci/index.js +221 -106
  122. package/src/contract/aci/transformation.js +30 -422
  123. package/src/contract/compiler.js +45 -4
  124. package/src/contract/ga/helpers.js +2 -12
  125. package/src/contract/ga/index.js +22 -26
  126. package/src/index.js +2 -4
  127. package/src/node-pool/index.js +21 -12
  128. package/src/node.js +22 -26
  129. package/src/tx/builder/helpers.js +12 -24
  130. package/src/tx/builder/index.js +18 -15
  131. package/src/tx/builder/schema.js +43 -108
  132. package/src/tx/tx-object.js +0 -2
  133. package/src/tx/tx.js +157 -144
  134. package/src/tx/validator.js +134 -202
  135. package/src/utils/aepp-wallet-communication/rpc/aepp-rpc.js +1 -3
  136. package/src/utils/aepp-wallet-communication/rpc/wallet-rpc.js +9 -10
  137. package/src/utils/aepp-wallet-communication/schema.js +1 -3
  138. package/src/utils/amount-formatter.ts +1 -1
  139. package/src/utils/bignumber.ts +2 -1
  140. package/src/utils/crypto.js +4 -17
  141. package/src/utils/other.ts +1 -1
  142. package/src/utils/semver-satisfies.ts +1 -1
  143. package/src/utils/swagger.js +24 -7
  144. package/CHANGELOG.md +0 -1716
  145. package/src/contract/aci/helpers.js +0 -140
@@ -1,9 +1,7 @@
1
- import Joi from 'joi-browser'
2
- import { isHex } from '../../utils/string'
3
1
  import { toBytes } from '../../utils/bytes'
4
2
  import { decode } from '../../tx/builder/helpers'
5
3
  import { parseBigNumber } from '../../utils/bignumber'
6
- import { isAddressValid, addressFromDecimal, hash } from '../../utils/crypto'
4
+ import { addressFromDecimal, hash } from '../../utils/crypto'
7
5
 
8
6
  export const SOPHIA_TYPES = [
9
7
  'int',
@@ -24,441 +22,51 @@ export const SOPHIA_TYPES = [
24
22
  ].reduce((acc, type) => ({ ...acc, [type]: type }), { ChainTtl: 'Chain.ttl' })
25
23
 
26
24
  /**
27
- * Transform decoded event to JS type
28
- * @param {Object[]} events Array of events
29
- * @param {Object} [options={}] Options
30
- * @param {Object} [options.schema=[]] SC function ACI schema
25
+ * Decode events fields
26
+ * @param {Object[]} events Array of events with encoded fields
27
+ * @param {Array} schemas Smart contract event ACI schemas
31
28
  * @return {Object}
32
29
  */
33
- export function decodeEvents (events, options = { schema: [] }) {
34
- if (!events.length) return []
35
-
36
- return events.map(l => {
37
- const [eName, ...eParams] = l.topics
38
- const hexHash = toBytes(eName, true).toString('hex')
39
- const { schema } = options.schema
40
- .reduce(
41
- (acc, el) => {
42
- if (hash(el.name).toString('hex') === hexHash) {
43
- l.name = el.name
44
- return {
45
- schema: el.types,
46
- name: el.name
47
- }
48
- }
49
- return acc
50
- },
51
- { schema: [] }
52
- )
53
- const { decoded } = schema.reduce((acc, el) => {
54
- if (el === SOPHIA_TYPES.string) {
55
- return { decoded: [...acc.decoded, transformEvent(l.data, el)], params: acc.params }
56
- }
57
- const [event, ...tail] = acc.params
58
- return { decoded: [...acc.decoded, transformEvent(event, el)], params: tail }
59
- }, { decoded: [], params: eParams })
30
+ export const decodeEvents = (events, schemas = []) => events.reduce((acc, event) => {
31
+ const [nameHash, ...params] = event.topics
32
+ const schema = schemas.find((s) => hash(s.name).equals(toBytes(nameHash, true)))
33
+ if (!schema) return acc
34
+ const stringCount = schema.types.filter(t => t === SOPHIA_TYPES.string).length
35
+ if (stringCount > 1) throw new Error(`Event schema contains more than one string: ${schema.types}`)
36
+ const topicsCount = schema.types.length - stringCount
37
+ if (topicsCount !== params.length) {
38
+ throw new Error(`Schema defines ${topicsCount} types, but ${params.length} topics present`)
39
+ }
60
40
 
61
- return {
62
- ...l,
63
- decoded
64
- }
41
+ acc.push({
42
+ ...event,
43
+ name: schema.name,
44
+ decoded: schema.types.map((type) =>
45
+ decodeEventField(type === SOPHIA_TYPES.string ? event.data : params.shift(), type))
65
46
  })
66
- }
47
+
48
+ return acc
49
+ }, [])
67
50
 
68
51
  /**
69
52
  * Transform Event based on type
70
- * @param {String|Number} event Event data
53
+ * @param {String|Number} field Event data
71
54
  * @param {String} type Event type from schema
72
55
  * @return {*}
73
56
  */
74
- export function transformEvent (event, type) {
57
+ function decodeEventField (field, type) {
75
58
  switch (type) {
76
59
  case SOPHIA_TYPES.int:
77
- return parseBigNumber(event)
60
+ return parseBigNumber(field)
78
61
  case SOPHIA_TYPES.bool:
79
- return !!event
80
- case SOPHIA_TYPES.hash:
81
- return toBytes(event, true).toString('hex')
82
- case SOPHIA_TYPES.address:
83
- return addressFromDecimal(event).split('_')[1]
84
- case SOPHIA_TYPES.string:
85
- return decode(event).toString('utf-8')
86
- default:
87
- return toBytes(event, true)
88
- }
89
- }
90
-
91
- export function injectVars (t, aciType) {
92
- const [[baseType, generic]] = Object.entries(aciType.typedef)
93
- const [[, varianValue]] = Object.entries(t)
94
- switch (baseType) {
95
- case SOPHIA_TYPES.variant:
96
- return {
97
- [baseType]: generic.map(el => {
98
- const [tag, gen] = Object.entries(el)[0]
99
- return {
100
- [tag]: gen.map(type => {
101
- const index = aciType.vars.map(e => e.name).indexOf(type)
102
- return index === -1
103
- ? type
104
- : varianValue[index]
105
- })
106
- }
107
- })
108
- }
109
- }
110
- }
111
-
112
- /**
113
- * Ling Type Defs
114
- * @param t
115
- * @param bindings
116
- * @return {Object}
117
- */
118
- export function linkTypeDefs (t, bindings) {
119
- const [root, typeDef] = typeof t === 'object' ? Object.keys(t)[0].split('.') : t.split('.')
120
- const contractTypeDefs = bindings.find(c => c.name === root)
121
- const aciType = [
122
- ...contractTypeDefs.type_defs,
123
- { name: 'state', typedef: contractTypeDefs.state, vars: [] }
124
- ].find(({ name }) => name === typeDef)
125
- if (aciType.vars.length) {
126
- aciType.typedef = injectVars(t, aciType)
127
- }
128
- return isTypedDefOrState(aciType.typedef, bindings) ? linkTypeDefs(aciType.typedef, bindings) : aciType.typedef
129
- }
130
-
131
- const isTypedDefOrState = (t, bindings) => {
132
- if (!['string', 'object'].includes(typeof t)) return false
133
-
134
- t = typeof t === 'object' ? Object.keys(t)[0] : t
135
- const [root, ...path] = t.split('.')
136
- // Remote Contract Address
137
- if (!path.length) return false
138
- return bindings.map(c => c.name).includes(root)
139
- }
140
-
141
- const isRemoteAddress = (t) => {
142
- if (typeof t !== 'string') return false
143
- const [root, ...path] = t.split('.')
144
- return !path.length && !Object.values(SOPHIA_TYPES).includes(root)
145
- }
146
-
147
- /**
148
- * Parse sophia type
149
- * @param type
150
- * @param returnType
151
- * @return {Object}
152
- */
153
- export function readType (type, { bindings } = {}) {
154
- let [t] = Array.isArray(type) ? type : [type]
155
-
156
- // If remote address
157
- if (isRemoteAddress(t)) return { t: SOPHIA_TYPES.address }
158
- // Link State and typeDef
159
- if (isTypedDefOrState(t, bindings)) t = linkTypeDefs(t, bindings)
160
- // Map, Tuple, List, Record, Bytes
161
- if (typeof t === 'object') {
162
- const [[baseType, generic]] = Object.entries(t)
163
- return { t: baseType, generic }
164
- }
165
- // Base types
166
- if (typeof t === 'string') return { t }
167
- }
168
-
169
- // FUNCTION ARGUMENTS TRANSFORMATION ↓↓↓
170
-
171
- /**
172
- * Transform JS type to Sophia-type
173
- * @param type
174
- * @param value
175
- * @param bindings
176
- * @return {string}
177
- */
178
- export function transform (type, value, { bindings } = {}) {
179
- const { t, generic } = readType(type, { bindings })
180
-
181
- switch (t) {
182
- case SOPHIA_TYPES.ChainTtl:
183
- return `${value}`
184
- case SOPHIA_TYPES.string:
185
- return `"${value}"`
186
- case SOPHIA_TYPES.list:
187
- return `[${value.map(el => transform(generic, el, { bindings }))}]`
188
- case SOPHIA_TYPES.tuple:
189
- return `(${value.map((el, i) => transform(generic[i], el, {
190
- bindings
191
- }))})`
192
- case SOPHIA_TYPES.option: {
193
- return value === undefined ? 'None' : `Some(${transform(generic, value, {
194
- bindings
195
- })})`
196
- }
62
+ return !!field
197
63
  case SOPHIA_TYPES.hash:
198
- case SOPHIA_TYPES.bytes:
199
- case SOPHIA_TYPES.signature:
200
- if (typeof value === 'string') {
201
- if (isHex(value)) return `#${value}`
202
- if (isAddressValid(value)) return `#${decode(value).toString('hex')}`
203
- }
204
- return `#${Buffer.from(value).toString('hex')}`
205
- case SOPHIA_TYPES.record:
206
- return `{${generic.reduce(
207
- (acc, { name, type }, i) => {
208
- acc += `${i !== 0 ? ',' : ''}${name} = ${transform(type, value[name], {
209
- bindings
210
- })}`
211
- return acc
212
- },
213
- ''
214
- )}}`
215
- case SOPHIA_TYPES.map:
216
- return transformMap(value, generic, { bindings })
217
- case SOPHIA_TYPES.variant:
218
- return transformVariant(value, generic, { bindings })
219
- }
220
-
221
- return `${value}`
222
- }
223
-
224
- export function transformVariant (value, generic, { bindings }) {
225
- const [[variant, variantArgs]] = typeof value === 'string' ? [[value, []]] : Object.entries(value)
226
- const [[v, type]] = Object.entries(generic.find(o => Object.keys(o)[0].toLowerCase() === variant.toLowerCase()))
227
- return `${v}${!type.length
228
- ? ''
229
- : `(${variantArgs.slice(0, type.length).map((el, i) => transform(type[i], el, {
230
- bindings
231
- }))})`
232
- }`
233
- }
234
-
235
- export function transformMap (value, generic, { bindings }) {
236
- if (!Array.isArray(value)) {
237
- if (value.entries) value = Array.from(value.entries())
238
- else if (value instanceof Object) value = Object.entries(value)
239
- }
240
-
241
- return [
242
- '{',
243
- value
244
- .map(([key, value]) => [
245
- `[${transform(generic[0], key, { bindings })}]`,
246
- transform(generic[1], value, { bindings })
247
- ].join(' = '))
248
- .join(),
249
- '}'
250
- ].join('')
251
- }
252
-
253
- // FUNCTION RETURN VALUE TRANSFORMATION ↓↓↓
254
-
255
- /**
256
- * Transform decoded data to JS type
257
- * @param aci
258
- * @param result
259
- * @param transformDecodedData
260
- * @return {*}
261
- */
262
- export function transformDecodedData (aci, result, { skipTransformDecoded = false, addressPrefix = 'ak', bindings } = {}) {
263
- if (skipTransformDecoded) return result
264
- const { t, generic } = readType(aci, { bindings })
265
-
266
- switch (t) {
267
- case SOPHIA_TYPES.bool:
268
- return !!result
64
+ return toBytes(field, true).toString('hex')
269
65
  case SOPHIA_TYPES.address:
270
- return result === 0
271
- ? 0
272
- : result
273
- case SOPHIA_TYPES.hash:
274
- case SOPHIA_TYPES.bytes:
275
- case SOPHIA_TYPES.signature:
276
- return result.split('#')[1]
277
- case SOPHIA_TYPES.map: {
278
- const [keyT, valueT] = generic
279
- return result
280
- .reduce(
281
- (acc, [key, val]) => {
282
- key = transformDecodedData(keyT, key, { bindings })
283
- val = transformDecodedData(valueT, val, { bindings })
284
- acc.push([key, val])
285
- return acc
286
- },
287
- []
288
- )
289
- }
290
- case SOPHIA_TYPES.option: {
291
- if (result === 'None') return undefined
292
- const [[variantType, [value]]] = Object.entries(result)
293
- return variantType === 'Some' ? transformDecodedData(generic, value, { bindings }) : undefined
294
- }
295
- case SOPHIA_TYPES.list:
296
- return result.map((value) => transformDecodedData(generic, value, { bindings }))
297
- case SOPHIA_TYPES.tuple:
298
- return result.map((value, i) => { return transformDecodedData(generic[i], value, { bindings }) })
299
- case SOPHIA_TYPES.record: {
300
- const genericMap = generic.reduce((acc, val) => ({ ...acc, [val.name]: { type: val.type } }), {})
301
- return Object.entries(result).reduce(
302
- (acc, [name, value]) =>
303
- ({
304
- ...acc,
305
- [name]: transformDecodedData(genericMap[name].type, value, { bindings })
306
- }),
307
- {}
308
- )
309
- }
310
- }
311
- return result
312
- }
313
-
314
- // FUNCTION ARGUMENTS VALIDATION ↓↓↓
315
-
316
- /**
317
- * Prepare Joi validation schema for sophia types
318
- * @param type
319
- * @param bindings
320
- * @return {Object} JoiSchema
321
- */
322
- export function prepareSchema (type, { bindings } = {}) {
323
- const { t, generic } = readType(type, { bindings })
324
-
325
- switch (t) {
326
- case SOPHIA_TYPES.int:
327
- return Joi.number().error(getJoiErrorMsg)
328
- case SOPHIA_TYPES.variant:
329
- return Joi.alternatives().try([
330
- Joi.string().valid(
331
- ...generic.reduce((acc, el) => {
332
- const [[t, g]] = Object.entries(el)
333
- if (!g || !g.length) acc.push(t)
334
- return acc
335
- }, [])
336
- ),
337
- Joi.object(generic
338
- .reduce(
339
- (acc, el) => {
340
- const variant = Object.keys(el)[0]
341
- return { ...acc, [variant]: Joi.array() }
342
- },
343
- {})
344
- ).or(...generic.map(e => Object.keys(e)[0]))
345
- ])
346
- case SOPHIA_TYPES.ChainTtl:
347
- return Joi.string().error(getJoiErrorMsg)
66
+ return addressFromDecimal(field)
348
67
  case SOPHIA_TYPES.string:
349
- return Joi.string().error(getJoiErrorMsg)
350
- case SOPHIA_TYPES.address:
351
- return Joi.string().regex(/^(ak_|ct_|ok_|oq_)/).error(getJoiErrorMsg)
352
- case SOPHIA_TYPES.bool:
353
- return Joi.boolean().error(getJoiErrorMsg)
354
- case SOPHIA_TYPES.list:
355
- return Joi.array().items(prepareSchema(generic, { bindings })).error(getJoiErrorMsg)
356
- case SOPHIA_TYPES.tuple:
357
- return Joi.array().ordered(generic.map(type => prepareSchema(type, { bindings }).required())).label('Tuple argument').error(getJoiErrorMsg)
358
- case SOPHIA_TYPES.record:
359
- return Joi.object(
360
- generic.reduce((acc, { name, type }) => ({ ...acc, [name]: prepareSchema(type, { bindings }) }), {})
361
- ).error(getJoiErrorMsg)
362
- case SOPHIA_TYPES.hash:
363
- return JoiBinary.binary().bufferCheck(32).error(getJoiErrorMsg)
364
- case SOPHIA_TYPES.bytes:
365
- return JoiBinary.binary().bufferCheck(generic).error(getJoiErrorMsg)
366
- case SOPHIA_TYPES.signature:
367
- return JoiBinary.binary().bufferCheck(64).error(getJoiErrorMsg)
368
- case SOPHIA_TYPES.option:
369
- return prepareSchema(generic, { bindings }).optional().error(getJoiErrorMsg)
370
- // @Todo Need to transform Map to Array of arrays before validating it
371
- // case SOPHIA_TYPES.map:
372
- // return Joi.array().items(Joi.array().ordered(generic.map(type => prepareSchema(type))))
68
+ return decode(field).toString('utf-8')
373
69
  default:
374
- return Joi.any()
375
- }
376
- }
377
-
378
- /**
379
- * Parse Joi validation error message
380
- * @param errors
381
- * @return {Object} JoiError
382
- */
383
- export function getJoiErrorMsg (errors) {
384
- return errors.map(err => {
385
- const { path, type, context } = err
386
- let value = Object.prototype.hasOwnProperty.call(context, 'value') ? context.value : context.label
387
- value = typeof value === 'object' ? JSON.stringify(value).slice(1).slice(0, -1) : value
388
- switch (type) {
389
- case 'string.base':
390
- return ({ ...err, message: `Value "${value}" at path: [${path}] not a string` })
391
- case 'number.base':
392
- return ({ ...err, message: `Value "${value}" at path: [${path}] not a number` })
393
- case 'boolean.base':
394
- return ({ ...err, message: `Value "${value}" at path: [${path}] not a boolean` })
395
- case 'array.base':
396
- return ({ ...err, message: `Value "${value}" at path: [${path}] not a array` })
397
- case 'object.base':
398
- return ({ ...err, message: `Value '${value}' at path: [${path}] not a object` })
399
- case 'object.type':
400
- return ({ ...err, message: `Value '${value}' at path: [${path}] not a ${context.type}` })
401
- case 'binary.bufferCheck':
402
- return ({
403
- ...err,
404
- message: `Value '${Buffer.from(value).toString('hex')}' at path: [${path}] not a ${context.size} bytes`
405
- })
406
- default:
407
- return err
408
- }
409
- })
410
- }
411
-
412
- /**
413
- * Custom Joi Validator for binary type
414
- */
415
- const JoiBinary = Joi.extend((joi) => ({
416
- name: 'binary',
417
- base: joi.any(),
418
- pre (value, state, options) {
419
- if (options.convert && typeof value === 'string') {
420
- if (isAddressValid(value)) {
421
- return decode(value)
422
- }
423
- try {
424
- return Buffer.from(value, 'hex')
425
- } catch (e) { return undefined }
426
- }
427
-
428
- return Buffer.from(value)
429
- },
430
- rules: [
431
- {
432
- name: 'bufferCheck',
433
- params: {
434
- size: joi.number().required()
435
- },
436
- validate (params, value, state, options) {
437
- if (!Buffer.isBuffer(value)) {
438
- return this.createError('binary.base', { value }, state, options)
439
- }
440
- if (value.length !== params.size) {
441
- return this.createError('binary.bufferCheck', { value, size: params.size }, state, options)
442
- }
443
-
444
- return value
445
- }
446
- }
447
- ]
448
- }))
449
-
450
- /**
451
- * Validation contract function arguments
452
- * @param aci
453
- * @param params
454
- */
455
- export function validateArguments (aci, params) {
456
- const validationSchema = Joi.array().ordered(
457
- aci.arguments
458
- .map(({ type }, i) => prepareSchema(type, { bindings: aci.bindings }).label(`[${params[i]}]`))
459
- ).sparse(true).label('Argument')
460
- const { error } = Joi.validate(params, validationSchema, { abortEarly: false })
461
- if (error) {
462
- throw error
70
+ return toBytes(field, true)
463
71
  }
464
72
  }
@@ -52,12 +52,29 @@ export default AsyncInit.compose(ContractBase, {
52
52
  compilerUrl = compilerUrl.replace(/\/$/, '')
53
53
  const client = await genSwaggerClient(`${compilerUrl}/api`, {
54
54
  disableBigNumbers: true,
55
- disableCaseConversion: true
55
+ disableCaseConversion: true,
56
+ responseInterceptor: response => {
57
+ if (response.ok) return
58
+ let message = `${new URL(response.url).pathname.slice(1)} error`
59
+ if (response.body.reason) {
60
+ message += ': ' + response.body.reason +
61
+ (response.body.parameter ? ` in ${response.body.parameter}` : '') +
62
+ // TODO: revising after improving documentation https://github.com/aeternity/aesophia_http/issues/78
63
+ (response.body.info ? ` (${JSON.stringify(response.body.info)})` : '')
64
+ }
65
+ if (Array.isArray(response.body)) {
66
+ message += ':\n' + response.body
67
+ .map(e => `${e.type}:${e.pos.line}:${e.pos.col}: ${e.message}${e.context ? `(${e.context})` : ''}`)
68
+ .map(e => e.trim()) // TODO: remove after fixing https://github.com/aeternity/aesophia_http/issues/80
69
+ .join('\n')
70
+ }
71
+ response.statusText = message
72
+ return response
73
+ }
56
74
  })
57
75
  this.compilerVersion = client.spec.info.version
58
76
  this._compilerApi = client.api
59
77
 
60
- this._isCompiler6 = semverSatisfies(this.compilerVersion, COMPILER_6_GE_VERSION, COMPILER_LT_VERSION)
61
78
  if (ignoreVersion) return
62
79
  if (!semverSatisfies(this.compilerVersion, COMPILER_GE_VERSION, COMPILER_LT_VERSION)) {
63
80
  throw new Error(`Unsupported compiler version ${this.compilerVersion}. ` +
@@ -74,6 +91,17 @@ export default AsyncInit.compose(ContractBase, {
74
91
  this._ensureCompilerReady()
75
92
  return Promise.resolve(this.compilerVersion)
76
93
  },
94
+ /**
95
+ * Encode call data for contract call
96
+ * @function
97
+ * @category async
98
+ * @param {String} source Contract source code
99
+ * @param {String} name Name of function to call
100
+ * @param {Array} args Argument's for call
101
+ * @param {Object} [options={}] Options
102
+ * @param {Object} [options.filesystem={}] Contract external namespaces map
103
+ * @return {Promise<String>}
104
+ */
77
105
  async contractEncodeCallDataAPI (source, name, args = [], options) {
78
106
  this._ensureCompilerReady()
79
107
  const { calldata } = await this._compilerApi.encodeCalldata({
@@ -109,6 +137,20 @@ export default AsyncInit.compose(ContractBase, {
109
137
  options: this._prepareCompilerOptions(options)
110
138
  })
111
139
  },
140
+ /**
141
+ * Decode contract call result data
142
+ * @function
143
+ * @category async
144
+ * @param {String} source - source code
145
+ * @param {String } fn - function name
146
+ * @param {String} callValue - result call data
147
+ * @param {String} callResult - result status
148
+ * @param {Object} [options={}] Options
149
+ * @param {Object} [options.filesystem={}] Contract external namespaces map
150
+ * @return {Promise<String>} Result object
151
+ * @example
152
+ * const decodedData = await sdk.contractDecodeCallResultAPI(SourceCode ,'functionName', 'cb_asdasdasd...', 'ok|revert')lt
153
+ */
112
154
  contractDecodeCallResultAPI (source, fn, callValue, callResult, options) {
113
155
  this._ensureCompilerReady()
114
156
  return this._compilerApi.decodeCallResult({
@@ -145,6 +187,5 @@ export default AsyncInit.compose(ContractBase, {
145
187
  }
146
188
  })
147
189
 
148
- const COMPILER_GE_VERSION = '4.1.0'
149
- const COMPILER_6_GE_VERSION = '6.0.0'
190
+ const COMPILER_GE_VERSION = '6.0.0'
150
191
  const COMPILER_LT_VERSION = '7.0.0'
@@ -1,7 +1,5 @@
1
1
  import BigNumber from 'bignumber.js'
2
- import { MAX_AUTH_FUN_GAS, TX_TYPE } from '../../tx/builder/schema'
3
- import { buildTx } from '../../tx/builder'
4
- import { hash } from '../../utils/crypto'
2
+ import { MAX_AUTH_FUN_GAS } from '../../tx/builder/schema'
5
3
 
6
4
  export const prepareGaParams = (ins) => async (authData, authFnName) => {
7
5
  if (typeof authData !== 'object') throw new Error('AuthData must be an object')
@@ -12,14 +10,6 @@ export const prepareGaParams = (ins) => async (authData, authFnName) => {
12
10
  return { authCallData: authData.callData, gas }
13
11
  } else {
14
12
  if (!authData.source || !authData.args) throw new Error('Auth data must contain source code and arguments.')
15
- return { authCallData: await ins.contractEncodeCall(authData.source, authFnName, authData.args), gas }
13
+ return { authCallData: await ins.contractEncodeCallDataAPI(authData.source, authFnName, authData.args), gas }
16
14
  }
17
15
  }
18
-
19
- export const getContractAuthFan = (ins) => async (source, fnName) => {
20
- const { bytecode } = await ins.contractCompile(source)
21
-
22
- return { bytecode, authFun: hash(fnName) }
23
- }
24
-
25
- export const wrapInEmptySignedTx = (rlp) => buildTx({ encodedTx: rlp, signatures: [] }, TX_TYPE.signed)
@@ -22,13 +22,11 @@
22
22
  * @export GeneralizeAccount
23
23
  * @example import { GeneralizeAccount } from '@aeternity/aepp-sdk'
24
24
  */
25
- import * as R from 'ramda'
26
-
27
25
  import { ContractAPI } from '../../ae/contract'
28
26
  import { TX_TYPE } from '../../tx/builder/schema'
29
- import { buildTx } from '../../tx/builder'
30
- import { getContractAuthFan, prepareGaParams, wrapInEmptySignedTx } from './helpers'
31
- import { assertedType, decodeBase64Check } from '../../utils/crypto'
27
+ import { buildTx, unpackTx } from '../../tx/builder'
28
+ import { prepareGaParams } from './helpers'
29
+ import { hash } from '../../utils/crypto'
32
30
 
33
31
  /**
34
32
  * GeneralizeAccount Stamp
@@ -81,26 +79,31 @@ async function isGA (address) {
81
79
  * @return {Promise<Readonly<{result: *, owner: *, createdAt: Date, address, rawTx: *, transaction: *}>>}
82
80
  */
83
81
  async function createGeneralizeAccount (authFnName, source, args = [], options = {}) {
84
- const opt = R.merge(this.Ae.defaults, options)
82
+ const opt = { ...this.Ae.defaults, ...options }
85
83
  const ownerId = await this.address(opt)
86
84
 
87
85
  if (await this.isGA(ownerId)) throw new Error(`Account ${ownerId} is already GA`)
88
86
 
89
- const { authFun, bytecode } = await getContractAuthFan(this)(source, authFnName)
90
- const callData = await this.contractEncodeCall(source, 'init', args)
91
-
92
- const { tx, contractId } = await this.gaAttachTx(R.merge(opt, { ownerId, code: bytecode, callData, authFun }))
87
+ const { tx, contractId } = await this.gaAttachTx({
88
+ ...opt,
89
+ ownerId,
90
+ code: (await this.contractCompile(source)).bytecode,
91
+ callData: await this.contractEncodeCallDataAPI(source, 'init', args),
92
+ authFun: hash(authFnName)
93
+ })
93
94
 
94
- const { hash, rawTx } = await this.send(tx, opt)
95
+ const { hash: transaction, rawTx } = await this.send(tx, opt)
95
96
 
96
97
  return Object.freeze({
97
98
  owner: ownerId,
98
- transaction: hash,
99
+ transaction,
99
100
  rawTx,
100
101
  gaContractId: contractId
101
102
  })
102
103
  }
103
104
 
105
+ const wrapInEmptySignedTx = (tx) => buildTx({ encodedTx: tx, signatures: [] }, TX_TYPE.signed)
106
+
104
107
  /**
105
108
  * Create a metaTx transaction
106
109
  * @alias module:@aeternity/aepp-sdk/es/contract/ga
@@ -115,33 +118,26 @@ async function createMetaTx (rawTransaction, authData, authFnName, options = {})
115
118
  if (!authData) throw new Error('authData is required')
116
119
  // Check if authData is callData or if it's an object prepare a callData from source and args
117
120
  const { authCallData, gas } = await prepareGaParams(this)(authData, authFnName)
118
- const opt = R.merge(this.Ae.defaults, options)
119
- // Get transaction rlp binary
120
- const rlpBinaryTx = decodeBase64Check(assertedType(rawTransaction, 'tx'))
121
- // Wrap in SIGNED tx with empty signatures
122
- const { rlpEncoded } = wrapInEmptySignedTx(rlpBinaryTx)
123
- // Get abi
121
+ const opt = { ...this.Ae.defaults, ...options }
124
122
  const { abiVersion } = await this.getVmVersion(TX_TYPE.contractCall)
125
- // Prepare params for META tx
123
+ const wrappedTx = wrapInEmptySignedTx(unpackTx(rawTransaction))
126
124
  const params = {
127
125
  ...opt,
128
- tx: rlpEncoded,
126
+ tx: {
127
+ ...wrappedTx,
128
+ tx: wrappedTx.txObject
129
+ },
129
130
  gaId: await this.address(opt),
130
131
  abiVersion: abiVersion,
131
132
  authData: authCallData,
132
133
  gas,
133
134
  vsn: 2
134
135
  }
135
- // Calculate fee, get absolute ttl (ttl + height), get account nonce
136
136
  const { fee } = await this.prepareTxParams(TX_TYPE.gaMeta, params)
137
- // Build META tx
138
137
  const { rlpEncoded: metaTxRlp } = buildTx(
139
138
  { ...params, fee: `${fee}` },
140
139
  TX_TYPE.gaMeta,
141
140
  { vsn: 2 }
142
141
  )
143
- // Wrap in empty signed tx
144
- const { tx } = wrapInEmptySignedTx(metaTxRlp)
145
- // Send tx to the chain
146
- return tx
142
+ return wrapInEmptySignedTx(metaTxRlp).tx
147
143
  }