@aeternity/aepp-sdk 8.2.1 → 10.0.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.
Files changed (159) hide show
  1. package/CHANGELOG.md +216 -337
  2. package/README.md +16 -9
  3. package/dist/aepp-sdk.browser-script.js +1 -1
  4. package/dist/aepp-sdk.browser-script.js.LICENSE.txt +0 -9
  5. package/dist/aepp-sdk.browser-script.js.map +1 -1
  6. package/dist/aepp-sdk.browser.js +1 -1
  7. package/dist/aepp-sdk.browser.js.map +1 -1
  8. package/dist/aepp-sdk.js +1 -1
  9. package/dist/aepp-sdk.js.map +1 -1
  10. package/es/account/base.js +36 -120
  11. package/es/account/base.js.map +1 -1
  12. package/es/account/memory.js +17 -19
  13. package/es/account/memory.js.map +1 -1
  14. package/es/account/multiple.js +79 -156
  15. package/es/account/multiple.js.map +1 -1
  16. package/es/ae/aens.js +205 -626
  17. package/es/ae/aens.js.map +1 -1
  18. package/es/ae/contract.js +114 -918
  19. package/es/ae/contract.js.map +1 -1
  20. package/es/ae/index.js +90 -250
  21. package/es/ae/index.js.map +1 -1
  22. package/es/ae/oracle.js +136 -504
  23. package/es/ae/oracle.js.map +1 -1
  24. package/es/ae/universal.js.map +1 -1
  25. package/es/chain/index.js +12 -27
  26. package/es/chain/index.js.map +1 -1
  27. package/es/chain/node.js +289 -1020
  28. package/es/chain/node.js.map +1 -1
  29. package/es/channel/handlers.js +597 -1086
  30. package/es/channel/handlers.js.map +1 -1
  31. package/es/channel/index.js +238 -465
  32. package/es/channel/index.js.map +1 -1
  33. package/es/channel/internal.js +129 -301
  34. package/es/channel/internal.js.map +1 -1
  35. package/es/contract/aci/index.js +328 -495
  36. package/es/contract/aci/index.js.map +1 -1
  37. package/es/contract/aci/transformation.js +35 -711
  38. package/es/contract/aci/transformation.js.map +1 -1
  39. package/es/contract/compiler.js +131 -203
  40. package/es/contract/compiler.js.map +1 -1
  41. package/es/contract/ga/helpers.js +17 -122
  42. package/es/contract/ga/helpers.js.map +1 -1
  43. package/es/contract/ga/index.js +108 -249
  44. package/es/contract/ga/index.js.map +1 -1
  45. package/es/contract/index.js +7 -3
  46. package/es/contract/index.js.map +1 -1
  47. package/es/index.js +3 -3
  48. package/es/index.js.map +1 -1
  49. package/es/node-pool/index.js +57 -74
  50. package/es/node-pool/index.js.map +1 -1
  51. package/es/node.js +65 -161
  52. package/es/node.js.map +1 -1
  53. package/es/other.d.ts +1 -1
  54. package/es/tx/builder/helpers.js +62 -115
  55. package/es/tx/builder/helpers.js.map +1 -1
  56. package/es/tx/builder/index.js +218 -309
  57. package/es/tx/builder/index.js.map +1 -1
  58. package/es/tx/builder/schema.js +586 -573
  59. package/es/tx/builder/schema.js.map +1 -1
  60. package/es/tx/index.js +102 -13
  61. package/es/tx/index.js.map +1 -1
  62. package/es/tx/tx-object.js +114 -138
  63. package/es/tx/tx-object.js.map +1 -1
  64. package/es/tx/tx.js +810 -1586
  65. package/es/tx/tx.js.map +1 -1
  66. package/es/tx/validator.js +191 -426
  67. package/es/tx/validator.js.map +1 -1
  68. package/es/utils/aepp-wallet-communication/connection/browser-runtime.js +20 -23
  69. package/es/utils/aepp-wallet-communication/connection/browser-runtime.js.map +1 -1
  70. package/es/utils/aepp-wallet-communication/connection/browser-window-message.js +53 -80
  71. package/es/utils/aepp-wallet-communication/connection/browser-window-message.js.map +1 -1
  72. package/es/utils/aepp-wallet-communication/connection/index.js +2 -1
  73. package/es/utils/aepp-wallet-communication/connection/index.js.map +1 -1
  74. package/es/utils/aepp-wallet-communication/content-script-bridge.js +24 -19
  75. package/es/utils/aepp-wallet-communication/content-script-bridge.js.map +1 -1
  76. package/es/utils/aepp-wallet-communication/helpers.js +60 -105
  77. package/es/utils/aepp-wallet-communication/helpers.js.map +1 -1
  78. package/es/utils/aepp-wallet-communication/rpc/aepp-rpc.js +191 -514
  79. package/es/utils/aepp-wallet-communication/rpc/aepp-rpc.js.map +1 -1
  80. package/es/utils/aepp-wallet-communication/rpc/rpc-client.js +78 -93
  81. package/es/utils/aepp-wallet-communication/rpc/rpc-client.js.map +1 -1
  82. package/es/utils/aepp-wallet-communication/rpc/wallet-rpc.js +381 -613
  83. package/es/utils/aepp-wallet-communication/rpc/wallet-rpc.js.map +1 -1
  84. package/es/utils/aepp-wallet-communication/schema.js +43 -39
  85. package/es/utils/aepp-wallet-communication/schema.js.map +1 -1
  86. package/es/utils/aepp-wallet-communication/wallet-detector.js +32 -58
  87. package/es/utils/aepp-wallet-communication/wallet-detector.js.map +1 -1
  88. package/es/utils/amount-formatter.js +41 -61
  89. package/es/utils/amount-formatter.js.map +1 -1
  90. package/es/utils/async-init.js +28 -64
  91. package/es/utils/async-init.js.map +1 -1
  92. package/es/utils/bignumber.js +3 -11
  93. package/es/utils/bignumber.js.map +1 -1
  94. package/es/utils/bytes.js +5 -9
  95. package/es/utils/bytes.js.map +1 -1
  96. package/es/utils/crypto.js +41 -106
  97. package/es/utils/crypto.js.map +1 -1
  98. package/es/utils/hd-wallet.js +45 -81
  99. package/es/utils/hd-wallet.js.map +1 -1
  100. package/es/utils/json-big.js +16 -49
  101. package/es/utils/json-big.js.map +1 -1
  102. package/es/utils/keystore.js +81 -246
  103. package/es/utils/keystore.js.map +1 -1
  104. package/es/utils/mptree.js +88 -134
  105. package/es/utils/mptree.js.map +1 -1
  106. package/es/utils/other.js +10 -60
  107. package/es/utils/other.js.map +1 -1
  108. package/es/utils/semver-satisfies.js +9 -28
  109. package/es/utils/semver-satisfies.js.map +1 -1
  110. package/es/utils/string.js +4 -13
  111. package/es/utils/string.js.map +1 -1
  112. package/es/utils/swagger.js +87 -224
  113. package/es/utils/swagger.js.map +1 -1
  114. package/package.json +51 -44
  115. package/src/account/base.js +11 -10
  116. package/src/account/multiple.js +24 -18
  117. package/src/ae/aens.js +64 -61
  118. package/src/ae/contract.js +71 -248
  119. package/src/ae/index.js +34 -9
  120. package/src/ae/oracle.js +30 -22
  121. package/src/ae/universal.js +3 -1
  122. package/src/chain/index.js +10 -16
  123. package/src/chain/node.js +38 -38
  124. package/src/channel/handlers.js +10 -4
  125. package/src/channel/index.js +44 -20
  126. package/src/contract/aci/index.js +234 -112
  127. package/src/contract/aci/transformation.js +30 -422
  128. package/src/contract/compiler.js +50 -5
  129. package/src/contract/ga/helpers.js +6 -14
  130. package/src/contract/ga/index.js +28 -28
  131. package/src/contract/index.js +6 -2
  132. package/src/index.js +4 -4
  133. package/src/node-pool/index.js +24 -13
  134. package/src/node.js +29 -30
  135. package/src/tx/builder/helpers.js +31 -56
  136. package/src/tx/builder/index.js +67 -28
  137. package/src/tx/builder/schema.js +79 -121
  138. package/src/tx/index.js +101 -12
  139. package/src/tx/tx-object.js +25 -8
  140. package/src/tx/tx.js +229 -150
  141. package/src/tx/validator.js +134 -202
  142. package/src/utils/aepp-wallet-communication/connection/browser-runtime.js +3 -2
  143. package/src/utils/aepp-wallet-communication/connection/browser-window-message.js +25 -7
  144. package/src/utils/aepp-wallet-communication/connection/index.js +2 -1
  145. package/src/utils/aepp-wallet-communication/content-script-bridge.js +10 -4
  146. package/src/utils/aepp-wallet-communication/helpers.js +4 -2
  147. package/src/utils/aepp-wallet-communication/rpc/aepp-rpc.js +33 -12
  148. package/src/utils/aepp-wallet-communication/rpc/rpc-client.js +9 -5
  149. package/src/utils/aepp-wallet-communication/rpc/wallet-rpc.js +59 -29
  150. package/src/utils/aepp-wallet-communication/schema.js +1 -3
  151. package/src/utils/aepp-wallet-communication/wallet-detector.js +4 -1
  152. package/src/utils/amount-formatter.ts +1 -1
  153. package/src/utils/bignumber.ts +2 -1
  154. package/src/utils/crypto.js +4 -68
  155. package/src/utils/keystore.js +10 -2
  156. package/src/utils/other.ts +1 -1
  157. package/src/utils/semver-satisfies.ts +1 -1
  158. package/src/utils/swagger.js +22 -10
  159. package/src/contract/aci/helpers.js +0 -140
@@ -24,172 +24,294 @@
24
24
 
25
25
  import * as R from 'ramda'
26
26
  import BigNumber from 'bignumber.js'
27
+ import { Encoder as Calldata } from '@aeternity/aepp-calldata'
28
+ import { decodeEvents } from './transformation'
29
+ import { DRY_RUN_ACCOUNT, DEPOSIT } from '../../tx/builder/schema'
30
+ import TxObject from '../../tx/tx-object'
31
+ import { decode } from '../../tx/builder/helpers'
27
32
 
28
- import {
29
- buildContractMethods,
30
- decodeCallResult,
31
- decodeEvents,
32
- getFunctionACI,
33
- prepareArgsForEncode as prepareArgs
34
- } from './helpers'
35
- import { isAddressValid } from '../../utils/crypto'
33
+ /**
34
+ * Get function schema from contract ACI object
35
+ * @param {Object} aci Contract ACI object
36
+ * @param {String} name Function name
37
+ * @param external
38
+ * @return {Object} function ACI
39
+ */
40
+ function getFunctionACI (aci, name, external) {
41
+ const fn = aci.functions.find(f => f.name === name)
42
+ if (!fn && name !== 'init') throw new Error(`Function ${name} doesn't exist in contract`)
43
+
44
+ return {
45
+ ...fn,
46
+ bindings: [
47
+ {
48
+ state: aci.state,
49
+ type_defs: aci.type_defs,
50
+ name: aci.name
51
+ },
52
+ ...external.map(R.pick(['state', 'type_defs', 'name']))
53
+ ],
54
+ event: aci.event ? aci.event.variant : []
55
+ }
56
+ }
36
57
 
37
58
  /**
38
- * Generate contract ACI object with predefined js methods for contract usage - can be used for creating a reference to already deployed contracts
59
+ * Generate contract ACI object with predefined js methods for contract usage - can be used for
60
+ * creating a reference to already deployed contracts
39
61
  * @alias module:@aeternity/aepp-sdk/es/contract/aci
40
- * @param {String} source Contract source code
41
62
  * @param {Object} [options={}] Options object
42
- * @param {String} [options.aci] Contract ACI
63
+ * @param {String} [options.source] Contract source code
64
+ * @param {String} [options.bytecode] Contract bytecode
65
+ * @param {Object} [options.aci] Contract ACI
43
66
  * @param {String} [options.contractAddress] Contract address
44
67
  * @param {Object} [options.filesystem] Contact source external namespaces map
45
- * @param {Object} [options.forceCodeCheck=true] Don't check contract code
46
- * @param {Object} [options.opt] Contract options
68
+ * @param {Boolean} [options.validateBytecode] Compare source code with on-chain version
47
69
  * @return {ContractInstance} JS Contract API
48
70
  * @example
49
- * const contractIns = await client.getContractInstance(sourceCode)
71
+ * const contractIns = await client.getContractInstance({ source })
50
72
  * await contractIns.deploy([321]) or await contractIns.methods.init(321)
51
- * const callResult = await contractIns.call('setState', [123]) or await contractIns.methods.setState.send(123, options)
52
- * const staticCallResult = await contractIns.call('setState', [123], { callStatic: true }) or await contractIns.methods.setState.get(123, options)
73
+ * const callResult = await contractIns.call('setState', [123]) or
74
+ * await contractIns.methods.setState.send(123, options)
75
+ * const staticCallResult = await contractIns.call('setState', [123], { callStatic: true }) or
76
+ * await contractIns.methods.setState.get(123, options)
53
77
  * Also you can call contract like: await contractIns.methods.setState(123, options)
54
- * Then sdk decide to make on-chain or static call(dry-run API) transaction based on function is stateful or not
78
+ * Then sdk decide to make on-chain or static call(dry-run API) transaction based on function is
79
+ * stateful or not
55
80
  */
56
- export default async function getContractInstance (source, { aci, contractAddress, filesystem = {}, forceCodeCheck = true, opt } = {}) {
57
- aci = aci || await this.contractGetACI(source, { filesystem })
58
- if (contractAddress) contractAddress = await this.resolveName(contractAddress, 'ct', { resolveByNode: true })
59
- const defaultOptions = {
60
- ...this.Ae.defaults,
61
- skipArgsConvert: false,
62
- skipTransformDecoded: false,
63
- callStatic: false,
64
- waitMined: true,
65
- verify: false,
66
- filesystem
81
+ export default async function getContractInstance ({
82
+ source,
83
+ bytecode,
84
+ aci,
85
+ contractAddress,
86
+ filesystem = {},
87
+ validateBytecode,
88
+ ...otherOptions
89
+ } = {}) {
90
+ aci = aci || (source && await this.contractGetACI(source, { filesystem }))
91
+ if (!aci) throw new Error('Either ACI or source code is required')
92
+ contractAddress = contractAddress && await this.resolveName(
93
+ contractAddress, 'contract_pubkey', { resolveByNode: true }
94
+ )
95
+ if (!contractAddress && !source && !bytecode) throw new Error('Can\'t create instance by ACI without address')
96
+
97
+ if (contractAddress) {
98
+ const contract = await this.getContract(contractAddress).catch(() => null)
99
+ if (!contract) throw new Error(`Contract with address ${contractAddress} not found on-chain`)
100
+ if (!contract.active) throw new Error(`Contract with address ${contractAddress} not active`)
67
101
  }
102
+
68
103
  const instance = {
69
104
  interface: R.defaultTo(null, R.prop('interface', aci)),
70
105
  aci: R.defaultTo(null, R.path(['encoded_aci', 'contract'], aci)),
71
- externalAci: aci.external_encoded_aci ? aci.external_encoded_aci.map(a => a.contract || a.namespace) : [],
106
+ calldata: new Calldata([aci.encoded_aci, ...aci.external_encoded_aci]),
107
+ externalAci: (aci.external_encoded_aci ?? []).map(a => a.contract || a.namespace),
72
108
  source,
73
- compiled: null,
109
+ bytecode,
74
110
  deployInfo: { address: contractAddress },
75
- options: R.merge(defaultOptions, opt),
76
- compilerVersion: this.compilerVersion,
77
- setOptions (opt) {
78
- this.options = R.merge(this.options, opt)
79
- }
111
+ options: {
112
+ ...this.Ae.defaults,
113
+ callStatic: false,
114
+ filesystem,
115
+ ...otherOptions
116
+ },
117
+ compilerVersion: this.compilerVersion
80
118
  }
81
119
 
82
- // Check for valid contract address and contract code
83
- if (contractAddress) {
84
- if (!isAddressValid(contractAddress, 'ct')) throw new Error('Invalid contract address')
85
- const contract = await this.getContract(contractAddress).catch(e => null)
86
- if (!contract || !contract.active) throw new Error(`Contract with address ${contractAddress} not found on-chain or not active`)
87
- if (!forceCodeCheck) {
88
- const onChanByteCode = (await this.getContractByteCode(contractAddress)).bytecode
89
- const isCorrespondingBytecode = await this.validateByteCodeAPI(onChanByteCode, instance.source, instance.options).catch(e => false)
90
- if (!isCorrespondingBytecode) throw new Error('Contract source do not correspond to the contract bytecode deployed on the chain')
91
- }
120
+ if (validateBytecode) {
121
+ if (!contractAddress) throw new Error('Can\'t validate bytecode without contract address')
122
+ const onChanBytecode = (await this.getContractByteCode(contractAddress)).bytecode
123
+ const isValid = (source && await this
124
+ .validateByteCodeAPI(onChanBytecode, source, instance.options).catch(() => false)) ||
125
+ bytecode === onChanBytecode
126
+ if (!isValid) throw new Error(`Contract ${source ? 'source' : 'bytecode'} do not correspond to the bytecode deployed on the chain`)
92
127
  }
93
128
 
94
129
  /**
95
130
  * Compile contract
96
131
  * @alias module:@aeternity/aepp-sdk/es/contract/aci
97
132
  * @rtype () => ContractInstance: Object
98
- * @return {ContractInstance} Contract ACI object with predefined js methods for contract usage
133
+ * @return {String} bytecode bytecode
99
134
  */
100
- instance.compile = compile({ client: this, instance })
135
+ instance.compile = async (options = {}) => {
136
+ if (instance.bytecode) throw new Error('Contract already compiled')
137
+ if (!instance.source) throw new Error('Can\'t compile without source code')
138
+ const { bytecode } = await this.contractCompile(
139
+ instance.source, { ...instance.options, ...options }
140
+ )
141
+ instance.bytecode = bytecode
142
+ return instance.bytecode
143
+ }
144
+
145
+ const sendAndProcess = async (tx, options) => {
146
+ const txData = await this.send(tx, options)
147
+ const result = {
148
+ hash: txData.hash, tx: TxObject({ tx: txData.rawTx }), txData, rawTx: txData.rawTx
149
+ }
150
+ if (options.waitMined === false) return result
151
+ const txInfo = await this.getTxInfo(txData.hash)
152
+ await handleCallError(txInfo)
153
+ return { ...result, result: txInfo }
154
+ }
155
+
156
+ const handleCallError = ({ returnType, returnValue }) => {
157
+ let message
158
+ // TODO: ensure that it works correctly https://github.com/aeternity/aepp-calldata-js/issues/88
159
+ switch (returnType) {
160
+ case 'ok': return
161
+ case 'revert':
162
+ message = instance.calldata.decodeFateString(returnValue)
163
+ break
164
+ case 'error':
165
+ message = decode(returnValue).toString()
166
+ break
167
+ default: throw new Error(`Unknown returnType: ${returnType}`)
168
+ }
169
+ throw new Error(`Invocation failed${message ? `: "${message}"` : ''}`)
170
+ }
171
+
101
172
  /**
102
173
  * Deploy contract
103
174
  * @alias module:@aeternity/aepp-sdk/es/contract/aci
104
- * @rtype (init: Array, options: Object = { skipArgsConvert: false }) => ContractInstance: Object
105
- * @param {Array} init Contract init function arguments array
106
- * @param {Object} [options={}] options Options object
107
- * @param {Boolean} [options.skipArgsConvert=false] Skip Validation and Transforming arguments before prepare call-data
108
- * @return {ContractInstance} Contract ACI object with predefined js methods for contract usage
175
+ * @rtype (init: Array, options: Object) => ContractInstance: Object
176
+ * @param {Array} params Contract init function arguments array
177
+ * @param {Object} [options] options
178
+ * @return {Object} deploy info
109
179
  */
110
- instance.deploy = deploy({ client: this, instance })
180
+ instance.deploy = async (params = [], options) => {
181
+ const opt = { ...instance.options, ...options, deposit: DEPOSIT }
182
+ if (!instance.bytecode) await instance.compile(opt)
183
+ if (opt.callStatic) return instance.call('init', params, opt)
184
+ if (instance.deployInfo.address) throw new Error('Contract already deployed')
185
+
186
+ const ownerId = await this.address(opt)
187
+ const { tx, contractId } = await this.contractCreateTx({
188
+ ...opt,
189
+ callData: instance.calldata.encode(instance.aci.name, 'init', params),
190
+ code: instance.bytecode,
191
+ ownerId
192
+ })
193
+ const { hash, rawTx, result, txData } = await sendAndProcess(tx, opt)
194
+ instance.deployInfo = Object.freeze({
195
+ result,
196
+ owner: ownerId,
197
+ transaction: hash,
198
+ rawTx,
199
+ txData,
200
+ address: contractId,
201
+ call: (name, args, options) =>
202
+ this.contractCall(instance.source, contractId, name, args, { ...opt, ...options }),
203
+ callStatic: (name, args, options) =>
204
+ this.contractCallStatic(instance.source, contractId, name, args, { ...opt, ...options }),
205
+ createdAt: new Date()
206
+ })
207
+ return instance.deployInfo
208
+ }
209
+
111
210
  /**
112
211
  * Call contract function
113
212
  * @alias module:@aeternity/aepp-sdk/es/contract/aci
114
- * @rtype (init: Array, options: Object = { skipArgsConvert: false, skipTransformDecoded: false, callStatic: false }) => CallResult: Object
213
+ * @rtype (init: Array, options: Object = { callStatic: false }) => CallResult: Object
115
214
  * @param {String} fn Function name
116
215
  * @param {Array} params Array of function arguments
117
216
  * @param {Object} [options={}] Array of function arguments
118
- * @param {Boolean} [options.skipArgsConvert=false] Skip Validation and Transforming arguments before prepare call-data
119
- * @param {Boolean} [options.skipTransformDecoded=false] Skip Transform decoded data to JS type
120
217
  * @param {Boolean} [options.callStatic=false] Static function call
121
218
  * @return {Object} CallResult
122
219
  */
123
- instance.call = call({ client: this, instance })
220
+ instance.call = async (fn, params = [], options = {}) => {
221
+ const opt = { ...instance.options, ...options }
222
+ const fnACI = getFunctionACI(instance.aci, fn, instance.externalAci)
223
+ const contractId = instance.deployInfo.address
224
+
225
+ if (!fn) throw new Error('Function name is required')
226
+ if (fn === 'init' && !opt.callStatic) throw new Error('"init" can be called only via dryRun')
227
+ if (!contractId && fn !== 'init') throw new Error('You need to deploy contract before calling!')
228
+ if (
229
+ BigNumber(opt.amount).gt(0) &&
230
+ (Object.prototype.hasOwnProperty.call(fnACI, 'payable') && !fnACI.payable)
231
+ ) throw new Error(`You try to pay "${opt.amount}" to function "${fn}" which is not payable. Only payable function can accept tokens`)
232
+
233
+ const callerId = await this.address(opt).catch(error => {
234
+ if (opt.callStatic) return DRY_RUN_ACCOUNT.pub
235
+ else throw error
236
+ })
237
+ const callData = instance.calldata.encode(instance.aci.name, fn, params)
238
+
239
+ let res
240
+ if (opt.callStatic) {
241
+ if (typeof opt.top === 'number') {
242
+ opt.top = (await this.getKeyBlock(opt.top)).hash
243
+ }
244
+ const txOpt = {
245
+ ...opt,
246
+ callData,
247
+ nonce: opt.top && (await this.getAccount(callerId, { hash: opt.top })).nonce + 1
248
+ }
249
+ const tx = fn === 'init'
250
+ ? (await this.contractCreateTx({ ...txOpt, code: instance.bytecode, ownerId: callerId })).tx
251
+ : await this.contractCallTx({ ...txOpt, callerId, contractId })
252
+
253
+ const { callObj, ...dryRunOther } = await this.txDryRun(tx, callerId, opt)
254
+ await handleCallError(callObj)
255
+ res = { ...dryRunOther, tx: TxObject({ tx }), result: callObj }
256
+ } else {
257
+ const tx = await this.contractCallTx({ ...opt, callerId, contractId, callData })
258
+ res = await sendAndProcess(tx, opt)
259
+ }
260
+ if (opt.waitMined || opt.callStatic) {
261
+ res.decodedResult = fnACI.returns && fnACI.returns !== 'unit' && fn !== 'init' &&
262
+ instance.calldata.decode(instance.aci.name, fn, res.result.returnValue)
263
+ res.decodedEvents = instance.decodeEvents(res.result.log)
264
+ }
265
+ return res
266
+ }
267
+
124
268
  /**
125
269
  * Decode Events
126
270
  * @alias module:@aeternity/aepp-sdk/es/contract/aci
127
- * @rtype (fn: String, events: Array) => DecodedEvents: Array
128
- * @param {String} fn Function name
271
+ * @rtype (events: Array) => DecodedEvents: Array
129
272
  * @param {Array} events Array of encoded events(callRes.result.log)
130
273
  * @return {Object} DecodedEvents
131
274
  */
132
- instance.decodeEvents = eventDecode({ instance })
275
+ instance.decodeEvents = (events) => {
276
+ const eventsACI = instance.aci.event ? instance.aci.event.variant : []
277
+ const eventsSchema = eventsACI.map(e => {
278
+ const name = Object.keys(e)[0]
279
+ return { name, types: e[name] }
280
+ })
281
+
282
+ return decodeEvents(events, eventsSchema)
283
+ }
133
284
 
134
285
  /**
135
286
  * Generate proto function based on contract function using Contract ACI schema
136
287
  * All function can be called like:
137
- * 'await contract.methods.testFunction()' -> then sdk will decide to use dry-run or send tx on-chain base on if function stateful or not.
288
+ * 'await contract.methods.testFunction()' -> then sdk will decide to use dry-run or send tx
289
+ * on-chain base on if function stateful or not.
138
290
  * Also you can manually do that:
139
291
  * `await contract.methods.testFunction.get()` -> use call-static(dry-run)
140
292
  * `await contract.methods.testFunction.send()` -> send tx on-chain
141
293
  */
142
- instance.methods = buildContractMethods(instance)()
143
- return instance
144
- }
145
-
146
- const eventDecode = ({ instance }) => (fn, events) => {
147
- return decodeEvents(events, getFunctionACI(instance.aci, fn, { external: instance.externalAci }))
148
- }
149
-
150
- const call = ({ client, instance }) => async (fn, params = [], options = {}) => {
151
- const opt = { ...instance.options, ...options }
152
- const fnACI = getFunctionACI(instance.aci, fn, { external: instance.externalAci })
153
- const source = opt.source || instance.source
154
-
155
- if (!fn) throw new Error('Function name is required')
156
- if (!instance.deployInfo.address) throw new Error('You need to deploy contract before calling!')
157
- if (
158
- BigNumber(opt.amount).gt(0) &&
159
- (Object.prototype.hasOwnProperty.call(fnACI, 'payable') && !fnACI.payable)
160
- ) throw new Error(`You try to pay "${opt.amount}" to function "${fn}" which is not payable. Only payable function can accept tokens`)
161
- params = !opt.skipArgsConvert ? await prepareArgs(fnACI, params) : params
162
- const result = opt.callStatic
163
- ? await client.contractCallStatic(source, instance.deployInfo.address, fn, params, opt)
164
- : await client.contractCall(source, instance.deployInfo.address, fn, params, opt)
165
- return {
166
- ...result,
167
- ...opt.waitMined ? await decodeCallResult(result, fnACI, opt) : {}
168
- }
169
- }
170
-
171
- const deploy = ({ client, instance }) => async (init = [], options = {}) => {
172
- const opt = { ...instance.options, ...options }
173
- const fnACI = getFunctionACI(instance.aci, 'init', { external: instance.externalAci })
174
- const source = opt.source || instance.source
175
-
176
- if (!instance.compiled) await instance.compile(opt)
177
- init = !opt.skipArgsConvert ? await prepareArgs(fnACI, init) : init
178
-
179
- if (opt.callStatic) {
180
- return client.contractCallStatic(source, null, 'init', init, {
181
- ...opt,
182
- bytecode: instance.compiled
294
+ instance.methods = Object.fromEntries(instance.aci.functions
295
+ .map(({ name, arguments: aciArgs, stateful }) => {
296
+ const genHandler = callStatic => (...args) => {
297
+ const options = args.length === aciArgs.length + 1 ? args.pop() : {}
298
+ if (typeof options !== 'object') throw new Error(`Options should be an object: ${options}`)
299
+ if (name === 'init') return instance.deploy(args, { callStatic, ...options })
300
+ return instance.call(name, args, { callStatic, ...options })
301
+ }
302
+ return [
303
+ name,
304
+ Object.assign(
305
+ genHandler(name === 'init' ? false : !stateful),
306
+ {
307
+ get: genHandler(true),
308
+ send: genHandler(false),
309
+ decodeEvents: events => instance.decodeEvents(events)
310
+ }
311
+ )
312
+ ]
183
313
  })
184
- } else {
185
- const { owner, transaction, address, createdAt, result, rawTx } = await client.contractDeploy(instance.compiled, opt.source || instance.source, init, opt)
186
- instance.deployInfo = { owner, transaction, address, createdAt, result, rawTx }
187
- return instance.deployInfo
188
- }
189
- }
314
+ )
190
315
 
191
- const compile = ({ client, instance }) => async (options = {}) => {
192
- const { bytecode } = await client.contractCompile(instance.source, { ...instance.options, ...options })
193
- instance.compiled = bytecode
194
- return instance.compiled
316
+ return instance
195
317
  }