starknet 2.2.0 → 2.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.
- package/CHANGELOG.md +38 -0
- package/__tests__/account.test.ts +3 -3
- package/__tests__/signer.test.ts +17 -0
- package/__tests__/utils/ellipticalCurve.test.ts +1 -1
- package/__tests__/utils/shortString.test.ts +22 -0
- package/__tests__/utils/typedData.test.ts +72 -0
- package/__tests__/utils/uint256.test.ts +32 -0
- package/constants.d.ts +5 -5
- package/contract.d.ts +9 -3
- package/contract.js +23 -5
- package/dist/constants.d.ts +5 -5
- package/dist/contract.d.ts +6 -3
- package/dist/contract.js +19 -5
- package/dist/index.d.ts +3 -0
- package/dist/index.js +4 -1
- package/dist/provider/default.d.ts +6 -6
- package/dist/provider/default.js +18 -17
- package/dist/provider/interface.d.ts +6 -6
- package/dist/signer/default.d.ts +20 -3
- package/dist/signer/default.js +61 -20
- package/dist/signer/interface.d.ts +22 -3
- package/dist/types.d.ts +7 -5
- package/dist/utils/ellipticCurve.d.ts +8 -1
- package/dist/utils/ellipticCurve.js +48 -9
- package/dist/utils/shortString.d.ts +4 -0
- package/dist/utils/shortString.js +26 -0
- package/dist/utils/stark.d.ts +2 -3
- package/dist/utils/typedData/index.d.ts +91 -0
- package/dist/utils/typedData/index.js +183 -0
- package/dist/utils/typedData/types.d.ts +82 -0
- package/dist/utils/typedData/types.js +47 -0
- package/dist/utils/typedData/utils.d.ts +24 -0
- package/dist/utils/typedData/utils.js +15 -0
- package/dist/utils/uint256.d.ts +11 -0
- package/dist/utils/uint256.js +28 -0
- package/index.d.ts +3 -0
- package/index.js +7 -1
- package/package.json +3 -1
- package/provider/default.d.ts +9 -5
- package/provider/default.js +21 -19
- package/provider/interface.d.ts +6 -5
- package/signer/default.d.ts +20 -3
- package/signer/default.js +60 -17
- package/signer/interface.d.ts +22 -3
- package/src/constants.ts +4 -6
- package/src/contract.ts +17 -14
- package/src/index.ts +3 -0
- package/src/provider/default.ts +15 -13
- package/src/provider/interface.ts +6 -5
- package/src/signer/default.ts +49 -17
- package/src/signer/interface.ts +26 -3
- package/src/types.ts +13 -5
- package/src/utils/ellipticCurve.ts +31 -9
- package/src/utils/shortString.ts +21 -0
- package/src/utils/stark.ts +4 -4
- package/src/utils/typedData/index.ts +176 -0
- package/src/utils/typedData/types.ts +82 -0
- package/src/utils/typedData/utils.ts +13 -0
- package/src/utils/uint256.ts +32 -0
- package/types.d.ts +9 -6
- package/utils/ellipticCurve.d.ts +12 -1
- package/utils/ellipticCurve.js +72 -23
- package/utils/shortString.d.ts +4 -0
- package/utils/shortString.js +34 -0
- package/utils/stark.d.ts +2 -3
- package/utils/typedData/index.d.ts +113 -0
- package/utils/typedData/index.js +247 -0
- package/utils/typedData/types.d.ts +103 -0
- package/utils/typedData/types.js +57 -0
- package/utils/typedData/utils.d.ts +27 -0
- package/utils/typedData/utils.js +15 -0
- package/utils/uint256.d.ts +11 -0
- package/utils/uint256.js +38 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { computeHashOnElements } from '../hash';
|
|
2
|
+
import { BigNumberish, toBN, toHex } from '../number';
|
|
3
|
+
import { encodeShortString } from '../shortString';
|
|
4
|
+
import { getSelectorFromName } from '../stark';
|
|
5
|
+
import { TypedData } from './types';
|
|
6
|
+
import { validateTypedData } from './utils';
|
|
7
|
+
|
|
8
|
+
export * from './types';
|
|
9
|
+
|
|
10
|
+
function getHex(value: BigNumberish): string {
|
|
11
|
+
try {
|
|
12
|
+
return toHex(toBN(value));
|
|
13
|
+
} catch (e) {
|
|
14
|
+
if (typeof value === 'string') {
|
|
15
|
+
return toHex(toBN(encodeShortString(value)));
|
|
16
|
+
}
|
|
17
|
+
throw new Error(`Invalid BigNumberish: ${value}`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Get the dependencies of a struct type. If a struct has the same dependency multiple times, it's only included once
|
|
23
|
+
* in the resulting array.
|
|
24
|
+
*
|
|
25
|
+
* @param {TypedData} typedData
|
|
26
|
+
* @param {string} type
|
|
27
|
+
* @param {string[]} [dependencies]
|
|
28
|
+
* @return {string[]}
|
|
29
|
+
*/
|
|
30
|
+
export const getDependencies = (
|
|
31
|
+
typedData: TypedData,
|
|
32
|
+
type: string,
|
|
33
|
+
dependencies: string[] = []
|
|
34
|
+
): string[] => {
|
|
35
|
+
// `getDependencies` is called by most other functions, so we validate the JSON schema here
|
|
36
|
+
if (!validateTypedData(typedData)) {
|
|
37
|
+
throw new Error('Typed data does not match JSON schema');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (dependencies.includes(type)) {
|
|
41
|
+
return dependencies;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (!typedData.types[type]) {
|
|
45
|
+
return dependencies;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return [
|
|
49
|
+
type,
|
|
50
|
+
...typedData.types[type].reduce<string[]>(
|
|
51
|
+
(previous, t) => [
|
|
52
|
+
...previous,
|
|
53
|
+
...getDependencies(typedData, t.type, previous).filter(
|
|
54
|
+
(dependency) => !previous.includes(dependency)
|
|
55
|
+
),
|
|
56
|
+
],
|
|
57
|
+
[]
|
|
58
|
+
),
|
|
59
|
+
];
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Encode a type to a string. All dependant types are alphabetically sorted.
|
|
64
|
+
*
|
|
65
|
+
* @param {TypedData} typedData
|
|
66
|
+
* @param {string} type
|
|
67
|
+
* @return {string}
|
|
68
|
+
*/
|
|
69
|
+
export const encodeType = (typedData: TypedData, type: string): string => {
|
|
70
|
+
const [primary, ...dependencies] = getDependencies(typedData, type);
|
|
71
|
+
const types = [primary, ...dependencies.sort()];
|
|
72
|
+
|
|
73
|
+
return types
|
|
74
|
+
.map((dependency) => {
|
|
75
|
+
return `${dependency}(${typedData.types[dependency].map((t) => `${t.name}:${t.type}`)})`;
|
|
76
|
+
})
|
|
77
|
+
.join('');
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Get a type string as hash.
|
|
82
|
+
*
|
|
83
|
+
* @param {TypedData} typedData
|
|
84
|
+
* @param {string} type
|
|
85
|
+
* @return {string}
|
|
86
|
+
*/
|
|
87
|
+
export const getTypeHash = (typedData: TypedData, type: string): string => {
|
|
88
|
+
return getSelectorFromName(encodeType(typedData, type));
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Encodes a single value to an ABI serialisable string, number or Buffer. Returns the data as tuple, which consists of
|
|
93
|
+
* an array of ABI compatible types, and an array of corresponding values.
|
|
94
|
+
*
|
|
95
|
+
* @param {TypedData} typedData
|
|
96
|
+
* @param {string} type
|
|
97
|
+
* @param {any} data
|
|
98
|
+
* @returns {[string, string]}
|
|
99
|
+
*/
|
|
100
|
+
const encodeValue = (typedData: TypedData, type: string, data: unknown): [string, string] => {
|
|
101
|
+
if (typedData.types[type]) {
|
|
102
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
103
|
+
return [type, getStructHash(typedData, type, data as Record<string, unknown>)];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (type === 'felt*') {
|
|
107
|
+
return ['felt*', computeHashOnElements(data as string[])];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return [type, getHex(data as string)];
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Encode the data to an ABI encoded Buffer. The data should be a key -> value object with all the required values. All
|
|
115
|
+
* dependant types are automatically encoded.
|
|
116
|
+
*
|
|
117
|
+
* @param {TypedData} typedData
|
|
118
|
+
* @param {string} type
|
|
119
|
+
* @param {Record<string, any>} data
|
|
120
|
+
*/
|
|
121
|
+
export const encodeData = <T extends TypedData>(typedData: T, type: string, data: T['message']) => {
|
|
122
|
+
const [types, values] = typedData.types[type].reduce<[string[], string[]]>(
|
|
123
|
+
([ts, vs], field) => {
|
|
124
|
+
if (data[field.name] === undefined || data[field.name] === null) {
|
|
125
|
+
throw new Error(`Cannot encode data: missing data for '${field.name}'`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const value = data[field.name];
|
|
129
|
+
const [t, encodedValue] = encodeValue(typedData, field.type, value);
|
|
130
|
+
|
|
131
|
+
return [
|
|
132
|
+
[...ts, t],
|
|
133
|
+
[...vs, encodedValue],
|
|
134
|
+
];
|
|
135
|
+
},
|
|
136
|
+
[['felt'], [getTypeHash(typedData, type)]]
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
return [types, values];
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Get encoded data as a hash. The data should be a key -> value object with all the required values. All dependant
|
|
144
|
+
* types are automatically encoded.
|
|
145
|
+
*
|
|
146
|
+
* @param {TypedData} typedData
|
|
147
|
+
* @param {string} type
|
|
148
|
+
* @param {Record<string, any>} data
|
|
149
|
+
* @return {Buffer}
|
|
150
|
+
*/
|
|
151
|
+
export const getStructHash = <T extends TypedData>(
|
|
152
|
+
typedData: T,
|
|
153
|
+
type: string,
|
|
154
|
+
data: T['message']
|
|
155
|
+
) => {
|
|
156
|
+
return computeHashOnElements(encodeData(typedData, type, data)[1]);
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Get the EIP-191 encoded message to sign, from the typedData object. If `hash` is enabled, the message will be hashed
|
|
161
|
+
* with Keccak256.
|
|
162
|
+
*
|
|
163
|
+
* @param {TypedData} typedData
|
|
164
|
+
* @param {boolean} hash
|
|
165
|
+
* @return {string}
|
|
166
|
+
*/
|
|
167
|
+
export const getMessageHash = (typedData: TypedData, account: BigNumberish): string => {
|
|
168
|
+
const message = [
|
|
169
|
+
encodeShortString('StarkNet Message'),
|
|
170
|
+
getStructHash(typedData, 'StarkNetDomain', typedData.domain),
|
|
171
|
+
account,
|
|
172
|
+
getStructHash(typedData, typedData.primaryType, typedData.message),
|
|
173
|
+
];
|
|
174
|
+
|
|
175
|
+
return computeHashOnElements(message);
|
|
176
|
+
};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Infer,
|
|
3
|
+
array,
|
|
4
|
+
intersection,
|
|
5
|
+
number,
|
|
6
|
+
object,
|
|
7
|
+
optional,
|
|
8
|
+
record,
|
|
9
|
+
refine,
|
|
10
|
+
string,
|
|
11
|
+
type as t,
|
|
12
|
+
union,
|
|
13
|
+
} from 'superstruct';
|
|
14
|
+
|
|
15
|
+
export const ATOMIC_TYPES = ['felt', 'felt*'];
|
|
16
|
+
|
|
17
|
+
// Source: https://github.com/Mrtenz/eip-712/blob/master/src/eip-712.ts
|
|
18
|
+
// and modified to support starknet types
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Checks if a type is valid with the given `typedData`. The following types are valid:
|
|
22
|
+
* - Atomic types: felt, felt*
|
|
23
|
+
* - Reference types: struct type (e.g. SomeStruct)
|
|
24
|
+
*
|
|
25
|
+
* @param {Record<string, unknown>} types
|
|
26
|
+
* @param {string} type
|
|
27
|
+
* @return {boolean}
|
|
28
|
+
*/
|
|
29
|
+
export const isValidType = (types: Record<string, unknown>, type: string): boolean => {
|
|
30
|
+
if (ATOMIC_TYPES.includes(type as string)) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (types[type]) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return false;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const TYPE = refine(string(), 'Type', (type, context) => {
|
|
42
|
+
return isValidType(context.branch[0].types, type);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
export const STARKNET_TYPE = object({
|
|
46
|
+
name: string(),
|
|
47
|
+
type: TYPE,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* A single type, as part of a struct. The `type` field can be any of the EIP-712 supported types.
|
|
52
|
+
*
|
|
53
|
+
* Note that the `uint` and `int` aliases like in Solidity, and fixed point numbers are not supported by the EIP-712
|
|
54
|
+
* standard.
|
|
55
|
+
*/
|
|
56
|
+
export type StarkNetType = Infer<typeof STARKNET_TYPE>;
|
|
57
|
+
|
|
58
|
+
export const STARKNET_DOMAIN_TYPE = object({
|
|
59
|
+
name: optional(string()),
|
|
60
|
+
version: optional(string()),
|
|
61
|
+
chainId: optional(union([string(), number()])),
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The EIP712 domain struct. Any of these fields are optional, but it must contain at least one field.
|
|
66
|
+
*/
|
|
67
|
+
export type StarkNetDomain = Infer<typeof STARKNET_DOMAIN_TYPE>;
|
|
68
|
+
|
|
69
|
+
export const STARKNET_TYPED_DATA_TYPE = object({
|
|
70
|
+
types: intersection([
|
|
71
|
+
t({ StarkNetDomain: array(STARKNET_TYPE) }),
|
|
72
|
+
record(string(), array(STARKNET_TYPE)),
|
|
73
|
+
]),
|
|
74
|
+
primaryType: string(),
|
|
75
|
+
domain: STARKNET_DOMAIN_TYPE,
|
|
76
|
+
message: object(),
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The complete typed data, with all the structs, domain data, primary type of the message, and the message itself.
|
|
81
|
+
*/
|
|
82
|
+
export type TypedData = Infer<typeof STARKNET_TYPED_DATA_TYPE>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { is } from 'superstruct';
|
|
2
|
+
|
|
3
|
+
import { STARKNET_TYPED_DATA_TYPE, TypedData } from './types';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Validates that `data` matches the EIP-712 JSON schema.
|
|
7
|
+
*
|
|
8
|
+
* @param {any} data
|
|
9
|
+
* @return {boolean}
|
|
10
|
+
*/
|
|
11
|
+
export const validateTypedData = (data: unknown): data is TypedData => {
|
|
12
|
+
return is(data, STARKNET_TYPED_DATA_TYPE);
|
|
13
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { addHexPrefix } from './encode';
|
|
2
|
+
import { BigNumberish, toBN } from './number';
|
|
3
|
+
|
|
4
|
+
// Represents an integer in the range [0, 2^256).
|
|
5
|
+
export interface Uint256 {
|
|
6
|
+
// The low 128 bits of the value.
|
|
7
|
+
low: BigNumberish;
|
|
8
|
+
// The high 128 bits of the value.
|
|
9
|
+
high: BigNumberish;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// function to convert Uint256 to BN
|
|
13
|
+
export function uint256ToBN(uint256: Uint256) {
|
|
14
|
+
return toBN(uint256.high).shln(128).add(toBN(uint256.low));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const UINT_128_MAX = toBN(1).shln(128).sub(toBN(1));
|
|
18
|
+
export const UINT_256_MAX = toBN(1).shln(256).sub(toBN(1));
|
|
19
|
+
// function to check if BN is smaller or equal 2**256-1
|
|
20
|
+
export function isUint256(bn: BigNumberish): boolean {
|
|
21
|
+
return toBN(bn).lte(UINT_256_MAX);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// function to convert BN to Uint256
|
|
25
|
+
export function bnToUint256(bignumber: BigNumberish): Uint256 {
|
|
26
|
+
const bn = toBN(bignumber);
|
|
27
|
+
if (!isUint256(bn)) throw new Error('Number is too large');
|
|
28
|
+
return {
|
|
29
|
+
low: addHexPrefix(bn.maskn(128).toString(16)),
|
|
30
|
+
high: addHexPrefix(bn.shrn(128).toString(16)),
|
|
31
|
+
};
|
|
32
|
+
}
|
package/types.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { ec as EC } from 'elliptic';
|
|
|
2
2
|
|
|
3
3
|
import type { BigNumberish } from './utils/number';
|
|
4
4
|
export declare type KeyPair = EC.KeyPair;
|
|
5
|
-
export declare type Signature =
|
|
5
|
+
export declare type Signature = BigNumberish[];
|
|
6
6
|
export declare type GetContractAddressesResponse = {
|
|
7
7
|
Starknet: string;
|
|
8
8
|
GpsStatementVerifier: string;
|
|
@@ -11,9 +11,10 @@ export declare type Status =
|
|
|
11
11
|
| 'NOT_RECEIVED'
|
|
12
12
|
| 'RECEIVED'
|
|
13
13
|
| 'PENDING'
|
|
14
|
-
| '
|
|
15
|
-
| '
|
|
16
|
-
|
|
14
|
+
| 'ACCEPTED_ON_L2'
|
|
15
|
+
| 'ACCEPTED_ON_L1'
|
|
16
|
+
| 'REJECTED';
|
|
17
|
+
export declare type TransactionStatus = 'TRANSACTION_RECEIVED';
|
|
17
18
|
export declare type Type = 'DEPLOY' | 'INVOKE_FUNCTION';
|
|
18
19
|
export declare type EntryPointType = 'EXTERNAL';
|
|
19
20
|
export declare type CompressedProgram = string;
|
|
@@ -50,14 +51,16 @@ export declare type DeployTransaction = {
|
|
|
50
51
|
contract_definition: CompressedCompiledContract;
|
|
51
52
|
contract_address_salt: BigNumberish;
|
|
52
53
|
constructor_calldata: string[];
|
|
54
|
+
nonce?: BigNumberish;
|
|
53
55
|
};
|
|
54
56
|
export declare type InvokeFunctionTransaction = {
|
|
55
57
|
type: 'INVOKE_FUNCTION';
|
|
56
58
|
contract_address: string;
|
|
57
|
-
signature?:
|
|
59
|
+
signature?: Signature;
|
|
58
60
|
entry_point_type?: EntryPointType;
|
|
59
61
|
entry_point_selector: string;
|
|
60
62
|
calldata?: string[];
|
|
63
|
+
nonce?: BigNumberish;
|
|
61
64
|
};
|
|
62
65
|
export declare type CallContractTransaction = Omit<InvokeFunctionTransaction, 'type'>;
|
|
63
66
|
export declare type Transaction = DeployTransaction | InvokeFunctionTransaction;
|
|
@@ -106,7 +109,7 @@ export declare type GetTransactionResponse = {
|
|
|
106
109
|
transaction_hash: string;
|
|
107
110
|
};
|
|
108
111
|
export declare type AddTransactionResponse = {
|
|
109
|
-
code:
|
|
112
|
+
code: TransactionStatus;
|
|
110
113
|
transaction_hash: string;
|
|
111
114
|
address?: string;
|
|
112
115
|
};
|
package/utils/ellipticCurve.d.ts
CHANGED
|
@@ -6,5 +6,16 @@ export declare const ec: EC;
|
|
|
6
6
|
export declare const genKeyPair: (options?: EC.GenKeyPairOptions | undefined) => EC.KeyPair;
|
|
7
7
|
export declare function getKeyPair(pk: BigNumberish): KeyPair;
|
|
8
8
|
export declare function getStarkKey(keyPair: KeyPair): string;
|
|
9
|
+
/**
|
|
10
|
+
* Takes a public key and casts it into `elliptic` KeyPair format.
|
|
11
|
+
*
|
|
12
|
+
* @param publicKey - public key which should get casted to a KeyPair
|
|
13
|
+
* @returns keyPair with public key only, which can be used to verify signatures, but cant sign anything
|
|
14
|
+
*/
|
|
15
|
+
export declare function getKeyPairFromPublicKey(publicKey: BigNumberish): KeyPair;
|
|
9
16
|
export declare function sign(keyPair: KeyPair, msgHash: string): Signature;
|
|
10
|
-
export declare function verify(
|
|
17
|
+
export declare function verify(
|
|
18
|
+
keyPair: KeyPair | KeyPair[],
|
|
19
|
+
msgHash: string,
|
|
20
|
+
sig: Signature
|
|
21
|
+
): boolean;
|
package/utils/ellipticCurve.js
CHANGED
|
@@ -1,4 +1,26 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
var __read =
|
|
3
|
+
(this && this.__read) ||
|
|
4
|
+
function (o, n) {
|
|
5
|
+
var m = typeof Symbol === 'function' && o[Symbol.iterator];
|
|
6
|
+
if (!m) return o;
|
|
7
|
+
var i = m.call(o),
|
|
8
|
+
r,
|
|
9
|
+
ar = [],
|
|
10
|
+
e;
|
|
11
|
+
try {
|
|
12
|
+
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
13
|
+
} catch (error) {
|
|
14
|
+
e = { error: error };
|
|
15
|
+
} finally {
|
|
16
|
+
try {
|
|
17
|
+
if (r && !r.done && (m = i['return'])) m.call(i);
|
|
18
|
+
} finally {
|
|
19
|
+
if (e) throw e.error;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return ar;
|
|
23
|
+
};
|
|
2
24
|
var __importDefault =
|
|
3
25
|
(this && this.__importDefault) ||
|
|
4
26
|
function (mod) {
|
|
@@ -7,6 +29,7 @@ var __importDefault =
|
|
|
7
29
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
8
30
|
exports.verify =
|
|
9
31
|
exports.sign =
|
|
32
|
+
exports.getKeyPairFromPublicKey =
|
|
10
33
|
exports.getStarkKey =
|
|
11
34
|
exports.getKeyPair =
|
|
12
35
|
exports.genKeyPair =
|
|
@@ -62,6 +85,20 @@ function getStarkKey(keyPair) {
|
|
|
62
85
|
);
|
|
63
86
|
}
|
|
64
87
|
exports.getStarkKey = getStarkKey;
|
|
88
|
+
/**
|
|
89
|
+
* Takes a public key and casts it into `elliptic` KeyPair format.
|
|
90
|
+
*
|
|
91
|
+
* @param publicKey - public key which should get casted to a KeyPair
|
|
92
|
+
* @returns keyPair with public key only, which can be used to verify signatures, but cant sign anything
|
|
93
|
+
*/
|
|
94
|
+
function getKeyPairFromPublicKey(publicKey) {
|
|
95
|
+
var publicKeyBn = (0, number_1.toBN)(publicKey);
|
|
96
|
+
return exports.ec.keyFromPublic(
|
|
97
|
+
(0, encode_1.removeHexPrefix)((0, number_1.toHex)(publicKeyBn)),
|
|
98
|
+
'hex'
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
exports.getKeyPairFromPublicKey = getKeyPairFromPublicKey;
|
|
65
102
|
/*
|
|
66
103
|
Signs a message using the provided key.
|
|
67
104
|
key should be an KeyPair with a valid private key.
|
|
@@ -99,9 +136,16 @@ function sign(keyPair, msgHash) {
|
|
|
99
136
|
(0, number_1.toBN)((0, encode_1.addHexPrefix)(constants_1.MAX_ECDSA_VAL)),
|
|
100
137
|
'w'
|
|
101
138
|
);
|
|
102
|
-
return
|
|
139
|
+
return [r, s];
|
|
103
140
|
}
|
|
104
141
|
exports.sign = sign;
|
|
142
|
+
function chunkArray(arr, n) {
|
|
143
|
+
return Array(Math.ceil(arr.length / n))
|
|
144
|
+
.fill('')
|
|
145
|
+
.map(function (_, i) {
|
|
146
|
+
return arr.slice(i * n, i * n + n);
|
|
147
|
+
});
|
|
148
|
+
}
|
|
105
149
|
/*
|
|
106
150
|
Verifies a message using the provided key.
|
|
107
151
|
key should be an KeyPair with a valid public key.
|
|
@@ -109,35 +153,40 @@ exports.sign = sign;
|
|
|
109
153
|
Returns a boolean true if the verification succeeds.
|
|
110
154
|
*/
|
|
111
155
|
function verify(keyPair, msgHash, sig) {
|
|
156
|
+
var keyPairArray = Array.isArray(keyPair) ? keyPair : [keyPair];
|
|
112
157
|
var msgHashBN = (0, number_1.toBN)((0, encode_1.addHexPrefix)(msgHash));
|
|
158
|
+
(0, minimalistic_assert_1.default)(
|
|
159
|
+
sig.length % 2 === 0,
|
|
160
|
+
'Signature must be an array of length dividable by 2'
|
|
161
|
+
);
|
|
113
162
|
(0, number_1.assertInRange)(
|
|
114
163
|
msgHashBN,
|
|
115
164
|
constants_1.ZERO,
|
|
116
165
|
(0, number_1.toBN)((0, encode_1.addHexPrefix)(constants_1.MAX_ECDSA_VAL)),
|
|
117
166
|
'msgHash'
|
|
118
167
|
);
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
// Verify signature has valid length.
|
|
123
|
-
(0, number_1.assertInRange)(
|
|
124
|
-
r,
|
|
125
|
-
constants_1.ONE,
|
|
126
|
-
(0, number_1.toBN)((0, encode_1.addHexPrefix)(constants_1.MAX_ECDSA_VAL)),
|
|
127
|
-
'r'
|
|
128
|
-
);
|
|
129
|
-
(0, number_1.assertInRange)(
|
|
130
|
-
s,
|
|
131
|
-
constants_1.ONE,
|
|
132
|
-
(0, number_1.toBN)((0, encode_1.addHexPrefix)(constants_1.EC_ORDER)),
|
|
133
|
-
's'
|
|
134
|
-
);
|
|
135
|
-
(0, number_1.assertInRange)(
|
|
136
|
-
w,
|
|
137
|
-
constants_1.ONE,
|
|
138
|
-
(0, number_1.toBN)((0, encode_1.addHexPrefix)(constants_1.MAX_ECDSA_VAL)),
|
|
139
|
-
'w'
|
|
168
|
+
(0, minimalistic_assert_1.default)(
|
|
169
|
+
keyPairArray.length === sig.length / 2,
|
|
170
|
+
'Signature and keyPair length must be equal'
|
|
140
171
|
);
|
|
141
|
-
return
|
|
172
|
+
return chunkArray(sig, 2).every(function (_a, i) {
|
|
173
|
+
var _b;
|
|
174
|
+
var _c = __read(_a, 2),
|
|
175
|
+
r = _c[0],
|
|
176
|
+
s = _c[1];
|
|
177
|
+
var rBN = (0, number_1.toBN)(r);
|
|
178
|
+
var sBN = (0, number_1.toBN)(s);
|
|
179
|
+
var w = sBN.invm(exports.ec.n);
|
|
180
|
+
(0,
|
|
181
|
+
number_1.assertInRange)(rBN, constants_1.ONE, (0, number_1.toBN)((0, encode_1.addHexPrefix)(constants_1.MAX_ECDSA_VAL)), 'r');
|
|
182
|
+
(0,
|
|
183
|
+
number_1.assertInRange)(sBN, constants_1.ONE, (0, number_1.toBN)((0, encode_1.addHexPrefix)(constants_1.EC_ORDER)), 's');
|
|
184
|
+
(0,
|
|
185
|
+
number_1.assertInRange)(w, constants_1.ONE, (0, number_1.toBN)((0, encode_1.addHexPrefix)(constants_1.MAX_ECDSA_VAL)), 'w');
|
|
186
|
+
return (_b = exports.ec.verify(fixMessage(msgHash), { r: rBN, s: sBN }, keyPairArray[i])) !==
|
|
187
|
+
null && _b !== void 0
|
|
188
|
+
? _b
|
|
189
|
+
: false;
|
|
190
|
+
});
|
|
142
191
|
}
|
|
143
192
|
exports.verify = verify;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
3
|
+
exports.decodeShortString =
|
|
4
|
+
exports.encodeShortString =
|
|
5
|
+
exports.isShortString =
|
|
6
|
+
exports.isASCII =
|
|
7
|
+
void 0;
|
|
8
|
+
var encode_1 = require('./encode');
|
|
9
|
+
function isASCII(str) {
|
|
10
|
+
// eslint-disable-next-line no-control-regex
|
|
11
|
+
return /^[\x00-\x7F]*$/.test(str);
|
|
12
|
+
}
|
|
13
|
+
exports.isASCII = isASCII;
|
|
14
|
+
// function to check if string has less or equal 31 characters
|
|
15
|
+
function isShortString(str) {
|
|
16
|
+
return str.length <= 31;
|
|
17
|
+
}
|
|
18
|
+
exports.isShortString = isShortString;
|
|
19
|
+
function encodeShortString(str) {
|
|
20
|
+
if (!isASCII(str)) throw new Error(str + ' is not an ASCII string');
|
|
21
|
+
if (!isShortString(str)) throw new Error(str + ' is too long');
|
|
22
|
+
return (0, encode_1.addHexPrefix)(
|
|
23
|
+
str.replace(/./g, function (char) {
|
|
24
|
+
return char.charCodeAt(0).toString(16);
|
|
25
|
+
})
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
exports.encodeShortString = encodeShortString;
|
|
29
|
+
function decodeShortString(str) {
|
|
30
|
+
return (0, encode_1.removeHexPrefix)(str).replace(/.{2}/g, function (hex) {
|
|
31
|
+
return String.fromCharCode(parseInt(hex, 16));
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
exports.decodeShortString = decodeShortString;
|
package/utils/stark.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { CompressedProgram, Program } from '../types';
|
|
2
|
-
import { BigNumberish } from './number';
|
|
1
|
+
import { CompressedProgram, Program, Signature } from '../types';
|
|
3
2
|
/**
|
|
4
3
|
* Function to compress compiled cairo program
|
|
5
4
|
*
|
|
@@ -18,4 +17,4 @@ export declare function compressProgram(jsonProgram: Program | string): Compress
|
|
|
18
17
|
export declare function getSelectorFromName(funcName: string): string;
|
|
19
18
|
export declare function randomAddress(): string;
|
|
20
19
|
export declare function makeAddress(input: string): string;
|
|
21
|
-
export declare function formatSignature(sig?:
|
|
20
|
+
export declare function formatSignature(sig?: Signature): string[];
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { BigNumberish } from '../number';
|
|
2
|
+
import { TypedData } from './types';
|
|
3
|
+
export * from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Get the dependencies of a struct type. If a struct has the same dependency multiple times, it's only included once
|
|
6
|
+
* in the resulting array.
|
|
7
|
+
*
|
|
8
|
+
* @param {TypedData} typedData
|
|
9
|
+
* @param {string} type
|
|
10
|
+
* @param {string[]} [dependencies]
|
|
11
|
+
* @return {string[]}
|
|
12
|
+
*/
|
|
13
|
+
export declare const getDependencies: (
|
|
14
|
+
typedData: TypedData,
|
|
15
|
+
type: string,
|
|
16
|
+
dependencies?: string[]
|
|
17
|
+
) => string[];
|
|
18
|
+
/**
|
|
19
|
+
* Encode a type to a string. All dependant types are alphabetically sorted.
|
|
20
|
+
*
|
|
21
|
+
* @param {TypedData} typedData
|
|
22
|
+
* @param {string} type
|
|
23
|
+
* @return {string}
|
|
24
|
+
*/
|
|
25
|
+
export declare const encodeType: (typedData: TypedData, type: string) => string;
|
|
26
|
+
/**
|
|
27
|
+
* Get a type string as hash.
|
|
28
|
+
*
|
|
29
|
+
* @param {TypedData} typedData
|
|
30
|
+
* @param {string} type
|
|
31
|
+
* @return {string}
|
|
32
|
+
*/
|
|
33
|
+
export declare const getTypeHash: (typedData: TypedData, type: string) => string;
|
|
34
|
+
/**
|
|
35
|
+
* Encode the data to an ABI encoded Buffer. The data should be a key -> value object with all the required values. All
|
|
36
|
+
* dependant types are automatically encoded.
|
|
37
|
+
*
|
|
38
|
+
* @param {TypedData} typedData
|
|
39
|
+
* @param {string} type
|
|
40
|
+
* @param {Record<string, any>} data
|
|
41
|
+
*/
|
|
42
|
+
export declare const encodeData: <
|
|
43
|
+
T extends {
|
|
44
|
+
types: {
|
|
45
|
+
StarkNetDomain: {
|
|
46
|
+
type: string;
|
|
47
|
+
name: string;
|
|
48
|
+
}[];
|
|
49
|
+
} & Record<
|
|
50
|
+
string,
|
|
51
|
+
{
|
|
52
|
+
type: string;
|
|
53
|
+
name: string;
|
|
54
|
+
}[]
|
|
55
|
+
>;
|
|
56
|
+
primaryType: string;
|
|
57
|
+
domain: {
|
|
58
|
+
name?: string | undefined;
|
|
59
|
+
version?: string | undefined;
|
|
60
|
+
chainId?: string | number | undefined;
|
|
61
|
+
};
|
|
62
|
+
message: Record<string, unknown>;
|
|
63
|
+
}
|
|
64
|
+
>(
|
|
65
|
+
typedData: T,
|
|
66
|
+
type: string,
|
|
67
|
+
data: T['message']
|
|
68
|
+
) => string[][];
|
|
69
|
+
/**
|
|
70
|
+
* Get encoded data as a hash. The data should be a key -> value object with all the required values. All dependant
|
|
71
|
+
* types are automatically encoded.
|
|
72
|
+
*
|
|
73
|
+
* @param {TypedData} typedData
|
|
74
|
+
* @param {string} type
|
|
75
|
+
* @param {Record<string, any>} data
|
|
76
|
+
* @return {Buffer}
|
|
77
|
+
*/
|
|
78
|
+
export declare const getStructHash: <
|
|
79
|
+
T extends {
|
|
80
|
+
types: {
|
|
81
|
+
StarkNetDomain: {
|
|
82
|
+
type: string;
|
|
83
|
+
name: string;
|
|
84
|
+
}[];
|
|
85
|
+
} & Record<
|
|
86
|
+
string,
|
|
87
|
+
{
|
|
88
|
+
type: string;
|
|
89
|
+
name: string;
|
|
90
|
+
}[]
|
|
91
|
+
>;
|
|
92
|
+
primaryType: string;
|
|
93
|
+
domain: {
|
|
94
|
+
name?: string | undefined;
|
|
95
|
+
version?: string | undefined;
|
|
96
|
+
chainId?: string | number | undefined;
|
|
97
|
+
};
|
|
98
|
+
message: Record<string, unknown>;
|
|
99
|
+
}
|
|
100
|
+
>(
|
|
101
|
+
typedData: T,
|
|
102
|
+
type: string,
|
|
103
|
+
data: T['message']
|
|
104
|
+
) => string;
|
|
105
|
+
/**
|
|
106
|
+
* Get the EIP-191 encoded message to sign, from the typedData object. If `hash` is enabled, the message will be hashed
|
|
107
|
+
* with Keccak256.
|
|
108
|
+
*
|
|
109
|
+
* @param {TypedData} typedData
|
|
110
|
+
* @param {boolean} hash
|
|
111
|
+
* @return {string}
|
|
112
|
+
*/
|
|
113
|
+
export declare const getMessageHash: (typedData: TypedData, account: BigNumberish) => string;
|