starknet 2.7.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/.eslintrc +3 -1
  2. package/CHANGELOG.md +47 -0
  3. package/CONTRIBUTING.md +1 -1
  4. package/README.md +18 -16
  5. package/__mocks__/typedDataExample.json +35 -0
  6. package/__tests__/account.test.ts +52 -87
  7. package/__tests__/accountContract.test.ts +160 -0
  8. package/__tests__/contract.test.ts +3 -1
  9. package/__tests__/jest.setup.ts +9 -0
  10. package/__tests__/provider.test.ts +16 -33
  11. package/__tests__/utils/address.test.ts +16 -0
  12. package/__tests__/utils/typedData.test.ts +1 -36
  13. package/account/default.d.ts +66 -0
  14. package/account/default.js +440 -0
  15. package/account/index.d.ts +2 -0
  16. package/account/index.js +27 -0
  17. package/account/interface.d.ts +83 -0
  18. package/account/interface.js +37 -0
  19. package/constants.d.ts +2 -0
  20. package/constants.js +4 -0
  21. package/contract.d.ts +6 -6
  22. package/contract.js +16 -14
  23. package/dist/account/default.d.ts +55 -0
  24. package/dist/account/default.js +272 -0
  25. package/dist/account/index.d.ts +2 -0
  26. package/dist/account/index.js +14 -0
  27. package/dist/account/interface.d.ts +69 -0
  28. package/dist/account/interface.js +27 -0
  29. package/dist/constants.d.ts +2 -0
  30. package/dist/constants.js +3 -1
  31. package/dist/contract.d.ts +6 -6
  32. package/dist/contract.js +9 -12
  33. package/dist/index.d.ts +2 -1
  34. package/dist/index.js +2 -1
  35. package/dist/provider/default.d.ts +27 -16
  36. package/dist/provider/default.js +157 -100
  37. package/dist/provider/interface.d.ts +29 -32
  38. package/dist/provider/utils.d.ts +21 -5
  39. package/dist/provider/utils.js +53 -10
  40. package/dist/signer/default.d.ts +7 -31
  41. package/dist/signer/default.js +25 -121
  42. package/dist/signer/index.d.ts +1 -1
  43. package/dist/signer/index.js +1 -1
  44. package/dist/signer/interface.d.ts +17 -18
  45. package/dist/signer/interface.js +2 -20
  46. package/dist/{types.d.ts → types/api.d.ts} +72 -41
  47. package/dist/{types.js → types/api.js} +0 -0
  48. package/dist/types/index.d.ts +3 -0
  49. package/dist/types/index.js +15 -0
  50. package/dist/types/lib.d.ts +57 -0
  51. package/dist/types/lib.js +2 -0
  52. package/dist/types/signer.d.ts +4 -0
  53. package/dist/types/signer.js +2 -0
  54. package/dist/utils/address.d.ts +2 -0
  55. package/dist/utils/address.js +22 -0
  56. package/dist/utils/number.d.ts +1 -0
  57. package/dist/utils/number.js +5 -1
  58. package/index.d.ts +2 -1
  59. package/index.js +2 -1
  60. package/package.json +8 -2
  61. package/provider/default.d.ts +45 -36
  62. package/provider/default.js +216 -201
  63. package/provider/interface.d.ts +36 -49
  64. package/provider/utils.d.ts +23 -8
  65. package/provider/utils.js +57 -11
  66. package/signer/default.d.ts +11 -31
  67. package/signer/default.js +52 -169
  68. package/signer/index.d.ts +1 -1
  69. package/signer/index.js +1 -1
  70. package/signer/interface.d.ts +21 -18
  71. package/signer/interface.js +3 -32
  72. package/src/account/default.ts +152 -0
  73. package/src/account/index.ts +2 -0
  74. package/src/account/interface.ts +91 -0
  75. package/src/constants.ts +2 -0
  76. package/src/contract.ts +17 -18
  77. package/src/index.ts +2 -1
  78. package/src/provider/default.ts +141 -110
  79. package/src/provider/interface.ts +36 -52
  80. package/src/provider/utils.ts +60 -13
  81. package/src/signer/default.ts +33 -76
  82. package/src/signer/index.ts +1 -1
  83. package/src/signer/interface.ts +21 -20
  84. package/src/types/api.ts +165 -0
  85. package/src/types/index.ts +3 -0
  86. package/src/types/lib.ts +73 -0
  87. package/src/types/signer.ts +5 -0
  88. package/src/utils/address.ts +23 -0
  89. package/src/utils/number.ts +4 -0
  90. package/types/api.d.ts +152 -0
  91. package/{types.js → types/api.js} +0 -0
  92. package/types/index.d.ts +3 -0
  93. package/types/index.js +28 -0
  94. package/types/lib.d.ts +64 -0
  95. package/types/lib.js +2 -0
  96. package/types/signer.d.ts +4 -0
  97. package/types/signer.js +2 -0
  98. package/utils/address.d.ts +2 -0
  99. package/utils/address.js +22 -0
  100. package/utils/number.d.ts +3 -0
  101. package/utils/number.js +8 -1
  102. package/__tests__/signer.test.ts +0 -119
  103. package/src/types.ts +0 -131
  104. package/types.d.ts +0 -116
@@ -1,37 +1,8 @@
1
1
  'use strict';
2
- var __extends =
3
- (this && this.__extends) ||
4
- (function () {
5
- var extendStatics = function (d, b) {
6
- extendStatics =
7
- Object.setPrototypeOf ||
8
- ({ __proto__: [] } instanceof Array &&
9
- function (d, b) {
10
- d.__proto__ = b;
11
- }) ||
12
- function (d, b) {
13
- for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p];
14
- };
15
- return extendStatics(d, b);
16
- };
17
- return function (d, b) {
18
- if (typeof b !== 'function' && b !== null)
19
- throw new TypeError('Class extends value ' + String(b) + ' is not a constructor or null');
20
- extendStatics(d, b);
21
- function __() {
22
- this.constructor = d;
23
- }
24
- d.prototype = b === null ? Object.create(b) : ((__.prototype = b.prototype), new __());
25
- };
26
- })();
27
2
  Object.defineProperty(exports, '__esModule', { value: true });
28
3
  exports.SignerInterface = void 0;
29
- var provider_1 = require('../provider');
30
- var SignerInterface = /** @class */ (function (_super) {
31
- __extends(SignerInterface, _super);
32
- function SignerInterface() {
33
- return (_super !== null && _super.apply(this, arguments)) || this;
34
- }
4
+ var SignerInterface = /** @class */ (function () {
5
+ function SignerInterface() {}
35
6
  return SignerInterface;
36
- })(provider_1.Provider);
7
+ })();
37
8
  exports.SignerInterface = SignerInterface;
@@ -0,0 +1,152 @@
1
+ import { compileCalldata } from '../contract';
2
+ import { Provider } from '../provider';
3
+ import { Signer, SignerInterface } from '../signer';
4
+ import {
5
+ Abi,
6
+ AddTransactionResponse,
7
+ ExecuteInvocation,
8
+ InvocationsDetails,
9
+ KeyPair,
10
+ Signature,
11
+ } from '../types';
12
+ import { BigNumberish, bigNumberishArrayToDecimalStringArray, toBN, toHex } from '../utils/number';
13
+ import { getSelectorFromName } from '../utils/stark';
14
+ import { TypedData, getMessageHash } from '../utils/typedData';
15
+ import { AccountInterface } from './interface';
16
+
17
+ export class Account extends Provider implements AccountInterface {
18
+ public address: string;
19
+
20
+ private signer: SignerInterface;
21
+
22
+ constructor(provider: Provider, address: string, keyPair: KeyPair) {
23
+ super(provider);
24
+ this.signer = new Signer(keyPair);
25
+ this.address = address;
26
+ }
27
+
28
+ public async getNonce(): Promise<string> {
29
+ const { result } = await this.callContract({
30
+ contractAddress: this.address,
31
+ entrypoint: 'get_nonce',
32
+ });
33
+ return toHex(toBN(result[0]));
34
+ }
35
+
36
+ /**
37
+ * Invoke execute function in account contract
38
+ *
39
+ * [Reference](https://github.com/starkware-libs/cairo-lang/blob/f464ec4797361b6be8989e36e02ec690e74ef285/src/starkware/starknet/services/api/gateway/gateway_client.py#L13-L17)
40
+ *
41
+ * @param transaction - transaction to be invoked
42
+ * @returns a confirmation of invoking a function on the starknet contract
43
+ */
44
+ public async execute(
45
+ transactions: ExecuteInvocation | ExecuteInvocation[],
46
+ abis: Abi[] = [],
47
+ transactionsDetail: InvocationsDetails = {}
48
+ ): Promise<AddTransactionResponse> {
49
+ if (Array.isArray(transactions) && transactions.length !== 1) {
50
+ throw new Error('Only one transaction at a time is currently supported');
51
+ }
52
+
53
+ const {
54
+ contractAddress,
55
+ calldata = [],
56
+ entrypoint,
57
+ ...invocation
58
+ } = Array.isArray(transactions) ? transactions[0] : transactions;
59
+ const { nonce } = transactionsDetail;
60
+
61
+ const nonceBn = toBN(nonce ?? (await this.getNonce()));
62
+ const calldataDecimal = bigNumberishArrayToDecimalStringArray(calldata);
63
+
64
+ const signature = await this.signer.signTransaction(
65
+ [
66
+ {
67
+ ...invocation,
68
+ contractAddress,
69
+ calldata: calldataDecimal,
70
+ entrypoint,
71
+ },
72
+ ],
73
+ { walletAddress: this.address, nonce: nonceBn },
74
+ abis
75
+ );
76
+
77
+ const entrypointSelector = getSelectorFromName(entrypoint);
78
+
79
+ return super.invokeFunction({
80
+ contractAddress: this.address,
81
+ entrypoint: 'execute',
82
+ calldata: [
83
+ contractAddress,
84
+ entrypointSelector,
85
+ calldataDecimal.length.toString(),
86
+ ...calldataDecimal,
87
+ nonceBn.toString(),
88
+ ],
89
+ signature,
90
+ });
91
+ }
92
+
93
+ /**
94
+ * Sign an JSON object with the starknet private key and return the signature
95
+ *
96
+ * @param json - JSON object to be signed
97
+ * @returns the signature of the JSON object
98
+ * @throws {Error} if the JSON object is not a valid JSON
99
+ */
100
+ public async signMessage(typedData: TypedData): Promise<Signature> {
101
+ return this.signer.signMessage(typedData, this.address);
102
+ }
103
+
104
+ /**
105
+ * Hash a JSON object with pederson hash and return the hash
106
+ *
107
+ * @param json - JSON object to be hashed
108
+ * @returns the hash of the JSON object
109
+ * @throws {Error} if the JSON object is not a valid JSON
110
+ */
111
+ public async hashMessage(typedData: TypedData): Promise<string> {
112
+ return getMessageHash(typedData, this.address);
113
+ }
114
+
115
+ /**
116
+ * Verify a signature of a JSON object
117
+ *
118
+ * @param json - JSON object to be verified
119
+ * @param signature - signature of the JSON object
120
+ * @returns true if the signature is valid, false otherwise
121
+ * @throws {Error} if the JSON object is not a valid JSON or the signature is not a valid signature
122
+ */
123
+ public async verifyMessageHash(hash: BigNumberish, signature: Signature): Promise<boolean> {
124
+ try {
125
+ await this.callContract({
126
+ contractAddress: this.address,
127
+ entrypoint: 'is_valid_signature',
128
+ calldata: compileCalldata({
129
+ hash: toBN(hash).toString(),
130
+ signature: signature.map((x) => toBN(x).toString()),
131
+ }),
132
+ });
133
+ return true;
134
+ } catch {
135
+ return false;
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Verify a signature of a given hash
141
+ * @warning This method is not recommended, use verifyMessage instead
142
+ *
143
+ * @param hash - hash to be verified
144
+ * @param signature - signature of the hash
145
+ * @returns true if the signature is valid, false otherwise
146
+ * @throws {Error} if the signature is not a valid signature
147
+ */
148
+ public async verifyMessage(typedData: TypedData, signature: Signature): Promise<boolean> {
149
+ const hash = await this.hashMessage(typedData);
150
+ return this.verifyMessageHash(hash, signature);
151
+ }
152
+ }
@@ -0,0 +1,2 @@
1
+ export * from './default';
2
+ export * from './interface';
@@ -0,0 +1,91 @@
1
+ import { ProviderInterface } from '../provider';
2
+ import {
3
+ Abi,
4
+ AddTransactionResponse,
5
+ DeployContractPayload,
6
+ ExecuteInvocation,
7
+ InvocationsDetails,
8
+ Signature,
9
+ } from '../types';
10
+ import { BigNumberish } from '../utils/number';
11
+ import { TypedData } from '../utils/typedData/types';
12
+
13
+ export abstract class AccountInterface extends ProviderInterface {
14
+ public abstract address: string;
15
+
16
+ /**
17
+ * Deploys a given compiled contract (json) to starknet
18
+ *
19
+ * @param payload payload to be deployed containing:
20
+ * - compiled contract code
21
+ * - constructor calldata
22
+ * - address salt
23
+ * @param abi the abi of the contract
24
+ * @returns a confirmation of sending a transaction on the starknet contract
25
+ */
26
+ public abstract override deployContract(
27
+ payload: DeployContractPayload,
28
+ abi?: Abi
29
+ ): Promise<AddTransactionResponse>;
30
+
31
+ /**
32
+ * Invoke execute function in account contract
33
+ *
34
+ * @param transactions the invocation object or an array of them, containing:
35
+ * - contractAddress - the address of the contract
36
+ * - entrypoint - the entrypoint of the contract
37
+ * - calldata - (defaults to []) the calldata
38
+ * - signature - (defaults to []) the signature
39
+ * @param abi (optional) the abi of the contract for better displaying
40
+ *
41
+ * @returns response from addTransaction
42
+ */
43
+ public abstract execute(
44
+ transactions: ExecuteInvocation | ExecuteInvocation[],
45
+ abis?: Abi[],
46
+ transactionsDetail?: InvocationsDetails
47
+ ): Promise<AddTransactionResponse>;
48
+
49
+ /**
50
+ * Sign an JSON object for off-chain usage with the starknet private key and return the signature
51
+ * This adds a message prefix so it cant be interchanged with transactions
52
+ *
53
+ * @param json - JSON object to be signed
54
+ * @returns the signature of the JSON object
55
+ * @throws {Error} if the JSON object is not a valid JSON
56
+ */
57
+ public abstract signMessage(typedData: TypedData): Promise<Signature>;
58
+
59
+ /**
60
+ * Hash a JSON object with pederson hash and return the hash
61
+ * This adds a message prefix so it cant be interchanged with transactions
62
+ *
63
+ * @param json - JSON object to be hashed
64
+ * @returns the hash of the JSON object
65
+ * @throws {Error} if the JSON object is not a valid JSON
66
+ */
67
+ public abstract hashMessage(typedData: TypedData): Promise<string>;
68
+
69
+ /**
70
+ * Verify a signature of a JSON object
71
+ *
72
+ * @param json - JSON object to be verified
73
+ * @param signature - signature of the JSON object
74
+ * @returns true if the signature is valid, false otherwise
75
+ * @throws {Error} if the JSON object is not a valid JSON or the signature is not a valid signature
76
+ */
77
+ public abstract verifyMessage(typedData: TypedData, signature: Signature): Promise<boolean>;
78
+
79
+ /**
80
+ * Verify a signature of a given hash
81
+ * @warning This method is not recommended, use verifyMessage instead
82
+ *
83
+ * @param hash - hash to be verified
84
+ * @param signature - signature of the hash
85
+ * @returns true if the signature is valid, false otherwise
86
+ * @throws {Error} if the signature is not a valid signature
87
+ */
88
+ public abstract verifyMessageHash(hash: BigNumberish, signature: Signature): Promise<boolean>;
89
+
90
+ public abstract getNonce(): Promise<string>;
91
+ }
package/src/constants.ts CHANGED
@@ -6,6 +6,7 @@ export const ZERO = toBN(0);
6
6
  export const ONE = toBN(1);
7
7
  export const TWO = toBN(2);
8
8
  export const MASK_250 = TWO.pow(toBN(250)).sub(ONE); // 2 ** 250 - 1
9
+ export const MASK_251 = TWO.pow(toBN(251));
9
10
 
10
11
  /**
11
12
  * 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
@@ -13,6 +14,7 @@ export const MASK_250 = TWO.pow(toBN(250)).sub(ONE); // 2 ** 250 - 1
13
14
  */
14
15
  export const FIELD_PRIME = '800000000000011000000000000000000000000000000000000000000000001';
15
16
  export const FIELD_GEN = '3';
17
+ export const FIELD_SIZE = 251;
16
18
  export const EC_ORDER = '800000000000010FFFFFFFFFFFFFFFFB781126DCAE7B2321E66A241ADC64D2F';
17
19
  export const ALPHA = '1';
18
20
  export const BETA = '6F21413EFBE40DE150E596D72F7A8C5609AD26C15C915C1F4CDFCB99CEE9E89';
package/src/contract.ts CHANGED
@@ -2,14 +2,13 @@ import BN from 'bn.js';
2
2
  import assert from 'minimalistic-assert';
3
3
 
4
4
  import { Provider, defaultProvider } from './provider';
5
- import { Abi, AbiEntry, FunctionAbi, Signature, StructAbi } from './types';
5
+ import { BlockIdentifier } from './provider/utils';
6
+ import { Abi, AbiEntry, FunctionAbi, RawCalldata, Signature, StructAbi } from './types';
6
7
  import { BigNumberish, toBN } from './utils/number';
7
- import { getSelectorFromName } from './utils/stark';
8
8
 
9
9
  export type Args = {
10
10
  [inputName: string]: string | string[] | { type: 'struct'; [k: string]: BigNumberish };
11
11
  };
12
- export type Calldata = string[];
13
12
 
14
13
  function parseFelt(candidate: string): BN {
15
14
  try {
@@ -28,7 +27,7 @@ function isFelt(candidate: string): boolean {
28
27
  }
29
28
  }
30
29
 
31
- export function compileCalldata(args: Args): Calldata {
30
+ export function compileCalldata(args: Args): RawCalldata {
32
31
  return Object.values(args).flatMap((value) => {
33
32
  if (Array.isArray(value))
34
33
  return [toBN(value.length).toString(), ...value.map((x) => toBN(x).toString())];
@@ -43,7 +42,7 @@ export function compileCalldata(args: Args): Calldata {
43
42
  export class Contract {
44
43
  connectedTo: string | null = null;
45
44
 
46
- abi: Abi[];
45
+ abi: Abi;
47
46
 
48
47
  structs: { [name: string]: StructAbi };
49
48
 
@@ -55,7 +54,7 @@ export class Contract {
55
54
  * @param abi - Abi of the contract object
56
55
  * @param address (optional) - address to connect to
57
56
  */
58
- constructor(abi: Abi[], address: string | null = null, provider: Provider = defaultProvider) {
57
+ constructor(abi: Abi, address: string | null = null, provider: Provider = defaultProvider) {
59
58
  this.connectedTo = address;
60
59
  this.provider = provider;
61
60
  this.abi = abi;
@@ -154,19 +153,17 @@ export class Contract {
154
153
  this.validateMethodAndArgs('INVOKE', method, args);
155
154
 
156
155
  // compile calldata
157
- const entrypointSelector = getSelectorFromName(method);
158
156
  const calldata = compileCalldata(args);
159
157
 
160
- return this.provider.addTransaction({
161
- type: 'INVOKE_FUNCTION',
162
- contract_address: this.connectedTo,
158
+ return this.provider.invokeFunction({
159
+ contractAddress: this.connectedTo,
163
160
  signature,
164
161
  calldata,
165
- entry_point_selector: entrypointSelector,
162
+ entrypoint: method,
166
163
  });
167
164
  }
168
165
 
169
- public async call(method: string, args: Args = {}) {
166
+ public async call(method: string, args: Args = {}, blockIdentifier: BlockIdentifier = null) {
170
167
  // ensure contract is connected
171
168
  assert(this.connectedTo !== null, 'contract isnt connected to an address');
172
169
 
@@ -174,15 +171,17 @@ export class Contract {
174
171
  this.validateMethodAndArgs('CALL', method, args);
175
172
 
176
173
  // compile calldata
177
- const entrypointSelector = getSelectorFromName(method);
178
174
  const calldata = compileCalldata(args);
179
175
 
180
176
  return this.provider
181
- .callContract({
182
- contract_address: this.connectedTo,
183
- calldata,
184
- entry_point_selector: entrypointSelector,
185
- })
177
+ .callContract(
178
+ {
179
+ contractAddress: this.connectedTo,
180
+ entrypoint: method,
181
+ calldata,
182
+ },
183
+ blockIdentifier
184
+ )
186
185
  .then((x) => this.parseResponse(method, x.result));
187
186
  }
188
187
  }
package/src/index.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  export * from './types';
5
5
  export * from './contract';
6
6
  export * from './provider';
7
- export * from './signer';
7
+ export * from './account';
8
8
 
9
9
  /**
10
10
  * Utils
@@ -19,3 +19,4 @@ export * as ec from './utils/ellipticCurve';
19
19
  export * as uint256 from './utils/uint256';
20
20
  export * as shortString from './utils/shortString';
21
21
  export * as typedData from './utils/typedData';
22
+ export * from './utils/address';