@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
@@ -24,112 +24,257 @@
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
59
  * Generate contract ACI object with predefined js methods for contract usage - can be used for creating a reference to already deployed contracts
39
60
  * @alias module:@aeternity/aepp-sdk/es/contract/aci
40
- * @param {String} source Contract source code
41
61
  * @param {Object} [options={}] Options object
42
- * @param {String} [options.aci] Contract ACI
62
+ * @param {String} [options.source] Contract source code
63
+ * @param {String} [options.bytecode] Contract bytecode
64
+ * @param {Object} [options.aci] Contract ACI
43
65
  * @param {String} [options.contractAddress] Contract address
44
66
  * @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
67
+ * @param {Boolean} [options.validateBytecode] Compare source code with on-chain version
47
68
  * @return {ContractInstance} JS Contract API
48
69
  * @example
49
- * const contractIns = await client.getContractInstance(sourceCode)
70
+ * const contractIns = await client.getContractInstance({ source })
50
71
  * await contractIns.deploy([321]) or await contractIns.methods.init(321)
51
72
  * const callResult = await contractIns.call('setState', [123]) or await contractIns.methods.setState.send(123, options)
52
73
  * const staticCallResult = await contractIns.call('setState', [123], { callStatic: true }) or await contractIns.methods.setState.get(123, options)
53
74
  * Also you can call contract like: await contractIns.methods.setState(123, options)
54
75
  * Then sdk decide to make on-chain or static call(dry-run API) transaction based on function is stateful or not
55
76
  */
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
77
+ export default async function getContractInstance ({
78
+ source,
79
+ bytecode,
80
+ aci,
81
+ contractAddress,
82
+ filesystem = {},
83
+ validateBytecode,
84
+ ...otherOptions
85
+ } = {}) {
86
+ aci = aci || (source && await this.contractGetACI(source, { filesystem }))
87
+ if (!aci) throw new Error('Either ACI or source code is required')
88
+ contractAddress = contractAddress && await this.resolveName(
89
+ contractAddress, 'ct', { resolveByNode: true }
90
+ )
91
+ if (!contractAddress && !source && !bytecode) throw new Error('Can\'t create instance by ACI without address')
92
+
93
+ if (contractAddress) {
94
+ const contract = await this.getContract(contractAddress).catch(() => null)
95
+ if (!contract) throw new Error(`Contract with address ${contractAddress} not found on-chain`)
96
+ if (!contract.active) throw new Error(`Contract with address ${contractAddress} not active`)
67
97
  }
98
+
68
99
  const instance = {
69
100
  interface: R.defaultTo(null, R.prop('interface', aci)),
70
101
  aci: R.defaultTo(null, R.path(['encoded_aci', 'contract'], aci)),
102
+ calldata: new Calldata([aci.encoded_aci, ...aci.external_encoded_aci]),
71
103
  externalAci: aci.external_encoded_aci ? aci.external_encoded_aci.map(a => a.contract || a.namespace) : [],
72
104
  source,
73
- compiled: null,
105
+ bytecode,
74
106
  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
- }
107
+ options: {
108
+ ...this.Ae.defaults,
109
+ callStatic: false,
110
+ filesystem,
111
+ ...otherOptions
112
+ },
113
+ compilerVersion: this.compilerVersion
80
114
  }
81
115
 
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
- }
116
+ if (validateBytecode) {
117
+ if (!contractAddress) throw new Error('Can\'t validate bytecode without contract address')
118
+ const onChanBytecode = (await this.getContractByteCode(contractAddress)).bytecode
119
+ const isValid = (source && await this
120
+ .validateByteCodeAPI(onChanBytecode, source, instance.options).catch(() => false)) ||
121
+ bytecode === onChanBytecode
122
+ if (!isValid) throw new Error(`Contract ${source ? 'source' : 'bytecode'} do not correspond to the bytecode deployed on the chain`)
92
123
  }
93
124
 
94
125
  /**
95
126
  * Compile contract
96
127
  * @alias module:@aeternity/aepp-sdk/es/contract/aci
97
128
  * @rtype () => ContractInstance: Object
98
- * @return {ContractInstance} Contract ACI object with predefined js methods for contract usage
129
+ * @return {String} bytecode bytecode
99
130
  */
100
- instance.compile = compile({ client: this, instance })
131
+ instance.compile = async (options = {}) => {
132
+ if (instance.bytecode) throw new Error('Contract already compiled')
133
+ if (!instance.source) throw new Error('Can\'t compile without source code')
134
+ const { bytecode } = await this.contractCompile(instance.source, { ...instance.options, ...options })
135
+ instance.bytecode = bytecode
136
+ return instance.bytecode
137
+ }
138
+
139
+ const sendAndProcess = async (tx, options) => {
140
+ const txData = await this.send(tx, options)
141
+ const result = {
142
+ hash: txData.hash, tx: TxObject({ tx: txData.rawTx }), txData, rawTx: txData.rawTx
143
+ }
144
+ if (options.waitMined === false) return result
145
+ const txInfo = await this.getTxInfo(txData.hash)
146
+ await handleCallError(txInfo)
147
+ return { ...result, result: txInfo }
148
+ }
149
+
150
+ const handleCallError = ({ returnType, returnValue }) => {
151
+ let message
152
+ // TODO: ensure that it works correctly https://github.com/aeternity/aepp-calldata-js/issues/88
153
+ switch (returnType) {
154
+ case 'ok': return
155
+ case 'revert':
156
+ message = instance.calldata.decodeFateString(returnValue)
157
+ break
158
+ case 'error':
159
+ message = decode(returnValue).toString()
160
+ break
161
+ default: throw new Error(`Unknown returnType: ${returnType}`)
162
+ }
163
+ throw new Error(`Invocation failed${message ? `: "${message}"` : ''}`)
164
+ }
165
+
101
166
  /**
102
167
  * Deploy contract
103
168
  * @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
169
+ * @rtype (init: Array, options: Object) => ContractInstance: Object
170
+ * @param {Array} params Contract init function arguments array
171
+ * @param {Object} [options] options
172
+ * @return {Object} deploy info
109
173
  */
110
- instance.deploy = deploy({ client: this, instance })
174
+ instance.deploy = async (params = [], options) => {
175
+ const opt = { ...instance.options, ...options, deposit: DEPOSIT }
176
+ if (!instance.bytecode) await instance.compile(opt)
177
+ if (opt.callStatic) return instance.call('init', params, opt)
178
+ if (instance.deployInfo.address) throw new Error('Contract already deployed')
179
+
180
+ const ownerId = await this.address(opt)
181
+ const { tx, contractId } = await this.contractCreateTx({
182
+ ...opt,
183
+ callData: instance.calldata.encode(instance.aci.name, 'init', params),
184
+ code: instance.bytecode,
185
+ ownerId
186
+ })
187
+ const { hash, rawTx, result, txData } = await sendAndProcess(tx, opt)
188
+ instance.deployInfo = Object.freeze({
189
+ result,
190
+ owner: ownerId,
191
+ transaction: hash,
192
+ rawTx,
193
+ txData,
194
+ address: contractId,
195
+ call: (name, args, options) =>
196
+ this.contractCall(instance.source, contractId, name, args, { ...opt, ...options }),
197
+ callStatic: (name, args, options) =>
198
+ this.contractCallStatic(instance.source, contractId, name, args, { ...opt, ...options }),
199
+ createdAt: new Date()
200
+ })
201
+ return instance.deployInfo
202
+ }
203
+
111
204
  /**
112
205
  * Call contract function
113
206
  * @alias module:@aeternity/aepp-sdk/es/contract/aci
114
- * @rtype (init: Array, options: Object = { skipArgsConvert: false, skipTransformDecoded: false, callStatic: false }) => CallResult: Object
207
+ * @rtype (init: Array, options: Object = { callStatic: false }) => CallResult: Object
115
208
  * @param {String} fn Function name
116
209
  * @param {Array} params Array of function arguments
117
210
  * @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
211
  * @param {Boolean} [options.callStatic=false] Static function call
121
212
  * @return {Object} CallResult
122
213
  */
123
- instance.call = call({ client: this, instance })
214
+ instance.call = async (fn, params = [], options = {}) => {
215
+ const opt = { ...instance.options, ...options }
216
+ const fnACI = getFunctionACI(instance.aci, fn, instance.externalAci)
217
+ const contractId = instance.deployInfo.address
218
+
219
+ if (!fn) throw new Error('Function name is required')
220
+ if (fn === 'init' && !opt.callStatic) throw new Error('"init" can be called only via dryRun')
221
+ if (!contractId && fn !== 'init') throw new Error('You need to deploy contract before calling!')
222
+ if (
223
+ BigNumber(opt.amount).gt(0) &&
224
+ (Object.prototype.hasOwnProperty.call(fnACI, 'payable') && !fnACI.payable)
225
+ ) throw new Error(`You try to pay "${opt.amount}" to function "${fn}" which is not payable. Only payable function can accept tokens`)
226
+
227
+ const callerId = await this.address(opt).catch(error => {
228
+ if (opt.callStatic) return DRY_RUN_ACCOUNT.pub
229
+ else throw error
230
+ })
231
+ const callData = instance.calldata.encode(instance.aci.name, fn, params)
232
+
233
+ let res
234
+ if (opt.callStatic) {
235
+ if (typeof opt.top === 'number') {
236
+ opt.top = (await this.getKeyBlock(opt.top)).hash
237
+ }
238
+ const txOpt = {
239
+ ...opt,
240
+ callData,
241
+ nonce: opt.top && (await this.getAccount(callerId, { hash: opt.top })).nonce + 1
242
+ }
243
+ const tx = fn === 'init'
244
+ ? (await this.contractCreateTx({ ...txOpt, code: instance.bytecode, ownerId: callerId })).tx
245
+ : await this.contractCallTx({ ...txOpt, callerId, contractId })
246
+
247
+ const { callObj, ...dryRunOther } = await this.txDryRun(tx, callerId, opt)
248
+ await handleCallError(callObj)
249
+ res = { ...dryRunOther, tx: TxObject({ tx }), result: callObj }
250
+ } else {
251
+ const tx = await this.contractCallTx({ ...opt, callerId, contractId, callData })
252
+ res = await sendAndProcess(tx, opt)
253
+ }
254
+ if (opt.waitMined || opt.callStatic) {
255
+ res.decodedResult = fnACI.returns && fnACI.returns !== 'unit' && fn !== 'init' &&
256
+ instance.calldata.decode(instance.aci.name, fn, res.result.returnValue)
257
+ res.decodedEvents = instance.decodeEvents(res.result.log)
258
+ }
259
+ return res
260
+ }
261
+
124
262
  /**
125
263
  * Decode Events
126
264
  * @alias module:@aeternity/aepp-sdk/es/contract/aci
127
- * @rtype (fn: String, events: Array) => DecodedEvents: Array
128
- * @param {String} fn Function name
265
+ * @rtype (events: Array) => DecodedEvents: Array
129
266
  * @param {Array} events Array of encoded events(callRes.result.log)
130
267
  * @return {Object} DecodedEvents
131
268
  */
132
- instance.decodeEvents = eventDecode({ instance })
269
+ instance.decodeEvents = (events) => {
270
+ const eventsACI = instance.aci.event ? instance.aci.event.variant : []
271
+ const eventsSchema = eventsACI.map(e => {
272
+ const name = Object.keys(e)[0]
273
+ return { name, types: e[name] }
274
+ })
275
+
276
+ return decodeEvents(events, eventsSchema)
277
+ }
133
278
 
134
279
  /**
135
280
  * Generate proto function based on contract function using Contract ACI schema
@@ -139,57 +284,27 @@ export default async function getContractInstance (source, { aci, contractAddres
139
284
  * `await contract.methods.testFunction.get()` -> use call-static(dry-run)
140
285
  * `await contract.methods.testFunction.send()` -> send tx on-chain
141
286
  */
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
287
+ instance.methods = Object.fromEntries(instance.aci.functions
288
+ .map(({ name, arguments: aciArgs, stateful }) => {
289
+ const genHandler = callStatic => (...args) => {
290
+ const options = args.length === aciArgs.length + 1 ? args.pop() : {}
291
+ if (typeof options !== 'object') throw new Error(`Options should be an object: ${options}`)
292
+ if (name === 'init') return instance.deploy(args, { callStatic, ...options })
293
+ return instance.call(name, args, { callStatic, ...options })
294
+ }
295
+ return [
296
+ name,
297
+ Object.assign(
298
+ genHandler(name === 'init' ? false : !stateful),
299
+ {
300
+ get: genHandler(true),
301
+ send: genHandler(false),
302
+ decodeEvents: events => instance.decodeEvents(events)
303
+ }
304
+ )
305
+ ]
183
306
  })
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
- }
307
+ )
190
308
 
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
309
+ return instance
195
310
  }