starknet 2.0.0 → 2.1.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,34 @@
1
+ ## [2.1.1](https://github.com/seanjameshan/starknet.js/compare/v2.1.0...v2.1.1) (2021-11-30)
2
+
3
+ ### Bug Fixes
4
+
5
+ - correctly parse structs in Starknet return types ([5a4a318](https://github.com/seanjameshan/starknet.js/commit/5a4a318dad4c78fe84540ad92063fc1879317ac1))
6
+ - make Typescript compiler happy with constant types ([aedd895](https://github.com/seanjameshan/starknet.js/commit/aedd895a62e6018dd1d7330b004d54360007967f))
7
+
8
+ # [2.1.0](https://github.com/seanjameshan/starknet.js/compare/v2.0.1...v2.1.0) (2021-11-30)
9
+
10
+ ### Bug Fixes
11
+
12
+ - deps ([020ba39](https://github.com/seanjameshan/starknet.js/commit/020ba3948f03e41fc96c7c002b613250d73fbda6))
13
+ - transaction status pending ([198d82b](https://github.com/seanjameshan/starknet.js/commit/198d82b30dd8c0c978cfdd2d56cb5a7e5131cb6a))
14
+
15
+ ### Features
16
+
17
+ - support mainnet ([de07149](https://github.com/seanjameshan/starknet.js/commit/de07149ad6521edc9f79e2b0e9c82bf40f32fe02))
18
+
19
+ ## [2.0.2](https://github.com/seanjameshan/starknet.js/compare/v2.0.1...v2.0.2) (2021-11-22)
20
+
21
+ ### Bug Fixes
22
+
23
+ - correctly parse structs in Starknet return types ([5a4a318](https://github.com/seanjameshan/starknet.js/commit/5a4a318dad4c78fe84540ad92063fc1879317ac1))
24
+ - make Typescript compiler happy with constant types ([aedd895](https://github.com/seanjameshan/starknet.js/commit/aedd895a62e6018dd1d7330b004d54360007967f))
25
+
26
+ ## [2.0.1](https://github.com/seanjameshan/starknet.js/compare/v2.0.0...v2.0.1) (2021-11-18)
27
+
28
+ ### Bug Fixes
29
+
30
+ - msgHash length fix in signature verify function ([589b126](https://github.com/seanjameshan/starknet.js/commit/589b126b2b87bf7d0b2730f53a40ee2d9ef9aca0))
31
+
1
32
  # [2.0.0](https://github.com/seanjameshan/starknet.js/compare/v1.7.0...v2.0.0) (2021-11-18)
2
33
 
3
34
  ### Features
@@ -23,7 +54,13 @@
23
54
  ### Features
24
55
 
25
56
  - add invokeFunction ([7e04b5e](https://github.com/seanjameshan/starknet.js/commit/7e04b5ec383fa6d466e9e06d9fa02e2d0c36b020))
26
- - add signer and provider v1 ([909fdc0](https://github.com/seanjameshan/starknet.js/commit/909fdc0b2b211755b9124b62f97476d89b655de1))
57
+ - # add signer and provider v1 ([909fdc0](https://github.com/seanjameshan/starknet.js/commit/909fdc0b2b211755b9124b62f97476d89b655de1))
58
+
59
+ ## [1.5.5](https://github.com/seanjameshan/starknet.js/compare/v1.5.4...v1.5.5) (2021-11-13)
60
+
61
+ ### Bug Fixes
62
+
63
+ - msgHash length fix in signature verify function ([589b126](https://github.com/seanjameshan/starknet.js/commit/589b126b2b87bf7d0b2730f53a40ee2d9ef9aca0))
27
64
 
28
65
  ## [1.5.4](https://github.com/seanjameshan/starknet.js/compare/v1.5.3...v1.5.4) (2021-11-05)
29
66
 
package/README.md CHANGED
@@ -44,23 +44,74 @@ $ npm install starknet
44
44
 
45
45
  Import `starknet` and use the [API](https://www.starknetjs.com/modules.html)
46
46
 
47
+ The following code is used to build a [simple AMM example](https://starkfin.netlify.app/) from the [cairo docs](https://www.cairo-lang.org/docs/hello_starknet/amm.html)
48
+
47
49
  ```javascript
48
- import { defaultProvider } from 'starknet';
50
+ import { defaultProvider, stark } from 'starknet';
51
+ const { getSelectorFromName } = stark;
52
+
53
+ const CONTRACT_ADDRESS =
54
+ "0x03e19baa6cb2078631bcdb34844f3f7879449a544c9ce722681a54af08cff4b9";
55
+
56
+ /**
57
+ * addTransaction() example
58
+ **/
59
+
60
+ /** Reset the liquidity pool **/
61
+ const addTokenResponse = await provider.addTransaction({
62
+ type: "INVOKE_FUNCTION",
63
+ contract_address: CONTRACT_ADDRESS,
64
+ entry_point_selector: getSelectorFromName("init_pool"),
65
+ calldata: ["1000000", "1000000"],
66
+ });
67
+ console.log(addTokenResponse);
68
+
69
+ /**
70
+ * callContract() example
71
+ **/
72
+
73
+ /** Get the balance of the liquidity pool of token A **/
74
+ const poolBalanceTokenA = await callContract({
75
+ contract_address: CONTRACT_ADDRESS,
76
+ entry_point_selector: getSelectorFromName("get_pool_token_balance"),
77
+ calldata: ["1"],
78
+ });
79
+ const balanceA = poolBalanceTokenA.result[0];
80
+ console.log('token a liquidity pool balance: ', parseInt(balanceA, 16));
49
81
 
50
- defaultProvider.getContractAddresses().then((data) => {
51
- console.log(data);
82
+ /** Get the balance of the liquidity pool of token B **/
83
+ const poolBalanceTokenB = await callContract({
84
+ contract_address: CONTRACT_ADDRESS,
85
+ entry_point_selector: getSelectorFromName("get_pool_token_balance"),
86
+ calldata: ["2"],
52
87
  });
88
+ const balanceB = poolBalanceTokenB.result[0];
89
+ console.log('token b liquidity pool balance: ', parseInt(balanceB, 16));
53
90
  ```
54
91
 
92
+ For more information about **signing transactions**, please take a look at this [pull request](https://github.com/seanjameshan/starknet.js/pull/51)
93
+
55
94
  ## 🌐 API
56
95
 
57
96
  [Click Here](https://www.starknetjs.com/modules.html)
58
97
 
59
- ## Contributing
98
+ ## 🚀 Powered by Starknet.js
99
+
100
+ - [Argent X - the first StarkNet wallet](https://github.com/argentlabs/argent-x)
101
+ - [React + Starknet.js boilerplate](https://github.com/fracek/starknet-react-example)
102
+ - [AMM Demo](https://www.starknetswap.com/)
103
+
104
+ ## ✏️ Contributing
60
105
 
61
106
  If you consider to contribute to this project please read [CONTRIBUTING.md](https://github.com/seanjameshan/starknet.js/blob/main/CONTRIBUTING.md) first.
62
107
 
63
- ## License
108
+ ## ❤️ Special Thanks
109
+
110
+ Special thanks to all the [contributors](https://github.com/seanjameshan/starknet.js/graphs/contributors), especially to Janek ([@janek26](https://github.com/janek26)) from [Argent](https://github.com/argentlabs) for driving the development of Starknet.js.
111
+
112
+ This library would not be possible without these rockstars.
113
+
114
+ ## 📜 License
64
115
 
65
116
  Copyright (c) 2021 Sean James Han
66
117
 
@@ -49,17 +49,17 @@ describe('defaultProvider', () => {
49
49
  )
50
50
  ).resolves.not.toThrow();
51
51
  });
52
- test('getTransactionStatus()', () => {
52
+ test('getTransactionStatus()', async () => {
53
53
  return expect(
54
54
  defaultProvider.getTransactionStatus(
55
- '0x774f7856b1ce6d5ce023a18cd5a06ab67e3a6d81c7bfcd01f99f32243c2d2ef'
55
+ '0x72add9621ecdcb07405a4f943fe410bf57003ca250400f01ce70f8a6fc72147'
56
56
  )
57
57
  ).resolves.not.toThrow();
58
58
  });
59
59
  test('getTransaction()', async () => {
60
60
  return expect(
61
61
  defaultProvider.getTransaction(
62
- '0x774f7856b1ce6d5ce023a18cd5a06ab67e3a6d81c7bfcd01f99f32243c2d2ef'
62
+ '0x72add9621ecdcb07405a4f943fe410bf57003ca250400f01ce70f8a6fc72147'
63
63
  )
64
64
  ).resolves.not.toThrow();
65
65
  });
@@ -1,4 +1,4 @@
1
- import { getKeyPair, getStarkKey, sign } from '../../src/utils/ellipticCurve';
1
+ import { ec, getKeyPair, getStarkKey, sign, verify } 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';
@@ -48,3 +48,15 @@ test('hashMessage()', () => {
48
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
+ });
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
@@ -1,16 +1,18 @@
1
1
  import { AddTransactionResponse, CallContractResponse, CallContractTransaction, CompiledContract, GetBlockResponse, GetCodeResponse, GetContractAddressesResponse, GetTransactionResponse, GetTransactionStatusResponse, Transaction } from '../types';
2
2
  import { BigNumberish } from '../utils/number';
3
3
  import { ProviderInterface } from './interface';
4
- declare type NetworkName = 'alpha';
5
- interface ProviderOptions {
6
- network?: NetworkName;
7
- }
4
+ declare type NetworkName = 'mainnet-alpha' | 'georli-alpha';
5
+ declare type ProviderOptions = {
6
+ network: NetworkName;
7
+ } | {
8
+ baseUrl: string;
9
+ };
8
10
  export declare class Provider implements ProviderInterface {
9
11
  baseUrl: string;
10
12
  feederGatewayUrl: string;
11
13
  gatewayUrl: string;
12
14
  constructor(optionsOrProvider?: ProviderOptions | Provider);
13
- protected static getNetworkFromName(name: NetworkName): string;
15
+ protected static getNetworkFromName(name: NetworkName): "http://alpha-mainnet.starknet.io/" | "https://alpha4.starknet.io";
14
16
  /**
15
17
  * Gets the smart contract address on the goerli testnet.
16
18
  *
@@ -60,14 +60,16 @@ function wait(delay) {
60
60
  }
61
61
  var Provider = /** @class */ (function () {
62
62
  function Provider(optionsOrProvider) {
63
+ if (optionsOrProvider === void 0) { optionsOrProvider = { network: 'georli-alpha' }; }
63
64
  if (optionsOrProvider instanceof Provider) {
64
65
  this.baseUrl = optionsOrProvider.baseUrl;
65
66
  this.feederGatewayUrl = optionsOrProvider.feederGatewayUrl;
66
67
  this.gatewayUrl = optionsOrProvider.gatewayUrl;
67
68
  }
68
69
  else {
69
- var _a = (optionsOrProvider || {}).network, network = _a === void 0 ? 'alpha' : _a;
70
- var baseUrl = Provider.getNetworkFromName(network);
70
+ var baseUrl = 'baseUrl' in optionsOrProvider
71
+ ? optionsOrProvider.baseUrl
72
+ : Provider.getNetworkFromName(optionsOrProvider.network);
71
73
  this.baseUrl = baseUrl;
72
74
  this.feederGatewayUrl = baseUrl + "/feeder_gateway";
73
75
  this.gatewayUrl = baseUrl + "/gateway";
@@ -75,7 +77,9 @@ var Provider = /** @class */ (function () {
75
77
  }
76
78
  Provider.getNetworkFromName = function (name) {
77
79
  switch (name) {
78
- case 'alpha':
80
+ case 'mainnet-alpha':
81
+ return 'http://alpha-mainnet.starknet.io/';
82
+ case 'georli-alpha':
79
83
  default:
80
84
  return 'https://alpha4.starknet.io';
81
85
  }
@@ -296,14 +300,13 @@ var Provider = /** @class */ (function () {
296
300
  });
297
301
  };
298
302
  Provider.prototype.waitForTx = function (txHash, retryInterval) {
299
- if (retryInterval === void 0) { retryInterval = 5000; }
303
+ if (retryInterval === void 0) { retryInterval = 8000; }
300
304
  return __awaiter(this, void 0, void 0, function () {
301
- var onchain, firstRun, res;
305
+ var onchain, res;
302
306
  return __generator(this, function (_a) {
303
307
  switch (_a.label) {
304
308
  case 0:
305
309
  onchain = false;
306
- firstRun = true;
307
310
  _a.label = 1;
308
311
  case 1:
309
312
  if (!!onchain) return [3 /*break*/, 4];
@@ -315,16 +318,17 @@ var Provider = /** @class */ (function () {
315
318
  return [4 /*yield*/, this.getTransactionStatus(txHash)];
316
319
  case 3:
317
320
  res = _a.sent();
318
- if (res.tx_status === 'ACCEPTED_ONCHAIN' || res.tx_status === 'PENDING') {
321
+ if (res.tx_status === 'ACCEPTED_ONCHAIN' ||
322
+ (res.tx_status === 'PENDING' && res.block_hash !== 'pending') // This is needed as of today. In the future there will be a different status for pending transactions.
323
+ ) {
319
324
  onchain = true;
320
325
  }
321
326
  else if (res.tx_status === 'REJECTED') {
322
327
  throw Error('REJECTED');
323
328
  }
324
- else if (res.tx_status === 'NOT_RECEIVED' && !firstRun) {
329
+ else if (res.tx_status === 'NOT_RECEIVED') {
325
330
  throw Error('NOT_RECEIVED');
326
331
  }
327
- firstRun = false;
328
332
  return [3 /*break*/, 1];
329
333
  case 4: return [2 /*return*/];
330
334
  }
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 = {
@@ -54,14 +61,14 @@ export declare type CallContractResponse = {
54
61
  export declare type GetBlockResponse = {
55
62
  sequence_number: number;
56
63
  state_root: string;
57
- block_id: number;
64
+ block_hash: string;
58
65
  transactions: {
59
66
  [txHash: string]: Transaction;
60
67
  };
61
68
  timestamp: number;
62
69
  transaction_receipts: {
63
70
  [txHash: string]: {
64
- block_id: number;
71
+ block_hash: string;
65
72
  transaction_hash: string;
66
73
  l2_to_l1_messages: {
67
74
  to_address: string;
@@ -73,7 +80,7 @@ export declare type GetBlockResponse = {
73
80
  transaction_index: number;
74
81
  };
75
82
  };
76
- previous_block_id: number;
83
+ previous_block_hash: string;
77
84
  status: Status;
78
85
  };
79
86
  export declare type GetCodeResponse = {
@@ -82,12 +89,12 @@ export declare type GetCodeResponse = {
82
89
  };
83
90
  export declare type GetTransactionStatusResponse = {
84
91
  tx_status: Status;
85
- block_id: number;
92
+ block_hash: string;
86
93
  };
87
94
  export declare type GetTransactionResponse = {
88
95
  status: Status;
89
96
  transaction: Transaction;
90
- block_id: number;
97
+ block_hash: string;
91
98
  block_number: number;
92
99
  transaction_index: number;
93
100
  transaction_hash: string;
@@ -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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "starknet",
3
- "version": "2.0.0",
3
+ "version": "2.1.1",
4
4
  "description": "JavaScript library for StarkNet",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -12,16 +12,22 @@ import {
12
12
  } from '../types';
13
13
  import { BigNumberish } from '../utils/number';
14
14
  import { ProviderInterface } from './interface';
15
- declare type NetworkName = 'alpha';
16
- interface ProviderOptions {
17
- network?: NetworkName;
18
- }
15
+ declare type NetworkName = 'mainnet-alpha' | 'georli-alpha';
16
+ declare type ProviderOptions =
17
+ | {
18
+ network: NetworkName;
19
+ }
20
+ | {
21
+ baseUrl: string;
22
+ };
19
23
  export declare class Provider implements ProviderInterface {
20
24
  baseUrl: string;
21
25
  feederGatewayUrl: string;
22
26
  gatewayUrl: string;
23
27
  constructor(optionsOrProvider?: ProviderOptions | Provider);
24
- protected static getNetworkFromName(name: NetworkName): string;
28
+ protected static getNetworkFromName(
29
+ name: NetworkName
30
+ ): 'http://alpha-mainnet.starknet.io/' | 'https://alpha4.starknet.io';
25
31
  /**
26
32
  * Gets the smart contract address on the goerli testnet.
27
33
  *
@@ -162,14 +162,18 @@ function wait(delay) {
162
162
  }
163
163
  var Provider = /** @class */ (function () {
164
164
  function Provider(optionsOrProvider) {
165
+ if (optionsOrProvider === void 0) {
166
+ optionsOrProvider = { network: 'georli-alpha' };
167
+ }
165
168
  if (optionsOrProvider instanceof Provider) {
166
169
  this.baseUrl = optionsOrProvider.baseUrl;
167
170
  this.feederGatewayUrl = optionsOrProvider.feederGatewayUrl;
168
171
  this.gatewayUrl = optionsOrProvider.gatewayUrl;
169
172
  } else {
170
- var _a = (optionsOrProvider || {}).network,
171
- network = _a === void 0 ? 'alpha' : _a;
172
- var baseUrl = Provider.getNetworkFromName(network);
173
+ var baseUrl =
174
+ 'baseUrl' in optionsOrProvider
175
+ ? optionsOrProvider.baseUrl
176
+ : Provider.getNetworkFromName(optionsOrProvider.network);
173
177
  this.baseUrl = baseUrl;
174
178
  this.feederGatewayUrl = baseUrl + '/feeder_gateway';
175
179
  this.gatewayUrl = baseUrl + '/gateway';
@@ -177,7 +181,9 @@ var Provider = /** @class */ (function () {
177
181
  }
178
182
  Provider.getNetworkFromName = function (name) {
179
183
  switch (name) {
180
- case 'alpha':
184
+ case 'mainnet-alpha':
185
+ return 'http://alpha-mainnet.starknet.io/';
186
+ case 'georli-alpha':
181
187
  default:
182
188
  return 'https://alpha4.starknet.io';
183
189
  }
@@ -484,15 +490,14 @@ var Provider = /** @class */ (function () {
484
490
  };
485
491
  Provider.prototype.waitForTx = function (txHash, retryInterval) {
486
492
  if (retryInterval === void 0) {
487
- retryInterval = 5000;
493
+ retryInterval = 8000;
488
494
  }
489
495
  return __awaiter(this, void 0, void 0, function () {
490
- var onchain, firstRun, res;
496
+ var onchain, res;
491
497
  return __generator(this, function (_a) {
492
498
  switch (_a.label) {
493
499
  case 0:
494
500
  onchain = false;
495
- firstRun = true;
496
501
  _a.label = 1;
497
502
  case 1:
498
503
  if (!!onchain) return [3 /*break*/, 4];
@@ -504,14 +509,16 @@ var Provider = /** @class */ (function () {
504
509
  return [4 /*yield*/, this.getTransactionStatus(txHash)];
505
510
  case 3:
506
511
  res = _a.sent();
507
- if (res.tx_status === 'ACCEPTED_ONCHAIN' || res.tx_status === 'PENDING') {
512
+ if (
513
+ res.tx_status === 'ACCEPTED_ONCHAIN' ||
514
+ (res.tx_status === 'PENDING' && res.block_hash !== 'pending') // This is needed as of today. In the future there will be a different status for pending transactions.
515
+ ) {
508
516
  onchain = true;
509
517
  } else if (res.tx_status === 'REJECTED') {
510
518
  throw Error('REJECTED');
511
- } else if (res.tx_status === 'NOT_RECEIVED' && !firstRun) {
519
+ } else if (res.tx_status === 'NOT_RECEIVED') {
512
520
  throw Error('NOT_RECEIVED');
513
521
  }
514
- firstRun = false;
515
522
  return [3 /*break*/, 1];
516
523
  case 4:
517
524
  return [2 /*return*/];
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]) {
@@ -17,11 +17,15 @@ import { BigNumberish, toBN, toHex } from '../utils/number';
17
17
  import { compressProgram, formatSignature, randomAddress } from '../utils/stark';
18
18
  import { ProviderInterface } from './interface';
19
19
 
20
- type NetworkName = 'alpha';
20
+ type NetworkName = 'mainnet-alpha' | 'georli-alpha';
21
21
 
22
- interface ProviderOptions {
23
- network?: NetworkName;
24
- }
22
+ type ProviderOptions =
23
+ | {
24
+ network: NetworkName;
25
+ }
26
+ | {
27
+ baseUrl: string;
28
+ };
25
29
 
26
30
  function wait(delay: number) {
27
31
  return new Promise((res) => setTimeout(res, delay));
@@ -34,14 +38,16 @@ export class Provider implements ProviderInterface {
34
38
 
35
39
  public gatewayUrl: string;
36
40
 
37
- constructor(optionsOrProvider?: ProviderOptions | Provider) {
41
+ constructor(optionsOrProvider: ProviderOptions | Provider = { network: 'georli-alpha' }) {
38
42
  if (optionsOrProvider instanceof Provider) {
39
43
  this.baseUrl = optionsOrProvider.baseUrl;
40
44
  this.feederGatewayUrl = optionsOrProvider.feederGatewayUrl;
41
45
  this.gatewayUrl = optionsOrProvider.gatewayUrl;
42
46
  } else {
43
- const { network = 'alpha' } = optionsOrProvider || {};
44
- const baseUrl = Provider.getNetworkFromName(network);
47
+ const baseUrl =
48
+ 'baseUrl' in optionsOrProvider
49
+ ? optionsOrProvider.baseUrl
50
+ : Provider.getNetworkFromName(optionsOrProvider.network);
45
51
  this.baseUrl = baseUrl;
46
52
  this.feederGatewayUrl = `${baseUrl}/feeder_gateway`;
47
53
  this.gatewayUrl = `${baseUrl}/gateway`;
@@ -50,7 +56,9 @@ export class Provider implements ProviderInterface {
50
56
 
51
57
  protected static getNetworkFromName(name: NetworkName) {
52
58
  switch (name) {
53
- case 'alpha':
59
+ case 'mainnet-alpha':
60
+ return 'http://alpha-mainnet.starknet.io/';
61
+ case 'georli-alpha':
54
62
  default:
55
63
  return 'https://alpha4.starknet.io';
56
64
  }
@@ -257,23 +265,24 @@ export class Provider implements ProviderInterface {
257
265
  });
258
266
  }
259
267
 
260
- public async waitForTx(txHash: BigNumberish, retryInterval: number = 5000) {
268
+ public async waitForTx(txHash: BigNumberish, retryInterval: number = 8000) {
261
269
  let onchain = false;
262
- let firstRun = true;
263
270
  while (!onchain) {
264
271
  // eslint-disable-next-line no-await-in-loop
265
272
  await wait(retryInterval);
266
273
  // eslint-disable-next-line no-await-in-loop
267
274
  const res = await this.getTransactionStatus(txHash);
268
275
 
269
- if (res.tx_status === 'ACCEPTED_ONCHAIN' || res.tx_status === 'PENDING') {
276
+ if (
277
+ res.tx_status === 'ACCEPTED_ONCHAIN' ||
278
+ (res.tx_status === 'PENDING' && res.block_hash !== 'pending') // This is needed as of today. In the future there will be a different status for pending transactions.
279
+ ) {
270
280
  onchain = true;
271
281
  } else if (res.tx_status === 'REJECTED') {
272
282
  throw Error('REJECTED');
273
- } else if (res.tx_status === 'NOT_RECEIVED' && !firstRun) {
283
+ } else if (res.tx_status === 'NOT_RECEIVED') {
274
284
  throw Error('NOT_RECEIVED');
275
285
  }
276
- firstRun = false;
277
286
  }
278
287
  }
279
288
  }
package/src/types.ts CHANGED
@@ -16,13 +16,25 @@ export type Type = 'DEPLOY' | 'INVOKE_FUNCTION';
16
16
  export type EntryPointType = 'EXTERNAL';
17
17
  export type CompressedProgram = string;
18
18
 
19
- export type Abi = {
20
- inputs: { name: string; type: 'felt' | 'felt*' }[];
19
+ export type AbiEntry = { name: string; type: 'felt' | 'felt*' | string };
20
+
21
+ export type FunctionAbi = {
22
+ inputs: AbiEntry[];
21
23
  name: string;
22
- outputs: { name: string; type: 'felt' | 'felt*' }[];
24
+ outputs: AbiEntry[];
23
25
  stateMutability?: 'view';
24
26
  type: 'function';
25
27
  };
28
+
29
+ export type StructAbi = {
30
+ members: (AbiEntry & { offset: number })[];
31
+ name: string;
32
+ size: number;
33
+ type: 'struct';
34
+ };
35
+
36
+ export type Abi = FunctionAbi | StructAbi;
37
+
26
38
  export type EntryPointsByType = object;
27
39
  export type Program = object;
28
40
 
@@ -61,14 +73,14 @@ export type CallContractResponse = {
61
73
  export type GetBlockResponse = {
62
74
  sequence_number: number;
63
75
  state_root: string;
64
- block_id: number;
76
+ block_hash: string;
65
77
  transactions: {
66
78
  [txHash: string]: Transaction;
67
79
  };
68
80
  timestamp: number;
69
81
  transaction_receipts: {
70
82
  [txHash: string]: {
71
- block_id: number;
83
+ block_hash: string;
72
84
  transaction_hash: string;
73
85
  l2_to_l1_messages: {
74
86
  to_address: string;
@@ -80,7 +92,7 @@ export type GetBlockResponse = {
80
92
  transaction_index: number;
81
93
  };
82
94
  };
83
- previous_block_id: number;
95
+ previous_block_hash: string;
84
96
  status: Status;
85
97
  };
86
98
 
@@ -91,13 +103,13 @@ export type GetCodeResponse = {
91
103
 
92
104
  export type GetTransactionStatusResponse = {
93
105
  tx_status: Status;
94
- block_id: number;
106
+ block_hash: string;
95
107
  };
96
108
 
97
109
  export type GetTransactionResponse = {
98
110
  status: Status;
99
111
  transaction: Transaction;
100
- block_id: number;
112
+ block_hash: string;
101
113
  block_number: number;
102
114
  transaction_index: number;
103
115
  transaction_hash: string;
@@ -88,5 +88,5 @@ export function verify(keyPair: KeyPair, msgHash: string, sig: Signature): boole
88
88
  assertInRange(s, ONE, toBN(addHexPrefix(EC_ORDER)), 's');
89
89
  assertInRange(w, ONE, toBN(addHexPrefix(MAX_ECDSA_VAL)), 'w');
90
90
 
91
- return keyPair.verify(msgHash, sig);
91
+ return keyPair.verify(fixMessage(msgHash), sig);
92
92
  }
package/tsconfig.json CHANGED
@@ -105,11 +105,12 @@
105
105
  "include": ["src/**/*"],
106
106
  "exclude": ["node_modules"],
107
107
  "typedocOptions": {
108
- "entryPoints": ["src/starknet.ts", "src/types.ts"],
108
+ "entryPoints": "src/index.ts",
109
+ "entryPointStrategy": "expand",
109
110
  "out": "docs",
110
111
  "githubPages": false,
111
112
  "readme": "./README.md",
112
113
  "name": "StarkNet.js Docs",
113
- "sort": "source-order"
114
+ "sort": "required-first"
114
115
  }
115
116
  }
package/types.d.ts CHANGED
@@ -17,19 +17,26 @@ export declare type TxStatus = 'TRANSACTION_RECEIVED';
17
17
  export declare type Type = 'DEPLOY' | 'INVOKE_FUNCTION';
18
18
  export declare type EntryPointType = 'EXTERNAL';
19
19
  export declare type CompressedProgram = string;
20
- export declare type Abi = {
21
- inputs: {
22
- name: string;
23
- type: 'felt' | 'felt*';
24
- }[];
20
+ export declare type AbiEntry = {
25
21
  name: string;
26
- outputs: {
27
- name: string;
28
- type: 'felt' | 'felt*';
29
- }[];
22
+ type: 'felt' | 'felt*' | string;
23
+ };
24
+ export declare type FunctionAbi = {
25
+ inputs: AbiEntry[];
26
+ name: string;
27
+ outputs: AbiEntry[];
30
28
  stateMutability?: 'view';
31
29
  type: 'function';
32
30
  };
31
+ export declare type StructAbi = {
32
+ members: (AbiEntry & {
33
+ offset: number;
34
+ })[];
35
+ name: string;
36
+ size: number;
37
+ type: 'struct';
38
+ };
39
+ export declare type Abi = FunctionAbi | StructAbi;
33
40
  export declare type EntryPointsByType = object;
34
41
  export declare type Program = object;
35
42
  export declare type CompiledContract = {
@@ -60,14 +67,14 @@ export declare type CallContractResponse = {
60
67
  export declare type GetBlockResponse = {
61
68
  sequence_number: number;
62
69
  state_root: string;
63
- block_id: number;
70
+ block_hash: string;
64
71
  transactions: {
65
72
  [txHash: string]: Transaction;
66
73
  };
67
74
  timestamp: number;
68
75
  transaction_receipts: {
69
76
  [txHash: string]: {
70
- block_id: number;
77
+ block_hash: string;
71
78
  transaction_hash: string;
72
79
  l2_to_l1_messages: {
73
80
  to_address: string;
@@ -79,7 +86,7 @@ export declare type GetBlockResponse = {
79
86
  transaction_index: number;
80
87
  };
81
88
  };
82
- previous_block_id: number;
89
+ previous_block_hash: string;
83
90
  status: Status;
84
91
  };
85
92
  export declare type GetCodeResponse = {
@@ -88,12 +95,12 @@ export declare type GetCodeResponse = {
88
95
  };
89
96
  export declare type GetTransactionStatusResponse = {
90
97
  tx_status: Status;
91
- block_id: number;
98
+ block_hash: string;
92
99
  };
93
100
  export declare type GetTransactionResponse = {
94
101
  status: Status;
95
102
  transaction: Transaction;
96
- block_id: number;
103
+ block_hash: string;
97
104
  block_number: number;
98
105
  transaction_index: number;
99
106
  transaction_hash: string;
@@ -138,6 +138,6 @@ function verify(keyPair, msgHash, sig) {
138
138
  (0, number_1.toBN)((0, encode_1.addHexPrefix)(constants_1.MAX_ECDSA_VAL)),
139
139
  'w'
140
140
  );
141
- return keyPair.verify(msgHash, sig);
141
+ return keyPair.verify(fixMessage(msgHash), sig);
142
142
  }
143
143
  exports.verify = verify;