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 Feb 18, 2021
2 parents c4d04d9 + 813a8a7 commit 56a5aa0
Show file tree
Hide file tree
Showing 47 changed files with 747 additions and 372 deletions.
7 changes: 3 additions & 4 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ step_setup_solc_select: &step_setup_solc_select
run:
name: "Setup solc-select"
command: |
git clone https://github.com/crytic/solc-select.git
bash ./solc-select/scripts/install.sh
sudo pip3 install solc-select
solc-select install 0.5.4
solc-select install 0.6.12
jobs:
unit-test:
<<: *job_common
Expand Down Expand Up @@ -115,8 +116,6 @@ jobs:
name: "Check TokenPriceRegistry tokens for ERC20 compliance"
command: |
export PATH=/home/circleci/.solc-select:$PATH
echo "export PATH=/home/circleci/.solc-select:$PATH" >> ~/.bashrc
solc --version
npm run validate:erc20
- run:
name: "Run slither on infrastructure contracts based on solc 0.5"
Expand Down
12 changes: 12 additions & 0 deletions .github/ISSUE_TEMPLATE/custom.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
name: Custom issue template
about: Describe this issue template's purpose here.
title: ''
labels: ''
assignees: ''

---

<!--- For issues with the Argent app, please email [email protected] -->

## Issue description
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ tmp
bin
.outputParameter
flatten

flat
## Core latex/pdflatex auxiliary files:
*.aux
*.lof
Expand Down
131 changes: 98 additions & 33 deletions contracts/infrastructure/WalletFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import "./base/Managed.sol";
import "./storage/IGuardianStorage.sol";
import "./IModuleRegistry.sol";
import "../modules/common/IVersionManager.sol";
import "../modules/common/Utils.sol";

/**
* @title WalletFactory
Expand All @@ -31,56 +32,40 @@ import "../modules/common/IVersionManager.sol";
*/
contract WalletFactory is Owned, Managed {

address constant internal ETH_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

// The address of the module dregistry
address public moduleRegistry;
// The address of the base wallet implementation
address public walletImplementation;
// The address of the GuardianStorage
address public guardianStorage;
// The recipient of the refund
address public refundAddress;

// *************** Events *************************** //

event ModuleRegistryChanged(address addr);
event WalletCreated(address indexed wallet, address indexed owner, address indexed guardian);
event RefundAddressChanged(address addr);
event WalletCreated(address indexed wallet, address indexed owner, address indexed guardian, address refundToken, uint256 refundAmount);

// *************** Constructor ********************** //

/**
* @notice Default constructor.
*/
constructor(address _moduleRegistry, address _walletImplementation, address _guardianStorage) public {
constructor(address _moduleRegistry, address _walletImplementation, address _guardianStorage, address _refundAddress) public {
require(_moduleRegistry != address(0), "WF: ModuleRegistry address not defined");
require(_walletImplementation != address(0), "WF: WalletImplementation address not defined");
require(_guardianStorage != address(0), "WF: GuardianStorage address not defined");
require(_refundAddress != address(0), "WF: refund address not defined");
moduleRegistry = _moduleRegistry;
walletImplementation = _walletImplementation;
guardianStorage = _guardianStorage;
refundAddress = _refundAddress;
}

// *************** External Functions ********************* //
/**
* @notice Lets the manager create a wallet for an owner account.
* The wallet is initialised with the version manager module, a version number and a first guardian.
* The wallet is created using the CREATE opcode.
* @param _owner The account address.
* @param _versionManager The version manager module
* @param _guardian The guardian address.
* @param _version The version of the feature bundle.
*/
function createWallet(
address _owner,
address _versionManager,
address _guardian,
uint256 _version
)
external
onlyManager
{
validateInputs(_owner, _versionManager, _guardian, _version);
Proxy proxy = new Proxy(walletImplementation);
address payable wallet = address(proxy);
configureWallet(BaseWallet(wallet), _owner, _versionManager, _guardian, _version);
}

/**
* @notice Lets the manager create a wallet for an owner account at a specific address.
Expand All @@ -97,7 +82,10 @@ contract WalletFactory is Owned, Managed {
address _versionManager,
address _guardian,
bytes32 _salt,
uint256 _version
uint256 _version,
uint256 _refundAmount,
address _refundToken,
bytes calldata _ownerSignature
)
external
onlyManager
Expand All @@ -108,6 +96,15 @@ contract WalletFactory is Owned, Managed {
Proxy proxy = new Proxy{salt: newsalt}(walletImplementation);
address payable wallet = address(proxy);
configureWallet(BaseWallet(wallet), _owner, _versionManager, _guardian, _version);
if (_refundAmount > 0 && _ownerSignature.length == 65) {
validateAndRefund(wallet, _owner, _refundAmount, _refundToken, _ownerSignature);
}
// remove the factory from the authorised modules
BaseWallet(wallet).authoriseModule(address(this), false);

// emit event
emit WalletCreated(wallet, _owner, _guardian, _refundToken, _refundAmount);

return wallet;
}

Expand Down Expand Up @@ -148,6 +145,16 @@ contract WalletFactory is Owned, Managed {
emit ModuleRegistryChanged(_moduleRegistry);
}

/**
* @notice Lets the owner change the refund address.
* @param _refundAddress The address to use for refunds.
*/
function changeRefundAddress(address _refundAddress) external onlyOwner {
require(_refundAddress != address(0), "WF: address cannot be null");
refundAddress = _refundAddress;
emit RefundAddressChanged(_refundAddress);
}

/**
* @notice Inits the module for a wallet by doing nothing.
* The method can only be called by the wallet itself.
Expand Down Expand Up @@ -189,12 +196,6 @@ contract WalletFactory is Owned, Managed {

// upgrade the wallet
IVersionManager(_versionManager).upgradeWallet(address(_wallet), _version);

// remove the factory from the authorised modules
_wallet.authoriseModule(address(this), false);

// emit event
emit WalletCreated(address(_wallet), _owner, _guardian);
}

/**
Expand Down Expand Up @@ -222,4 +223,68 @@ contract WalletFactory is Owned, Managed {
require(_guardian != (address(0)), "WF: guardian cannot be null");
require(_version > 0, "WF: invalid _version");
}
}

/**
* @notice Refunds the creation of the wallet when provided with a valid signature from the wallet owner.
* @param _wallet The wallet created
* @param _owner The owner address
* @param _refundAmount The amount to refund
* @param _refundToken The token to use for the refund
* @param _ownerSignature A signature from the wallet owner approving the refund amount and token.
*/
function validateAndRefund(
address _wallet,
address _owner,
uint256 _refundAmount,
address _refundToken,
bytes memory _ownerSignature
)
internal
{
bytes32 signedHash = keccak256(abi.encodePacked(
"\x19Ethereum Signed Message:\n32",
keccak256(abi.encodePacked(_refundAmount, _refundToken))
));
address signer = Utils.recoverSigner(signedHash, _ownerSignature, 0);
if (signer == _owner) {
if (_refundToken == ETH_TOKEN) {
invokeWallet(_wallet, refundAddress, _refundAmount, "");
} else {
bytes memory methodData = abi.encodeWithSignature("transfer(address,uint256)", refundAddress, _refundAmount);
bytes memory transferSuccessBytes = invokeWallet(_wallet, _refundToken, 0, methodData);
if (transferSuccessBytes.length > 0) {
require(abi.decode(transferSuccessBytes, (bool)), "WF: Refund transfer failed");
}
}
}
}

/**
* @notice Invoke the wallet to execute the refund transfer.
* @param _wallet The wallet
* @param _to The destination of the call
* @param _value The value of the call
* @param _data The data associated to the call
*/
function invokeWallet(
address _wallet,
address _to,
uint256 _value,
bytes memory _data
)
internal
returns (bytes memory _res)
{
bool success;
(success, _res) = _wallet.call(abi.encodeWithSignature("invoke(address,uint256,bytes)", _to, _value, _data));
if (success) {
(_res) = abi.decode(_res, (bytes));
} else {
// solhint-disable-next-line no-inline-assembly
assembly {
returndatacopy(0, 0, returndatasize())
revert(0, returndatasize())
}
}
}
}
2 changes: 1 addition & 1 deletion deployment/2_deploy_contracts.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ async function main() {
walletRootEns, utils.namehash(walletRootEns), newConfig.ENS.ensRegistry, ENSResolverWrapper.address);
// Deploy the Wallet Factory
const WalletFactoryWrapper = await WalletFactory.new(
ModuleRegistryWrapper.address, BaseWalletWrapper.address, GuardianStorageWrapper.address);
ModuleRegistryWrapper.address, BaseWalletWrapper.address, GuardianStorageWrapper.address, prevConfig.backend.refundCollector);

// Deploy and configure Maker Registry
const ScdMcdMigrationWrapper = await ScdMcdMigration.at(newConfig.defi.maker.migration);
Expand Down
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"test": "npx truffle test --compile-none",
"ctest": "npm run compile && npm run test",
"provision:lib:artefacts": "bash ./scripts/provision_lib_artefacts.sh",
"test:coverage": "node scripts/coverage.js && istanbul check-coverage --statements 82 --branches 78 --functions 82 --lines 82",
"test:coverage": "COVERAGE=1 node scripts/coverage.js && istanbul check-coverage --statements 82 --branches 78 --functions 82 --lines 82",
"lint:js": "eslint .",
"lint:contracts": "npx solhint contracts/**/*.sol && npx solhint contracts/**/**/*.sol",
"test:deployment": "./scripts/deploy.sh --no-compile development `seq 1 6`",
Expand Down
6 changes: 2 additions & 4 deletions scripts/configReader.js → scripts/config_reader.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Script to print environment configuration from AWS.
//
// Can be executed (from the project root as we're loading .env file from root via `dotenv`) as:
// bash ./scripts/execute_script.sh --no-compile scripts/configReader.js <network>
// bash ./scripts/execute_script.sh --no-compile scripts/config_reader.js <network>
//
// where:
// - network = [test, staging, prod]
Expand Down Expand Up @@ -40,6 +40,4 @@ async function main() {
configurator._validate();
}

main().catch((err) => {
throw err;
});
module.exports = (cb) => main().then(cb).catch(cb);
12 changes: 6 additions & 6 deletions scripts/deploy_custom_upgrader.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,20 @@ async function main() {
"0xE739e93dD617D28216dB669AcFdbFC70BF95663c",
];
const upgraderName = "0x4ef2f261_0xee7263da";

const ModuleRegistryWrapper = await ModuleRegistry.at(config.contracts.ModuleRegistry);
const MultiSigWrapper = await MultiSig.at(config.contracts.MultiSigWallet);
const multisigExecutor = new MultisigExecutor(MultiSigWrapper, deploymentAccount, config.multisig.autosign);

const UpgraderWrapper = await Upgrader.new(
modulesToRemove,
modulesToAdd,
{ gas: 1200000 }
);

await multisigExecutor.executeCall(ModuleRegistryWrapper, "registerUpgrader",
[UpgraderWrapper.address, utils.asciiToBytes32(upgraderName)]);
[UpgraderWrapper.address, utils.asciiToBytes32(upgraderName)], { gas: 500000 });

await multisigExecutor.executeCall(ModuleRegistryWrapper, "registerModule",
[UpgraderWrapper.address, utils.asciiToBytes32(upgraderName)], { gas: 500000 });
}

main().catch((err) => {
throw err;
});
module.exports = (cb) => main().then(cb).catch(cb);
4 changes: 1 addition & 3 deletions scripts/deploy_defi.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,4 @@ async function main() {
console.log("********************************");
}

main().catch((err) => {
throw err;
});
module.exports = (cb) => main().then(cb).catch(cb);
4 changes: 1 addition & 3 deletions scripts/deploy_wallet_detector.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@ async function main() {
]);
}

main().catch((err) => {
throw err;
});
module.exports = (cb) => main().then(cb).catch(cb);

// contract deployed to prod at 0xeca4B0bDBf7c55E9b7925919d03CbF8Dc82537E8
52 changes: 52 additions & 0 deletions scripts/deploy_wallet_factory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// ///////////////////////////////////////////////////////////////////
// Script to deploy a new WalletFactory contract
//
// Can be executed as:
// ./scripts/execute_script.sh --no-compile scripts/deploy_wallet_factory.js <network>
//
// where:
// - network = [development, test, staging, prod]
// ////////////////////////////////////////////////////////////////////

/* global artifacts */
global.web3 = web3;

const WalletFactory = artifacts.require("WalletFactory");

const deployManager = require("../utils/deploy-manager.js");

async function main() {
const { configurator, abiUploader } = await deployManager.getProps();
const { config } = configurator;
console.log("Config:", config);

// Deploy new WalletFactory
console.log("Deploying new WalletFactory...");
const NewWalletFactoryWrapper = await WalletFactory.new(
config.contracts.ModuleRegistry,
config.contracts.BaseWallet,
config.modules.GuardianStorage,
config.backend.refundCollector);

console.log("WalletFactory deployed at", NewWalletFactoryWrapper.address);

console.log("Setting the backend accounts as managers for the new WalletFactory...");
for (let idx = 0; idx < config.backend.accounts.length; idx += 1) {
const account = config.backend.accounts[idx];
// Set `account` as the manager of the WalletFactory
await NewWalletFactoryWrapper.addManager(account);
}

console.log("Setting the multisig as the owner of the new WalletFactory...");
await NewWalletFactoryWrapper.changeOwner(config.contracts.MultiSigWallet);

console.log("Saving new config...");
configurator.updateInfrastructureAddresses({ WalletFactory: NewWalletFactoryWrapper.address });
await configurator.save();

await abiUploader.upload(NewWalletFactoryWrapper, "contracts");

console.log("WalletFactory Update DONE.");
}

module.exports = (cb) => main().then(cb).catch(cb);
2 changes: 1 addition & 1 deletion scripts/execute_script.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ fi
NETWORK=$1
shift

AWS_PROFILE=argent-$NETWORK AWS_SDK_LOAD_CONFIG=true node $FILE --network $NETWORK "$@"
AWS_PROFILE=argent-$NETWORK AWS_SDK_LOAD_CONFIG=true npx truffle exec $FILE --network $NETWORK "$@"
Loading

0 comments on commit 56a5aa0

Please sign in to comment.