starknet 1.6.0 → 2.0.2

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.
@@ -1,4 +1,4 @@
1
- import { getKeyPair, getStarkKey, sign } from '../../src/utils/ellipticCurve';
1
+ import { getKeyPair, getStarkKey, sign, verify, ec } from '../../src/utils/ellipticCurve';
2
2
  import { removeHexPrefix } from '../../src/utils/encode';
3
3
  import { hashCalldata, hashMessage, pedersen } from '../../src/utils/hash';
4
4
  import { toBN, toHex } from '../../src/utils/number';
@@ -20,12 +20,12 @@ test('pedersen()', () => {
20
20
  test('hashCalldata()', () => {
21
21
  const array = ['1', '2', '3', '4'];
22
22
  expect(hashCalldata(array)).toBe(
23
- '0x1439c58e1c389a2ac51f8462ecc0a4ec7f812be1c04e3b82ce2af1c2cf959ef'
23
+ '0x66bd4335902683054d08a0572747ea78ebd9e531536fb43125424ca9f902084'
24
24
  );
25
25
  expect(array).toStrictEqual(['1', '2', '3', '4']);
26
26
 
27
27
  expect(hashCalldata(['1', '2'])).toBe(
28
- '0x2ab889bd35e684623df9b4ea4a4a1f6d9e0ef39b67c1293b8a89dd17e351235'
28
+ '0x501a3a8e6cd4f5241c639c74052aaa34557aafa84dd4ba983d6443c590ab7df'
29
29
  );
30
30
  });
31
31
 
@@ -38,13 +38,25 @@ test('hashMessage()', () => {
38
38
  ['1', '2'],
39
39
  '2'
40
40
  );
41
- expect(hashMsg).toBe('0xf7ec4a68876819eed838be83b5d5dc337081f4a5fb8e421f3d9bdef7c69e9b');
41
+ expect(hashMsg).toBe('0x7f15c38ea577a26f4f553282fcfe4f1feeb8ecfaad8f221ae41abf8224cbddd');
42
42
  const keyPair = getKeyPair(privateKey);
43
43
  const { r, s } = sign(keyPair, removeHexPrefix(hashMsg));
44
44
  expect(r.toString()).toStrictEqual(
45
- toBN('2699852629692218907583414128365108566181098618321049245303767746418549764831').toString()
45
+ toBN('2458502865976494910213617956670505342647705497324144349552978333078363662855').toString()
46
46
  );
47
47
  expect(s.toString()).toStrictEqual(
48
- toBN('2362979021721299440845279407227912881357338080403308888611869245024056250189').toString()
48
+ toBN('3439514492576562277095748549117516048613512930236865921315982886313695689433').toString()
49
49
  );
50
50
  });
51
+
52
+ test('verify signed message()', () => {
53
+ const pk = '0x019800ea6a9a73f94aee6a3d2edf018fc770443e90c7ba121e8303ec6b349279';
54
+ const account = '0x33f45f07e1bd1a51b45fc24ec8c8c9908db9e42191be9e169bfcac0c0d99745';
55
+ const price = '1';
56
+ const hashMsg = pedersen([account, price]);
57
+ const keyPair = getKeyPair(pk);
58
+ const signature = sign(keyPair, removeHexPrefix(hashMsg));
59
+ const pubKey = keyPair.getPublic('hex');
60
+ const pubKeyPair = ec.keyFromPublic(pubKey, 'hex');
61
+ expect(verify(pubKeyPair, removeHexPrefix(hashMsg), signature)).toBe(true);
62
+ });
@@ -1,6 +1,6 @@
1
1
  import fs from 'fs';
2
2
 
3
- import { constants, json, number, stark } from '../../src';
3
+ import { constants, hash, json, number, stark } from '../../src';
4
4
 
5
5
  const { IS_BROWSER } = constants;
6
6
 
@@ -59,3 +59,21 @@ describe('getSelectorFromName()', () => {
59
59
  );
60
60
  });
61
61
  });
62
+ describe('computeHashOnElements()', () => {
63
+ test('should return valid hash for empty array', () => {
64
+ const res = hash.computeHashOnElements([]);
65
+ expect(res).toMatchInlineSnapshot(
66
+ `"0x49ee3eba8c1600700ee1b87eb599f16716b0b1022947733551fde4050ca6804"`
67
+ );
68
+ });
69
+ test('should return valid hash for valid array', () => {
70
+ const res = hash.computeHashOnElements([
71
+ number.toBN(123782376),
72
+ number.toBN(213984),
73
+ number.toBN(128763521321),
74
+ ]);
75
+ expect(res).toMatchInlineSnapshot(
76
+ `"0x7b422405da6571242dfc245a43de3b0fe695e7021c148b918cd9cdb462cac59"`
77
+ );
78
+ });
79
+ });
package/constants.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- /// <reference types="bn.js" />
1
+ import BN from 'bn.js';
2
2
  export { IS_BROWSER } from './utils/encode';
3
- export declare const ZERO: import('bn.js');
4
- export declare const ONE: import('bn.js');
5
- export declare const TWO: import('bn.js');
6
- export declare const MASK_250: import('bn.js');
3
+ export declare const ZERO: BN;
4
+ export declare const ONE: BN;
5
+ export declare const TWO: BN;
6
+ export declare const MASK_250: BN;
7
7
  /**
8
8
  * The following is taken from https://github.com/starkware-libs/starkex-resources/blob/master/crypto/starkware/crypto/signature/pedersen_params.json but converted to hex, because JS is very bad handling big integers by default
9
9
  * Please do not edit until the JSON changes.
package/contract.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Provider } from './provider';
2
- import { Abi } from './types';
2
+ import { Abi, StructAbi } from './types';
3
3
  import { BigNumberish } from './utils/number';
4
4
  export declare type Args = {
5
5
  [inputName: string]: string | string[];
@@ -9,6 +9,9 @@ export declare function compileCalldata(args: Args): Calldata;
9
9
  export declare class Contract {
10
10
  connectedTo: string | null;
11
11
  abi: Abi[];
12
+ structs: {
13
+ [name: string]: StructAbi;
14
+ };
12
15
  provider: Provider;
13
16
  /**
14
17
  * Contract class to handle contract methods
@@ -19,6 +22,7 @@ export declare class Contract {
19
22
  constructor(abi: Abi[], address?: string | null, provider?: Provider);
20
23
  connect(address: string): Contract;
21
24
  private validateMethodAndArgs;
25
+ private parseResponseField;
22
26
  private parseResponse;
23
27
  invoke(
24
28
  method: string,
package/contract.js CHANGED
@@ -238,6 +238,14 @@ var Contract = /** @class */ (function () {
238
238
  this.connectedTo = address;
239
239
  this.provider = provider;
240
240
  this.abi = abi;
241
+ this.structs = abi
242
+ .filter(function (abiEntry) {
243
+ return abiEntry.type === 'struct';
244
+ })
245
+ .reduce(function (acc, abiEntry) {
246
+ var _a;
247
+ return __assign(__assign({}, acc), ((_a = {}), (_a[abiEntry.name] = abiEntry), _a));
248
+ }, {});
241
249
  }
242
250
  Contract.prototype.connect = function (address) {
243
251
  this.connectedTo = address;
@@ -250,9 +258,9 @@ var Contract = /** @class */ (function () {
250
258
  // ensure provided method exists
251
259
  var invokeableFunctionNames = this.abi
252
260
  .filter(function (abi) {
261
+ if (abi.type !== 'function') return false;
253
262
  var isView = abi.stateMutability === 'view';
254
- var isFunction = abi.type === 'function';
255
- return isFunction && type === 'INVOKE' ? !isView : isView;
263
+ return type === 'INVOKE' ? !isView : isView;
256
264
  })
257
265
  .map(function (abi) {
258
266
  return abi.name;
@@ -263,7 +271,7 @@ var Contract = /** @class */ (function () {
263
271
  );
264
272
  // ensure args match abi type
265
273
  var methodAbi = this.abi.find(function (abi) {
266
- return abi.name === method;
274
+ return abi.name === method && abi.type === 'function';
267
275
  });
268
276
  methodAbi.inputs.forEach(function (input) {
269
277
  if (args[input.name] !== undefined) {
@@ -291,14 +299,31 @@ var Contract = /** @class */ (function () {
291
299
  }
292
300
  });
293
301
  };
302
+ Contract.prototype.parseResponseField = function (element, responseIterator) {
303
+ var _this = this;
304
+ var entries = [];
305
+ if (['felt', 'felt*'].includes(element.type)) {
306
+ return responseIterator.next().value;
307
+ }
308
+ if (element.type in this.structs) {
309
+ entries = this.structs[element.type].members;
310
+ } else if ('outputs' in element) {
311
+ entries = element.outputs;
312
+ }
313
+ return entries.reduce(function (acc, member) {
314
+ var _a;
315
+ return __assign(
316
+ __assign({}, acc),
317
+ ((_a = {}), (_a[member.name] = _this.parseResponseField(member, responseIterator)), _a)
318
+ );
319
+ }, {});
320
+ };
294
321
  Contract.prototype.parseResponse = function (method, response) {
295
322
  var methodAbi = this.abi.find(function (abi) {
296
323
  return abi.name === method;
297
324
  });
298
- return methodAbi.outputs.reduce(function (acc, output, i) {
299
- var _a;
300
- return __assign(__assign({}, acc), ((_a = {}), (_a[output.name] = response[i]), _a));
301
- }, {});
325
+ var responseIterator = response.flat()[Symbol.iterator]();
326
+ return this.parseResponseField(methodAbi, responseIterator);
302
327
  };
303
328
  Contract.prototype.invoke = function (method, args, signature) {
304
329
  if (args === void 0) {
@@ -1,9 +1,9 @@
1
- /// <reference types="bn.js" />
1
+ import BN from 'bn.js';
2
2
  export { IS_BROWSER } from './utils/encode';
3
- export declare const ZERO: import("bn.js");
4
- export declare const ONE: import("bn.js");
5
- export declare const TWO: import("bn.js");
6
- export declare const MASK_250: import("bn.js");
3
+ export declare const ZERO: BN;
4
+ export declare const ONE: BN;
5
+ export declare const TWO: BN;
6
+ export declare const MASK_250: BN;
7
7
  /**
8
8
  * The following is taken from https://github.com/starkware-libs/starkex-resources/blob/master/crypto/starkware/crypto/signature/pedersen_params.json but converted to hex, because JS is very bad handling big integers by default
9
9
  * Please do not edit until the JSON changes.
@@ -1,5 +1,5 @@
1
1
  import { Provider } from './provider';
2
- import { Abi } from './types';
2
+ import { Abi, StructAbi } from './types';
3
3
  import { BigNumberish } from './utils/number';
4
4
  export declare type Args = {
5
5
  [inputName: string]: string | string[];
@@ -9,6 +9,9 @@ export declare function compileCalldata(args: Args): Calldata;
9
9
  export declare class Contract {
10
10
  connectedTo: string | null;
11
11
  abi: Abi[];
12
+ structs: {
13
+ [name: string]: StructAbi;
14
+ };
12
15
  provider: Provider;
13
16
  /**
14
17
  * Contract class to handle contract methods
@@ -19,6 +22,7 @@ export declare class Contract {
19
22
  constructor(abi: Abi[], address?: string | null, provider?: Provider);
20
23
  connect(address: string): Contract;
21
24
  private validateMethodAndArgs;
25
+ private parseResponseField;
22
26
  private parseResponse;
23
27
  invoke(method: string, args?: Args, signature?: [BigNumberish, BigNumberish]): Promise<import("./types").AddTransactionResponse>;
24
28
  call(method: string, args?: Args): Promise<Args>;
package/dist/contract.js CHANGED
@@ -119,6 +119,12 @@ var Contract = /** @class */ (function () {
119
119
  this.connectedTo = address;
120
120
  this.provider = provider;
121
121
  this.abi = abi;
122
+ this.structs = abi
123
+ .filter(function (abiEntry) { return abiEntry.type === 'struct'; })
124
+ .reduce(function (acc, abiEntry) {
125
+ var _a;
126
+ return (__assign(__assign({}, acc), (_a = {}, _a[abiEntry.name] = abiEntry, _a)));
127
+ }, {});
122
128
  }
123
129
  Contract.prototype.connect = function (address) {
124
130
  this.connectedTo = address;
@@ -129,14 +135,15 @@ var Contract = /** @class */ (function () {
129
135
  // ensure provided method exists
130
136
  var invokeableFunctionNames = this.abi
131
137
  .filter(function (abi) {
138
+ if (abi.type !== 'function')
139
+ return false;
132
140
  var isView = abi.stateMutability === 'view';
133
- var isFunction = abi.type === 'function';
134
- return isFunction && type === 'INVOKE' ? !isView : isView;
141
+ return type === 'INVOKE' ? !isView : isView;
135
142
  })
136
143
  .map(function (abi) { return abi.name; });
137
144
  (0, minimalistic_assert_1.default)(invokeableFunctionNames.includes(method), (type === 'INVOKE' ? 'invokeable' : 'viewable') + " method not found in abi");
138
145
  // ensure args match abi type
139
- var methodAbi = this.abi.find(function (abi) { return abi.name === method; });
146
+ var methodAbi = this.abi.find(function (abi) { return abi.name === method && abi.type === 'function'; });
140
147
  methodAbi.inputs.forEach(function (input) {
141
148
  if (args[input.name] !== undefined) {
142
149
  if (input.type === 'felt') {
@@ -153,13 +160,28 @@ var Contract = /** @class */ (function () {
153
160
  }
154
161
  });
155
162
  };
156
- Contract.prototype.parseResponse = function (method, response) {
157
- var methodAbi = this.abi.find(function (abi) { return abi.name === method; });
158
- return methodAbi.outputs.reduce(function (acc, output, i) {
163
+ Contract.prototype.parseResponseField = function (element, responseIterator) {
164
+ var _this = this;
165
+ var entries = [];
166
+ if (['felt', 'felt*'].includes(element.type)) {
167
+ return responseIterator.next().value;
168
+ }
169
+ if (element.type in this.structs) {
170
+ entries = this.structs[element.type].members;
171
+ }
172
+ else if ('outputs' in element) {
173
+ entries = element.outputs;
174
+ }
175
+ return entries.reduce(function (acc, member) {
159
176
  var _a;
160
- return __assign(__assign({}, acc), (_a = {}, _a[output.name] = response[i], _a));
177
+ return (__assign(__assign({}, acc), (_a = {}, _a[member.name] = _this.parseResponseField(member, responseIterator), _a)));
161
178
  }, {});
162
179
  };
180
+ Contract.prototype.parseResponse = function (method, response) {
181
+ var methodAbi = this.abi.find(function (abi) { return abi.name === method; });
182
+ var responseIterator = response.flat()[Symbol.iterator]();
183
+ return this.parseResponseField(methodAbi, responseIterator);
184
+ };
163
185
  Contract.prototype.invoke = function (method, args, signature) {
164
186
  if (args === void 0) { args = {}; }
165
187
  // ensure contract is connected
@@ -77,7 +77,7 @@ var Provider = /** @class */ (function () {
77
77
  switch (name) {
78
78
  case 'alpha':
79
79
  default:
80
- return 'https://alpha3.starknet.io';
80
+ return 'https://alpha4.starknet.io';
81
81
  }
82
82
  };
83
83
  /**
@@ -296,13 +296,14 @@ var Provider = /** @class */ (function () {
296
296
  });
297
297
  };
298
298
  Provider.prototype.waitForTx = function (txHash, retryInterval) {
299
- if (retryInterval === void 0) { retryInterval = 2000; }
299
+ if (retryInterval === void 0) { retryInterval = 5000; }
300
300
  return __awaiter(this, void 0, void 0, function () {
301
- var onchain, res;
301
+ var onchain, firstRun, res;
302
302
  return __generator(this, function (_a) {
303
303
  switch (_a.label) {
304
304
  case 0:
305
305
  onchain = false;
306
+ firstRun = true;
306
307
  _a.label = 1;
307
308
  case 1:
308
309
  if (!!onchain) return [3 /*break*/, 4];
@@ -320,9 +321,10 @@ var Provider = /** @class */ (function () {
320
321
  else if (res.tx_status === 'REJECTED') {
321
322
  throw Error('REJECTED');
322
323
  }
323
- else if (res.tx_status === 'NOT_RECEIVED') {
324
+ else if (res.tx_status === 'NOT_RECEIVED' && !firstRun) {
324
325
  throw Error('NOT_RECEIVED');
325
326
  }
327
+ firstRun = false;
326
328
  return [3 /*break*/, 1];
327
329
  case 4: return [2 /*return*/];
328
330
  }
@@ -114,14 +114,13 @@ var Signer = /** @class */ (function (_super) {
114
114
  (0, minimalistic_assert_1.default)(!tx.signature, "Adding signatures to a signer tx currently isn't supported");
115
115
  return [4 /*yield*/, this.callContract({
116
116
  contract_address: this.address,
117
- entry_point_selector: (0, stark_1.getSelectorFromName)('get_current_nonce'),
117
+ entry_point_selector: (0, stark_1.getSelectorFromName)('get_nonce'),
118
118
  })];
119
119
  case 1:
120
120
  result = (_b.sent()).result;
121
121
  nonceBn = (0, number_1.toBN)(result[0]);
122
122
  calldataDecimal = (tx.calldata || []).map(function (x) { return (0, number_1.toBN)(x).toString(); });
123
- msgHash = (0, encode_1.addHexPrefix)((0, hash_1.hashMessage)('0', // needs to be walletAddress once it's possible to retrieve address(self) in cairo
124
- tx.contract_address, tx.entry_point_selector, calldataDecimal, nonceBn.toString()));
123
+ msgHash = (0, encode_1.addHexPrefix)((0, hash_1.hashMessage)(this.address, tx.contract_address, tx.entry_point_selector, calldataDecimal, nonceBn.toString()));
125
124
  _a = (0, ellipticCurve_1.sign)(this.keyPair, msgHash), r = _a.r, s = _a.s;
126
125
  return [2 /*return*/, _super.prototype.addTransaction.call(this, {
127
126
  type: 'INVOKE_FUNCTION',
package/dist/types.d.ts CHANGED
@@ -11,19 +11,26 @@ export declare type TxStatus = 'TRANSACTION_RECEIVED';
11
11
  export declare type Type = 'DEPLOY' | 'INVOKE_FUNCTION';
12
12
  export declare type EntryPointType = 'EXTERNAL';
13
13
  export declare type CompressedProgram = string;
14
- export declare type Abi = {
15
- inputs: {
16
- name: string;
17
- type: 'felt' | 'felt*';
18
- }[];
14
+ export declare type AbiEntry = {
19
15
  name: string;
20
- outputs: {
21
- name: string;
22
- type: 'felt' | 'felt*';
23
- }[];
16
+ type: 'felt' | 'felt*' | string;
17
+ };
18
+ export declare type FunctionAbi = {
19
+ inputs: AbiEntry[];
20
+ name: string;
21
+ outputs: AbiEntry[];
24
22
  stateMutability?: 'view';
25
23
  type: 'function';
26
24
  };
25
+ export declare type StructAbi = {
26
+ members: (AbiEntry & {
27
+ offset: number;
28
+ })[];
29
+ name: string;
30
+ size: number;
31
+ type: 'struct';
32
+ };
33
+ export declare type Abi = FunctionAbi | StructAbi;
27
34
  export declare type EntryPointsByType = object;
28
35
  export declare type Program = object;
29
36
  export declare type CompiledContract = {
@@ -95,5 +102,5 @@ export declare type GetTransactionResponse = {
95
102
  export declare type AddTransactionResponse = {
96
103
  code: TxStatus;
97
104
  transaction_hash: string;
98
- address: string;
105
+ address?: string;
99
106
  };
@@ -84,6 +84,6 @@ function verify(keyPair, msgHash, sig) {
84
84
  (0, number_1.assertInRange)(r, constants_1.ONE, (0, number_1.toBN)((0, encode_1.addHexPrefix)(constants_1.MAX_ECDSA_VAL)), 'r');
85
85
  (0, number_1.assertInRange)(s, constants_1.ONE, (0, number_1.toBN)((0, encode_1.addHexPrefix)(constants_1.EC_ORDER)), 's');
86
86
  (0, number_1.assertInRange)(w, constants_1.ONE, (0, number_1.toBN)((0, encode_1.addHexPrefix)(constants_1.MAX_ECDSA_VAL)), 'w');
87
- return keyPair.verify(msgHash, sig);
87
+ return keyPair.verify(fixMessage(msgHash), sig);
88
88
  }
89
89
  exports.verify = verify;
@@ -9,5 +9,6 @@ import { BigNumberish } from './number';
9
9
  */
10
10
  export declare function starknetKeccak(value: string): BN;
11
11
  export declare function pedersen(input: [BigNumberish, BigNumberish]): string;
12
+ export declare function computeHashOnElements(data: BigNumberish[]): string;
12
13
  export declare function hashCalldata(calldata: string[]): string;
13
14
  export declare function hashMessage(account: string, to: string, selector: string, calldata: string[], nonce: string): string;
@@ -28,7 +28,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
28
28
  return (mod && mod.__esModule) ? mod : { "default": mod };
29
29
  };
30
30
  Object.defineProperty(exports, "__esModule", { value: true });
31
- exports.hashMessage = exports.hashCalldata = exports.pedersen = exports.starknetKeccak = void 0;
31
+ exports.hashMessage = exports.hashCalldata = exports.computeHashOnElements = exports.pedersen = exports.starknetKeccak = void 0;
32
32
  var keccak_1 = require("ethereum-cryptography/keccak");
33
33
  var minimalistic_assert_1 = __importDefault(require("minimalistic-assert"));
34
34
  var constants_1 = require("../constants");
@@ -69,24 +69,16 @@ function pedersen(input) {
69
69
  return (0, encode_1.addHexPrefix)(point.getX().toString(16));
70
70
  }
71
71
  exports.pedersen = pedersen;
72
+ function computeHashOnElements(data) {
73
+ return __spreadArray(__spreadArray([], __read(data), false), [data.length], false).reduce(function (x, y) { return pedersen([x, y]); }, 0).toString();
74
+ }
75
+ exports.computeHashOnElements = computeHashOnElements;
72
76
  function hashCalldata(calldata) {
73
- var calldataCopy = __spreadArray([], __read(calldata), false);
74
- if (calldataCopy.length === 0) {
75
- return '0';
76
- }
77
- if (calldataCopy.length === 1) {
78
- return calldataCopy[0];
79
- }
80
- // calldata element will always be there as it was checked by an if statement before (!)
81
- var calldataEl = calldataCopy.shift();
82
- return pedersen([hashCalldata(calldataCopy), calldataEl]);
77
+ return computeHashOnElements(calldata);
83
78
  }
84
79
  exports.hashCalldata = hashCalldata;
85
80
  function hashMessage(account, to, selector, calldata, nonce) {
86
- var hash0 = pedersen([account, to]);
87
- var hash1 = pedersen([hash0, selector]);
88
81
  var calldataHash = hashCalldata(calldata);
89
- var hash2 = pedersen([hash1, calldataHash]);
90
- return pedersen([hash2, nonce]);
82
+ return computeHashOnElements([account, to, selector, calldataHash, nonce]);
91
83
  }
92
84
  exports.hashMessage = hashMessage;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "starknet",
3
- "version": "1.6.0",
3
+ "version": "2.0.2",
4
4
  "description": "JavaScript library for StarkNet",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -179,7 +179,7 @@ var Provider = /** @class */ (function () {
179
179
  switch (name) {
180
180
  case 'alpha':
181
181
  default:
182
- return 'https://alpha3.starknet.io';
182
+ return 'https://alpha4.starknet.io';
183
183
  }
184
184
  };
185
185
  /**
@@ -484,14 +484,15 @@ var Provider = /** @class */ (function () {
484
484
  };
485
485
  Provider.prototype.waitForTx = function (txHash, retryInterval) {
486
486
  if (retryInterval === void 0) {
487
- retryInterval = 2000;
487
+ retryInterval = 5000;
488
488
  }
489
489
  return __awaiter(this, void 0, void 0, function () {
490
- var onchain, res;
490
+ var onchain, firstRun, res;
491
491
  return __generator(this, function (_a) {
492
492
  switch (_a.label) {
493
493
  case 0:
494
494
  onchain = false;
495
+ firstRun = true;
495
496
  _a.label = 1;
496
497
  case 1:
497
498
  if (!!onchain) return [3 /*break*/, 4];
@@ -507,9 +508,10 @@ var Provider = /** @class */ (function () {
507
508
  onchain = true;
508
509
  } else if (res.tx_status === 'REJECTED') {
509
510
  throw Error('REJECTED');
510
- } else if (res.tx_status === 'NOT_RECEIVED') {
511
+ } else if (res.tx_status === 'NOT_RECEIVED' && !firstRun) {
511
512
  throw Error('NOT_RECEIVED');
512
513
  }
514
+ firstRun = false;
513
515
  return [3 /*break*/, 1];
514
516
  case 4:
515
517
  return [2 /*return*/];
package/signer/default.js CHANGED
@@ -233,7 +233,7 @@ var Signer = /** @class */ (function (_super) {
233
233
  4 /*yield*/,
234
234
  this.callContract({
235
235
  contract_address: this.address,
236
- entry_point_selector: (0, stark_1.getSelectorFromName)('get_current_nonce'),
236
+ entry_point_selector: (0, stark_1.getSelectorFromName)('get_nonce'),
237
237
  }),
238
238
  ];
239
239
  case 1:
@@ -244,7 +244,7 @@ var Signer = /** @class */ (function (_super) {
244
244
  });
245
245
  msgHash = (0, encode_1.addHexPrefix)(
246
246
  (0, hash_1.hashMessage)(
247
- '0', // needs to be walletAddress once it's possible to retrieve address(self) in cairo
247
+ this.address,
248
248
  tx.contract_address,
249
249
  tx.entry_point_selector,
250
250
  calldataDecimal,
package/src/constants.ts CHANGED
@@ -1,11 +1,13 @@
1
+ import BN from 'bn.js';
2
+
1
3
  import { toBN } from './utils/number';
2
4
 
3
5
  export { IS_BROWSER } from './utils/encode';
4
6
 
5
- export const ZERO = toBN(0);
6
- export const ONE = toBN(1);
7
- export const TWO = toBN(2);
8
- export const MASK_250 = TWO.pow(toBN(250)).sub(ONE); // 2 ** 250 - 1
7
+ export const ZERO: BN = toBN(0);
8
+ export const ONE: BN = toBN(1);
9
+ export const TWO: BN = toBN(2);
10
+ export const MASK_250: BN = TWO.pow(toBN(250)).sub(ONE); // 2 ** 250 - 1
9
11
 
10
12
  /**
11
13
  * The following is taken from https://github.com/starkware-libs/starkex-resources/blob/master/crypto/starkware/crypto/signature/pedersen_params.json but converted to hex, because JS is very bad handling big integers by default
package/src/contract.ts CHANGED
@@ -2,7 +2,7 @@ import BN from 'bn.js';
2
2
  import assert from 'minimalistic-assert';
3
3
 
4
4
  import { Provider, defaultProvider } from './provider';
5
- import { Abi } from './types';
5
+ import { Abi, AbiEntry, FunctionAbi, StructAbi } from './types';
6
6
  import { BigNumberish, toBN } from './utils/number';
7
7
  import { getSelectorFromName } from './utils/stark';
8
8
 
@@ -39,6 +39,8 @@ export class Contract {
39
39
 
40
40
  abi: Abi[];
41
41
 
42
+ structs: { [name: string]: StructAbi };
43
+
42
44
  provider: Provider;
43
45
 
44
46
  /**
@@ -51,6 +53,15 @@ export class Contract {
51
53
  this.connectedTo = address;
52
54
  this.provider = provider;
53
55
  this.abi = abi;
56
+ this.structs = abi
57
+ .filter((abiEntry) => abiEntry.type === 'struct')
58
+ .reduce(
59
+ (acc, abiEntry) => ({
60
+ ...acc,
61
+ [abiEntry.name]: abiEntry,
62
+ }),
63
+ {}
64
+ );
54
65
  }
55
66
 
56
67
  public connect(address: string): Contract {
@@ -62,9 +73,9 @@ export class Contract {
62
73
  // ensure provided method exists
63
74
  const invokeableFunctionNames = this.abi
64
75
  .filter((abi) => {
76
+ if (abi.type !== 'function') return false;
65
77
  const isView = abi.stateMutability === 'view';
66
- const isFunction = abi.type === 'function';
67
- return isFunction && type === 'INVOKE' ? !isView : isView;
78
+ return type === 'INVOKE' ? !isView : isView;
68
79
  })
69
80
  .map((abi) => abi.name);
70
81
  assert(
@@ -73,7 +84,9 @@ export class Contract {
73
84
  );
74
85
 
75
86
  // ensure args match abi type
76
- const methodAbi = this.abi.find((abi) => abi.name === method)!;
87
+ const methodAbi = this.abi.find(
88
+ (abi) => abi.name === method && abi.type === 'function'
89
+ ) as FunctionAbi;
77
90
  methodAbi.inputs.forEach((input) => {
78
91
  if (args[input.name] !== undefined) {
79
92
  if (input.type === 'felt') {
@@ -102,14 +115,32 @@ export class Contract {
102
115
  });
103
116
  }
104
117
 
105
- private parseResponse(method: string, response: (string | string[])[]): Args {
106
- const methodAbi = this.abi.find((abi) => abi.name === method)!;
107
- return methodAbi.outputs.reduce((acc, output, i) => {
108
- return {
118
+ private parseResponseField(
119
+ element: AbiEntry | FunctionAbi,
120
+ responseIterator: Iterator<string>
121
+ ): Args {
122
+ let entries: AbiEntry[] = [];
123
+ if (['felt', 'felt*'].includes(element.type)) {
124
+ return responseIterator.next().value;
125
+ }
126
+ if (element.type in this.structs) {
127
+ entries = this.structs[element.type].members;
128
+ } else if ('outputs' in element) {
129
+ entries = element.outputs;
130
+ }
131
+ return entries.reduce(
132
+ (acc, member) => ({
109
133
  ...acc,
110
- [output.name]: response[i],
111
- };
112
- }, {} as Args);
134
+ [member.name]: this.parseResponseField(member, responseIterator),
135
+ }),
136
+ {}
137
+ );
138
+ }
139
+
140
+ private parseResponse(method: string, response: string[]): Args {
141
+ const methodAbi = this.abi.find((abi) => abi.name === method) as FunctionAbi;
142
+ const responseIterator = response.flat()[Symbol.iterator]();
143
+ return this.parseResponseField(methodAbi, responseIterator);
113
144
  }
114
145
 
115
146
  public invoke(method: string, args: Args = {}, signature?: [BigNumberish, BigNumberish]) {