Skip to content

Commit b9a15b4

Browse files
Merge branch 'develop' into master
2 parents dbb1091 + 6ac16d3 commit b9a15b4

30 files changed

+975
-254
lines changed

contracts-test/TestFeature.sol

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,17 @@ contract TestFeature is BaseFeature {
1313

1414
bytes32 constant NAME = "TestFeature";
1515

16-
bool boolVal;
1716
uint uintVal;
18-
1917
TestDapp public dapp;
2018

2119
constructor(
2220
ILockStorage _lockStorage,
2321
IVersionManager _versionManager,
24-
bool _boolVal,
2522
uint _uintVal
2623
)
2724
BaseFeature(_lockStorage, _versionManager, NAME)
2825
public
2926
{
30-
boolVal = _boolVal;
3127
uintVal = _uintVal;
3228
dapp = new TestDapp();
3329
}
@@ -63,24 +59,29 @@ contract TestFeature is BaseFeature {
6359
* @inheritdoc IFeature
6460
*/
6561
function getStaticCallSignatures() external virtual override view returns (bytes4[] memory _sigs) {
66-
_sigs = new bytes4[](3);
62+
_sigs = new bytes4[](4);
6763
_sigs[0] = bytes4(keccak256("getBoolean()"));
6864
_sigs[1] = bytes4(keccak256("getUint()"));
6965
_sigs[2] = bytes4(keccak256("getAddress(address)"));
66+
_sigs[3] = bytes4(keccak256("badStaticCall()"));
7067
}
7168

7269
function getBoolean() public view returns (bool) {
73-
return boolVal;
70+
return true;
7471
}
7572

7673
function getUint() public view returns (uint) {
77-
return uintVal;
74+
return 42;
7875
}
7976

8077
function getAddress(address _addr) public pure returns (address) {
8178
return _addr;
8279
}
8380

81+
function badStaticCall() external {
82+
uintVal = 123456;
83+
}
84+
8485
function callDapp(address _wallet)
8586
external
8687
{
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// Copyright (C) 2018 Argent Labs Ltd. <https://argent.xyz>
2+
3+
// This program is free software: you can redistribute it and/or modify
4+
// it under the terms of the GNU General Public License as published by
5+
// the Free Software Foundation, either version 3 of the License, or
6+
// (at your option) any later version.
7+
8+
// This program is distributed in the hope that it will be useful,
9+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
// GNU General Public License for more details.
12+
13+
// You should have received a copy of the GNU General Public License
14+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
15+
16+
// SPDX-License-Identifier: GPL-3.0-only
17+
pragma solidity ^0.6.12;
18+
import "./base/Owned.sol";
19+
20+
interface IArgentWallet {
21+
/**
22+
* @notice Returns the implementation of the wallet.
23+
* @return The wallet implementation.
24+
*/
25+
function implementation() external view returns (address);
26+
}
27+
28+
/**
29+
* @title ArgentWalletDetector
30+
* @notice Simple contract to detect if a given address represents an Argent wallet.
31+
* The `isArgentWallet` method returns true if the codehash matches one of the deployed Proxy
32+
* and if the target implementation matches one of the deployed BaseWallet.
33+
* Only the owner of the contract can add code hash and implementations.
34+
* @author Julien Niset - <[email protected]>
35+
*/
36+
contract ArgentWalletDetector is Owned {
37+
38+
// The accepted code hashes
39+
bytes32[] private codes;
40+
// The accepted implementations
41+
address[] private implementations;
42+
// mapping to efficiently check if a code is accepted
43+
mapping (bytes32 => Info) public acceptedCodes;
44+
// mapping to efficiently check is an implementation is accepted
45+
mapping (address => Info) public acceptedImplementations;
46+
47+
struct Info {
48+
bool exists;
49+
uint128 index;
50+
}
51+
52+
// emits when a new accepted code is added
53+
event CodeAdded(bytes32 indexed code);
54+
// emits when a new accepted implementation is added
55+
event ImplementationAdded(address indexed implementation);
56+
57+
constructor(bytes32[] memory _codes, address[] memory _implementations) public {
58+
for(uint i = 0; i < _codes.length; i++) {
59+
addCode(_codes[i]);
60+
}
61+
for(uint j = 0; j < _implementations.length; j++) {
62+
addImplementation(_implementations[j]);
63+
}
64+
}
65+
66+
/**
67+
* @notice Adds a new accepted code hash.
68+
* @param _code The new code hash.
69+
*/
70+
function addCode(bytes32 _code) public onlyOwner {
71+
require(_code != bytes32(0), "AWR: empty _code");
72+
Info storage code = acceptedCodes[_code];
73+
if(!code.exists) {
74+
codes.push(_code);
75+
code.exists = true;
76+
code.index = uint128(codes.length - 1);
77+
emit CodeAdded(_code);
78+
}
79+
}
80+
81+
/**
82+
* @notice Adds a new accepted implementation.
83+
* @param _impl The new implementation.
84+
*/
85+
function addImplementation(address _impl) public onlyOwner {
86+
require(_impl != address(0), "AWR: empty _impl");
87+
Info storage impl = acceptedImplementations[_impl];
88+
if(!impl.exists) {
89+
implementations.push(_impl);
90+
impl.exists = true;
91+
impl.index = uint128(implementations.length - 1);
92+
emit ImplementationAdded(_impl);
93+
}
94+
}
95+
96+
/**
97+
* @notice Adds a new accepted code hash and implementation from a deployed Argent wallet.
98+
* @param _argentWallet The deployed Argent wallet.
99+
*/
100+
function addCodeAndImplementationFromWallet(address _argentWallet) external onlyOwner {
101+
bytes32 codeHash;
102+
// solhint-disable-next-line no-inline-assembly
103+
assembly { codeHash := extcodehash(_argentWallet) }
104+
addCode(codeHash);
105+
address implementation = IArgentWallet(_argentWallet).implementation();
106+
addImplementation(implementation);
107+
}
108+
109+
/**
110+
* @notice Gets the list of accepted implementations.
111+
*/
112+
function getImplementations() public view returns (address[] memory) {
113+
return implementations;
114+
}
115+
116+
/**
117+
* @notice Gets the list of accepted code hash.
118+
*/
119+
function getCodes() public view returns (bytes32[] memory) {
120+
return codes;
121+
}
122+
123+
/**
124+
* @notice Checks if an address is an Argent wallet
125+
* @param _wallet The target wallet
126+
*/
127+
function isArgentWallet(address _wallet) external view returns (bool) {
128+
bytes32 codeHash;
129+
// solhint-disable-next-line no-inline-assembly
130+
assembly { codeHash := extcodehash(_wallet) }
131+
return acceptedCodes[codeHash].exists && acceptedImplementations[IArgentWallet(_wallet).implementation()].exists;
132+
}
133+
}

contracts/modules/ApprovedTransfer.sol renamed to contracts/modules/ApprovedTransfer/ApprovedTransfer.sol

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@
1717
pragma solidity ^0.6.12;
1818
pragma experimental ABIEncoderV2;
1919

20-
import "./common/Utils.sol";
21-
import "./common/LimitUtils.sol";
22-
import "./common/BaseTransfer.sol";
23-
import "../infrastructure/storage/ILimitStorage.sol";
24-
import "../infrastructure/storage/IGuardianStorage.sol";
20+
import "../common/Utils.sol";
21+
import "../common/LimitUtils.sol";
22+
import "../common/BaseTransfer.sol";
23+
import "../../infrastructure/storage/ILimitStorage.sol";
24+
import "../../infrastructure/storage/IGuardianStorage.sol";
2525

2626
/**
2727
* @title ApprovedTransfer

contracts/modules/RelayerManager.sol renamed to contracts/modules/RelayerManager/RelayerManager.sol

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@
1717
pragma solidity ^0.6.12;
1818
pragma experimental ABIEncoderV2;
1919

20-
import "./common/Utils.sol";
21-
import "./common/BaseFeature.sol";
22-
import "./common/GuardianUtils.sol";
23-
import "./common/LimitUtils.sol";
24-
import "../infrastructure/storage/ILimitStorage.sol";
25-
import "../infrastructure/ITokenPriceRegistry.sol";
26-
import "../infrastructure/storage/IGuardianStorage.sol";
20+
import "../common/Utils.sol";
21+
import "../common/BaseFeature.sol";
22+
import "../common/GuardianUtils.sol";
23+
import "../common/LimitUtils.sol";
24+
import "../../infrastructure/storage/ILimitStorage.sol";
25+
import "../../infrastructure/ITokenPriceRegistry.sol";
26+
import "../../infrastructure/storage/IGuardianStorage.sol";
2727

2828
/**
2929
* @title RelayerManager

contracts/modules/TokenExchanger.sol renamed to contracts/modules/TokenExchanger/TokenExchanger.sol

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@
1717
pragma solidity ^0.6.12;
1818
pragma experimental ABIEncoderV2;
1919

20-
import "./common/BaseFeature.sol";
21-
import "../../lib/other/ERC20.sol";
22-
import "../../lib/paraswap/IAugustusSwapper.sol";
23-
import "../infrastructure/ITokenPriceRegistry.sol";
24-
import "../infrastructure/IDexRegistry.sol";
20+
import "../common/BaseFeature.sol";
21+
import "../../../lib/other/ERC20.sol";
22+
import "../../../lib/paraswap/IAugustusSwapper.sol";
23+
import "../../infrastructure/ITokenPriceRegistry.sol";
24+
import "../../infrastructure/IDexRegistry.sol";
2525

2626
/**
2727
* @title TokenExchanger

contracts/modules/TransferManager.sol renamed to contracts/modules/TransferManager/TransferManager.sol

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@
1717
pragma solidity ^0.6.12;
1818
pragma experimental ABIEncoderV2;
1919

20-
import "./common/Utils.sol";
21-
import "./common/BaseTransfer.sol";
22-
import "./common/LimitUtils.sol";
23-
import "../infrastructure/storage/ILimitStorage.sol";
24-
import "../infrastructure/storage/ITransferStorage.sol";
25-
import "../infrastructure/ITokenPriceRegistry.sol";
26-
import "../../lib/other/ERC20.sol";
20+
import "../common/Utils.sol";
21+
import "../common/BaseTransfer.sol";
22+
import "../common/LimitUtils.sol";
23+
import "../../infrastructure/storage/ILimitStorage.sol";
24+
import "../../infrastructure/storage/ITransferStorage.sol";
25+
import "../../infrastructure/ITokenPriceRegistry.sol";
26+
import "../../../lib/other/ERC20.sol";
2727

2828
/**
2929
* @title TransferManager

contracts/modules/VersionManager.sol

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,18 +175,37 @@ contract VersionManager is IVersionManager, IModule, BaseFeature, Owned {
175175
return (1, OwnerSignature.Required);
176176
}
177177

178+
/* ***************** Static Call Delegation ************************* */
179+
180+
/**
181+
* @notice This method is used by the VersionManager's fallback (via an internal call) to determine whether
182+
* the current transaction is a staticcall or not. The method succeeds if the current transaction is a static call,
183+
* and reverts otherwise.
184+
* @dev The use of an if/else allows to encapsulate the whole logic in a single function.
185+
*/
186+
function verifyStaticCall() public {
187+
if(msg.sender != address(this)) { // first entry in the method (via an internal call)
188+
(bool success,) = address(this).call{gas: 3000}(abi.encodeWithSelector(VersionManager(0).verifyStaticCall.selector));
189+
require(!success, "VM: not in a staticcall");
190+
} else { // second entry in the method (via an external call)
191+
// solhint-disable-next-line no-inline-assembly
192+
assembly { log0(0, 0) }
193+
}
194+
}
195+
178196
/**
179197
* @notice This method delegates the static call to a target feature
180198
*/
181199
fallback() external {
182200
uint256 version = walletVersions[msg.sender];
183201
address feature = staticCallExecutors[version][msg.sig];
184202
require(feature != address(0), "VM: static call not supported for wallet version");
203+
verifyStaticCall();
185204

186205
// solhint-disable-next-line no-inline-assembly
187206
assembly {
188207
calldatacopy(0, 0, calldatasize())
189-
let result := staticcall(gas(), feature, 0, calldatasize(), 0, 0)
208+
let result := delegatecall(gas(), feature, 0, calldatasize(), 0, 0)
190209
returndatacopy(0, 0, returndatasize())
191210
switch result
192211
case 0 {revert(0, returndatasize())}

0 commit comments

Comments
 (0)