Skip to content

Commit a3d5033

Browse files
committed
fix: serialize bigints
1 parent 7274ae2 commit a3d5033

File tree

6 files changed

+95
-133
lines changed

6 files changed

+95
-133
lines changed

yarn-project/end-to-end/scripts/web3signer/docker-compose.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ configs:
77
88
services:
99
web3signer:
10-
image: consensys/web3signer:25.3.0
10+
image: consensys/web3signer:25.6.0
1111
ports:
1212
- "9000:9000"
1313
configs:
@@ -17,7 +17,7 @@ services:
1717
- --http-listen-port=9000
1818
- --http-host-allowlist=*
1919
- --key-store-path=/keys
20-
- --logging=DEBUG
20+
- --logging=ALL
2121
- eth1
2222
- --chain-id=31337
2323

yarn-project/end-to-end/src/composed/web3signer/integration_remote_signer.test.ts

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ import { jest } from '@jest/globals';
66
import type { TransactionSerializable, TypedDataDefinition } from 'viem';
77
import { privateKeyToAddress } from 'viem/accounts';
88

9-
const { WEB3_SIGNER_URL, L1_CHAIN_ID = '31337', TEST_PRIVATE_KEY } = process.env;
9+
const {
10+
WEB3_SIGNER_URL = 'http://localhost:9000',
11+
L1_CHAIN_ID = '31337',
12+
TEST_PRIVATE_KEY = '0x1111111111111111111111111111111111111111111111111111111111111111',
13+
} = process.env;
1014

1115
describe('RemoteSigner integration: Web3Signer (compose)', () => {
1216
jest.setTimeout(180_000);
@@ -41,22 +45,30 @@ describe('RemoteSigner integration: Web3Signer (compose)', () => {
4145
remoteSigner = new RemoteSigner(address, web3SignerUrl);
4246
});
4347

44-
// the remote signer ends up calling a client? I'm not sure this is implemented in web3signer
45-
it.skip('signs EIP-712 typed data and matches r/s with local', async () => {
48+
it('signs EIP-712 typed data and matches r/s with local', async () => {
4649
const typedData: TypedDataDefinition = {
47-
domain: { name: 'Aztec', version: '1', chainId: 1 },
50+
domain: {
51+
name: 'TallySlashingProposer',
52+
version: '1',
53+
chainId,
54+
verifyingContract: EthAddress.random().toString(),
55+
},
4856
types: {
49-
Mail: [
50-
{ name: 'from', type: 'address' },
51-
{ name: 'to', type: 'address' },
52-
{ name: 'contents', type: 'string' },
57+
EIP712Domain: [
58+
{ name: 'name', type: 'string' },
59+
{ name: 'version', type: 'string' },
60+
{ name: 'chainId', type: 'uint256' },
61+
{ name: 'verifyingContract', type: 'address' },
62+
],
63+
Vote: [
64+
{ name: 'votes', type: 'bytes' },
65+
{ name: 'slot', type: 'uint256' },
5366
],
5467
},
55-
primaryType: 'Mail',
68+
primaryType: 'Vote',
5669
message: {
57-
from: address.toString(),
58-
to: address.toString(),
59-
contents: 'hello',
70+
votes: '0x1234',
71+
slot: 42n,
6072
},
6173
};
6274

yarn-project/ethereum/src/contracts/empire_base.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ export async function signSignalWithSig(
6464
};
6565

6666
const types = {
67+
EIP712Domain: [
68+
{ name: 'name', type: 'string' },
69+
{ name: 'version', type: 'string' },
70+
{ name: 'chainId', type: 'uint256' },
71+
{ name: 'verifyingContract', type: 'address' },
72+
],
6773
Signal: [
6874
{ name: 'payload', type: 'address' },
6975
{ name: 'slot', type: 'uint256' },

yarn-project/ethereum/src/contracts/tally_slashing_proposer.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,12 @@ export class TallySlashingProposerContract extends EventEmitter {
164164
};
165165

166166
const types = {
167+
EIP712Domain: [
168+
{ name: 'name', type: 'string' },
169+
{ name: 'version', type: 'string' },
170+
{ name: 'chainId', type: 'uint256' },
171+
{ name: 'verifyingContract', type: 'address' },
172+
],
167173
Vote: [
168174
{ name: 'votes', type: 'bytes' },
169175
{ name: 'slot', type: 'uint256' },

yarn-project/node-keystore/src/signer.ts

Lines changed: 57 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
*/
66
import type { EthSigner } from '@aztec/ethereum';
77
import { Buffer32 } from '@aztec/foundation/buffer';
8-
import { Secp256k1Signer, toRecoveryBit } from '@aztec/foundation/crypto';
8+
import { Secp256k1Signer, randomBytes, toRecoveryBit } from '@aztec/foundation/crypto';
99
import type { EthAddress } from '@aztec/foundation/eth-address';
1010
import { Signature, type ViemTransactionSignature } from '@aztec/foundation/eth-signature';
11+
import { jsonStringify } from '@aztec/foundation/json-rpc';
1112
import { withHexPrefix } from '@aztec/foundation/string';
1213

1314
import {
@@ -27,7 +28,7 @@ import type { EthRemoteSignerConfig } from './types.js';
2728
export class SignerError extends Error {
2829
constructor(
2930
message: string,
30-
public method: 'eth_sign' | 'eth_signTransaction' | 'eth_signTypedData_v4',
31+
public method: string,
3132
public url: string,
3233
public statusCode?: number,
3334
public errorCode?: number,
@@ -128,50 +129,12 @@ export class RemoteSigner implements EthSigner {
128129
* Make a JSON-RPC eth_sign request.
129130
*/
130131
private async makeJsonRpcSignRequest(data: Buffer32): Promise<Signature> {
131-
const url = this.getSignerUrl();
132-
133-
const body = {
134-
jsonrpc: '2.0',
135-
method: 'eth_sign',
136-
params: [this.address.toString(), data.toString()],
137-
id: 1,
138-
};
139-
140-
const response = await this.fetch(url, {
141-
method: 'POST',
142-
headers: {
143-
'Content-Type': 'application/json',
144-
},
145-
body: JSON.stringify(body),
146-
});
132+
let signatureHex = await this.makeJsonRpcRequest('eth_sign', this.address.toString(), data.toString());
147133

148-
if (!response.ok) {
149-
const errorText = await response.text();
150-
throw new SignerError(
151-
`Web3Signer request failed for eth_sign at ${url}: ${response.status} ${response.statusText} - ${errorText}`,
152-
'eth_sign',
153-
url,
154-
response.status,
155-
);
134+
if (typeof signatureHex !== 'string') {
135+
throw new Error('Invalid signature');
156136
}
157137

158-
const result = await response.json();
159-
160-
if (result.error) {
161-
throw new SignerError(
162-
`Web3Signer JSON-RPC error for eth_sign at ${url}: ${result.error.code} - ${result.error.message}`,
163-
'eth_sign',
164-
url,
165-
undefined,
166-
result.error.code,
167-
);
168-
}
169-
170-
if (!result.result) {
171-
throw new Error('Invalid response from Web3Signer: no result found');
172-
}
173-
174-
let signatureHex = result.result;
175138
if (!signatureHex.startsWith('0x')) {
176139
signatureHex = '0x' + signatureHex;
177140
}
@@ -183,50 +146,16 @@ export class RemoteSigner implements EthSigner {
183146
* Make a JSON-RPC eth_signTypedData_v4 request.
184147
*/
185148
private async makeJsonRpcSignTypedDataRequest(typedData: TypedDataDefinition): Promise<Signature> {
186-
const url = this.getSignerUrl();
187-
188-
const body = {
189-
jsonrpc: '2.0',
190-
method: 'eth_signTypedData_v4',
191-
params: [this.address.toString(), typedData],
192-
id: 1,
193-
};
194-
195-
const response = await this.fetch(url, {
196-
method: 'POST',
197-
headers: {
198-
'Content-Type': 'application/json',
199-
},
200-
body: JSON.stringify(body),
201-
});
202-
203-
if (!response.ok) {
204-
const errorText = await response.text();
205-
throw new SignerError(
206-
`Web3Signer request failed for eth_signTypedData_v4 at ${url}: ${response.status} ${response.statusText} - ${errorText}`,
207-
'eth_signTypedData_v4',
208-
url,
209-
response.status,
210-
);
149+
let signatureHex = await this.makeJsonRpcRequest(
150+
'eth_signTypedData',
151+
this.address.toString(),
152+
jsonStringify(typedData),
153+
);
154+
155+
if (typeof signatureHex !== 'string') {
156+
throw new Error('Invalid signature');
211157
}
212158

213-
const result = await response.json();
214-
215-
if (result.error) {
216-
throw new SignerError(
217-
`Web3Signer JSON-RPC error for eth_signTypedData_v4 at ${url}: ${result.error.code} - ${result.error.message}`,
218-
'eth_signTypedData_v4',
219-
url,
220-
undefined,
221-
result.error.code,
222-
);
223-
}
224-
225-
if (!result.result) {
226-
throw new Error('Invalid response from Web3Signer: no result found');
227-
}
228-
229-
let signatureHex = result.result;
230159
if (!signatureHex.startsWith('0x')) {
231160
signatureHex = '0x' + signatureHex;
232161
}
@@ -242,8 +171,6 @@ export class RemoteSigner implements EthSigner {
242171
throw new Error('This signer does not support tx type: ' + tx.type);
243172
}
244173

245-
const url = this.getSignerUrl();
246-
247174
const txObject: RemoteSignerTxObject = {
248175
from: this.address.toString(),
249176
to: tx.to ?? null,
@@ -263,26 +190,49 @@ export class RemoteSigner implements EthSigner {
263190
// blobs: tx.blobs?.map(blob => (typeof blob === 'string' ? blob : bufferToHex(Buffer.from(blob)))),
264191
};
265192

266-
const body = {
267-
jsonrpc: '2.0',
268-
method: 'eth_signTransaction',
269-
params: [txObject],
270-
id: 1,
271-
};
193+
let rawTxHex = await this.makeJsonRpcRequest('eth_signTransaction', txObject);
194+
195+
if (typeof rawTxHex !== 'string') {
196+
throw new Error('Invalid signed tx');
197+
}
198+
199+
if (!rawTxHex.startsWith('0x')) {
200+
rawTxHex = '0x' + rawTxHex;
201+
}
202+
203+
// we get back to whole signed tx. Deserialize it in order to read the signature
204+
const parsedTxWithSignature = parseTransaction(rawTxHex);
205+
if (
206+
parsedTxWithSignature.r === undefined ||
207+
parsedTxWithSignature.s === undefined ||
208+
parsedTxWithSignature.v === undefined
209+
) {
210+
throw new Error('Tx not signed by Web3Signer');
211+
}
212+
213+
return Signature.fromViemTransactionSignature(parsedTxWithSignature as ViemTransactionSignature);
214+
}
215+
216+
/**
217+
* Sends a JSON-RPC request and returns its result
218+
*/
219+
private async makeJsonRpcRequest(method: string, ...params: any[]): Promise<any> {
220+
const url = this.getSignerUrl();
221+
const id = this.generateId();
272222

273223
const response = await this.fetch(url, {
274224
method: 'POST',
275225
headers: {
276226
'Content-Type': 'application/json',
277227
},
278-
body: JSON.stringify(body),
228+
body: jsonStringify({ jsonrpc: '2.0', method, params, id }),
279229
});
280230

281231
if (!response.ok) {
282232
const errorText = await response.text();
283233
throw new SignerError(
284-
`Web3Signer request failed for eth_signTransaction at ${url}: ${response.status} ${response.statusText} - ${errorText}`,
285-
'eth_signTransaction',
234+
`Web3Signer request failed for ${method} at ${url}: ${response.status} ${response.statusText} - ${errorText}`,
235+
method,
286236
url,
287237
response.status,
288238
);
@@ -292,10 +242,10 @@ export class RemoteSigner implements EthSigner {
292242

293243
if (result.error) {
294244
throw new SignerError(
295-
`Web3Signer JSON-RPC error for eth_signTransaction at ${url}: ${result.error.code} - ${result.error.message}`,
296-
'eth_signTransaction',
245+
`Web3Signer JSON-RPC error for ${method} at ${url}: ${result.error.code} - ${result.error.message}`,
246+
method,
297247
url,
298-
undefined,
248+
response.status,
299249
result.error.code,
300250
);
301251
}
@@ -304,22 +254,7 @@ export class RemoteSigner implements EthSigner {
304254
throw new Error('Invalid response from Web3Signer: no result found');
305255
}
306256

307-
let rawTxHex = result.result;
308-
if (!rawTxHex.startsWith('0x')) {
309-
rawTxHex = '0x' + rawTxHex;
310-
}
311-
312-
// we get back to whole signed tx. Deserialize it in order to read the signature
313-
const parsedTxWithSignature = parseTransaction(rawTxHex);
314-
if (
315-
parsedTxWithSignature.r === undefined ||
316-
parsedTxWithSignature.s === undefined ||
317-
parsedTxWithSignature.v === undefined
318-
) {
319-
throw new Error('Tx not signed by Web3Signer');
320-
}
321-
322-
return Signature.fromViemTransactionSignature(parsedTxWithSignature as ViemTransactionSignature);
257+
return result.result;
323258
}
324259

325260
/**
@@ -331,4 +266,11 @@ export class RemoteSigner implements EthSigner {
331266
}
332267
return this.config.remoteSignerUrl;
333268
}
269+
270+
/**
271+
* Generate an id to use for a JSON-RPC call
272+
*/
273+
private generateId(): string {
274+
return randomBytes(4).toString('hex');
275+
}
334276
}

yarn-project/sequencer-client/src/sequencer/sequencer.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -943,10 +943,6 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
943943
);
944944
}
945945

946-
private getTxTimeoutForSlot(slotNumber: number | bigint): Date {
947-
return new Date((this.getSlotStartBuildTimestamp(slotNumber) + this.aztecSlotDuration) * 1000);
948-
}
949-
950946
private getSecondsIntoSlot(slotNumber: number | bigint): number {
951947
const slotStartTimestamp = this.getSlotStartBuildTimestamp(slotNumber);
952948
return Number((this.dateProvider.now() / 1000 - slotStartTimestamp).toFixed(3));

0 commit comments

Comments
 (0)