Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/upgrade oz libraries #107

Open
wants to merge 2 commits into
base: feat/integrate_email_auth
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,12 @@ mdbook serve
<br />

☆ Built using [zk-email](https://github.com/zkemail/zk-email-verify) ☆

NOTE:

If you get an error with `yarn install`, try to install python-setuptools

```
# For macOS
brew install python-setuptools
```
8 changes: 4 additions & 4 deletions packages/contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
"lint": "solhint 'src/**/*.sol'"
},
"dependencies": {
"@openzeppelin/contracts": "^4.9.2",
"@openzeppelin/contracts-upgradeable": "^4.9.2",
"@openzeppelin/contracts": "^5.0.0",
"@openzeppelin/contracts-upgradeable": "^5.0.0",
"@safe-global/safe-contracts": "1.4.1",
"@uniswap/v3-core": "https://github.com/Uniswap/v3-core#0.8",
"@uniswap/v3-periphery": "https://github.com/Uniswap/v3-periphery.git",
"@zk-email/contracts": "^4.1.0",
"accountabstraction": "eth-infinitism/account-abstraction#v0.6.0",
"@zk-email/contracts": "^6.1.5",
"accountabstraction": "eth-infinitism/account-abstraction#v0.7.0",
"solady": "^0.0.123",
"solidity-stringutils": "https://github.com/Arachnid/solidity-stringutils.git"
},
Expand Down
1 change: 1 addition & 0 deletions packages/contracts/remappings.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@openzeppelin/=../../node_modules/@openzeppelin
@openzeppelin/contracts-upgradeable/=../../node_modules/@openzeppelin/contracts-upgradeable
@zk-email/=../../node_modules/@zk-email
@uniswap/=../../node_modules/@uniswap
forge-std/=../../node_modules/forge-std/src
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts/script/03_DeployDKIMRegistry.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ contract Deploy is Script {
}

vm.startBroadcast(deployerPrivateKey);
DKIMRegistry dkim = new DKIMRegistry();
DKIMRegistry dkim = new DKIMRegistry(msg.sender);
vm.stopBroadcast();

console.log("DKIMRegistry deployed at: %s", address(dkim));
Expand Down
6 changes: 1 addition & 5 deletions packages/contracts/script/MintTestNFT.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import "forge-std/Script.sol";
contract MyToken is ERC721, ERC721URIStorage, ERC721Burnable, Ownable {
constructor()
ERC721("MyToken", "MTK")
Ownable()
Ownable(msg.sender)
{}

function safeMint(address to, uint256 tokenId, string memory uri)
Expand Down Expand Up @@ -37,10 +37,6 @@ contract MyToken is ERC721, ERC721URIStorage, ERC721Burnable, Ownable {
{
return super.supportsInterface(interfaceId);
}

function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
super._burn(tokenId);
}
}

contract Deploy is Script {
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts/script/UpgradeCore.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ contract Upgrade is Script {
EmailWalletCore coreImpl = new EmailWalletCore();

EmailWalletCore coreProxy = EmailWalletCore(payable(core));
coreProxy.upgradeTo(address(coreImpl));
coreProxy.upgradeToAndCall(address(coreImpl), new bytes(0));

// If you want to call some v2 function, refer to the following steps
//
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts/script/UpgradeTokenRegistry.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ contract Upgrade is Script {
TokenRegistry tokenRegistryImpl = new TokenRegistry();

TokenRegistry tokenRegistryProxy = TokenRegistry(payable(address(tokenRegistry)));
tokenRegistryProxy.upgradeTo(address(tokenRegistryImpl));
tokenRegistryProxy.upgradeToAndCall(address(tokenRegistryImpl), new bytes(0));

// If you want to call some v2 function, refer to the following steps
//
Expand Down
106 changes: 63 additions & 43 deletions packages/contracts/src/EmailWalletCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Ini
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {Create2Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/Create2Upgradeable.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {IERC20, ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
Expand All @@ -27,6 +26,35 @@ import "./interfaces/Types.sol";
import "./interfaces/Commands.sol";
import "./interfaces/Events.sol";

/// @notice Struct to store initialization parameters
/// @dev This struct is used to initialize the EmailWalletCore contract
/// @param _relayerHandler Address of the relayer handler contract
/// @param _accountHandler Address of the account handler contract
/// @param _unclaimsHandler Address of the unclaims handler contract
/// @param _extensionHandler Address of the extension handler contract
/// @param _verifier Address of the ZK proof verifier
/// @param _tokenRegistry Address of the token registry contract
/// @param _priceOracle Address of the price oracle contract
/// @param _wethContract Address of the WETH contract
/// @param _maxFeePerGas Max fee per gas in wei that relayer can set in a UserOp
/// @param _emailValidityDuration Time period until which a email is valid for EmailOp based on the timestamp of the email signature
/// @param _unclaimedFundClaimGas Gas required to claim unclaimed funds
/// @param _unclaimedStateClaimGas Gas required to claim unclaimed state

struct InitParams {
address relayerHandler;
address accountHandler;
address unclaimsHandler;
address extensionHandler;
address verifier;
address tokenRegistry;
address priceOracle;
address wethContract;
uint256 maxFeePerGas;
uint256 emailValidityDuration;
uint256 unclaimedFundClaimGas;
uint256 unclaimedStateClaimGas;
}
contract EmailWalletCore is Initializable, UUPSUpgradeable, OwnableUpgradeable {
using SafeERC20 for IERC20;
// ZK proof verifier
Expand Down Expand Up @@ -77,45 +105,24 @@ contract EmailWalletCore is Initializable, UUPSUpgradeable, OwnableUpgradeable {
}

/// @notice Constructor
/// @param _relayerHandler Address of the relayer handler contract
/// @param _accountHandler Address of the account handler contract
/// @param _unclaimsHandler Address of the unclaims handler contract
/// @param _extensionHandler Address of the extension handler contract
/// @param _verifier Address of the ZK proof verifier
/// @param _tokenRegistry Address of the token registry contract
/// @param _priceOracle Address of the price oracle contract
/// @param _wethContract Address of the WETH contract
/// @param _maxFeePerGas Max fee per gas in wei that relayer can set in a UserOp
/// @param _emailValidityDuration Time period until which a email is valid for EmailOp based on the timestamp of the email signature
/// @param _unclaimedFundClaimGas Gas required to claim unclaimed funds
/// @param _unclaimedStateClaimGas Gas required to claim unclaimed state
/// @param initParams Initialization parameters
/// @dev This function is called by the proxy contract during deployment
function initialize(
address _relayerHandler,
address _accountHandler,
address _unclaimsHandler,
address _extensionHandler,
address _verifier,
address _tokenRegistry,
address _priceOracle,
address _wethContract,
uint256 _maxFeePerGas,
uint256 _emailValidityDuration,
uint256 _unclaimedFundClaimGas,
uint256 _unclaimedStateClaimGas
InitParams memory initParams
) public initializer {
__Ownable_init();
relayerHandler = RelayerHandler(_relayerHandler);
accountHandler = AccountHandler(_accountHandler);
unclaimsHandler = UnclaimsHandler(payable(_unclaimsHandler));
extensionHandler = ExtensionHandler(_extensionHandler);
verifier = IVerifier(_verifier);
tokenRegistry = TokenRegistry(_tokenRegistry);
priceOracle = IPriceOracle(_priceOracle);
wethContract = _wethContract;
maxFeePerGas = _maxFeePerGas;
emailValidityDuration = _emailValidityDuration;
unclaimedFundClaimGas = _unclaimedFundClaimGas;
unclaimedStateClaimGas = _unclaimedStateClaimGas;
__Ownable_init(msg.sender);
relayerHandler = RelayerHandler(initParams.relayerHandler);
accountHandler = AccountHandler(initParams.accountHandler);
unclaimsHandler = UnclaimsHandler(payable(initParams.unclaimsHandler));
extensionHandler = ExtensionHandler(initParams.extensionHandler);
verifier = IVerifier(initParams.verifier);
tokenRegistry = TokenRegistry(initParams.tokenRegistry);
priceOracle = IPriceOracle(initParams.priceOracle);
wethContract = initParams.wethContract;
maxFeePerGas = initParams.maxFeePerGas;
emailValidityDuration = initParams.emailValidityDuration;
unclaimedFundClaimGas = initParams.unclaimedFundClaimGas;
unclaimedStateClaimGas = initParams.unclaimedStateClaimGas;
}

function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
Expand Down Expand Up @@ -374,7 +381,7 @@ contract EmailWalletCore is Initializable, UUPSUpgradeable, OwnableUpgradeable {

// Prevent extension from calling ERC20 tokens directly (tokenName should be empty)
require(
Address.isContract(target) &&
address(target).code.length > 0 &&
target != currContext.walletAddr &&
bytes(tokenRegistry.getTokenNameOfAddress(target)).length == 0,
"invalid target for executeAsExtension"
Expand Down Expand Up @@ -547,9 +554,15 @@ contract EmailWalletCore is Initializable, UUPSUpgradeable, OwnableUpgradeable {
} catch Error(string memory reason) {
success = false;
returnData = bytes(reason);
} catch {
success = false;
returnData = bytes("err executing extension");
} catch (bytes memory lowLevelData) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SoraSuegami
With the use of contract in v5, return data is now Custom Error, so I am unable to get the reason and have a selector as shown below. I would like to discuss the implementation policy, whether to implement all types of errrors or ignore the reason strings.

bytes4 selector;
assembly {
selector := mload(add(lowLevelData, 0x20))
}
if (selector == bytes4(keccak256("ERC721NonexistentToken(uint256)"))) {
return (false, bytes("ERC721NonexistentToken"));
}
return (false, bytes("err executing extension"));
}
}
}
Expand All @@ -576,7 +589,14 @@ contract EmailWalletCore is Initializable, UUPSUpgradeable, OwnableUpgradeable {
success = true;
} catch Error(string memory reason) {
return (false, bytes(reason));
} catch {
} catch (bytes memory lowLevelData) {
bytes4 selector;
assembly {
selector := mload(add(lowLevelData, 0x20))
}
if (selector == bytes4(keccak256("ERC20InsufficientBalance(address,uint256,uint256)"))) {
return (false, bytes("ERC20InsufficientBalance"));
}
return (false, bytes("err unknown wallet exec"));
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts/src/Wallet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ contract Wallet is TokenCallbackHandler, OwnableUpgradeable, UUPSUpgradeable {

/// @notice Initialize the contract
function initialize() public initializer {
__Ownable_init();
__Ownable_init(msg.sender);
}

/// @notice Execute a function on an external contract
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts/src/extensions/NFTExtension.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ contract NFTExtension is Extension, IERC721Receiver, Initializable, UUPSUpgradea
}

function initialize(address coreAddr) initializer public {
__Ownable_init();
__Ownable_init(msg.sender);
core = EmailWalletCore(payable(coreAddr));
templates = new string[][](2);
templates[0] = ["NFT", "Send", "{uint}", "of", "{string}", "to", "{recipient}"];
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts/src/extensions/Safe2FAExtension.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ contract Safe2FAExtension is Extension, Initializable, UUPSUpgradeable, OwnableU
}

function initialize(address coreAddr) public initializer {
__Ownable_init();
__Ownable_init(msg.sender);
core = EmailWalletCore(payable(coreAddr));
templates = new string[][](4);
templates[0] = ["Safe", "Transaction:", "Approve", "{string}", "from", "{address}"];
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts/src/extensions/UniswapExtension.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ contract UniswapExtension is Extension, Initializable, UUPSUpgradeable, OwnableU
}

function initialize(address coreAddr, address _tokenReg, address _router, address _factory) initializer public {
__Ownable_init();
__Ownable_init(msg.sender);
core = EmailWalletCore(payable(coreAddr));
tokenRegistry = TokenRegistry(_tokenReg);
router = ISwapRouter(_router);
Expand Down
10 changes: 5 additions & 5 deletions packages/contracts/src/handlers/AccountHandler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeab
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {IDKIMRegistry} from "@zk-email/contracts/interfaces/IDKIMRegistry.sol";
import {Create2Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/Create2Upgradeable.sol";
import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import {Wallet} from "../Wallet.sol";
import {RelayerHandler} from "./RelayerHandler.sol";
Expand Down Expand Up @@ -58,7 +58,7 @@ contract AccountHandler is Initializable, UUPSUpgradeable, OwnableUpgradeable {
address _walletImplementation,
uint _emailValidityDuration
) public initializer {
__Ownable_init();
__Ownable_init(msg.sender);
deployer = _msgSender();
emailValidityDuration = _emailValidityDuration;
defaultDkimRegistry = IDKIMRegistry(_defaultDkimRegistry);
Expand All @@ -85,7 +85,7 @@ contract AccountHandler is Initializable, UUPSUpgradeable, OwnableUpgradeable {
/// @param emailProof Proof and instances of the email proof
function createAccount(EmailProof calldata emailProof) public returns (Wallet wallet) {
require(emailProof.accountSalt != bytes32(0), "invalid wallet salt");
require(Address.isContract(getWalletOfSalt(emailProof.accountSalt)) == false, "wallet already deployed");
require(address(getWalletOfSalt(emailProof.accountSalt)).code.length == 0, "wallet already deployed");
require(emailNullifiers[emailProof.emailNullifier] == false, "email already nullified");
require(
isDKIMPublicKeyHashValid(emailProof.accountSalt, emailProof.emailDomain, emailProof.dkimPublicKeyHash),
Expand All @@ -111,7 +111,7 @@ contract AccountHandler is Initializable, UUPSUpgradeable, OwnableUpgradeable {
/// @notice Return true iff the wallet is deployed for the given wallet salt
/// @param accountSalt Salt used to deploy the wallet
function isAccountSaltDeployed(bytes32 accountSalt) public view returns (bool) {
return Address.isContract(getWalletOfSalt(accountSalt));
return address(getWalletOfSalt(accountSalt)).code.length > 0;
}

/// @notice Return the DKIM public key hash for a given email domain and accountSalt
Expand Down Expand Up @@ -142,7 +142,7 @@ contract AccountHandler is Initializable, UUPSUpgradeable, OwnableUpgradeable {
/// @param salt Salt used to deploy the wallet
function getWalletOfSalt(bytes32 salt) public view returns (address) {
return
Create2Upgradeable.computeAddress(
Create2.computeAddress(
salt,
keccak256(
abi.encodePacked(
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts/src/handlers/ExtensionHandler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ contract ExtensionHandler is Initializable, UUPSUpgradeable, OwnableUpgradeable
}

function initialize() initializer public {
__Ownable_init();
__Ownable_init(msg.sender);
deployer = _msgSender();
}

Expand Down
2 changes: 1 addition & 1 deletion packages/contracts/src/handlers/RelayerHandler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ contract RelayerHandler is Initializable, UUPSUpgradeable, OwnableUpgradeable {
}

function initialize() initializer public {
__Ownable_init();
__Ownable_init(msg.sender);
deployer = _msgSender();
}

Expand Down
15 changes: 12 additions & 3 deletions packages/contracts/src/handlers/UnclaimsHandler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity ^0.8.12;
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../interfaces/Types.sol";
Expand Down Expand Up @@ -76,7 +76,7 @@ contract UnclaimsHandler is ReentrancyGuard, Initializable, UUPSUpgradeable, Own
uint256 _unclaimsExpiryDuration,
uint256 _maxFeePerGas
) public initializer {
__Ownable_init();
__Ownable_init(msg.sender);
deployer = _msgSender();
relayerHandler = RelayerHandler(_relayerHandler);
accountHandler = AccountHandler(_accountHandler);
Expand Down Expand Up @@ -294,7 +294,16 @@ contract UnclaimsHandler is ReentrancyGuard, Initializable, UUPSUpgradeable, Own

try extension.registerUnclaimedState(us, false) {} catch Error(string memory reason) {
revert(string.concat("unclaimed state reg err: ", reason));
} catch {
} catch (bytes memory lowLevelData) {
// Handle specific ERC721NonexistentToken error
bytes4 selector;
assembly {
selector := mload(add(lowLevelData, 0x20))
}
if (selector == bytes4(keccak256("ERC721NonexistentToken(uint256)"))) {
revert(string(abi.encodePacked("unclaimed state reg err: ERC721NonexistentToken()")));
}
// Handle other low-level errors
revert("unclaimed state reg err");
}

Expand Down
2 changes: 1 addition & 1 deletion packages/contracts/src/libraries/StringUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ library StringUtils {
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return Strings.toString(value);
return Strings.toStringSigned(value);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/contracts/src/libraries/SubjectUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ library SubjectUtils {
(address target, , bytes memory data) = abi.decode(emailOp.executeCallData, (address, uint256, bytes));

require(target != address(0), "invalid execute target");
require(Address.isContract(target), "target is not a contract");
require(address(target).code.length > 0, "target is not a contract");

require(
target != address(core) &&
Expand Down Expand Up @@ -249,7 +249,7 @@ library SubjectUtils {
// {int} for negative values
else if (Strings.equal(matcher, Commands.INT_TEMPLATE)) {
int256 num = abi.decode(emailOp.extensionParams.subjectParams[nextParamIndex], (int256));
value = Strings.toString(num);
value = Strings.toStringSigned(num);
nextParamIndex++;
}
// {addres} for wallet address
Expand Down
Loading
Loading