starknet 3.1.0 → 3.4.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 +19 -0
- package/__mocks__/ArgentAccount.json +68548 -51944
- package/__mocks__/TestDapp.json +12962 -0
- package/__tests__/account.test.ts +63 -50
- package/__tests__/accountContract.test.ts +51 -71
- package/__tests__/contract.test.ts +32 -20
- package/__tests__/fixtures.ts +13 -0
- package/__tests__/provider.test.ts +3 -15
- 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 +20 -13
- package/__tests__/utils/utils.test.ts +3 -3
- package/account/default.d.ts +10 -4
- package/account/default.js +165 -84
- package/account/interface.d.ts +2 -2
- package/dist/account/default.d.ts +8 -3
- package/dist/account/default.js +129 -55
- package/dist/account/interface.d.ts +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/provider/default.d.ts +6 -4
- package/dist/provider/default.js +42 -17
- package/dist/provider/interface.d.ts +5 -1
- package/dist/signer/default.d.ts +1 -1
- package/dist/signer/default.js +6 -18
- package/dist/signer/interface.d.ts +3 -2
- package/dist/types/api.d.ts +5 -0
- package/dist/types/lib.d.ts +3 -3
- package/dist/utils/ellipticCurve.js +1 -1
- package/dist/utils/hash.d.ts +12 -2
- package/dist/utils/hash.js +37 -9
- package/dist/utils/stark.d.ts +0 -8
- package/dist/utils/stark.js +1 -14
- package/dist/utils/transaction.d.ts +19 -0
- package/dist/utils/transaction.js +75 -0
- package/dist/utils/typedData/index.d.ts +1 -1
- package/dist/utils/typedData/index.js +2 -3
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/package.json +1 -1
- package/provider/default.d.ts +6 -4
- package/provider/default.js +55 -19
- package/provider/interface.d.ts +5 -1
- package/signer/default.d.ts +1 -1
- package/signer/default.js +10 -44
- package/signer/interface.d.ts +3 -2
- package/src/account/default.ts +129 -42
- package/src/account/interface.ts +2 -2
- package/src/index.ts +1 -0
- package/src/provider/default.ts +32 -22
- package/src/provider/interface.ts +6 -1
- package/src/signer/default.ts +10 -26
- package/src/signer/interface.ts +3 -2
- package/src/types/api.ts +5 -0
- package/src/types/lib.ts +3 -4
- package/src/utils/ellipticCurve.ts +1 -1
- package/src/utils/hash.ts +39 -12
- package/src/utils/stark.ts +1 -14
- package/src/utils/transaction.ts +50 -0
- package/src/utils/typedData/index.ts +2 -3
- package/types/api.d.ts +5 -0
- package/types/lib.d.ts +3 -3
- package/utils/ellipticCurve.js +1 -1
- package/utils/hash.d.ts +15 -6
- package/utils/hash.js +42 -10
- package/utils/stark.d.ts +0 -8
- package/utils/stark.js +0 -14
- package/utils/transaction.d.ts +19 -0
- package/utils/transaction.js +99 -0
- package/utils/typedData/index.d.ts +1 -1
- package/utils/typedData/index.js +2 -3
package/src/account/default.ts
CHANGED
|
@@ -1,15 +1,27 @@
|
|
|
1
|
+
import assert from 'minimalistic-assert';
|
|
2
|
+
|
|
1
3
|
import { Provider } from '../provider';
|
|
2
4
|
import { Signer, SignerInterface } from '../signer';
|
|
3
5
|
import {
|
|
4
6
|
Abi,
|
|
5
7
|
AddTransactionResponse,
|
|
6
|
-
|
|
8
|
+
Call,
|
|
7
9
|
InvocationsDetails,
|
|
10
|
+
InvokeFunctionTransaction,
|
|
8
11
|
KeyPair,
|
|
9
12
|
Signature,
|
|
13
|
+
Transaction,
|
|
10
14
|
} from '../types';
|
|
15
|
+
import { sign } from '../utils/ellipticCurve';
|
|
16
|
+
import {
|
|
17
|
+
computeHashOnElements,
|
|
18
|
+
getSelectorFromName,
|
|
19
|
+
transactionPrefix,
|
|
20
|
+
transactionVersion,
|
|
21
|
+
} from '../utils/hash';
|
|
11
22
|
import { BigNumberish, bigNumberishArrayToDecimalStringArray, toBN, toHex } from '../utils/number';
|
|
12
|
-
import { compileCalldata
|
|
23
|
+
import { compileCalldata } from '../utils/stark';
|
|
24
|
+
import { fromCallsToExecuteCalldata } from '../utils/transaction';
|
|
13
25
|
import { TypedData, getMessageHash } from '../utils/typedData';
|
|
14
26
|
import { AccountInterface } from './interface';
|
|
15
27
|
|
|
@@ -41,51 +53,126 @@ export class Account extends Provider implements AccountInterface {
|
|
|
41
53
|
* @returns a confirmation of invoking a function on the starknet contract
|
|
42
54
|
*/
|
|
43
55
|
public async execute(
|
|
44
|
-
|
|
45
|
-
abis: Abi[] =
|
|
56
|
+
calls: Call | Call[],
|
|
57
|
+
abis: Abi[] | undefined = undefined,
|
|
46
58
|
transactionsDetail: InvocationsDetails = {}
|
|
47
59
|
): Promise<AddTransactionResponse> {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
60
|
+
const transactions = Array.isArray(calls) ? calls : [calls];
|
|
61
|
+
|
|
62
|
+
const signerDetails = {
|
|
63
|
+
walletAddress: this.address,
|
|
64
|
+
nonce: toBN(transactionsDetail.nonce ?? (await this.getNonce())),
|
|
65
|
+
maxFee: toBN(transactionsDetail.maxFee ?? '0'),
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const signature = await this.signer.signTransaction(transactions, signerDetails, abis);
|
|
69
|
+
|
|
70
|
+
const calldata = [...fromCallsToExecuteCalldata(transactions), signerDetails.nonce.toString()];
|
|
71
|
+
|
|
72
|
+
return this.fetchEndpoint('add_transaction', undefined, {
|
|
73
|
+
type: 'INVOKE_FUNCTION',
|
|
74
|
+
contract_address: this.address,
|
|
75
|
+
entry_point_selector: getSelectorFromName('__execute__'),
|
|
76
|
+
calldata,
|
|
77
|
+
signature: bigNumberishArrayToDecimalStringArray(signature),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Temporary method to allow dapps on starknet.js v2 to work with Argent X v3
|
|
83
|
+
* @deprecated to remove ASAP
|
|
84
|
+
*/
|
|
85
|
+
public async LEGACY_addTransaction(transaction: Transaction): Promise<AddTransactionResponse> {
|
|
86
|
+
if (transaction.type === 'DEPLOY') throw new Error('No DEPLOYS');
|
|
51
87
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
entrypoint,
|
|
56
|
-
...invocation
|
|
57
|
-
} = Array.isArray(transactions) ? transactions[0] : transactions;
|
|
58
|
-
const { nonce } = transactionsDetail;
|
|
59
|
-
|
|
60
|
-
const nonceBn = toBN(nonce ?? (await this.getNonce()));
|
|
61
|
-
const calldataDecimal = bigNumberishArrayToDecimalStringArray(calldata);
|
|
62
|
-
|
|
63
|
-
const signature = await this.signer.signTransaction(
|
|
64
|
-
[
|
|
65
|
-
{
|
|
66
|
-
...invocation,
|
|
67
|
-
contractAddress,
|
|
68
|
-
calldata: calldataDecimal,
|
|
69
|
-
entrypoint,
|
|
70
|
-
},
|
|
71
|
-
],
|
|
72
|
-
{ walletAddress: this.address, nonce: nonceBn },
|
|
73
|
-
abis
|
|
88
|
+
assert(
|
|
89
|
+
!transaction.signature,
|
|
90
|
+
"Adding signatures to a signer transaction currently isn't supported"
|
|
74
91
|
);
|
|
75
92
|
|
|
76
|
-
|
|
93
|
+
let nonceBn;
|
|
94
|
+
if (transaction.nonce) {
|
|
95
|
+
nonceBn = toBN(transaction.nonce);
|
|
96
|
+
} else {
|
|
97
|
+
const { result } = await this.callContract({
|
|
98
|
+
contractAddress: this.address,
|
|
99
|
+
entrypoint: 'get_nonce',
|
|
100
|
+
});
|
|
101
|
+
nonceBn = toBN(result[0]);
|
|
102
|
+
}
|
|
77
103
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
104
|
+
function hashMulticall(
|
|
105
|
+
account: string,
|
|
106
|
+
transactions: InvokeFunctionTransaction[],
|
|
107
|
+
nonce: string,
|
|
108
|
+
maxFee: string
|
|
109
|
+
) {
|
|
110
|
+
const hashArray = transactions
|
|
111
|
+
.map(({ contract_address, entry_point_selector, calldata }) => [
|
|
112
|
+
contract_address,
|
|
113
|
+
entry_point_selector,
|
|
114
|
+
computeHashOnElements(calldata || []),
|
|
115
|
+
])
|
|
116
|
+
.map(bigNumberishArrayToDecimalStringArray)
|
|
117
|
+
.map(computeHashOnElements);
|
|
118
|
+
|
|
119
|
+
return computeHashOnElements([
|
|
120
|
+
transactionPrefix,
|
|
121
|
+
account,
|
|
122
|
+
computeHashOnElements(hashArray),
|
|
123
|
+
nonce,
|
|
124
|
+
maxFee,
|
|
125
|
+
transactionVersion,
|
|
126
|
+
]);
|
|
127
|
+
}
|
|
128
|
+
const msgHash = hashMulticall(this.address, [transaction], nonceBn.toString(), '0');
|
|
129
|
+
if (!('keyPair' in this.signer)) {
|
|
130
|
+
throw new Error('No keyPair');
|
|
131
|
+
}
|
|
132
|
+
const signature = sign((this.signer as any).keyPair, msgHash);
|
|
133
|
+
|
|
134
|
+
const transformCallsToMulticallArrays = (calls: InvokeFunctionTransaction[]) => {
|
|
135
|
+
const callArray: any[] = [];
|
|
136
|
+
const calldata: BigNumberish[] = [];
|
|
137
|
+
calls.forEach((call) => {
|
|
138
|
+
const data = call.calldata || [];
|
|
139
|
+
callArray.push({
|
|
140
|
+
to: toBN(call.contract_address).toString(10),
|
|
141
|
+
selector: toBN(call.entry_point_selector).toString(10),
|
|
142
|
+
data_offset: calldata.length.toString(),
|
|
143
|
+
data_len: data.length.toString(),
|
|
144
|
+
});
|
|
145
|
+
calldata.push(...data);
|
|
146
|
+
});
|
|
147
|
+
return {
|
|
148
|
+
callArray,
|
|
149
|
+
calldata: bigNumberishArrayToDecimalStringArray(calldata),
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const fromCallsToExecuteCalldata2 = (calls: InvokeFunctionTransaction[]): string[] => {
|
|
154
|
+
const { callArray, calldata } = transformCallsToMulticallArrays(calls);
|
|
155
|
+
return [
|
|
156
|
+
callArray.length.toString(),
|
|
157
|
+
...callArray
|
|
158
|
+
.map(
|
|
159
|
+
({ to, selector, data_offset, data_len }) =>
|
|
160
|
+
[to, selector, data_offset, data_len] as string[]
|
|
161
|
+
)
|
|
162
|
+
.flat(),
|
|
163
|
+
calldata.length.toString(),
|
|
164
|
+
...calldata,
|
|
165
|
+
];
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const calldata = [...fromCallsToExecuteCalldata2([transaction]), nonceBn.toString()];
|
|
169
|
+
|
|
170
|
+
return this.fetchEndpoint('add_transaction', undefined, {
|
|
171
|
+
type: 'INVOKE_FUNCTION',
|
|
172
|
+
contract_address: this.address,
|
|
173
|
+
entry_point_selector: getSelectorFromName('__execute__'),
|
|
174
|
+
calldata,
|
|
175
|
+
signature: bigNumberishArrayToDecimalStringArray(signature),
|
|
89
176
|
});
|
|
90
177
|
}
|
|
91
178
|
|
|
@@ -114,7 +201,7 @@ export class Account extends Provider implements AccountInterface {
|
|
|
114
201
|
/**
|
|
115
202
|
* Verify a signature of a JSON object
|
|
116
203
|
*
|
|
117
|
-
* @param
|
|
204
|
+
* @param hash - JSON object to be verified
|
|
118
205
|
* @param signature - signature of the JSON object
|
|
119
206
|
* @returns true if the signature is valid, false otherwise
|
|
120
207
|
* @throws {Error} if the JSON object is not a valid JSON or the signature is not a valid signature
|
package/src/account/interface.ts
CHANGED
|
@@ -2,8 +2,8 @@ import { ProviderInterface } from '../provider';
|
|
|
2
2
|
import {
|
|
3
3
|
Abi,
|
|
4
4
|
AddTransactionResponse,
|
|
5
|
+
Call,
|
|
5
6
|
DeployContractPayload,
|
|
6
|
-
ExecuteInvocation,
|
|
7
7
|
InvocationsDetails,
|
|
8
8
|
Signature,
|
|
9
9
|
} from '../types';
|
|
@@ -41,7 +41,7 @@ export abstract class AccountInterface extends ProviderInterface {
|
|
|
41
41
|
* @returns response from addTransaction
|
|
42
42
|
*/
|
|
43
43
|
public abstract execute(
|
|
44
|
-
transactions:
|
|
44
|
+
transactions: Call | Call[],
|
|
45
45
|
abis?: Abi[],
|
|
46
46
|
transactionsDetail?: InvocationsDetails
|
|
47
47
|
): Promise<AddTransactionResponse>;
|
package/src/index.ts
CHANGED
package/src/provider/default.ts
CHANGED
|
@@ -17,21 +17,16 @@ import {
|
|
|
17
17
|
Invocation,
|
|
18
18
|
TransactionReceipt,
|
|
19
19
|
} from '../types';
|
|
20
|
+
import { getSelectorFromName } from '../utils/hash';
|
|
20
21
|
import { parse, stringify } from '../utils/json';
|
|
21
22
|
import { BigNumberish, bigNumberishArrayToDecimalStringArray, toBN, toHex } from '../utils/number';
|
|
22
|
-
import { compressProgram,
|
|
23
|
+
import { compressProgram, randomAddress } from '../utils/stark';
|
|
23
24
|
import { ProviderInterface } from './interface';
|
|
24
25
|
import { BlockIdentifier, getFormattedBlockIdentifier, txIdentifier } from './utils';
|
|
25
26
|
|
|
26
27
|
type NetworkName = 'mainnet-alpha' | 'goerli-alpha';
|
|
27
28
|
|
|
28
|
-
type ProviderOptions =
|
|
29
|
-
| {
|
|
30
|
-
network: NetworkName;
|
|
31
|
-
}
|
|
32
|
-
| {
|
|
33
|
-
baseUrl: string;
|
|
34
|
-
};
|
|
29
|
+
type ProviderOptions = { network: NetworkName } | { baseUrl: string };
|
|
35
30
|
|
|
36
31
|
function wait(delay: number) {
|
|
37
32
|
return new Promise((res) => setTimeout(res, delay));
|
|
@@ -133,14 +128,21 @@ export class Provider implements ProviderInterface {
|
|
|
133
128
|
const queryString = this.getQueryString(query);
|
|
134
129
|
const headers = this.getHeaders(method);
|
|
135
130
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
131
|
+
try {
|
|
132
|
+
const { data } = await axios.request<Endpoints[T]['RESPONSE']>({
|
|
133
|
+
method,
|
|
134
|
+
url: urljoin(baseUrl, endpoint, queryString),
|
|
135
|
+
data: stringify(request),
|
|
136
|
+
headers,
|
|
137
|
+
});
|
|
138
|
+
return data;
|
|
139
|
+
} catch (error: any) {
|
|
140
|
+
const data = error?.response?.data;
|
|
141
|
+
if (data?.message) {
|
|
142
|
+
throw new Error(`${data.code}: ${data.message}`);
|
|
143
|
+
}
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
144
146
|
}
|
|
145
147
|
|
|
146
148
|
/**
|
|
@@ -315,10 +317,8 @@ export class Provider implements ProviderInterface {
|
|
|
315
317
|
* Invokes a function on starknet
|
|
316
318
|
* @deprecated This method wont be supported as soon as fees are mandatory
|
|
317
319
|
*
|
|
318
|
-
* @param
|
|
319
|
-
* @param
|
|
320
|
-
* @param calldata - (optional, default []) calldata
|
|
321
|
-
* @param signature - (optional) signature to send along
|
|
320
|
+
* @param invocation
|
|
321
|
+
* @param _abi - (optional) signature to send along
|
|
322
322
|
* @returns response from addTransaction
|
|
323
323
|
*/
|
|
324
324
|
public invokeFunction(invocation: Invocation, _abi?: Abi): Promise<AddTransactionResponse> {
|
|
@@ -331,7 +331,7 @@ export class Provider implements ProviderInterface {
|
|
|
331
331
|
});
|
|
332
332
|
}
|
|
333
333
|
|
|
334
|
-
public async
|
|
334
|
+
public async waitForTransaction(txHash: BigNumberish, retryInterval: number = 8000) {
|
|
335
335
|
let onchain = false;
|
|
336
336
|
await wait(retryInterval);
|
|
337
337
|
|
|
@@ -344,10 +344,20 @@ export class Provider implements ProviderInterface {
|
|
|
344
344
|
if (res.tx_status === 'ACCEPTED_ON_L1' || res.tx_status === 'ACCEPTED_ON_L2') {
|
|
345
345
|
onchain = true;
|
|
346
346
|
} else if (res.tx_status === 'REJECTED' || res.tx_status === 'NOT_RECEIVED') {
|
|
347
|
-
const
|
|
347
|
+
const message = res.tx_failure_reason
|
|
348
|
+
? `${res.tx_status}: ${res.tx_failure_reason.code}\n${res.tx_failure_reason.error_message}`
|
|
349
|
+
: res.tx_status;
|
|
350
|
+
const error = new Error(message) as Error & { response: GetTransactionStatusResponse };
|
|
348
351
|
error.response = res;
|
|
349
352
|
throw error;
|
|
350
353
|
}
|
|
351
354
|
}
|
|
352
355
|
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* @deprecated use `waitForTransaction` instead
|
|
359
|
+
*/
|
|
360
|
+
public async waitForTx(txHash: BigNumberish, retryInterval: number = 8000) {
|
|
361
|
+
return this.waitForTransaction(txHash, retryInterval);
|
|
362
|
+
}
|
|
353
363
|
}
|
|
@@ -137,5 +137,10 @@ export abstract class ProviderInterface {
|
|
|
137
137
|
*/
|
|
138
138
|
public abstract invokeFunction(invocation: Invocation): Promise<AddTransactionResponse>;
|
|
139
139
|
|
|
140
|
-
public abstract
|
|
140
|
+
public abstract waitForTransaction(txHash: BigNumberish, retryInterval?: number): Promise<void>;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* @deprecated use `waitForTransaction` instead
|
|
144
|
+
*/
|
|
145
|
+
public abstract waitForTransaction(txHash: BigNumberish, retryInterval?: number): Promise<void>;
|
|
141
146
|
}
|
package/src/signer/default.ts
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import { Abi, Invocation, InvocationsSignerDetails, KeyPair, Signature } from '../types';
|
|
2
2
|
import { getStarkKey, sign } from '../utils/ellipticCurve';
|
|
3
|
-
import {
|
|
4
|
-
import { hashMessage } from '../utils/hash';
|
|
5
|
-
import { bigNumberishArrayToDecimalStringArray, toBN } from '../utils/number';
|
|
6
|
-
import { getSelectorFromName } from '../utils/stark';
|
|
3
|
+
import { hashMulticall } from '../utils/hash';
|
|
7
4
|
import { TypedData, getMessageHash } from '../utils/typedData';
|
|
8
5
|
import { SignerInterface } from './interface';
|
|
9
6
|
|
|
@@ -21,38 +18,25 @@ export class Signer implements SignerInterface {
|
|
|
21
18
|
public async signTransaction(
|
|
22
19
|
transactions: Invocation[],
|
|
23
20
|
transactionsDetail: InvocationsSignerDetails,
|
|
24
|
-
abis
|
|
21
|
+
abis?: Abi[]
|
|
25
22
|
): Promise<Signature> {
|
|
26
|
-
if (
|
|
27
|
-
throw new Error('Only one transaction at a time is currently supported by this signer');
|
|
28
|
-
}
|
|
29
|
-
if (abis?.length !== 0 && abis.length !== transactions.length) {
|
|
23
|
+
if (abis && abis.length !== transactions.length) {
|
|
30
24
|
throw new Error('ABI must be provided for each transaction or no transaction');
|
|
31
25
|
}
|
|
32
26
|
// now use abi to display decoded data somewhere, but as this signer is headless, we can't do that
|
|
33
27
|
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const calldataDecimal = bigNumberishArrayToDecimalStringArray(calldata);
|
|
40
|
-
|
|
41
|
-
const msgHash = addHexPrefix(
|
|
42
|
-
hashMessage(
|
|
43
|
-
walletAddress,
|
|
44
|
-
contractAddress,
|
|
45
|
-
entrypointSelector,
|
|
46
|
-
calldataDecimal,
|
|
47
|
-
nonceBn.toString()
|
|
48
|
-
)
|
|
28
|
+
const msgHash = hashMulticall(
|
|
29
|
+
transactionsDetail.walletAddress,
|
|
30
|
+
transactions,
|
|
31
|
+
transactionsDetail.nonce.toString(),
|
|
32
|
+
transactionsDetail.maxFee.toString()
|
|
49
33
|
);
|
|
50
34
|
|
|
51
35
|
return sign(this.keyPair, msgHash);
|
|
52
36
|
}
|
|
53
37
|
|
|
54
|
-
public async signMessage(typedData: TypedData,
|
|
55
|
-
const msgHash = getMessageHash(typedData,
|
|
38
|
+
public async signMessage(typedData: TypedData, accountAddress: string): Promise<Signature> {
|
|
39
|
+
const msgHash = getMessageHash(typedData, accountAddress);
|
|
56
40
|
return sign(this.keyPair, msgHash);
|
|
57
41
|
}
|
|
58
42
|
}
|
package/src/signer/interface.ts
CHANGED
|
@@ -13,11 +13,12 @@ export abstract class SignerInterface {
|
|
|
13
13
|
* Sign an JSON object for off-chain usage with the starknet private key and return the signature
|
|
14
14
|
* This adds a message prefix so it cant be interchanged with transactions
|
|
15
15
|
*
|
|
16
|
-
* @param
|
|
16
|
+
* @param typedData - JSON object to be signed
|
|
17
|
+
* @param accountAddress - account
|
|
17
18
|
* @returns the signature of the JSON object
|
|
18
19
|
* @throws {Error} if the JSON object is not a valid JSON
|
|
19
20
|
*/
|
|
20
|
-
public abstract signMessage(typedData: TypedData,
|
|
21
|
+
public abstract signMessage(typedData: TypedData, accountAddress: string): Promise<Signature>;
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* Signs a transaction with the starknet private key and returns the signature
|
package/src/types/api.ts
CHANGED
|
@@ -137,6 +137,11 @@ export type GetCodeResponse = {
|
|
|
137
137
|
export type GetTransactionStatusResponse = {
|
|
138
138
|
tx_status: Status;
|
|
139
139
|
block_hash: string;
|
|
140
|
+
tx_failure_reason?: {
|
|
141
|
+
tx_id: number;
|
|
142
|
+
code: string;
|
|
143
|
+
error_message: string;
|
|
144
|
+
};
|
|
140
145
|
};
|
|
141
146
|
|
|
142
147
|
export type GetTransactionResponse = {
|
package/src/types/lib.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { ec as EC } from 'elliptic';
|
|
|
3
3
|
import type { BigNumberish } from '../utils/number';
|
|
4
4
|
|
|
5
5
|
export type KeyPair = EC.KeyPair;
|
|
6
|
-
export type Signature =
|
|
6
|
+
export type Signature = string[];
|
|
7
7
|
export type RawCalldata = BigNumberish[];
|
|
8
8
|
|
|
9
9
|
export type DeployContractPayload = {
|
|
@@ -19,14 +19,13 @@ export type Invocation = {
|
|
|
19
19
|
signature?: Signature;
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
-
export type
|
|
22
|
+
export type Call = Omit<Invocation, 'signature'>;
|
|
23
23
|
|
|
24
24
|
export type InvocationsDetails = {
|
|
25
25
|
nonce?: BigNumberish;
|
|
26
|
+
maxFee?: BigNumberish;
|
|
26
27
|
};
|
|
27
28
|
|
|
28
|
-
export type Call = Omit<Invocation, 'signature' | 'nonce'>;
|
|
29
|
-
|
|
30
29
|
export type Status =
|
|
31
30
|
| 'NOT_RECEIVED'
|
|
32
31
|
| 'RECEIVED'
|
|
@@ -80,7 +80,7 @@ export function sign(keyPair: KeyPair, msgHash: string): Signature {
|
|
|
80
80
|
assertInRange(r, ONE, toBN(addHexPrefix(MAX_ECDSA_VAL)), 'r');
|
|
81
81
|
assertInRange(s, ONE, toBN(addHexPrefix(EC_ORDER)), 's');
|
|
82
82
|
assertInRange(w, ONE, toBN(addHexPrefix(MAX_ECDSA_VAL)), 'w');
|
|
83
|
-
return [r, s];
|
|
83
|
+
return [r.toString(), s.toString()];
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
function chunkArray(arr: any[], n: number): any[][] {
|
package/src/utils/hash.ts
CHANGED
|
@@ -3,9 +3,14 @@ import { keccak256 } from 'ethereum-cryptography/keccak';
|
|
|
3
3
|
import assert from 'minimalistic-assert';
|
|
4
4
|
|
|
5
5
|
import { CONSTANT_POINTS, FIELD_PRIME, MASK_250, ONE, ZERO } from '../constants';
|
|
6
|
+
import { Call } from '../types';
|
|
6
7
|
import { ec } from './ellipticCurve';
|
|
7
8
|
import { addHexPrefix, buf2hex, utf8ToArray } from './encode';
|
|
8
|
-
import { BigNumberish, toBN } from './number';
|
|
9
|
+
import { BigNumberish, bigNumberishArrayToDecimalStringArray, toBN, toHex } from './number';
|
|
10
|
+
import { encodeShortString } from './shortString';
|
|
11
|
+
|
|
12
|
+
export const transactionPrefix = encodeShortString('StarkNet Transaction');
|
|
13
|
+
export const transactionVersion = 0;
|
|
9
14
|
|
|
10
15
|
function keccakHex(value: string): string {
|
|
11
16
|
return addHexPrefix(buf2hex(keccak256(utf8ToArray(value))));
|
|
@@ -22,6 +27,18 @@ export function starknetKeccak(value: string): BN {
|
|
|
22
27
|
return toBN(keccakHex(value)).and(MASK_250);
|
|
23
28
|
}
|
|
24
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Function to get the hex selector from a given function name
|
|
32
|
+
*
|
|
33
|
+
* [Reference](https://github.com/starkware-libs/cairo-lang/blob/master/src/starkware/starknet/public/abi.py#L25-L26)
|
|
34
|
+
* @param funcName - selectors abi function name
|
|
35
|
+
* @returns hex selector of given abi function name
|
|
36
|
+
*/
|
|
37
|
+
export function getSelectorFromName(funcName: string) {
|
|
38
|
+
// sometimes BigInteger pads the hex string with zeros, which isnt allowed in the starknet api
|
|
39
|
+
return toHex(starknetKeccak(funcName));
|
|
40
|
+
}
|
|
41
|
+
|
|
25
42
|
const constantPoints = CONSTANT_POINTS.map((coords: string[]) =>
|
|
26
43
|
ec.curve.point(coords[0], coords[1])
|
|
27
44
|
);
|
|
@@ -47,17 +64,27 @@ export function computeHashOnElements(data: BigNumberish[]) {
|
|
|
47
64
|
return [...data, data.length].reduce((x, y) => pedersen([x, y]), 0).toString();
|
|
48
65
|
}
|
|
49
66
|
|
|
50
|
-
export function
|
|
51
|
-
return computeHashOnElements(calldata);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function hashMessage(
|
|
67
|
+
export function hashMulticall(
|
|
55
68
|
account: string,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
nonce: string
|
|
69
|
+
transactions: Call[],
|
|
70
|
+
nonce: string,
|
|
71
|
+
maxFee: string
|
|
60
72
|
) {
|
|
61
|
-
const
|
|
62
|
-
|
|
73
|
+
const hashArray = transactions
|
|
74
|
+
.map(({ contractAddress, entrypoint, calldata }) => [
|
|
75
|
+
contractAddress,
|
|
76
|
+
getSelectorFromName(entrypoint),
|
|
77
|
+
computeHashOnElements(calldata || []),
|
|
78
|
+
])
|
|
79
|
+
.map(bigNumberishArrayToDecimalStringArray)
|
|
80
|
+
.map(computeHashOnElements);
|
|
81
|
+
|
|
82
|
+
return computeHashOnElements([
|
|
83
|
+
transactionPrefix,
|
|
84
|
+
account,
|
|
85
|
+
computeHashOnElements(hashArray),
|
|
86
|
+
nonce,
|
|
87
|
+
maxFee,
|
|
88
|
+
transactionVersion,
|
|
89
|
+
]);
|
|
63
90
|
}
|
package/src/utils/stark.ts
CHANGED
|
@@ -3,9 +3,8 @@ import { gzip } from 'pako';
|
|
|
3
3
|
import { Calldata, CompressedProgram, Program, RawArgs, Signature } from '../types';
|
|
4
4
|
import { genKeyPair, getStarkKey } from './ellipticCurve';
|
|
5
5
|
import { addHexPrefix, btoaUniversal } from './encode';
|
|
6
|
-
import { starknetKeccak } from './hash';
|
|
7
6
|
import { stringify } from './json';
|
|
8
|
-
import { toBN
|
|
7
|
+
import { toBN } from './number';
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* Function to compress compiled cairo program
|
|
@@ -20,18 +19,6 @@ export function compressProgram(jsonProgram: Program | string): CompressedProgra
|
|
|
20
19
|
return btoaUniversal(compressedProgram);
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
/**
|
|
24
|
-
* Function to get the hex selector from a given function name
|
|
25
|
-
*
|
|
26
|
-
* [Reference](https://github.com/starkware-libs/cairo-lang/blob/master/src/starkware/starknet/public/abi.py#L25-L26)
|
|
27
|
-
* @param funcName - selectors abi function name
|
|
28
|
-
* @returns hex selector of given abi function name
|
|
29
|
-
*/
|
|
30
|
-
export function getSelectorFromName(funcName: string) {
|
|
31
|
-
// sometimes BigInteger pads the hex string with zeros, which isnt allowed in the starknet api
|
|
32
|
-
return toHex(starknetKeccak(funcName));
|
|
33
|
-
}
|
|
34
|
-
|
|
35
22
|
export function randomAddress(): string {
|
|
36
23
|
const randomKeyPair = genKeyPair();
|
|
37
24
|
return getStarkKey(randomKeyPair);
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ParsedStruct } from '../contract';
|
|
2
|
+
import { Call } from '../types';
|
|
3
|
+
import { getSelectorFromName } from './hash';
|
|
4
|
+
import { BigNumberish, bigNumberishArrayToDecimalStringArray, toBN } from './number';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Transforms a list of Calls, each with their own calldata, into
|
|
8
|
+
* two arrays: one with the entrypoints, and one with the concatenated calldata.
|
|
9
|
+
* @param calls
|
|
10
|
+
* @returns
|
|
11
|
+
*/
|
|
12
|
+
export const transformCallsToMulticallArrays = (calls: Call[]) => {
|
|
13
|
+
const callArray: ParsedStruct[] = [];
|
|
14
|
+
const calldata: BigNumberish[] = [];
|
|
15
|
+
calls.forEach((call) => {
|
|
16
|
+
const data = call.calldata || [];
|
|
17
|
+
callArray.push({
|
|
18
|
+
to: toBN(call.contractAddress).toString(10),
|
|
19
|
+
selector: toBN(getSelectorFromName(call.entrypoint)).toString(10),
|
|
20
|
+
data_offset: calldata.length.toString(),
|
|
21
|
+
data_len: data.length.toString(),
|
|
22
|
+
});
|
|
23
|
+
calldata.push(...data);
|
|
24
|
+
});
|
|
25
|
+
return {
|
|
26
|
+
callArray,
|
|
27
|
+
calldata: bigNumberishArrayToDecimalStringArray(calldata),
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Transforms a list of calls in the full flattened calldata expected
|
|
33
|
+
* by the __execute__ protocol.
|
|
34
|
+
* @param calls
|
|
35
|
+
* @returns
|
|
36
|
+
*/
|
|
37
|
+
export const fromCallsToExecuteCalldata = (calls: Call[]): string[] => {
|
|
38
|
+
const { callArray, calldata } = transformCallsToMulticallArrays(calls);
|
|
39
|
+
return [
|
|
40
|
+
callArray.length.toString(),
|
|
41
|
+
...callArray
|
|
42
|
+
.map(
|
|
43
|
+
({ to, selector, data_offset, data_len }) =>
|
|
44
|
+
[to, selector, data_offset, data_len] as string[]
|
|
45
|
+
)
|
|
46
|
+
.flat(),
|
|
47
|
+
calldata.length.toString(),
|
|
48
|
+
...calldata,
|
|
49
|
+
];
|
|
50
|
+
};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { computeHashOnElements } from '../hash';
|
|
1
|
+
import { computeHashOnElements, getSelectorFromName } from '../hash';
|
|
2
2
|
import { BigNumberish, toBN, toHex } from '../number';
|
|
3
3
|
import { encodeShortString } from '../shortString';
|
|
4
|
-
import { getSelectorFromName } from '../stark';
|
|
5
4
|
import { TypedData } from './types';
|
|
6
5
|
import { validateTypedData } from './utils';
|
|
7
6
|
|
|
@@ -161,7 +160,7 @@ export const getStructHash = <T extends TypedData>(
|
|
|
161
160
|
* with Keccak256.
|
|
162
161
|
*
|
|
163
162
|
* @param {TypedData} typedData
|
|
164
|
-
* @param {
|
|
163
|
+
* @param {BigNumberish} account
|
|
165
164
|
* @return {string}
|
|
166
165
|
*/
|
|
167
166
|
export const getMessageHash = (typedData: TypedData, account: BigNumberish): string => {
|
package/types/api.d.ts
CHANGED
|
@@ -127,6 +127,11 @@ export declare type GetCodeResponse = {
|
|
|
127
127
|
export declare type GetTransactionStatusResponse = {
|
|
128
128
|
tx_status: Status;
|
|
129
129
|
block_hash: string;
|
|
130
|
+
tx_failure_reason?: {
|
|
131
|
+
tx_id: number;
|
|
132
|
+
code: string;
|
|
133
|
+
error_message: string;
|
|
134
|
+
};
|
|
130
135
|
};
|
|
131
136
|
export declare type GetTransactionResponse = {
|
|
132
137
|
status: Status;
|