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.
- package/CHANGELOG.md +36 -1
- package/README.md +13 -2
- package/__mocks__/ArgentAccount.json +42401 -49045
- package/__mocks__/ERC20.json +3721 -3274
- package/__mocks__/Readme.md +2 -0
- package/__tests__/account.test.ts +6 -6
- package/__tests__/provider.test.ts +4 -4
- package/__tests__/signer.test.ts +1 -1
- package/__tests__/utils/__snapshots__/utils.browser.test.ts.snap +2 -2
- package/__tests__/utils/__snapshots__/utils.test.ts.snap +2 -2
- package/__tests__/utils/ellipticalCurve.test.ts +18 -6
- package/__tests__/utils/utils.test.ts +19 -1
- package/constants.d.ts +5 -5
- package/contract.d.ts +5 -1
- package/contract.js +32 -7
- package/dist/constants.d.ts +5 -5
- package/dist/contract.d.ts +5 -1
- package/dist/contract.js +29 -7
- package/dist/provider/default.js +6 -4
- package/dist/signer/default.js +2 -3
- package/dist/types.d.ts +17 -10
- package/dist/utils/ellipticCurve.js +1 -1
- package/dist/utils/hash.d.ts +1 -0
- package/dist/utils/hash.js +7 -15
- package/package.json +1 -1
- package/provider/default.js +6 -4
- package/signer/default.js +2 -2
- package/src/constants.ts +6 -4
- package/src/contract.ts +42 -11
- package/src/provider/default.ts +5 -3
- package/src/signer/default.ts +2 -2
- package/src/types.ts +16 -4
- package/src/utils/ellipticCurve.ts +1 -1
- package/src/utils/hash.ts +6 -14
- package/tsconfig.json +3 -2
- package/types.d.ts +17 -10
- package/utils/ellipticCurve.js +1 -1
- package/utils/hash.d.ts +1 -0
- package/utils/hash.js +16 -15
|
@@ -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
|
-
'
|
|
23
|
+
'0x66bd4335902683054d08a0572747ea78ebd9e531536fb43125424ca9f902084'
|
|
24
24
|
);
|
|
25
25
|
expect(array).toStrictEqual(['1', '2', '3', '4']);
|
|
26
26
|
|
|
27
27
|
expect(hashCalldata(['1', '2'])).toBe(
|
|
28
|
-
'
|
|
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('
|
|
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('
|
|
45
|
+
toBN('2458502865976494910213617956670505342647705497324144349552978333078363662855').toString()
|
|
46
46
|
);
|
|
47
47
|
expect(s.toString()).toStrictEqual(
|
|
48
|
-
toBN('
|
|
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
|
-
|
|
1
|
+
import BN from 'bn.js';
|
|
2
2
|
export { IS_BROWSER } from './utils/encode';
|
|
3
|
-
export declare const ZERO:
|
|
4
|
-
export declare const ONE:
|
|
5
|
-
export declare const TWO:
|
|
6
|
-
export declare const MASK_250:
|
|
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
|
-
|
|
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
|
-
|
|
299
|
-
|
|
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) {
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import BN from 'bn.js';
|
|
2
2
|
export { IS_BROWSER } from './utils/encode';
|
|
3
|
-
export declare const ZERO:
|
|
4
|
-
export declare const ONE:
|
|
5
|
-
export declare const TWO:
|
|
6
|
-
export declare const MASK_250:
|
|
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/dist/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(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
|
-
|
|
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.
|
|
157
|
-
var
|
|
158
|
-
|
|
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[
|
|
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
|
package/dist/provider/default.js
CHANGED
|
@@ -77,7 +77,7 @@ var Provider = /** @class */ (function () {
|
|
|
77
77
|
switch (name) {
|
|
78
78
|
case 'alpha':
|
|
79
79
|
default:
|
|
80
|
-
return 'https://
|
|
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 =
|
|
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
|
}
|
package/dist/signer/default.js
CHANGED
|
@@ -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)('
|
|
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)(
|
|
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
|
|
15
|
-
inputs: {
|
|
16
|
-
name: string;
|
|
17
|
-
type: 'felt' | 'felt*';
|
|
18
|
-
}[];
|
|
14
|
+
export declare type AbiEntry = {
|
|
19
15
|
name: string;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
|
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;
|
package/dist/utils/hash.d.ts
CHANGED
|
@@ -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;
|
package/dist/utils/hash.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
90
|
-
return pedersen([hash2, nonce]);
|
|
82
|
+
return computeHashOnElements([account, to, selector, calldataHash, nonce]);
|
|
91
83
|
}
|
|
92
84
|
exports.hashMessage = hashMessage;
|
package/package.json
CHANGED
package/provider/default.js
CHANGED
|
@@ -179,7 +179,7 @@ var Provider = /** @class */ (function () {
|
|
|
179
179
|
switch (name) {
|
|
180
180
|
case 'alpha':
|
|
181
181
|
default:
|
|
182
|
-
return 'https://
|
|
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 =
|
|
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)('
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
-
[
|
|
111
|
-
}
|
|
112
|
-
|
|
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]) {
|