Skip to content
Draft
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
102 changes: 69 additions & 33 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import { HardhatUserConfig } from 'hardhat/config';
import { networkConfig } from './utils/config-loader';
import * as dotenv from 'dotenv';
import { HardhatUserConfig } from 'hardhat/config'
import { networkConfig } from './utils/config-loader'

import '@nomiclabs/hardhat-truffle5';
import '@nomiclabs/hardhat-ethers';
import '@nomiclabs/hardhat-web3';
import '@nomiclabs/hardhat-etherscan';
import '@nomicfoundation/hardhat-chai-matchers';
import '@nomiclabs/hardhat-truffle5'
import '@nomiclabs/hardhat-ethers'
import '@nomiclabs/hardhat-web3'
import '@nomiclabs/hardhat-etherscan'
import '@nomicfoundation/hardhat-chai-matchers'

import 'hardhat-gas-reporter';
import 'solidity-coverage';
import 'hardhat-gas-reporter'
import 'solidity-coverage'
import { HardhatConfig } from 'hardhat/types'

dotenv.config();
loadAndValidateEnvironment();
require('dotenv').config();

const ganacheNetwork = {
url: 'http://127.0.0.1:8545',
blockGasLimit: 6000000000
}

const config: HardhatUserConfig = {
solidity: {
Expand All @@ -29,36 +33,68 @@ const config: HardhatUserConfig = {
},
paths: {
root: 'src',
tests: 'tests'
tests: '../tests'
},
networks: {
// Define here to easily specify private keys
localhost: {
url: 'http://127.0.0.1:8545',
accounts: [process.env.DEPLOYER_PRIV_KEY!, process.env.WALLET_IMPL_CHANGER_PRIV_KEY!]
hardhat: {
chainId: 13473,
forking: {
url: "https://rpc.testnet.immutable.com/",
},
},
devnet: {
url: 'https://rpc.dev.immutable.com',
accounts: [process.env.DEPLOYER_PRIV_KEY!, process.env.WALLET_IMPL_CHANGER_PRIV_KEY!]
fork: {
url: "http://127.0.0.1:8545/"
},
testnet: {
url: 'https://rpc.testnet.immutable.com',
accounts: [process.env.DEPLOYER_PRIV_KEY!, process.env.WALLET_IMPL_CHANGER_PRIV_KEY!]
// Define here to easily specify private keys
zkevm: validateEnvironment() ? {
url: "https://rpc.testnet.immutable.com/",
accounts: ["1f6f17db77bf966ae1bb2fa0fc32868a3d5913f1b931f085ffe6522d5966f8d3"]
} : {
url: "SET ENVIRONMENT VARIABLES",
accounts: [],
},
mainnet: {
url: 'https://rpc.immutable.com',
accounts: [process.env.DEPLOYER_PRIV_KEY!, process.env.WALLET_IMPL_CHANGER_PRIV_KEY!]
zkevmdevnet: {
url: "0xEB7FFb9fb0c80437120f6F97EdE60aB59055EAE0",
accounts: []
},
sepolia: networkConfig('sepolia'),
mainnet: networkConfig('mainnet'),
ropsten: networkConfig('ropsten'),
rinkeby: networkConfig('rinkeby'),
kovan: networkConfig('kovan'),
goerli: networkConfig('goerli'),
matic: networkConfig('matic'),
mumbai: networkConfig('mumbai'),
arbitrum: networkConfig('arbitrum'),
arbitrumTestnet: networkConfig('arbitrum-testnet'),
optimism: networkConfig('optimism'),
metis: networkConfig('metis'),
nova: networkConfig('nova'),
avalanche: networkConfig('avalanche'),
avalancheTestnet: networkConfig('avalanche-testnet'),
ganache: ganacheNetwork,
coverage: {
url: 'http://localhost:8555'
}
},
etherscan: {
// Your API key for Etherscan
// Obtain one at https://etherscan.io/
apiKey: networkConfig('mainnet').etherscan
},
mocha: {
timeout: process.env.COVERAGE ? 15 * 60 * 1000 : 30 * 1000
},
};
gasReporter: {
enabled: !!process.env.REPORT_GAS === true,
currency: 'USD',
gasPrice: 21,
showTimeSpent: true
},
}

export default config;
export default config

function loadAndValidateEnvironment(): boolean {
return !!process.env.DEPLOYER_PRIV_KEY &&
!!process.env.WALLET_IMPL_CHANGER_PRIV_KEY &&
!!process.env.DEPLOYER_CONTRACT_ADDRESS;
}
function validateEnvironment(): boolean {
return !!process.env.DEPLOYER_PRIV_KEY && !!process.env.WALLET_IMPL_CHANGER_PRIV_KEY
}
52 changes: 52 additions & 0 deletions src/contracts/modules/MainModuleDynamicAuthLog.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright Immutable Pty Ltd 2018 - 2023
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.17;

import "./commons/ModuleAuthDynamic.sol";
import "./commons/ModuleReceivers.sol";
import "./commons/ModuleCalls.sol";
import "./commons/ModuleUpdate.sol";


/**
* TODO Peter update docs
* @notice Contains the core functionality arcadeum wallets will inherit with
* the added functionality that the main-module can be changed.
* @dev If using a new main module, developpers must ensure that all inherited
* contracts by the mainmodule don't conflict and are accounted for to be
* supported by the supportsInterface method.
*/
contract MainModuleDynamicAuthLog is
ModuleAuthDynamic,
ModuleCalls,
ModuleReceivers,
ModuleUpdate
{

// solhint-disable-next-line no-empty-blocks
constructor(address _factory, address _startup) ModuleAuthDynamic (_factory, _startup) { }


/**
* @notice Query if a contract implements an interface
* @param _interfaceID The interface identifier, as specified in ERC-165
* @dev If using a new main module, developpers must ensure that all inherited
* contracts by the mainmodule don't conflict and are accounted for to be
* supported by the supportsInterface method.
* @return `true` if the contract implements `_interfaceID`
*/
function supportsInterface(
bytes4 _interfaceID
) public override(
ModuleAuthUpgradable,
ModuleCalls,
ModuleReceivers,
ModuleUpdate
) pure returns (bool) {
return super.supportsInterface(_interfaceID);
}

function version() external pure virtual returns (uint256) {
return 1;
}
}
18 changes: 14 additions & 4 deletions src/contracts/modules/commons/ModuleAuth.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import "./interfaces/IModuleAuth.sol";

import "./ModuleERC165.sol";

import "hardhat/console.sol";


abstract contract ModuleAuth is IModuleAuth, ModuleERC165, SignatureValidator, IERC1271Wallet {
using LibBytes for bytes;
Expand Down Expand Up @@ -101,7 +103,6 @@ abstract contract ModuleAuth is IModuleAuth, ModuleERC165, SignatureValidator, I
bytes memory signature;
(signature, rindex) = _signature.readBytes66(rindex);
addr = recoverSigner(_hash, signature);

// Acumulate total weight of the signature
totalWeight += addrWeight;
} else if (flag == FLAG_DYNAMIC_SIGNATURE) {
Expand All @@ -115,7 +116,9 @@ abstract contract ModuleAuth is IModuleAuth, ModuleERC165, SignatureValidator, I
// Read dynamic size signature
bytes memory signature;
(signature, rindex) = _signature.readBytes(rindex, size);
require(isValidSignature(_hash, addr, signature), "ModuleAuth#_signatureValidation: INVALID_SIGNATURE");
console.log("ModuleAuth: isValidSignature");
console.logBool(isValidSignature(_hash, addr, signature));
require(isValidSignature(_hash, addr, signature), "ModuleAuth#_signatureValidation: INVALID_SIGNATURE");

// Acumulate total weight of the signature
totalWeight += addrWeight;
Expand All @@ -124,10 +127,15 @@ abstract contract ModuleAuth is IModuleAuth, ModuleERC165, SignatureValidator, I
}

// Write weight and address to image
console.log("Calculating image hash for %s with weight %s", addr, addrWeight);
imageHash = keccak256(abi.encode(imageHash, addrWeight, addr));
}

(bool verified, bool needsUpdate) = _isValidImage(imageHash);
console.log("Verified");
console.logBool(verified);
console.log("Needs update");
console.logBool(needsUpdate);
return ((totalWeight >= threshold && verified), needsUpdate, imageHash);
}

Expand Down Expand Up @@ -166,7 +174,7 @@ abstract contract ModuleAuth is IModuleAuth, ModuleERC165, SignatureValidator, I
// solhint-disable-next-line no-empty-blocks
function updateImageHashInternal(bytes32 _imageHash) internal virtual {
// Default implementation does nothing
}
}



Expand All @@ -183,6 +191,7 @@ abstract contract ModuleAuth is IModuleAuth, ModuleERC165, SignatureValidator, I
bytes calldata _data,
bytes calldata _signatures
) external override view returns (bytes4) {
console.log("====== IS VALID SIGNATURE ======");
// Validate signatures
if (_signatureValidationInternal(_subDigest(keccak256(_data)), _signatures)) {
return SELECTOR_ERC1271_BYTES_BYTES;
Expand All @@ -203,6 +212,7 @@ abstract contract ModuleAuth is IModuleAuth, ModuleERC165, SignatureValidator, I
bytes32 _hash,
bytes calldata _signatures
) external override view returns (bytes4) {
console.log("====== IS VALID SIGNATURE bytes32 HASH ======");
// Validate signatures
if (_signatureValidationInternal(_subDigest(_hash), _signatures)) {
return SELECTOR_ERC1271_BYTES32_BYTES;
Expand Down
43 changes: 42 additions & 1 deletion src/contracts/modules/commons/ModuleAuthDynamic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,48 @@ abstract contract ModuleAuthDynamic is ModuleAuthUpgradable {
* @return true if the signature image is valid, and true if the image hash needs to be updated
*/
function _isValidImage(bytes32 _imageHash) internal view override returns (bool, bool) {
console.log("IS VALID IMAGE 1:");
console.logBytes32(_imageHash);
console.log("GOT %s", address(
uint160(uint256(
keccak256(
abi.encodePacked(
bytes1(0xff),
FACTORY,
_imageHash,
INIT_CODE_HASH
)
)
))
));
console.log("WANT %s", address(this));
bytes32 storedImageHash = ModuleStorage.readBytes32(ImageHashKey.IMAGE_HASH_KEY);
console.log("WANT (calculate) %s", address(
uint160(uint256(
keccak256(
abi.encodePacked(
bytes1(0xff),
FACTORY,
storedImageHash,
INIT_CODE_HASH
)
)
))
));
console.log("STORED IMAGE HASH: ");
console.logBytes32(storedImageHash);
address(
uint160(uint256(
keccak256(
abi.encodePacked(
bytes1(0xff),
FACTORY,
_imageHash,
INIT_CODE_HASH
)
)
))
);
if (storedImageHash == 0) {
// No image hash stored. Check that the image hash was used as the salt when
// deploying the wallet proxy contract.
Expand All @@ -47,7 +88,7 @@ abstract contract ModuleAuthDynamic is ModuleAuthUpgradable {
// Indicate need to update = true. This will trigger a call to store the image hash
return (authenticated, true);
}

// Image hash has been stored.
return ((_imageHash != bytes32(0) && _imageHash == storedImageHash), false);
}
Expand Down
85 changes: 85 additions & 0 deletions tests/EIP712Debug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { ethers, network } from 'hardhat'

// Fork network @ https://rpc.testnet.immutable.com/
// Attach contract at LatestWalletImplLocator
// Get MainModuleDynamicAuth address
// Deploy MainModuleDynamicAuth (with console logs)
// Get code at the newly deployed MainModuleDynamicAuth (w/ logs)
// Set the code at the MainModuleDynamicAuth to be the newly deployed MainModuleDynamicAuth (w/ logs)
// Do signature verification
// inspect console.log lines

// "passport": {
// "zkevm_eth_address": "0x3878cadc6a521dceb1f46599913ce726c430a8e1",
// "zkevm_user_admin_address": "0xa110e9ccdc3714d1dabb2f25e8883061f75011bd"

async function main() {
// Get signature values
const typedHash = '0x0b8f209be8d541a4ded6b82c0414aac2cee9cb89f19518b6ee1502ba555cb16c'
const messageSubDigest = '0xede3e129db20579573bccededc094e9a0f3cb8c8df59bbf3526eb7072bffa6f3'
const packedAggregateSignature =
'0x000202011b1d383526a2815d26550eb314b5d7e0551327330043c9d1d1d25201bd592da3eb99a5c4568105a79c168b93eebe2444ddf1f7a61174394b2b8616ba8ce9aae7741e2131caf66b80773f3557e18ec0d93a68a17090cb1b010300014f84dcc8d9fe6c2d8ed83d2edc01cc1fc81e29a6a75bce6301072b3e30f972b744f259055466795f372eb5d82c5314a781209c827c634fd3435d617ce58639481c02'
const relayerSig =
'0xc9d1d1d25201bd592da3eb99a5c4568105a79c168b93eebe2444ddf1f7a61174394b2b8616ba8ce9aae7741e2131caf66b80773f3557e18ec0d93a68a17090cb1b01'

// Recover signer
// const signer = await ethers.getContractFactory('SignerCheck')
// const signerDeployed = await signer.deploy()
// await signerDeployed.deployed()
// const signerRet = await signerDeployed.recover(messageSubDigest, relayerSig)

// Verify supplied signature against Immutable signer
// const immutableSignerAddr = '0x1B1D383526A2815d26550eb314B5d7e055132733'
// const immutableSigner = await ethers.getContractAt('ImmutableSigner', immutableSignerAddr)
// const immutableSignerPubKey = await immutableSigner.primarySigner()

// // Verify returned signer against Immutable signer
// if (signerRet !== immutableSignerPubKey) {
// console.log('Signer mismatch')
// process.exit(0)
// }

// Set addresses
const scwAddr = '0x3878cadc6a521dceb1f46599913ce726c430a8e1'
const factoryAddr = '0x55b9d1cd803d5acA8ea23ccd96f6a756DED9f5a9'
const startupAddr = '0x8df826438e652f7124fe07F413fA3556cd57edB5'
const walletImplLocatorAddr = '0x657d339b8616033fee25f66ea1d00c3f30b14171'

// Get MainModuleDynamicAuth address
const walletImplLocator = await ethers.getContractAt('LatestWalletImplLocator', walletImplLocatorAddr)
const mainModuleAddr = await walletImplLocator.latestWalletImplementation()

// Deploy new MainModuleDynamicAuthLog
const ModuleLog = await ethers.getContractFactory('MainModuleDynamicAuthLog')
const moduleLog = await ModuleLog.deploy(factoryAddr, startupAddr)
await moduleLog.deployed()

// Get code for logging
const modLogCode = await ethers.provider.getCode(moduleLog.address)

// Get address for main module
const walletProxy = await ethers.getContractAt('IWalletProxy', scwAddr)

// Set code
// await network.provider.send('hardhat_setCode', [mainModuleAddr, modLogCode])
// await network.provider.send('hardhat_mine', ["0x100"])
// console.log('MAIN MODULE ADDDR: ', moduleLog.address)
console.log("STORAGE AT: ", await ethers.provider.getStorageAt(scwAddr, scwAddr));
console.log('PROXY IMPLEMENTATION: ', await walletProxy.PROXY_getImplementation())
const implementationValue = "0x000000000000000000000000" + moduleLog.address.substring(2);
await network.provider.send('hardhat_setStorageAt', [scwAddr, scwAddr, implementationValue])


// Do signature verification
// Attatch to SCW
const moduleAuth = await ethers.getContractAt('ModuleAuth', scwAddr)
// Verify 2-of-2 signature
const magicValue = await moduleAuth['isValidSignature(bytes32,bytes)'](typedHash, packedAggregateSignature)

console.log('MAGIC VALUE', magicValue)
}

main().catch(error => {
console.error(error)
process.exit(1)
})
Loading