Skip to content

Commit 3ec26b5

Browse files
[hebaov2] allow recover function to reset guardians (#2446)
* [hebaov2] add a new recover function which can reset guardians * update * add unit test * feedback * update * update * add test for duplicated guardians * Hebao v2: fix potential duplicate guardian bug (#2463) * fix tests Co-authored-by: Daniel Wang <[email protected]>
1 parent c0a84d4 commit 3ec26b5

File tree

18 files changed

+666
-199
lines changed

18 files changed

+666
-199
lines changed

packages/hebao_v2/contracts/base/SmartWallet.sol

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,12 @@ contract SmartWallet is ERC1271
108108
require(owner != address(0), "INVALID_OWNER");
109109

110110
wallet.owner = owner;
111-
if (guardians.length != 0) {
112-
wallet.setInitialGuardians(guardians);
113-
}
111+
wallet.addGuardiansImmediately(guardians);
112+
114113
if (quota != 0) {
115114
wallet.setQuota(quota, 0);
116115
}
116+
117117
if (inheritor != address(0)) {
118118
wallet.setInheritor(inheritor, 365 days);
119119
}
@@ -363,15 +363,17 @@ contract SmartWallet is ERC1271
363363
//
364364

365365
function recover(
366-
Approval calldata approval,
367-
address newOwner
366+
Approval calldata approval,
367+
address newOwner,
368+
address[] calldata newGuardians
368369
)
369370
external
370371
{
371372
wallet.recover(
372373
DOMAIN_SEPARATOR,
373374
approval,
374-
newOwner
375+
newOwner,
376+
newGuardians
375377
);
376378
}
377379

packages/hebao_v2/contracts/base/libwallet/GuardianLib.sol

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,17 @@ library GuardianLib
3535
event GuardianAdded (address guardian, uint effectiveTime);
3636
event GuardianRemoved (address guardian, uint effectiveTime);
3737

38-
function setInitialGuardians(
38+
function addGuardiansImmediately(
3939
Wallet storage wallet,
4040
address[] memory _guardians
4141
)
4242
external
4343
{
44-
require(_guardians.length < MAX_GUARDIANS, "TOO_MANY_GUARDIANS");
45-
for (uint i = 0; i < _guardians.length; i++) {
46-
_addGuardian(wallet, _guardians[i], 0, true);
44+
address guardian = address(0);
45+
for (uint i = 0; i < _guardians.length; i++) {
46+
require(_guardians[i] > guardian, "INVALID_ORDERING");
47+
guardian = _guardians[i];
48+
_addGuardian(wallet, guardian, 0, true);
4749
}
4850
}
4951

@@ -314,7 +316,7 @@ library GuardianLib
314316

315317
uint pos = wallet.guardianIdx[addr];
316318

317-
if(pos == 0) {
319+
if (pos == 0) {
318320
// Add the new guardian
319321
Guardian memory _g = Guardian(
320322
addr,

packages/hebao_v2/contracts/base/libwallet/MetaTxLib.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ library MetaTxLib
7272
keccak256(metaTx.data)
7373
);
7474
bytes32 metaTxHash = EIP712.hashPacked(DOMAIN_SEPARATOR, encoded);
75-
require(metaTxHash.verifySignature(wallet.owner, metaTx.signature), "INVALID_SIGNATURE");
75+
require(metaTxHash.verifySignature(wallet.owner, metaTx.signature), "METATX_INVALID_SIGNATURE");
7676
return metaTxHash;
7777
}
7878

packages/hebao_v2/contracts/base/libwallet/RecoverLib.sol

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,19 @@ library RecoverLib
2222
event Recovered(address newOwner);
2323

2424
bytes32 public constant RECOVER_TYPEHASH = keccak256(
25-
"recover(address wallet,uint256 validUntil,address newOwner)"
25+
"recover(address wallet,uint256 validUntil,address newOwner,address[] newGuardians)"
2626
);
2727

28-
/// @dev Recover a wallet by setting a new owner.
28+
/// @dev Recover a wallet by setting a new owner and guardians.
2929
/// @param approval The approval.
3030
/// @param newOwner The new owner address to set.
31+
/// @param newGuardians The new guardians addresses to set.
3132
function recover(
32-
Wallet storage wallet,
33-
bytes32 domainSeperator,
34-
Approval calldata approval,
35-
address newOwner
33+
Wallet storage wallet,
34+
bytes32 domainSeperator,
35+
Approval calldata approval,
36+
address newOwner,
37+
address[] calldata newGuardians
3638
)
3739
external
3840
{
@@ -47,18 +49,28 @@ library RecoverLib
4749
RECOVER_TYPEHASH,
4850
approval.wallet,
4951
approval.validUntil,
50-
newOwner
52+
newOwner,
53+
keccak256(abi.encodePacked(newGuardians))
5154
)
5255
);
5356

54-
if (wallet.isGuardian(newOwner, true)) {
55-
wallet.deleteGuardian(newOwner, block.timestamp, true);
56-
}
57-
5857
wallet.owner = newOwner;
5958
wallet.setLock(address(this), false);
60-
wallet.cancelPendingGuardians();
59+
60+
if (newGuardians.length > 0) {
61+
for (uint i = 0; i < newGuardians.length; i++) {
62+
require(newGuardians[i] != newOwner, "INVALID_NEW_WALLET_GUARDIAN");
63+
}
64+
wallet.removeAllGuardians();
65+
wallet.addGuardiansImmediately(newGuardians);
66+
} else {
67+
if (wallet.isGuardian(newOwner, true)) {
68+
wallet.deleteGuardian(newOwner, block.timestamp, true);
69+
}
70+
wallet.cancelPendingGuardians();
71+
}
6172

6273
emit Recovered(newOwner);
6374
}
75+
6476
}

packages/hebao_v2/contracts/base/libwallet/WalletData.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ struct Wallet
5151
// relayer => nonce
5252
uint nonce;
5353
// hash => consumed
54-
mapping(bytes32 => bool) hashes;
54+
mapping (bytes32 => bool) hashes;
5555

5656
bool locked;
5757

@@ -65,5 +65,5 @@ struct Wallet
6565
Quota quota;
6666

6767
// whitelisted address => effective timestamp
68-
mapping(address => uint) whitelisted;
68+
mapping (address => uint) whitelisted;
6969
}

packages/hebao_v2/contracts/test/LRCToken.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ library SafeMath {
6262
*/
6363
contract BasicToken is ERC20Basic {
6464
using SafeMath for uint;
65-
mapping(address => uint) balances;
65+
mapping (address => uint) balances;
6666
uint totalSupply_;
6767
/**
6868
* @dev total number of tokens in existence

packages/hebao_v2/contracts/thirdparty/MockContract.sol

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -87,17 +87,17 @@ contract MockContract is MockInterface {
8787
bytes4 public constant SENTINEL_ANY_MOCKS = hex"01";
8888

8989
// A linked list allows easy iteration and inclusion checks
90-
mapping(bytes32 => bytes) calldataMocks;
91-
mapping(bytes => MockType) calldataMockTypes;
92-
mapping(bytes => bytes) calldataExpectations;
93-
mapping(bytes => string) calldataRevertMessage;
94-
mapping(bytes32 => uint) calldataInvocations;
95-
96-
mapping(bytes4 => bytes4) methodIdMocks;
97-
mapping(bytes4 => MockType) methodIdMockTypes;
98-
mapping(bytes4 => bytes) methodIdExpectations;
99-
mapping(bytes4 => string) methodIdRevertMessages;
100-
mapping(bytes32 => uint) methodIdInvocations;
90+
mapping (bytes32 => bytes) calldataMocks;
91+
mapping (bytes => MockType) calldataMockTypes;
92+
mapping (bytes => bytes) calldataExpectations;
93+
mapping (bytes => string) calldataRevertMessage;
94+
mapping (bytes32 => uint) calldataInvocations;
95+
96+
mapping (bytes4 => bytes4) methodIdMocks;
97+
mapping (bytes4 => MockType) methodIdMockTypes;
98+
mapping (bytes4 => bytes) methodIdExpectations;
99+
mapping (bytes4 => string) methodIdRevertMessages;
100+
mapping (bytes32 => uint) methodIdInvocations;
101101

102102
MockType fallbackMockType;
103103
bytes fallbackExpectation;
@@ -262,7 +262,7 @@ contract MockContract is MockInterface {
262262
bytes memory nextMock = calldataMocks[MOCKS_LIST_START];
263263
bytes32 mockHash = keccak256(nextMock);
264264
// We cannot compary bytes
265-
while(mockHash != MOCKS_LIST_END_HASH) {
265+
while (mockHash != MOCKS_LIST_END_HASH) {
266266
// Reset all mock maps
267267
calldataMockTypes[nextMock] = MockType.Return;
268268
calldataExpectations[nextMock] = hex"";
@@ -279,7 +279,7 @@ contract MockContract is MockInterface {
279279

280280
// Reset all any calldataMocks
281281
bytes4 nextAnyMock = methodIdMocks[SENTINEL_ANY_MOCKS];
282-
while(nextAnyMock != SENTINEL_ANY_MOCKS) {
282+
while (nextAnyMock != SENTINEL_ANY_MOCKS) {
283283
bytes4 currentAnyMock = nextAnyMock;
284284
methodIdMockTypes[currentAnyMock] = MockType.Return;
285285
methodIdExpectations[currentAnyMock] = hex"";
@@ -298,7 +298,7 @@ contract MockContract is MockInterface {
298298
}
299299

300300
function useAllGas() private {
301-
while(true) {
301+
while (true) {
302302
bool s;
303303
assembly {
304304
//expensive call to EC multiply contract

packages/hebao_v2/contracts/thirdparty/strings.sol

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ library strings {
4646

4747
function memcpy(uint dest, uint src, uint _len) private pure {
4848
// Copy word-length chunks while possible
49-
for(; _len >= 32; _len -= 32) {
49+
for (; _len >= 32; _len -= 32) {
5050
assembly {
5151
mstore(dest, mload(src))
5252
}
@@ -165,13 +165,13 @@ library strings {
165165
assembly { b := and(mload(ptr), 0xFF) }
166166
if (b < 0x80) {
167167
ptr += 1;
168-
} else if(b < 0xE0) {
168+
} else if (b < 0xE0) {
169169
ptr += 2;
170-
} else if(b < 0xF0) {
170+
} else if (b < 0xF0) {
171171
ptr += 3;
172-
} else if(b < 0xF8) {
172+
} else if (b < 0xF8) {
173173
ptr += 4;
174-
} else if(b < 0xFC) {
174+
} else if (b < 0xFC) {
175175
ptr += 5;
176176
} else {
177177
ptr += 6;
@@ -214,7 +214,7 @@ library strings {
214214
if (a != b) {
215215
// Mask out irrelevant bytes and check again
216216
uint256 mask = uint256(-1); // 0xffff...
217-
if(shortest < 32) {
217+
if (shortest < 32) {
218218
mask = ~(2 ** (8 * (32 - shortest + idx)) - 1);
219219
}
220220
uint256 diff = (a & mask) - (b & mask);
@@ -258,9 +258,9 @@ library strings {
258258
assembly { b := and(mload(sub(mload(add(self, 32)), 31)), 0xFF) }
259259
if (b < 0x80) {
260260
l = 1;
261-
} else if(b < 0xE0) {
261+
} else if (b < 0xE0) {
262262
l = 2;
263-
} else if(b < 0xF0) {
263+
} else if (b < 0xF0) {
264264
l = 3;
265265
} else {
266266
l = 4;
@@ -310,10 +310,10 @@ library strings {
310310
if (b < 0x80) {
311311
ret = b;
312312
length = 1;
313-
} else if(b < 0xE0) {
313+
} else if (b < 0xE0) {
314314
ret = b & 0x1F;
315315
length = 2;
316-
} else if(b < 0xF0) {
316+
} else if (b < 0xF0) {
317317
ret = b & 0x0F;
318318
length = 3;
319319
} else {
@@ -697,14 +697,14 @@ library strings {
697697
return "";
698698

699699
uint length = self._len * (parts.length - 1);
700-
for(uint i = 0; i < parts.length; i++)
700+
for (uint i = 0; i < parts.length; i++)
701701
length += parts[i]._len;
702702

703703
string memory ret = new string(length);
704704
uint retptr;
705705
assembly { retptr := add(ret, 32) }
706706

707-
for(uint i = 0; i < parts.length; i++) {
707+
for (uint i = 0; i < parts.length; i++) {
708708
memcpy(retptr, parts[i]._ptr, parts[i]._len);
709709
retptr += parts[i]._len;
710710
if (i < parts.length - 1) {

packages/hebao_v2/hardhat.config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ export default {
6161
},
6262

6363
arbitrum: {
64-
chainId: 212984383488152,
65-
url: "https://kovan4.arbitrum.io/rpc",
64+
chainId: 144545313136048,
65+
url: "https://kovan5.arbitrum.io/rpc",
6666
gas: "auto",
6767
gasPrice: "auto",
6868
gasMultiplier: 1,

packages/hebao_v2/script/deploy-arbitrum.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,13 @@ import { signCreateWallet } from "../test/helper/signatureUtils";
55
import BN = require("bn.js");
66

77
async function newWallet() {
8-
const smartWalletAddress = "0x19F3338C71a16696D27B68DEF0d2fB27Aa4b8807";
9-
const walletFactoryAddress = "0x44B74caF7CB28cC243EaA9D1d1b3eCb2Ddc2C9f1";
8+
// walletFactory and smartWallet contract on test v4:
9+
// const smartWalletAddress = "0x19F3338C71a16696D27B68DEF0d2fB27Aa4b8807";
10+
// const walletFactoryAddress = "0x44B74caF7CB28cC243EaA9D1d1b3eCb2Ddc2C9f1";
11+
12+
// walletFactory and smartWallet contract on test v5:
13+
const smartWalletAddress = "0xE708Cb725D6F2aDeEab2258262Aa9129D2A28312";
14+
const walletFactoryAddress = "0x5Dd70df24364DC05D46C8F40611BFDd107927263";
1015

1116
const ownerAccount = (await ethers.getSigners())[0];
1217
const ownerAddr = await ownerAccount.getAddress();
@@ -34,9 +39,9 @@ async function newWallet() {
3439
signature: Buffer.from(signature.txSignature.slice(2), "hex")
3540
};
3641

37-
const walletFactory = await (
38-
await ethers.getContractFactory("WalletFactory")
39-
).attach(walletFactoryAddress);
42+
const walletFactory = await (await ethers.getContractFactory(
43+
"WalletFactory"
44+
)).attach(walletFactoryAddress);
4045

4146
const walletAddrComputed = await walletFactory.computeWalletAddress(
4247
ownerAddr,

0 commit comments

Comments
 (0)