starknet 3.4.0 → 3.5.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 (62) hide show
  1. package/.eslintrc +2 -1
  2. package/CHANGELOG.md +20 -0
  3. package/__tests__/account.test.ts +7 -17
  4. package/__tests__/accountContract.test.ts +13 -25
  5. package/__tests__/contract.test.ts +152 -55
  6. package/__tests__/utils/utils.browser.test.ts +1 -3
  7. package/contract/contractFactory.d.ts +36 -0
  8. package/contract/contractFactory.js +218 -0
  9. package/contract/default.d.ts +143 -0
  10. package/{contract.js → contract/default.js} +357 -86
  11. package/contract/index.d.ts +3 -0
  12. package/contract/index.js +28 -0
  13. package/contract/interface.d.ts +79 -0
  14. package/contract/interface.js +8 -0
  15. package/dist/contract/contractFactory.d.ts +32 -0
  16. package/dist/contract/contractFactory.js +102 -0
  17. package/dist/contract/default.d.ts +121 -0
  18. package/dist/{contract.js → contract/default.js} +321 -73
  19. package/dist/contract/index.d.ts +3 -0
  20. package/dist/contract/index.js +15 -0
  21. package/dist/contract/interface.d.ts +72 -0
  22. package/dist/contract/interface.js +9 -0
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.js +1 -1
  25. package/dist/provider/default.d.ts +4 -1
  26. package/dist/provider/default.js +15 -6
  27. package/dist/provider/interface.d.ts +3 -1
  28. package/dist/types/api.d.ts +6 -0
  29. package/dist/types/contract.d.ts +5 -0
  30. package/dist/types/contract.js +2 -0
  31. package/dist/types/index.d.ts +1 -0
  32. package/dist/types/index.js +1 -0
  33. package/dist/types/lib.d.ts +11 -1
  34. package/dist/utils/transaction.d.ts +1 -2
  35. package/index.d.ts +1 -1
  36. package/index.js +1 -1
  37. package/package.json +1 -1
  38. package/provider/default.d.ts +4 -1
  39. package/provider/default.js +25 -16
  40. package/provider/interface.d.ts +3 -1
  41. package/src/contract/contractFactory.ts +78 -0
  42. package/src/contract/default.ts +622 -0
  43. package/src/contract/index.ts +3 -0
  44. package/src/contract/interface.ts +87 -0
  45. package/src/index.ts +1 -1
  46. package/src/provider/default.ts +19 -14
  47. package/src/provider/interface.ts +3 -1
  48. package/src/types/api.ts +7 -0
  49. package/src/types/contract.ts +5 -0
  50. package/src/types/index.ts +1 -0
  51. package/src/types/lib.ts +12 -1
  52. package/src/utils/transaction.ts +1 -2
  53. package/types/api.d.ts +6 -0
  54. package/types/contract.d.ts +5 -0
  55. package/types/contract.js +2 -0
  56. package/types/index.d.ts +1 -0
  57. package/types/index.js +1 -0
  58. package/types/lib.d.ts +11 -1
  59. package/utils/transaction.d.ts +1 -2
  60. package/contract.d.ts +0 -98
  61. package/dist/contract.d.ts +0 -94
  62. package/src/contract.ts +0 -357
package/src/contract.ts DELETED
@@ -1,357 +0,0 @@
1
- import BN from 'bn.js';
2
- import assert from 'minimalistic-assert';
3
-
4
- import { Provider, defaultProvider } from './provider';
5
- import { BlockIdentifier } from './provider/utils';
6
- import { Abi, AbiEntry, Calldata, FunctionAbi, Signature, StructAbi } from './types';
7
- import { BigNumberish, toBN, toFelt } from './utils/number';
8
-
9
- export type Struct = {
10
- type: 'struct';
11
- [k: string]: BigNumberish;
12
- };
13
- export type ParsedStruct = {
14
- [key: string]: BigNumberish | ParsedStruct;
15
- };
16
- export type Args = {
17
- [inputName: string]: BigNumberish | BigNumberish[] | ParsedStruct | ParsedStruct[];
18
- };
19
-
20
- function parseFelt(candidate: string): BN {
21
- try {
22
- return toBN(candidate);
23
- } catch (e) {
24
- throw Error('Couldnt parse felt');
25
- }
26
- }
27
-
28
- export class Contract {
29
- connectedTo: string | null = null;
30
-
31
- abi: Abi;
32
-
33
- structs: { [name: string]: StructAbi };
34
-
35
- provider: Provider;
36
-
37
- /**
38
- * Contract class to handle contract methods
39
- *
40
- * @param abi - Abi of the contract object
41
- * @param address (optional) - address to connect to
42
- */
43
- constructor(abi: Abi, address: string | null = null, provider: Provider = defaultProvider) {
44
- this.connectedTo = address;
45
- this.provider = provider;
46
- this.abi = abi;
47
- this.structs = abi
48
- .filter((abiEntry) => abiEntry.type === 'struct')
49
- .reduce(
50
- (acc, abiEntry) => ({
51
- ...acc,
52
- [abiEntry.name]: abiEntry,
53
- }),
54
- {}
55
- );
56
- }
57
-
58
- /**
59
- * Saves the address of the contract deployed on network that will be used for interaction
60
- *
61
- * @param address - address of the contract
62
- * @returns Contract
63
- */
64
- public connect(address: string): Contract {
65
- this.connectedTo = address;
66
- return this;
67
- }
68
-
69
- /**
70
- * Validates if all arguments that are passed to the method are corresponding to the ones in the abi
71
- *
72
- * @param type - type of the method
73
- * @param method - name of the method
74
- * @param args - arguments that are passed to the method
75
- */
76
- private validateMethodAndArgs(type: 'INVOKE' | 'CALL', method: string, args: Args = {}) {
77
- // ensure provided method exists
78
- const invokeableFunctionNames = this.abi
79
- .filter((abi) => {
80
- if (abi.type !== 'function') return false;
81
- const isView = abi.stateMutability === 'view';
82
- return type === 'INVOKE' ? !isView : isView;
83
- })
84
- .map((abi) => abi.name);
85
- assert(
86
- invokeableFunctionNames.includes(method),
87
- `${type === 'INVOKE' ? 'invokeable' : 'viewable'} method not found in abi`
88
- );
89
-
90
- // ensure args match abi type
91
- const methodAbi = this.abi.find(
92
- (abi) => abi.name === method && abi.type === 'function'
93
- ) as FunctionAbi;
94
- methodAbi.inputs.forEach((input) => {
95
- const arg = args[input.name];
96
- if (arg !== undefined) {
97
- if (input.type === 'felt') {
98
- assert(
99
- typeof arg === 'string' || typeof arg === 'number' || arg instanceof BN,
100
- `arg ${input.name} should be a felt (string, number, BigNumber)`
101
- );
102
- } else if (typeof arg === 'object' && input.type in this.structs) {
103
- this.structs[input.type].members.forEach(({ name }) => {
104
- assert(Object.keys(arg).includes(name), `arg should have a property ${name}`);
105
- });
106
- } else {
107
- assert(Array.isArray(arg), `arg ${input.name} should be an Array`);
108
- if (input.type === 'felt*') {
109
- arg.forEach((felt) => {
110
- assert(
111
- typeof felt === 'string' || typeof felt === 'number' || felt instanceof BN,
112
- `arg ${input.name} should be an array of string, number or BigNumber`
113
- );
114
- });
115
- } else if (/\(felt/.test(input.type)) {
116
- const tupleLength = input.type.split(',').length;
117
- assert(
118
- arg.length === tupleLength,
119
- `arg ${input.name} should have ${tupleLength} elements in tuple`
120
- );
121
- arg.forEach((felt) => {
122
- assert(
123
- typeof felt === 'string' || typeof felt === 'number' || felt instanceof BN,
124
- `arg ${input.name} should be an array of string, number or BigNumber`
125
- );
126
- });
127
- } else {
128
- const arrayType = input.type.replace('*', '');
129
- arg.forEach((struct) => {
130
- this.structs[arrayType].members.forEach(({ name }) => {
131
- assert(
132
- Object.keys(struct).includes(name),
133
- `arg ${input.name} should be an array of ${arrayType}`
134
- );
135
- });
136
- });
137
- }
138
- }
139
- }
140
- });
141
- }
142
-
143
- /**
144
- * Deep parse of the object that has been passed to the method
145
- *
146
- * @param element - element that needs to be parsed
147
- * @param type - name of the method
148
- * @return {string | string[]} - parsed arguments in format that contract is expecting
149
- */
150
- private parseCalldataObject(
151
- element: ParsedStruct | BigNumberish,
152
- type: string
153
- ): string | string[] {
154
- if (element === undefined) {
155
- throw Error('Missing element in calldata object');
156
- }
157
- // checking if the passed element is struct or element in struct
158
- if (this.structs[type] && this.structs[type].members.length) {
159
- // going through all the members of the struct and parsing the value
160
- return this.structs[type].members.reduce((acc, member: AbiEntry) => {
161
- // if the member of the struct is another struct this will return array of the felts if not it will be single felt
162
- // TODO: refactor types so member name can be used as keyof ParsedStruct
163
- /* @ts-ignore */
164
- const parsedData = this.parseCalldataObject(element[member.name], member.type);
165
- if (typeof parsedData === 'string') {
166
- acc.push(parsedData);
167
- } else {
168
- acc.push(...parsedData);
169
- }
170
- return acc;
171
- }, [] as string[]);
172
- }
173
- return toFelt(element as BigNumberish);
174
- }
175
-
176
- /**
177
- * Parse of the response elements that are converted to Object (Struct) by using the abi
178
- *
179
- * @param responseIterator - iterator of the response
180
- * @param type - type of the struct
181
- * @return {BigNumberish | ParsedStruct} - parsed arguments in format that contract is expecting
182
- */
183
- private parseResponseStruct(
184
- responseIterator: Iterator<string>,
185
- type: string
186
- ): BigNumberish | ParsedStruct {
187
- // check the type of current element
188
- if (type in this.structs && this.structs[type]) {
189
- return this.structs[type].members.reduce((acc, el) => {
190
- // parse each member of the struct (member can felt or nested struct)
191
- acc[el.name] = this.parseResponseStruct(responseIterator, el.type);
192
- return acc;
193
- }, {} as any);
194
- }
195
- return parseFelt(responseIterator.next().value);
196
- }
197
-
198
- /**
199
- * Parse one field of the calldata by using input field from the abi for that method
200
- *
201
- * @param args - value of the field
202
- * @param input - input(field) information from the abi that will be used to parse the data
203
- * @return {string | string[]} - parsed arguments in format that contract is expecting
204
- */
205
- private parsCalldataField(args: Args, input: AbiEntry): string | string[] {
206
- const { name, type } = input;
207
- const value = args[name];
208
- const propName = name.replace(/_len$/, '');
209
- switch (true) {
210
- case /_len$/.test(name):
211
- if (Array.isArray(args[propName])) {
212
- const arr = args[propName] as (BigNumberish | ParsedStruct)[];
213
- return toFelt(arr.length);
214
- }
215
- throw Error(`Expected ${propName} to be array`);
216
- case /\*/.test(type):
217
- if (Array.isArray(value)) {
218
- return (value as (BigNumberish | ParsedStruct)[]).reduce((acc, el) => {
219
- if (/felt/.test(type)) {
220
- acc.push(toFelt(el as BigNumberish));
221
- } else {
222
- acc.push(...this.parseCalldataObject(el, type.replace('*', '')));
223
- }
224
- return acc;
225
- }, [] as string[]);
226
- }
227
- throw Error(`Expected ${name} to be array`);
228
- case type in this.structs:
229
- return this.parseCalldataObject(value as ParsedStruct, type);
230
- case /\(felt/.test(type):
231
- if (Array.isArray(value)) {
232
- return value.map((el) => toFelt(el as BigNumberish));
233
- }
234
- throw Error(`Expected ${name} to be array`);
235
- default:
236
- return toFelt(value as BigNumberish);
237
- }
238
- }
239
-
240
- /**
241
- * Parse the calldata by using input fields from the abi for that method
242
- *
243
- * @param args - arguments passed the the method
244
- * @param inputs - list of inputs(fields) that are in the abi
245
- * @return {Calldata} - parsed arguments in format that contract is expecting
246
- */
247
- private compileCalldata(args: Args, inputs: AbiEntry[]): Calldata {
248
- return inputs.reduce((acc, input) => {
249
- const parsedData = this.parsCalldataField(args, input);
250
- if (Array.isArray(parsedData)) {
251
- acc.push(...parsedData);
252
- } else {
253
- acc.push(parsedData);
254
- }
255
- return acc;
256
- }, [] as Calldata);
257
- }
258
-
259
- /**
260
- * Parse elements of the response and structuring them into one field by using output property from the abi for that method
261
- *
262
- * @param responseIterator - iterator of the response
263
- * @param output - output(field) information from the abi that will be used to parse the data
264
- * @return - parsed response corresponding to the abi structure of the field
265
- */
266
- private parseResponseField(
267
- responseIterator: Iterator<string>,
268
- output: AbiEntry,
269
- parsedResult?: Args
270
- ): any {
271
- const { name, type } = output;
272
- let arrLen: number;
273
- const parsedDataArr: (BigNumberish | ParsedStruct)[] = [];
274
- switch (true) {
275
- case /_len$/.test(name):
276
- return parseFelt(responseIterator.next().value).toNumber();
277
- case /\(felt/.test(type):
278
- return type.split(',').reduce((acc) => {
279
- acc.push(parseFelt(responseIterator.next().value));
280
- return acc;
281
- }, [] as BigNumberish[]);
282
- case /\*/.test(type):
283
- if (parsedResult && parsedResult[`${name}_len`]) {
284
- arrLen = parsedResult[`${name}_len`] as number;
285
- while (parsedDataArr.length < arrLen) {
286
- parsedDataArr.push(
287
- this.parseResponseStruct(responseIterator, output.type.replace('*', ''))
288
- );
289
- }
290
- }
291
- return parsedDataArr;
292
- case type in this.structs:
293
- return this.parseResponseStruct(responseIterator, type);
294
- default:
295
- return parseFelt(responseIterator.next().value);
296
- }
297
- }
298
-
299
- /**
300
- * Parse elements of the response array and structuring them into response object
301
- *
302
- * @param method - method name
303
- * @param response - response from the method
304
- * @return - parsed response corresponding to the abi
305
- */
306
- private parseResponse(method: string, response: string[]): Args {
307
- const { outputs } = this.abi.find((abi) => abi.name === method) as FunctionAbi;
308
- const responseIterator = response.flat()[Symbol.iterator]();
309
- return outputs.flat().reduce((acc, output) => {
310
- acc[output.name] = this.parseResponseField(responseIterator, output, acc);
311
- if (acc[output.name] && acc[`${output.name}_len`]) {
312
- delete acc[`${output.name}_len`];
313
- }
314
- return acc;
315
- }, {} as Args);
316
- }
317
-
318
- public invoke(method: string, args: Args = {}, signature?: Signature) {
319
- // ensure contract is connected
320
- assert(this.connectedTo !== null, 'contract isnt connected to an address');
321
- // validate method and args
322
- this.validateMethodAndArgs('INVOKE', method, args);
323
- const { inputs } = this.abi.find((abi) => abi.name === method) as FunctionAbi;
324
-
325
- // compile calldata
326
- const calldata = this.compileCalldata(args, inputs);
327
-
328
- return this.provider.invokeFunction({
329
- contractAddress: this.connectedTo,
330
- signature,
331
- calldata,
332
- entrypoint: method,
333
- });
334
- }
335
-
336
- public async call(method: string, args: Args = {}, blockIdentifier: BlockIdentifier = null) {
337
- // ensure contract is connected
338
- assert(this.connectedTo !== null, 'contract isnt connected to an address');
339
-
340
- // validate method and args
341
- this.validateMethodAndArgs('CALL', method, args);
342
- const { inputs } = this.abi.find((abi) => abi.name === method) as FunctionAbi;
343
-
344
- // compile calldata
345
- const calldata = this.compileCalldata(args, inputs);
346
- return this.provider
347
- .callContract(
348
- {
349
- contractAddress: this.connectedTo,
350
- calldata,
351
- entrypoint: method,
352
- },
353
- blockIdentifier
354
- )
355
- .then((x) => this.parseResponse(method, x.result));
356
- }
357
- }