Skip to content

Commit

Permalink
Submodules structure for forked repositories
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex Connolly authored and Alex Connolly committed Dec 11, 2023
1 parent d2bc8c3 commit 2ee9312
Show file tree
Hide file tree
Showing 308 changed files with 67,456 additions and 11 deletions.
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "passport"]
path = passport
url = https://github.com/immutable/wallet-contracts
[submodule "forks/seaport"]
path = forks/seaport
url = https://github.com/immutable/seaport
59 changes: 59 additions & 0 deletions contracts/passport/Factory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.17;
import '@openzeppelin/contracts/access/AccessControl.sol';
import "./Wallet.sol";

/**
* @title Factory
* @notice Factory contract to retrieve counterfactual wallet addresses and
* deploy new Sequence wallet instances to those addresses
*/
contract Factory is AccessControl {
// Role to deploy new wallets
bytes32 public constant DEPLOYER_ROLE = keccak256('DEPLOYER_ROLE');

event WalletDeployed(address indexed wallet, address indexed mainModule, bytes32 salt);

constructor(address _admin, address _deployer) {
_grantRole(DEFAULT_ADMIN_ROLE, _admin);
_grantRole(DEPLOYER_ROLE, _deployer);
}

/**
* @notice Returns a deterministic contract address given a salt
* @param _mainModule Address of the main module to be used by the wallet
* @param _salt Salt used to generate the address
* @return _address The deterministic address
*/
function getAddress(address _mainModule, bytes32 _salt) external view returns (address _address) {
bytes32 _hash = keccak256(
abi.encodePacked(
bytes1(0xff),
address(this),
_salt,
keccak256(abi.encodePacked(Wallet.creationCode, uint256(uint160(_mainModule))))
)
);
return address(uint160(uint256(_hash)));
}

/**
* @notice Will deploy a new wallet instance using create2
* @param _mainModule Address of the main module to be used by the wallet
* @param _salt Salt used to generate the wallet, which is the imageHash
* of the wallet's configuration.
* @dev It is recommended to not have more than 200 signers as opcode repricing
* could make transactions impossible to execute as all the signers must be
* passed for each transaction.
*/
function deploy(address _mainModule, bytes32 _salt) external payable onlyRole(DEPLOYER_ROLE) returns (address _contract) {
bytes memory code = abi.encodePacked(Wallet.creationCode, uint256(uint160(_mainModule)));
assembly {
_contract := create2(callvalue(), add(code, 32), mload(code), _salt)
}
// check deployment success
require(_contract != address(0), 'WalletFactory: deployment failed');
// emit event, increases gas cost by ~2k
emit WalletDeployed(_contract, _mainModule, _salt);
}
}
11 changes: 11 additions & 0 deletions contracts/passport/IWalletProxy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright Immutable Pty Ltd 2018 - 2023
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.3;

/**
* Interface that WalletProxy.yul implements.
*/
interface IWalletProxy {
/// @dev Retrieve current implementation contract used by proxy
function PROXY_getImplementation() external view returns (address implementation);
}
72 changes: 72 additions & 0 deletions contracts/passport/MultiCallDeploy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright (c) Immutable Pty Ltd 2018 - 2023
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.17;

import "./modules/commons/interfaces/IModuleCalls.sol";
import '@openzeppelin/contracts/access/AccessControl.sol';
import "./interfaces/IFactory.sol";

/**
* @title MultiCallDeploy
* @notice This contract is bundles the wallet deployment and the users first write transaction into a single transaction.
* Contract usage is intended for the submitter inside the relayer service, which will call either of the functions.
*/
contract MultiCallDeploy is AccessControl {
// Role to execute functions
bytes32 public constant EXECUTOR_ROLE = keccak256('EXECUTOR_ROLE');

constructor(address _admin, address _executor) {
_grantRole(DEFAULT_ADMIN_ROLE, _admin);
_grantRole(EXECUTOR_ROLE, _executor);
}

/*
* @dev Grants EXECUTOR_ROLE to an user.
* @param _executor Address that will be allowed to execute functions
*/
function grantExecutorRole(address _executor) external onlyRole(DEFAULT_ADMIN_ROLE) {
_grantRole(EXECUTOR_ROLE, _executor);
}

/*
* @dev Deploy wallet and execute transaction.
* @param _mainModule Address of the main module to be used by the wallet
* @param _salt Salt used to generate the address
* @param factory address of the factory contract
* @param _txs transaction to execute
* @param _nonce nonce of the wallet
* @param _signature transaction signature from wallet
*/
function deployExecute(address _mainModule, bytes32 _salt, address factory, IModuleCalls.Transaction[] calldata _txs, uint256 _nonce, bytes calldata _signature) external onlyRole(EXECUTOR_ROLE) {
address ret = IFactory(factory).deploy(_mainModule, _salt);
IModuleCalls(ret).execute(_txs, _nonce, _signature);
}

/*
* @dev Handles deployment of wallet and transaction execution for both cases
* @param cfa counter factual address of the wallet
* @param _mainModule Address of the main module to be used by the wallet
* @param _salt Salt used to generate the address
* @param factory address of the factory contract
* @param _txs transaction to execute
* @param _nonce nonce of the wallet
* @param _signature transaction signature from wallet
*/
function deployAndExecute(address cfa, address _mainModule, bytes32 _salt, address factory, IModuleCalls.Transaction[] calldata _txs, uint256 _nonce, bytes calldata _signature) external onlyRole(EXECUTOR_ROLE){
// Get code size at CFA
uint32 size;
assembly {
size := extcodesize(cfa)
}

// If size is 0, deploy the proxy and execute write tx
// Else, execute the users transaction
if (size == 0) {
address ret = IFactory(factory).deploy(_mainModule, _salt);
require(cfa == ret, "MultiCallDeploy: deployed address does not match CFA");
IModuleCalls(ret).execute(_txs, _nonce, _signature);
} else {
IModuleCalls(cfa).execute(_txs, _nonce, _signature);
}
}
}
1 change: 1 addition & 0 deletions contracts/passport/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DO NOT MODIFY THESE CONTRACTS DIRECTLY. This folder has been automatically extracted from https://github.com/immutable/wallet-contracts via a submodule in this repository's forks directory. See the upstream repository for full context.
10 changes: 10 additions & 0 deletions contracts/passport/Wallet.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright Immutable Pty Ltd 2018 - 2023
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.17;

// Holds the creation code of the WalletProxy.yul used by smart contract wallet instances.
// Generate this bytecode using ./compileWalletProxyYul.sh
library Wallet {
// This bytecode must precisely match that in tests/utils/helpers.ts
bytes internal constant creationCode = hex"6054600f3d396034805130553df3fe63906111273d3560e01c14602b57363d3d373d3d3d3d369030545af43d82803e156027573d90f35b3d90fd5b30543d5260203df3";
}
81 changes: 81 additions & 0 deletions contracts/passport/WalletProxy.yul
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright (c) Immutable Pty Ltd 2018 - 2023
// SPDX-License-Identifier: Apache-2.0
//
// This Yul code creates a minimalist transparent proxy with a function to fetch
// the address of the contract being proxied to using the interface described in
// IWalletProxy.sol .
//
object "ProxyGetImplYul" {
// This is the initcode of the contract.
code {
// Copy the runtime code plus the address of the implementation
// parameter (32 bytes) which is appended to the end to memory.
// copy s bytes from code at position f to mem at position t
// codecopy(t, f, s)
// This will turn into a memory->memory copy for Ewasm and
// a codecopy for EVM
// The constant 0x54 is datasize("runtime") + 32. The solc compiler is
// unable to do constant addition as part of the compilation process, hence
// the constant.
// If the runtime code is to be updated, uncomment the following line, and comment
// out the following line, so that datasize("runtime") can be determined. It will
// be the byte following the 0x60 push1 opcode.
// datacopy(returndatasize(), dataoffset("runtime"), add(datasize("runtime"), 32))
datacopy(returndatasize(), dataoffset("runtime"), 0x54)

// Store the implementation address at the storage slot which is
// equivalent to the deployed address of this contract.
let implAddress := mload(datasize("runtime"))
sstore(address(), implAddress)

// now return the runtime object (the currently
// executing code is the constructor code)
return(returndatasize(), datasize("runtime"))
}


// Code for deployed contract
object "runtime" {
code {
// Load the function selector (the first four bytes of calldata) by shifting the
// word to the right.
let selector := shr(224, calldataload(returndatasize()))

if eq(selector, 0x90611127) /* Function selector for "PROXY_getImplementation()" */ {
let impl := sload(address())
mstore(returndatasize(), impl)
return(returndatasize(), 0x20)
}

// Load calldata to memory location 0.
// Copy s bytes from calldata at position f to mem at position t
// calldatacopy(t, f, s)
calldatacopy(returndatasize(), returndatasize(), calldatasize())

// Use returndatasize to load zero.
let zero := returndatasize()

// Execute delegate call. Have outsize set to zero, to indicate
// don't return any data automatically.
// Call contract at address a with input mem[in…(in+insize))
// providing g gas and v wei and output area
// mem[out…(out+outsize)) returning 0 on error
// (eg. out of gas) and 1 on success
// delegatecall(g, a, in, insize, out, outsize)
// Use sload(address()) to load the implemntation address.
let success := delegatecall(gas(), sload(address()), returndatasize(), calldatasize(), returndatasize(), returndatasize())

// Copy the return result to memory location 0.
// Copy s bytes from returndata at position f to mem at position t
// returndatacopy(t, f, s)
returndatacopy(zero, zero, returndatasize())

// Return or revert: memory location 0 contains either the return value
// or the revert information.
if iszero(success) {
revert (zero,returndatasize())
}
return (zero,returndatasize())
}
}
}
38 changes: 38 additions & 0 deletions contracts/passport/interfaces/IERC1271Wallet.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.17;


interface IERC1271Wallet {

/**
* @notice Verifies whether the provided signature is valid with respect to the provided data
* @dev MUST return the correct magic value if the signature provided is valid for the provided data
* > The bytes4 magic value to return when signature is valid is 0x20c13b0b : bytes4(keccak256("isValidSignature(bytes,bytes)")
* > This function MAY modify Ethereum's state
* @param _data Arbitrary length data signed on the behalf of address(this)
* @param _signature Signature byte array associated with _data
* @return magicValue Magic value 0x20c13b0b if the signature is valid and 0x0 otherwise
*/
function isValidSignature(
bytes calldata _data,
bytes calldata _signature)
external
view
returns (bytes4 magicValue);

/**
* @notice Verifies whether the provided signature is valid with respect to the provided hash
* @dev MUST return the correct magic value if the signature provided is valid for the provided hash
* > The bytes4 magic value to return when signature is valid is 0x20c13b0b : bytes4(keccak256("isValidSignature(bytes,bytes)")
* > This function MAY modify Ethereum's state
* @param _hash keccak256 hash that was signed
* @param _signature Signature byte array associated with _data
* @return magicValue Magic value 0x20c13b0b if the signature is valid and 0x0 otherwise
*/
function isValidSignature(
bytes32 _hash,
bytes calldata _signature)
external
view
returns (bytes4 magicValue);
}
29 changes: 29 additions & 0 deletions contracts/passport/interfaces/IFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.17;

/**
* @title IFactory
* @notice Factory interface to interact with wallet factory
*/
interface IFactory {
event WalletDeployed(address indexed wallet, address indexed mainModule, bytes32 salt);

/**
* @notice Returns a deterministic contract address given a salt
* @param _mainModule Address of the main module to be used by the wallet
* @param _salt Salt used to generate the address
* @return _address The deterministic address
*/
function getAddress(address _mainModule, bytes32 _salt) external view returns (address);

/**
* @notice Will deploy a new wallet instance using create2
* @param _mainModule Address of the main module to be used by the wallet
* @param _salt Salt used to generate the wallet, which is the imageHash
* of the wallet's configuration.
* @dev It is recommended to not have more than 200 signers as opcode repricing
* could make transactions impossible to execute as all the signers must be
* passed for each transaction.
*/
function deploy(address _mainModule, bytes32 _salt) external payable returns (address);
}
8 changes: 8 additions & 0 deletions contracts/passport/interfaces/receivers/IERC1155Receiver.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.17;


interface IERC1155Receiver {
function onERC1155Received(address, address, uint256, uint256, bytes calldata) external returns (bytes4);
function onERC1155BatchReceived(address, address, uint256[] calldata, uint256[] calldata, bytes calldata) external returns (bytes4);
}
7 changes: 7 additions & 0 deletions contracts/passport/interfaces/receivers/IERC223Receiver.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.17;


interface IERC223Receiver {
function tokenFallback(address, uint256, bytes calldata) external;
}
7 changes: 7 additions & 0 deletions contracts/passport/interfaces/receivers/IERC721Receiver.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.17;


interface IERC721Receiver {
function onERC721Received(address, address, uint256, bytes calldata) external returns (bytes4);
}
26 changes: 26 additions & 0 deletions contracts/passport/migrations/Migrations.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.17;


contract Migrations {
address public owner;
uint public last_completed_migration;

constructor() public {
owner = msg.sender;
}

modifier restricted() {
if (msg.sender == owner)
_;
}

function setCompleted(uint completed) public restricted {
last_completed_migration = completed;
}

function upgrade(address new_address) public restricted {
Migrations upgraded = Migrations(new_address);
upgraded.setCompleted(last_completed_migration);
}
}
9 changes: 9 additions & 0 deletions contracts/passport/mocks/AlwaysRevertMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.17;


contract AlwaysRevertMock {
fallback() external payable {
revert("AlwaysRevertMock#fallback: ALWAYS_REVERT");
}
}
Loading

0 comments on commit 2ee9312

Please sign in to comment.