Skip to content

Commit

Permalink
Merge branch 'develop' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
elenadimitrova committed Nov 16, 2020
2 parents dbb1091 + 6ac16d3 commit b9a15b4
Show file tree
Hide file tree
Showing 30 changed files with 975 additions and 254 deletions.
15 changes: 8 additions & 7 deletions contracts-test/TestFeature.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,17 @@ contract TestFeature is BaseFeature {

bytes32 constant NAME = "TestFeature";

bool boolVal;
uint uintVal;

TestDapp public dapp;

constructor(
ILockStorage _lockStorage,
IVersionManager _versionManager,
bool _boolVal,
uint _uintVal
)
BaseFeature(_lockStorage, _versionManager, NAME)
public
{
boolVal = _boolVal;
uintVal = _uintVal;
dapp = new TestDapp();
}
Expand Down Expand Up @@ -63,24 +59,29 @@ contract TestFeature is BaseFeature {
* @inheritdoc IFeature
*/
function getStaticCallSignatures() external virtual override view returns (bytes4[] memory _sigs) {
_sigs = new bytes4[](3);
_sigs = new bytes4[](4);
_sigs[0] = bytes4(keccak256("getBoolean()"));
_sigs[1] = bytes4(keccak256("getUint()"));
_sigs[2] = bytes4(keccak256("getAddress(address)"));
_sigs[3] = bytes4(keccak256("badStaticCall()"));
}

function getBoolean() public view returns (bool) {
return boolVal;
return true;
}

function getUint() public view returns (uint) {
return uintVal;
return 42;
}

function getAddress(address _addr) public pure returns (address) {
return _addr;
}

function badStaticCall() external {
uintVal = 123456;
}

function callDapp(address _wallet)
external
{
Expand Down
133 changes: 133 additions & 0 deletions contracts/infrastructure/ArgentWalletDetector.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// Copyright (C) 2018 Argent Labs Ltd. <https://argent.xyz>

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.6.12;
import "./base/Owned.sol";

interface IArgentWallet {
/**
* @notice Returns the implementation of the wallet.
* @return The wallet implementation.
*/
function implementation() external view returns (address);
}

/**
* @title ArgentWalletDetector
* @notice Simple contract to detect if a given address represents an Argent wallet.
* The `isArgentWallet` method returns true if the codehash matches one of the deployed Proxy
* and if the target implementation matches one of the deployed BaseWallet.
* Only the owner of the contract can add code hash and implementations.
* @author Julien Niset - <[email protected]>
*/
contract ArgentWalletDetector is Owned {

// The accepted code hashes
bytes32[] private codes;
// The accepted implementations
address[] private implementations;
// mapping to efficiently check if a code is accepted
mapping (bytes32 => Info) public acceptedCodes;
// mapping to efficiently check is an implementation is accepted
mapping (address => Info) public acceptedImplementations;

struct Info {
bool exists;
uint128 index;
}

// emits when a new accepted code is added
event CodeAdded(bytes32 indexed code);
// emits when a new accepted implementation is added
event ImplementationAdded(address indexed implementation);

constructor(bytes32[] memory _codes, address[] memory _implementations) public {
for(uint i = 0; i < _codes.length; i++) {
addCode(_codes[i]);
}
for(uint j = 0; j < _implementations.length; j++) {
addImplementation(_implementations[j]);
}
}

/**
* @notice Adds a new accepted code hash.
* @param _code The new code hash.
*/
function addCode(bytes32 _code) public onlyOwner {
require(_code != bytes32(0), "AWR: empty _code");
Info storage code = acceptedCodes[_code];
if(!code.exists) {
codes.push(_code);
code.exists = true;
code.index = uint128(codes.length - 1);
emit CodeAdded(_code);
}
}

/**
* @notice Adds a new accepted implementation.
* @param _impl The new implementation.
*/
function addImplementation(address _impl) public onlyOwner {
require(_impl != address(0), "AWR: empty _impl");
Info storage impl = acceptedImplementations[_impl];
if(!impl.exists) {
implementations.push(_impl);
impl.exists = true;
impl.index = uint128(implementations.length - 1);
emit ImplementationAdded(_impl);
}
}

/**
* @notice Adds a new accepted code hash and implementation from a deployed Argent wallet.
* @param _argentWallet The deployed Argent wallet.
*/
function addCodeAndImplementationFromWallet(address _argentWallet) external onlyOwner {
bytes32 codeHash;
// solhint-disable-next-line no-inline-assembly
assembly { codeHash := extcodehash(_argentWallet) }
addCode(codeHash);
address implementation = IArgentWallet(_argentWallet).implementation();
addImplementation(implementation);
}

/**
* @notice Gets the list of accepted implementations.
*/
function getImplementations() public view returns (address[] memory) {
return implementations;
}

/**
* @notice Gets the list of accepted code hash.
*/
function getCodes() public view returns (bytes32[] memory) {
return codes;
}

/**
* @notice Checks if an address is an Argent wallet
* @param _wallet The target wallet
*/
function isArgentWallet(address _wallet) external view returns (bool) {
bytes32 codeHash;
// solhint-disable-next-line no-inline-assembly
assembly { codeHash := extcodehash(_wallet) }
return acceptedCodes[codeHash].exists && acceptedImplementations[IArgentWallet(_wallet).implementation()].exists;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;

import "./common/Utils.sol";
import "./common/LimitUtils.sol";
import "./common/BaseTransfer.sol";
import "../infrastructure/storage/ILimitStorage.sol";
import "../infrastructure/storage/IGuardianStorage.sol";
import "../common/Utils.sol";
import "../common/LimitUtils.sol";
import "../common/BaseTransfer.sol";
import "../../infrastructure/storage/ILimitStorage.sol";
import "../../infrastructure/storage/IGuardianStorage.sol";

/**
* @title ApprovedTransfer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;

import "./common/Utils.sol";
import "./common/BaseFeature.sol";
import "./common/GuardianUtils.sol";
import "./common/LimitUtils.sol";
import "../infrastructure/storage/ILimitStorage.sol";
import "../infrastructure/ITokenPriceRegistry.sol";
import "../infrastructure/storage/IGuardianStorage.sol";
import "../common/Utils.sol";
import "../common/BaseFeature.sol";
import "../common/GuardianUtils.sol";
import "../common/LimitUtils.sol";
import "../../infrastructure/storage/ILimitStorage.sol";
import "../../infrastructure/ITokenPriceRegistry.sol";
import "../../infrastructure/storage/IGuardianStorage.sol";

/**
* @title RelayerManager
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;

import "./common/BaseFeature.sol";
import "../../lib/other/ERC20.sol";
import "../../lib/paraswap/IAugustusSwapper.sol";
import "../infrastructure/ITokenPriceRegistry.sol";
import "../infrastructure/IDexRegistry.sol";
import "../common/BaseFeature.sol";
import "../../../lib/other/ERC20.sol";
import "../../../lib/paraswap/IAugustusSwapper.sol";
import "../../infrastructure/ITokenPriceRegistry.sol";
import "../../infrastructure/IDexRegistry.sol";

/**
* @title TokenExchanger
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;

import "./common/Utils.sol";
import "./common/BaseTransfer.sol";
import "./common/LimitUtils.sol";
import "../infrastructure/storage/ILimitStorage.sol";
import "../infrastructure/storage/ITransferStorage.sol";
import "../infrastructure/ITokenPriceRegistry.sol";
import "../../lib/other/ERC20.sol";
import "../common/Utils.sol";
import "../common/BaseTransfer.sol";
import "../common/LimitUtils.sol";
import "../../infrastructure/storage/ILimitStorage.sol";
import "../../infrastructure/storage/ITransferStorage.sol";
import "../../infrastructure/ITokenPriceRegistry.sol";
import "../../../lib/other/ERC20.sol";

/**
* @title TransferManager
Expand Down
21 changes: 20 additions & 1 deletion contracts/modules/VersionManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -175,18 +175,37 @@ contract VersionManager is IVersionManager, IModule, BaseFeature, Owned {
return (1, OwnerSignature.Required);
}

/* ***************** Static Call Delegation ************************* */

/**
* @notice This method is used by the VersionManager's fallback (via an internal call) to determine whether
* the current transaction is a staticcall or not. The method succeeds if the current transaction is a static call,
* and reverts otherwise.
* @dev The use of an if/else allows to encapsulate the whole logic in a single function.
*/
function verifyStaticCall() public {
if(msg.sender != address(this)) { // first entry in the method (via an internal call)
(bool success,) = address(this).call{gas: 3000}(abi.encodeWithSelector(VersionManager(0).verifyStaticCall.selector));
require(!success, "VM: not in a staticcall");
} else { // second entry in the method (via an external call)
// solhint-disable-next-line no-inline-assembly
assembly { log0(0, 0) }
}
}

/**
* @notice This method delegates the static call to a target feature
*/
fallback() external {
uint256 version = walletVersions[msg.sender];
address feature = staticCallExecutors[version][msg.sig];
require(feature != address(0), "VM: static call not supported for wallet version");
verifyStaticCall();

// solhint-disable-next-line no-inline-assembly
assembly {
calldatacopy(0, 0, calldatasize())
let result := staticcall(gas(), feature, 0, calldatasize(), 0, 0)
let result := delegatecall(gas(), feature, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 {revert(0, returndatasize())}
Expand Down
Loading

0 comments on commit b9a15b4

Please sign in to comment.