Skip to content

Commit cb5d5f4

Browse files
committed
fix: cover proof-bearing browser joins
1 parent a05fa94 commit cb5d5f4

11 files changed

Lines changed: 443 additions & 178 deletions

File tree

‎e2e/config-default.e2e.ts‎

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import {test, expect, type Browser} from "@playwright/test";
2-
import {startAnvil, readStubCallCount, type AnvilHandle} from "./fixtures/chain";
3-
import {makeScratchEnv, runCli, readDescriptor, isPidAlive, type ScratchEnv} from "./fixtures/cli";
2+
import {ANVIL_KEY_0, startAnvil, readStubCallCount, type AnvilHandle} from "./fixtures/chain";
3+
import {
4+
installLocalOperator,
5+
makeScratchEnv,
6+
runCli,
7+
readDescriptor,
8+
isPidAlive,
9+
type ScratchEnv,
10+
} from "./fixtures/cli";
411
import {launchBrowser, establishSession, type BridgeDriver} from "./helpers/bridgePage";
512

613
/**
@@ -11,12 +18,14 @@ import {launchBrowser, establishSession, type BridgeDriver} from "./helpers/brid
1118
*/
1219
const CHAIN_ID = 61343;
1320
const HASH_RE = /0x[0-9a-fA-F]{64}/;
21+
const OPERATOR_PASSWORD = "operator-password";
1422

1523
test.describe.serial("S5 config default walletMode=browser", () => {
1624
let anvil: AnvilHandle;
1725
let browser: Browser;
1826
let driver: BridgeDriver;
1927
let scratch: ScratchEnv;
28+
let operator: `0x${string}`;
2029

2130
test.beforeAll(async () => {
2231
anvil = await startAnvil({chainId: CHAIN_ID});
@@ -28,6 +37,10 @@ test.describe.serial("S5 config default walletMode=browser", () => {
2837
walletMode: "browser",
2938
timing: {longPollMs: 1000},
3039
});
40+
operator = await installLocalOperator(scratch, {
41+
privateKey: ANVIL_KEY_0,
42+
password: OPERATOR_PASSWORD,
43+
});
3144
({driver} = await establishSession(browser, anvil, scratch));
3245
});
3346

@@ -46,7 +59,20 @@ test.describe.serial("S5 config default walletMode=browser", () => {
4659

4760
test("bare validator-join signs via session (no --wallet flag)", async () => {
4861
const before = await readStubCallCount(anvil);
49-
const res = await runCli(["staking", "validator-join", "--force", "--amount", "1"], scratch);
62+
const res = await runCli(
63+
[
64+
"staking",
65+
"validator-join",
66+
"--force",
67+
"--amount",
68+
"1",
69+
"--operator",
70+
operator,
71+
"--operator-password",
72+
OPERATOR_PASSWORD,
73+
],
74+
scratch,
75+
);
5076
expect(res.all).toContain("Validator created successfully!");
5177
expect(res.all.match(HASH_RE)?.[0]).toBeTruthy();
5278
expect(await readStubCallCount(anvil)).toBe(before + 1);
@@ -55,7 +81,19 @@ test.describe.serial("S5 config default walletMode=browser", () => {
5581
test("--wallet keystore overrides config, takes keystore path (no enqueue)", async () => {
5682
const before = await readStubCallCount(anvil);
5783
const res = await runCli(
58-
["staking", "validator-join", "--force", "--amount", "1", "--wallet", "keystore"],
84+
[
85+
"staking",
86+
"validator-join",
87+
"--force",
88+
"--amount",
89+
"1",
90+
"--wallet",
91+
"keystore",
92+
"--operator",
93+
operator,
94+
"--operator-password",
95+
OPERATOR_PASSWORD,
96+
],
5997
scratch,
6098
);
6199
// Keystore path selected: it fails on the missing account rather than

‎e2e/errors.e2e.ts‎

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {test, expect, type Browser} from "@playwright/test";
2-
import {startAnvil, type AnvilHandle} from "./fixtures/chain";
2+
import {ANVIL_KEY_0, startAnvil, type AnvilHandle} from "./fixtures/chain";
33
import {
4+
installLocalOperator,
45
makeScratchEnv,
56
runCli,
67
readDescriptor,
@@ -22,10 +23,12 @@ import {launchBrowser, establishSession, type BridgeDriver} from "./helpers/brid
2223

2324
test.describe.serial("S6a user reject (4001)", () => {
2425
const CHAIN_ID = 61344;
26+
const OPERATOR_PASSWORD = "operator-password";
2527
let anvil: AnvilHandle;
2628
let browser: Browser;
2729
let driver: BridgeDriver;
2830
let scratch: ScratchEnv;
31+
let operator: `0x${string}`;
2932

3033
test.beforeAll(async () => {
3134
anvil = await startAnvil({chainId: CHAIN_ID});
@@ -36,6 +39,10 @@ test.describe.serial("S6a user reject (4001)", () => {
3639
stubAddress: anvil.stubAddress,
3740
timing: {longPollMs: 1000},
3841
});
42+
operator = await installLocalOperator(scratch, {
43+
privateKey: ANVIL_KEY_0,
44+
password: OPERATOR_PASSWORD,
45+
});
3946
({driver} = await establishSession(browser, anvil, scratch, {behavior: "reject"}));
4047
});
4148

@@ -54,7 +61,19 @@ test.describe.serial("S6a user reject (4001)", () => {
5461

5562
test("reject surfaces the message, exits non-zero, session survives", async () => {
5663
const res = await runCli(
57-
["staking", "validator-join", "--force", "--amount", "1", "--wallet", "browser"],
64+
[
65+
"staking",
66+
"validator-join",
67+
"--force",
68+
"--amount",
69+
"1",
70+
"--wallet",
71+
"browser",
72+
"--operator",
73+
operator,
74+
"--operator-password",
75+
OPERATOR_PASSWORD,
76+
],
5877
scratch,
5978
);
6079
expect(res.all).toContain("Transaction rejected in wallet");

‎e2e/fixtures/StakingStub.json‎

Lines changed: 79 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,114 +1,138 @@
11
{
22
"abi": [
33
{
4-
"type": "function",
5-
"name": "callCount",
6-
"inputs": [],
7-
"outputs": [
4+
"anonymous": false,
5+
"inputs": [
86
{
9-
"name": "",
10-
"type": "uint256",
11-
"internalType": "uint256"
7+
"indexed": false,
8+
"internalType": "address",
9+
"name": "operator",
10+
"type": "address"
11+
},
12+
{
13+
"indexed": false,
14+
"internalType": "address",
15+
"name": "validator",
16+
"type": "address"
17+
},
18+
{
19+
"indexed": false,
20+
"internalType": "uint256",
21+
"name": "amount",
22+
"type": "uint256"
1223
}
1324
],
14-
"stateMutability": "view"
25+
"name": "ValidatorJoin",
26+
"type": "event"
1527
},
1628
{
17-
"type": "function",
18-
"name": "lastAmount",
1929
"inputs": [],
30+
"name": "callCount",
2031
"outputs": [
2132
{
33+
"internalType": "uint256",
2234
"name": "",
23-
"type": "uint256",
24-
"internalType": "uint256"
35+
"type": "uint256"
2536
}
2637
],
27-
"stateMutability": "view"
38+
"stateMutability": "view",
39+
"type": "function"
2840
},
2941
{
30-
"type": "function",
31-
"name": "lastOperator",
32-
"inputs": [],
42+
"inputs": [
43+
{
44+
"internalType": "string",
45+
"name": "_name",
46+
"type": "string"
47+
}
48+
],
49+
"name": "getAddress",
3350
"outputs": [
3451
{
52+
"internalType": "address",
3553
"name": "",
36-
"type": "address",
37-
"internalType": "address"
54+
"type": "address"
3855
}
3956
],
40-
"stateMutability": "view"
57+
"stateMutability": "view",
58+
"type": "function"
4159
},
4260
{
43-
"type": "function",
44-
"name": "lastValidator",
4561
"inputs": [],
62+
"name": "getAddressManager",
4663
"outputs": [
4764
{
65+
"internalType": "address",
4866
"name": "",
49-
"type": "address",
50-
"internalType": "address"
67+
"type": "address"
5168
}
5269
],
53-
"stateMutability": "view"
70+
"stateMutability": "view",
71+
"type": "function"
5472
},
5573
{
56-
"type": "function",
57-
"name": "validatorJoin",
58-
"inputs": [
74+
"inputs": [],
75+
"name": "lastAmount",
76+
"outputs": [
5977
{
60-
"name": "_operator",
61-
"type": "address",
62-
"internalType": "address"
78+
"internalType": "uint256",
79+
"name": "",
80+
"type": "uint256"
6381
}
6482
],
83+
"stateMutability": "view",
84+
"type": "function"
85+
},
86+
{
87+
"inputs": [],
88+
"name": "lastOperator",
6589
"outputs": [
6690
{
91+
"internalType": "address",
6792
"name": "",
68-
"type": "address",
69-
"internalType": "address"
93+
"type": "address"
7094
}
7195
],
72-
"stateMutability": "payable"
96+
"stateMutability": "view",
97+
"type": "function"
7398
},
7499
{
75-
"type": "function",
76-
"name": "validatorJoin",
77100
"inputs": [],
101+
"name": "lastValidator",
78102
"outputs": [
79103
{
104+
"internalType": "address",
80105
"name": "",
81-
"type": "address",
82-
"internalType": "address"
106+
"type": "address"
83107
}
84108
],
85-
"stateMutability": "payable"
109+
"stateMutability": "view",
110+
"type": "function"
86111
},
87112
{
88-
"type": "event",
89-
"name": "ValidatorJoin",
90113
"inputs": [
91114
{
92-
"name": "operator",
93-
"type": "address",
94-
"indexed": false,
95-
"internalType": "address"
115+
"internalType": "uint256[2]",
116+
"name": "_operatorPubKey",
117+
"type": "uint256[2]"
96118
},
97119
{
98-
"name": "validator",
99-
"type": "address",
100-
"indexed": false,
101-
"internalType": "address"
102-
},
120+
"internalType": "bytes",
121+
"name": "",
122+
"type": "bytes"
123+
}
124+
],
125+
"name": "validatorJoin",
126+
"outputs": [
103127
{
104-
"name": "amount",
105-
"type": "uint256",
106-
"indexed": false,
107-
"internalType": "uint256"
128+
"internalType": "address",
129+
"name": "",
130+
"type": "address"
108131
}
109132
],
110-
"anonymous": false
133+
"stateMutability": "payable",
134+
"type": "function"
111135
}
112136
],
113-
"bytecode": "0x6080604052348015600e575f5ffd5b5061050e8061001c5f395ff3fe608060405260043610610054575f3560e01c806301fe0a781461005857806330e7349f1461008857806330ebe468146100b25780634b28f9a2146100d05780636eb3cd49146100fa578063829a86d914610124575b5f5ffd5b610072600480360381019061006d919061032f565b61014e565b60405161007f9190610369565b60405180910390f35b348015610093575f5ffd5b5061009c61015f565b6040516100a99190610369565b60405180910390f35b6100ba610184565b6040516100c79190610369565b60405180910390f35b3480156100db575f5ffd5b506100e4610193565b6040516100f1919061039a565b60405180910390f35b348015610105575f5ffd5b5061010e610198565b60405161011b9190610369565b60405180910390f35b34801561012f575f5ffd5b506101386101bd565b604051610145919061039a565b60405180910390f35b5f610158826101c3565b9050919050565b60025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f61018e336101c3565b905090565b5f5481565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60035481565b5f60015f5f8282546101d591906103e0565b92505081905550335f546040516020016101f0929190610478565b604051602081830303815290604052805190602001205f1c90508160015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060025f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550346003819055507f2b7297b31452d0a13e57c605870ec3c9b4ac6ef33e5cbae7a0f00bc2a3e967828282346040516102c4939291906104a3565b60405180910390a1919050565b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6102fe826102d5565b9050919050565b61030e816102f4565b8114610318575f5ffd5b50565b5f8135905061032981610305565b92915050565b5f60208284031215610344576103436102d1565b5b5f6103518482850161031b565b91505092915050565b610363816102f4565b82525050565b5f60208201905061037c5f83018461035a565b92915050565b5f819050919050565b61039481610382565b82525050565b5f6020820190506103ad5f83018461038b565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6103ea82610382565b91506103f583610382565b925082820190508082111561040d5761040c6103b3565b5b92915050565b5f8160601b9050919050565b5f61042982610413565b9050919050565b5f61043a8261041f565b9050919050565b61045261044d826102f4565b610430565b82525050565b5f819050919050565b61047261046d82610382565b610458565b82525050565b5f6104838285610441565b6014820191506104938284610461565b6020820191508190509392505050565b5f6060820190506104b65f83018661035a565b6104c3602083018561035a565b6104d0604083018461038b565b94935050505056fea26469706673582212202ea3a8dac16f254ee61dc37f81eb395845a459b3af57d33fab7a95c141e032b664736f6c63430008210033"
137+
"bytecode": "0x6080604052348015600e575f5ffd5b506107f48061001c5f395ff3fe60806040526004361061006f575f3560e01c80636eb3cd491161004d5780636eb3cd49146100f1578063829a86d91461011b578063bf40fac114610145578063ea7845f5146101815761006f565b806330e7349f146100735780634b28f9a21461009d5780635492f302146100c7575b5f5ffd5b34801561007e575f5ffd5b506100876101b1565b604051610094919061041c565b60405180910390f35b3480156100a8575f5ffd5b506100b16101d6565b6040516100be919061044d565b60405180910390f35b3480156100d2575f5ffd5b506100db6101db565b6040516100e8919061041c565b60405180910390f35b3480156100fc575f5ffd5b506101056101e2565b604051610112919061041c565b60405180910390f35b348015610126575f5ffd5b5061012f610207565b60405161013c919061044d565b60405180910390f35b348015610150575f5ffd5b5061016b600480360381019061016691906104cf565b61020d565b604051610178919061041c565b60405180910390f35b61019b60048036038101906101969190610590565b61025e565b6040516101a8919061041c565b60405180910390f35b60025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f5481565b5f30905090565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60035481565b5f7fd6eae5385dae362d454164c313be55f54f548cd511c3559d852e3f3ffe7d65b6838360405161023f929190610629565b60405180910390200361025457309050610258565b5f90505b92915050565b5f5f845f6002811061027357610272610641565b5b60200201358560016002811061028c5761028b610641565b5b60200201356040516020016102a292919061068e565b604051602081830303815290604052805190602001205f1c90506102c5816102cf565b9150509392505050565b5f60015f5f8282546102e191906106e6565b92505081905550335f546040516020016102fc92919061075e565b604051602081830303815290604052805190602001205f1c90508160015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060025f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550346003819055507f2b7297b31452d0a13e57c605870ec3c9b4ac6ef33e5cbae7a0f00bc2a3e967828282346040516103d093929190610789565b60405180910390a1919050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610406826103dd565b9050919050565b610416816103fc565b82525050565b5f60208201905061042f5f83018461040d565b92915050565b5f819050919050565b61044781610435565b82525050565b5f6020820190506104605f83018461043e565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f84011261048f5761048e61046e565b5b8235905067ffffffffffffffff8111156104ac576104ab610472565b5b6020830191508360018202830111156104c8576104c7610476565b5b9250929050565b5f5f602083850312156104e5576104e4610466565b5b5f83013567ffffffffffffffff8111156105025761050161046a565b5b61050e8582860161047a565b92509250509250929050565b5f8190508260206002028201111561053557610534610476565b5b92915050565b5f5f83601f8401126105505761054f61046e565b5b8235905067ffffffffffffffff81111561056d5761056c610472565b5b60208301915083600182028301111561058957610588610476565b5b9250929050565b5f5f5f606084860312156105a7576105a6610466565b5b5f6105b48682870161051a565b935050604084013567ffffffffffffffff8111156105d5576105d461046a565b5b6105e18682870161053b565b92509250509250925092565b5f81905092915050565b828183375f83830152505050565b5f61061083856105ed565b935061061d8385846105f7565b82840190509392505050565b5f610635828486610605565b91508190509392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f819050919050565b61068861068382610435565b61066e565b82525050565b5f6106998285610677565b6020820191506106a98284610677565b6020820191508190509392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6106f082610435565b91506106fb83610435565b9250828201905080821115610713576107126106b9565b5b92915050565b5f8160601b9050919050565b5f61072f82610719565b9050919050565b5f61074082610725565b9050919050565b610758610753826103fc565b610736565b82525050565b5f6107698285610747565b6014820191506107798284610677565b6020820191508190509392505050565b5f60608201905061079c5f83018661040d565b6107a9602083018561040d565b6107b6604083018461043e565b94935050505056fea26469706673582212202e7c5c3be52ba719aa8579433c475f973a17163db3866f0a1b1df84a267d892c64736f6c63430008220033"
114138
}

‎e2e/fixtures/StakingStub.sol‎

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22
pragma solidity ^0.8.13;
33

44
/// Minimal recording stub for the Tier-2 browser-wallet e2e harness.
5-
/// Mimics the Staking `validatorJoin` selectors and emits the ValidatorJoin
5+
/// Mimics the proof-bearing Staking `validatorJoin` selector and emits the ValidatorJoin
66
/// event (address operator, address validator, uint256 amount) the CLI decodes.
7+
/// It also stands in for ConsensusMain, AddressManager, and
8+
/// ValidatorWalletFactory so the SDK can resolve and verify the registration
9+
/// domain before the browser signs the transaction.
710
/// It stands up NO consensus; it only records the call so the sign->broadcast
811
/// ->receipt loop can be asserted end to end.
912
contract StakingStub {
@@ -14,12 +17,31 @@ contract StakingStub {
1417
address public lastValidator;
1518
uint256 public lastAmount;
1619

17-
function validatorJoin() external payable returns (address) {
18-
return _join(msg.sender);
20+
function getAddressManager() external view returns (address) {
21+
return address(this);
1922
}
2023

21-
function validatorJoin(address _operator) external payable returns (address) {
22-
return _join(_operator);
24+
function getAddress(string calldata _name) external view returns (address) {
25+
if (keccak256(bytes(_name)) == keccak256("ValidatorWalletFactory")) {
26+
return address(this);
27+
}
28+
return address(0);
29+
}
30+
31+
function validatorJoin(
32+
uint256[2] calldata _operatorPubKey,
33+
bytes calldata
34+
) external payable returns (address) {
35+
address operator = address(
36+
uint160(
37+
uint256(
38+
keccak256(
39+
abi.encodePacked(_operatorPubKey[0], _operatorPubKey[1])
40+
)
41+
)
42+
)
43+
);
44+
return _join(operator);
2345
}
2446

2547
function _join(address operator) internal returns (address validator) {

0 commit comments

Comments
 (0)