Skip to content

Instantly share code, notes, and snippets.

@nambrot
Last active October 19, 2020 18:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nambrot/816fb1cfd71fc3df45844889d37a2d8e to your computer and use it in GitHub Desktop.
Save nambrot/816fb1cfd71fc3df45844889d37a2d8e to your computer and use it in GitHub Desktop.
diff --git a/packages/protocol/contracts/common/FixidityLib.sol b/packages/protocol/contracts/common/FixidityLib.sol
index e5ad4d1b4..15fd8f08f 100644
--- a/packages/protocol/contracts/common/FixidityLib.sol
+++ b/packages/protocol/contracts/common/FixidityLib.sol
@@ -19,6 +19,14 @@ library FixidityLib {
uint256 value;
}
+ /**
+ * @notice Returns the storage, major, minor, and patch version of the contract.
+ * @return The storage, major, minor, and patch version of the contract.
+ */
+ function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256) {
+ return (1, 1, 1, 0);
+ }
+
/**
* @notice Number of positions that the comma is shifted to the right.
*/
diff --git a/packages/protocol/contracts/common/MetaTransactionWallet.sol b/packages/protocol/contracts/common/MetaTransactionWallet.sol
index 9de5fddc3..e3c5f96ba 100644
--- a/packages/protocol/contracts/common/MetaTransactionWallet.sol
+++ b/packages/protocol/contracts/common/MetaTransactionWallet.sol
@@ -56,7 +56,7 @@ contract MetaTransactionWallet is
* @return The storage, major, minor, and patch version of the contract.
*/
function getVersionNumber() public pure returns (uint256, uint256, uint256, uint256) {
- return (1, 1, 0, 0);
+ return (1, 1, 0, 1);
}
/**
@@ -64,6 +64,7 @@ contract MetaTransactionWallet is
* @param _signer The address authorized to execute transactions via this wallet.
*/
function initialize(address _signer) external initializer {
+ _transferOwnership(msg.sender);
setSigner(_signer);
setEip712DomainSeparator();
// MetaTransactionWallet owns itself, which necessitates that all onlyOwner functions
@@ -108,6 +109,32 @@ contract MetaTransactionWallet is
emit EIP712DomainSeparatorSet(eip712DomainSeparator);
}
+ /**
+ * @notice Returns the struct hash of the MetaTransaction
+ * @param destination The address to which the meta-transaction is to be sent.
+ * @param value The CELO value to be sent with the meta-transaction.
+ * @param data The data to be sent with the meta-transaction.
+ * @param _nonce The nonce for this meta-transaction local to this wallet.
+ * @return The digest of the provided meta-transaction.
+ */
+ function _getMetaTransactionStructHash(
+ address destination,
+ uint256 value,
+ bytes memory data,
+ uint256 _nonce
+ ) internal view returns (bytes32) {
+ return
+ keccak256(
+ abi.encode(
+ EIP712_EXECUTE_META_TRANSACTION_TYPEHASH,
+ destination,
+ value,
+ keccak256(data),
+ _nonce
+ )
+ );
+ }
+
/**
* @notice Returns the digest of the provided meta-transaction, to be signed by `sender`.
* @param destination The address to which the meta-transaction is to be sent.
@@ -122,16 +149,8 @@ contract MetaTransactionWallet is
bytes memory data,
uint256 _nonce
) public view returns (bytes32) {
- bytes32 structHash = keccak256(
- abi.encode(
- EIP712_EXECUTE_META_TRANSACTION_TYPEHASH,
- destination,
- value,
- keccak256(data),
- _nonce
- )
- );
- return keccak256(abi.encodePacked("\x19\x01", eip712DomainSeparator, structHash));
+ bytes32 structHash = _getMetaTransactionStructHash(destination, value, data, _nonce);
+ return Signatures.toEthSignedTypedDataHash(eip712DomainSeparator, structHash);
}
/**
@@ -154,8 +173,8 @@ contract MetaTransactionWallet is
bytes32 r,
bytes32 s
) public view returns (address) {
- bytes32 digest = getMetaTransactionDigest(destination, value, data, _nonce);
- return Signatures.getSignerOfMessageHash(digest, v, r, s);
+ bytes32 structHash = _getMetaTransactionStructHash(destination, value, data, _nonce);
+ return Signatures.getSignerOfTypedDataHash(eip712DomainSeparator, structHash, v, r, s);
}
/**
diff --git a/packages/protocol/contracts/common/MetaTransactionWalletDeployer.sol b/packages/protocol/contracts/common/MetaTransactionWalletDeployer.sol
new file mode 100644
index 000000000..0f1dd510d
--- /dev/null
+++ b/packages/protocol/contracts/common/MetaTransactionWalletDeployer.sol
@@ -0,0 +1,99 @@
+pragma solidity ^0.5.13;
+import "openzeppelin-solidity/contracts/math/SafeMath.sol";
+import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
+import "solidity-bytes-utils/contracts/BytesLib.sol";
+
+import "./interfaces/ICeloVersionedContract.sol";
+import "./interfaces/IMetaTransactionWalletDeployer.sol";
+import "./proxies/MetaTransactionWalletProxy.sol";
+import "./ExternalCall.sol";
+import "./Initializable.sol";
+import "./MetaTransactionWallet.sol";
+
+contract MetaTransactionWalletDeployer is
+ IMetaTransactionWalletDeployer,
+ ICeloVersionedContract,
+ Initializable,
+ Ownable
+{
+ using SafeMath for uint256;
+ using BytesLib for bytes;
+
+ mapping(address => address) public wallets;
+ mapping(address => bool) public canDeploy;
+
+ event WalletDeployed(address indexed owner, address indexed wallet, address implementation);
+ event DeployerStatusGranted(address indexed addr);
+ event DeployerStatusRevoked(address indexed addr);
+
+ /**
+ * @dev Verifies that the sender is allowed to deploy a wallet
+ */
+ modifier onlyCanDeploy() {
+ require(msg.sender == owner() || canDeploy[msg.sender], "sender not allowed to deploy wallet");
+ _;
+ }
+
+ /**
+ * @notice Returns the storage, major, minor, and patch version of the contract.
+ * @return The storage, major, minor, and patch version of the contract.
+ */
+ function getVersionNumber() public pure returns (uint256, uint256, uint256, uint256) {
+ return (1, 1, 0, 0);
+ }
+
+ /**
+ * @notice Used in place of the constructor to allow the contract to be upgradable via proxy.
+ * @param initialDeployers a list of addresses that are allowed to deploy wallets
+ */
+ function initialize(address[] calldata initialDeployers) external initializer {
+ _transferOwnership(msg.sender);
+ for (uint256 i = 0; i < initialDeployers.length; i++) {
+ _changeDeployerPermission(initialDeployers[i], true);
+ }
+ }
+
+ /**
+ * @notice Change the permission of an address to deploy
+ * @param target The address to be allowed as a deployer
+ * @param allowedToDeploy toggle whether the address is allowed or not
+ */
+ function changeDeployerPermission(address target, bool allowedToDeploy) external onlyOwner {
+ _changeDeployerPermission(target, allowedToDeploy);
+ }
+
+ /**
+ * @notice Implementation of permission change
+ * @param target The address to be allowed as a deployer
+ * @param allowedToDeploy toggle whether the address is allowed or not
+ */
+ function _changeDeployerPermission(address target, bool allowedToDeploy) internal {
+ canDeploy[target] = allowedToDeploy;
+ if (allowedToDeploy) {
+ emit DeployerStatusGranted(target);
+ } else {
+ emit DeployerStatusRevoked(target);
+ }
+ }
+
+ /**
+ * @notice Used to deploy a MetaTransactionWalletProxy, set the implementation,
+ * initialize, transfer ownership and emit an event.
+ * @param owner The external account which will act as signer and owner of the proxy
+ * @param implementation The address of the implementation which the proxy will point to
+ * @param initCallData calldata pointing to a method on implementation used to initialize
+ */
+ function deploy(address owner, address implementation, bytes calldata initCallData)
+ external
+ onlyCanDeploy
+ {
+ require(wallets[owner] == address(0), "wallet already deployed");
+
+ MetaTransactionWalletProxy proxy = new MetaTransactionWalletProxy();
+ proxy._setAndInitializeImplementation(implementation, initCallData);
+ proxy._transferOwnership(owner);
+ wallets[owner] = address(proxy);
+
+ emit WalletDeployed(owner, address(proxy), implementation);
+ }
+}
diff --git a/packages/protocol/contracts/common/Signatures.sol b/packages/protocol/contracts/common/Signatures.sol
index 8a57aaa11..16dec10c5 100644
--- a/packages/protocol/contracts/common/Signatures.sol
+++ b/packages/protocol/contracts/common/Signatures.sol
@@ -8,7 +8,7 @@ library Signatures {
* @return The storage, major, minor, and patch version of the contract.
*/
function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256) {
- return (1, 1, 1, 0);
+ return (1, 1, 2, 0);
}
/**
@@ -49,4 +49,44 @@ library Signatures {
bytes32 prefixedHash = ECDSA.toEthSignedMessageHash(messageHash);
return ECDSA.recover(prefixedHash, signature);
}
+
+ /**
+ * @notice Given a domain separator and a structHash, construct the typed data hash
+ * @param eip712DomainSeparator Context specific domain separator
+ * @param structHash hash of the typed data struct
+ * @return The EIP712 typed data hash
+ */
+ function toEthSignedTypedDataHash(bytes32 eip712DomainSeparator, bytes32 structHash)
+ public
+ pure
+ returns (bytes32)
+ {
+ return keccak256(abi.encodePacked("\x19\x01", eip712DomainSeparator, structHash));
+ }
+
+ /**
+ * @notice Given a domain separator and a structHash and a signature return the signer
+ * @param eip712DomainSeparator Context specific domain separator
+ * @param structHash hash of the typed data struct
+ * @param v The recovery id of the incoming ECDSA signature.
+ * @param r Output value r of the ECDSA signature.
+ * @param s Output value s of the ECDSA signature.
+ */
+ function getSignerOfTypedDataHash(
+ bytes32 eip712DomainSeparator,
+ bytes32 structHash,
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ ) public pure returns (address) {
+ bytes memory signature = new bytes(65);
+ // Concatenate (r, s, v) into signature.
+ assembly {
+ mstore(add(signature, 32), r)
+ mstore(add(signature, 64), s)
+ mstore8(add(signature, 96), v)
+ }
+ bytes32 prefixedHash = toEthSignedTypedDataHash(eip712DomainSeparator, structHash);
+ return ECDSA.recover(prefixedHash, signature);
+ }
}
diff --git a/packages/protocol/contracts/common/interfaces/IMetaTransactionWalletDeployer.sol b/packages/protocol/contracts/common/interfaces/IMetaTransactionWalletDeployer.sol
new file mode 100644
index 000000000..58e9abbd9
--- /dev/null
+++ b/packages/protocol/contracts/common/interfaces/IMetaTransactionWalletDeployer.sol
@@ -0,0 +1,8 @@
+pragma solidity ^0.5.3;
+
+interface IMetaTransactionWalletDeployer {
+ function deploy(address, address, bytes calldata) external;
+ function changeDeployerPermission(address, bool) external;
+ function canDeploy(address) external view returns (bool);
+ function wallets(address) external view returns (address);
+}
diff --git a/packages/protocol/contracts/common/proxies/FixidityLibProxy.sol b/packages/protocol/contracts/common/proxies/FixidityLibProxy.sol
new file mode 100644
index 000000000..41424ca89
--- /dev/null
+++ b/packages/protocol/contracts/common/proxies/FixidityLibProxy.sol
@@ -0,0 +1,6 @@
+pragma solidity ^0.5.3;
+
+import "../Proxy.sol";
+
+/* solhint-disable no-empty-blocks */
+contract FixidityLibProxy is Proxy {}
diff --git a/packages/protocol/contracts/common/proxies/MetaTransactionWalletDeployerProxy.sol b/packages/protocol/contracts/common/proxies/MetaTransactionWalletDeployerProxy.sol
new file mode 100644
index 000000000..b6564ffff
--- /dev/null
+++ b/packages/protocol/contracts/common/proxies/MetaTransactionWalletDeployerProxy.sol
@@ -0,0 +1,6 @@
+pragma solidity ^0.5.3;
+
+import "../Proxy.sol";
+
+/* solhint-disable no-empty-blocks */
+contract MetaTransactionWalletDeployerProxy is Proxy {}
diff --git a/packages/protocol/contracts/common/proxies/MetaTransactionWalletProxy.sol b/packages/protocol/contracts/common/proxies/MetaTransactionWalletProxy.sol
new file mode 100644
index 000000000..dc7ba7a4e
--- /dev/null
+++ b/packages/protocol/contracts/common/proxies/MetaTransactionWalletProxy.sol
@@ -0,0 +1,6 @@
+pragma solidity ^0.5.3;
+
+import "../Proxy.sol";
+
+/* solhint-disable no-empty-blocks */
+contract MetaTransactionWalletProxy is Proxy {}
diff --git a/packages/protocol/contracts/stability/Exchange.sol b/packages/protocol/contracts/stability/Exchange.sol
index de3b0addc..0b80bcd00 100644
--- a/packages/protocol/contracts/stability/Exchange.sol
+++ b/packages/protocol/contracts/stability/Exchange.sol
@@ -294,10 +294,10 @@ contract Exchange is
}
/**
- * @notice Returns the sell token and buy token bucket sizes, in order. The ratio of
+ * @notice Returns the buy token and sell token bucket sizes, in order. The ratio of
* the two also represents the exchange rate between the two.
* @param sellGold `true` if gold is the sell token.
- * @return (sellTokenBucket, buyTokenBucket)
+ * @return (buyTokenBucket, sellTokenBucket)
*/
function _getBuyAndSellBuckets(bool sellGold) private view returns (uint256, uint256) {
if (sellGold) {
@nambrot
Copy link
Author

nambrot commented Oct 19, 2020

Ran git diff celo-core-contracts-v1.rc1 packages/protocol/contracts from celo-core-contracts-v2.pre-audit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment