Skip to content

Commit 00dd9e4

Browse files
authored
fix: resolve signature replication issue in weighted ecdsa validator (#101)
* fix weighted ecdsa validator signature replication issue * feat: port weighted ecdsa validator v2.4
1 parent 14b48f8 commit 00dd9e4

File tree

1 file changed

+46
-35
lines changed

1 file changed

+46
-35
lines changed

src/validator/WeightedECDSAValidator.sol

Lines changed: 46 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -59,34 +59,45 @@ contract WeightedECDSAValidator is EIP712, IValidator {
5959
event GuardianRemoved(address indexed guardian, address indexed kernel);
6060

6161
function _domainNameAndVersion() internal pure override returns (string memory, string memory) {
62-
return ("WeightedECDSAValidator", "0.0.2");
62+
return ("WeightedECDSAValidator", "0.0.3");
6363
}
6464

65-
function onInstall(bytes calldata _data) external payable override {
66-
(address[] memory _guardians, uint24[] memory _weights, uint24 _threshold, uint48 _delay) =
67-
abi.decode(_data, (address[], uint24[], uint24, uint48));
65+
function _addGuardians(address[] memory _guardians, uint24[] memory _weights, address _kernel) internal {
66+
uint24 totalWeight = weightedStorage[_kernel].totalWeight;
6867
require(_guardians.length == _weights.length, "Length mismatch");
69-
if (_isInitialized(msg.sender)) revert AlreadyInitialized(msg.sender);
70-
weightedStorage[msg.sender].firstGuardian = msg.sender;
68+
uint160 prevGuardian = uint160(weightedStorage[_kernel].firstGuardian);
7169
for (uint256 i = 0; i < _guardians.length; i++) {
72-
require(_guardians[i] != msg.sender, "Guardian cannot be self");
70+
require(_guardians[i] != _kernel, "Guardian cannot be self");
7371
require(_guardians[i] != address(0), "Guardian cannot be 0");
7472
require(_weights[i] != 0, "Weight cannot be 0");
75-
require(guardian[_guardians[i]][msg.sender].weight == 0, "Guardian already enabled");
76-
guardian[_guardians[i]][msg.sender] =
77-
GuardianStorage({weight: _weights[i], nextGuardian: weightedStorage[msg.sender].firstGuardian});
78-
weightedStorage[msg.sender].firstGuardian = _guardians[i];
79-
weightedStorage[msg.sender].totalWeight += _weights[i];
80-
emit GuardianAdded(_guardians[i], msg.sender, _weights[i]);
73+
require(guardian[_guardians[i]][_kernel].weight == 0, "Guardian already enabled");
74+
require(uint160(_guardians[i]) < prevGuardian, "Guardians not sorted");
75+
guardian[_guardians[i]][_kernel] =
76+
GuardianStorage({weight: _weights[i], nextGuardian: weightedStorage[_kernel].firstGuardian});
77+
weightedStorage[_kernel].firstGuardian = _guardians[i];
78+
totalWeight += _weights[i];
79+
prevGuardian = uint160(_guardians[i]);
80+
emit GuardianAdded(_guardians[i], _kernel, _weights[i]);
8181
}
82+
weightedStorage[_kernel].totalWeight = totalWeight;
83+
}
84+
85+
function onInstall(bytes calldata _data) external payable override {
86+
(address[] memory _guardians, uint24[] memory _weights, uint24 _threshold, uint48 _delay) =
87+
abi.decode(_data, (address[], uint24[], uint24, uint48));
88+
require(_guardians.length == _weights.length, "Length mismatch");
89+
if (_isInitialized(msg.sender)) revert AlreadyInitialized(msg.sender);
90+
weightedStorage[msg.sender].firstGuardian = address(uint160(type(uint160).max));
91+
_addGuardians(_guardians, _weights, msg.sender);
8292
weightedStorage[msg.sender].delay = _delay;
8393
weightedStorage[msg.sender].threshold = _threshold;
94+
require(_threshold <= weightedStorage[msg.sender].totalWeight, "Threshold too high");
8495
}
8596

8697
function onUninstall(bytes calldata) external payable override {
8798
if (!_isInitialized(msg.sender)) revert NotInitialized(msg.sender);
8899
address currentGuardian = weightedStorage[msg.sender].firstGuardian;
89-
while (currentGuardian != msg.sender) {
100+
while (currentGuardian != address(uint160(type(uint160).max))) {
90101
address nextGuardian = guardian[currentGuardian][msg.sender].nextGuardian;
91102
emit GuardianRemoved(currentGuardian, msg.sender);
92103
delete guardian[currentGuardian][msg.sender];
@@ -113,31 +124,21 @@ contract WeightedECDSAValidator is EIP712, IValidator {
113124
{
114125
if (!_isInitialized(msg.sender)) revert NotInitialized(msg.sender);
115126
address currentGuardian = weightedStorage[msg.sender].firstGuardian;
116-
while (currentGuardian != msg.sender) {
127+
while (currentGuardian != address(uint160(type(uint160).max))) {
117128
address nextGuardian = guardian[currentGuardian][msg.sender].nextGuardian;
118129
emit GuardianRemoved(currentGuardian, msg.sender);
119130
delete guardian[currentGuardian][msg.sender];
120131
currentGuardian = nextGuardian;
121132
}
122133
delete weightedStorage[msg.sender];
123134
require(_guardians.length == _weights.length, "Length mismatch");
124-
weightedStorage[msg.sender].firstGuardian = msg.sender;
125-
for (uint256 i = 0; i < _guardians.length; i++) {
126-
require(_guardians[i] != msg.sender, "Guardian cannot be self");
127-
require(_guardians[i] != address(0), "Guardian cannot be 0");
128-
require(_weights[i] != 0, "Weight cannot be 0");
129-
require(guardian[_guardians[i]][msg.sender].weight == 0, "Guardian already enabled");
130-
guardian[_guardians[i]][msg.sender] =
131-
GuardianStorage({weight: _weights[i], nextGuardian: weightedStorage[msg.sender].firstGuardian});
132-
weightedStorage[msg.sender].firstGuardian = _guardians[i];
133-
weightedStorage[msg.sender].totalWeight += _weights[i];
134-
emit GuardianAdded(_guardians[i], msg.sender, _weights[i]);
135-
}
135+
weightedStorage[msg.sender].firstGuardian = address(uint160(type(uint160).max));
136+
_addGuardians(_guardians, _weights, msg.sender);
136137
weightedStorage[msg.sender].delay = _delay;
137138
weightedStorage[msg.sender].threshold = _threshold;
138139
}
139140

140-
function approve(bytes32 _callDataAndNonceHash, address _kernel) external payable {
141+
function approve(bytes32 _callDataAndNonceHash, address _kernel) external {
141142
require(guardian[msg.sender][_kernel].weight != 0, "Guardian not enabled");
142143
require(weightedStorage[_kernel].threshold != 0, "Kernel not enabled");
143144
ProposalStorage storage proposal = proposalStatus[_callDataAndNonceHash][_kernel];
@@ -152,7 +153,7 @@ contract WeightedECDSAValidator is EIP712, IValidator {
152153
}
153154
}
154155

155-
function approveWithSig(bytes32 _callDataAndNonceHash, address _kernel, bytes calldata sigs) external payable {
156+
function approveWithSig(bytes32 _callDataAndNonceHash, address _kernel, bytes calldata sigs) external {
156157
uint256 sigCount = sigs.length / 65;
157158
require(weightedStorage[_kernel].threshold != 0, "Kernel not enabled");
158159
ProposalStorage storage proposal = proposalStatus[_callDataAndNonceHash][_kernel];
@@ -176,7 +177,7 @@ contract WeightedECDSAValidator is EIP712, IValidator {
176177
}
177178
}
178179

179-
function veto(bytes32 _callDataAndNonceHash) external payable {
180+
function veto(bytes32 _callDataAndNonceHash) external {
180181
ProposalStorage storage proposal = proposalStatus[_callDataAndNonceHash][msg.sender];
181182
require(
182183
proposal.status == ProposalStatus.Ongoing || proposal.status == ProposalStatus.Approved,
@@ -237,13 +238,19 @@ contract WeightedECDSAValidator is EIP712, IValidator {
237238
passed = true;
238239
}
239240
}
241+
proposal.status = ProposalStatus.Executed;
240242
if (passed && guardian[signer][msg.sender].weight != 0) {
241-
proposal.status = ProposalStatus.Executed;
242243
return packValidationData(ValidAfter.wrap(0), ValidUntil.wrap(0));
243244
}
245+
return SIG_VALIDATION_FAILED_UINT;
244246
} else if (proposal.status == ProposalStatus.Approved || passed) {
245-
address signer = ECDSA.recover(ECDSA.toEthSignedMessageHash(userOpHash), userOp.signature);
246-
if (guardian[signer][msg.sender].weight != 0) {
247+
if (userOp.paymasterAndData.length == 0 || address(bytes20(userOp.paymasterAndData[0:20])) == address(0)) {
248+
address signer = ECDSA.recover(ECDSA.toEthSignedMessageHash(userOpHash), userOp.signature);
249+
if (guardian[signer][msg.sender].weight != 0) {
250+
proposal.status = ProposalStatus.Executed;
251+
return packValidationData(proposal.validAfter, ValidUntil.wrap(0));
252+
}
253+
} else {
247254
proposal.status = ProposalStatus.Executed;
248255
return packValidationData(proposal.validAfter, ValidUntil.wrap(0));
249256
}
@@ -281,13 +288,17 @@ contract WeightedECDSAValidator is EIP712, IValidator {
281288
return ERC1271_INVALID;
282289
}
283290
uint256 totalWeight = 0;
284-
address signer;
291+
address prevSigner = address(uint160(type(uint160).max));
285292
for (uint256 i = 0; i < sigCount; i++) {
286-
signer = ECDSA.recover(hash, data[i * 65:(i + 1) * 65]);
293+
address signer = ECDSA.recover(hash, data[i * 65:(i + 1) * 65]);
287294
totalWeight += guardian[signer][msg.sender].weight;
288295
if (totalWeight >= strg.threshold) {
289296
return ERC1271_MAGICVALUE;
290297
}
298+
if (signer >= prevSigner) {
299+
return ERC1271_INVALID;
300+
}
301+
prevSigner = signer;
291302
}
292303
return ERC1271_INVALID;
293304
}

0 commit comments

Comments
 (0)