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

[WIP] feat: update contracts for zksync #32

Merged
merged 15 commits into from
Jul 25, 2024
Merged
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ RPC_METIS=https://andromeda.metis.io/?owner=1088
RPC_METIS_TESTNET=https://andromeda.metis.io/?owner=1088
RPC_BINANCE=https://bsc-dataseed.binance.org/
RPC_BINANCE_TESTNET=https://data-seed-prebsc-1-s1.binance.org:8545/
RPC_ZK_SYNC=https://mainnet.era.zksync.io
RPC_ZK_SYNC_TESTNET=https://sepolia.era.zksync.dev

# Etherscan api keys for verification & download utils
ETHERSCAN_API_KEY_MAINNET=
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ out/
broadcast
node_modules
package-lock.json
zkout/
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,17 @@ Modified from https://github.com/lifinance/create3-factory/blob/main/src/CREATE3
- removal of named returns
- changed name of getDeployed for predictAddress
- usage of create3 lib by Agustin Aguilar instead of solmate

## ZkSync

As ZkSync network requires the use of a [forked](https://github.com/matter-labs/foundry-zksync) version of foundry we have created different profiles so that they can run
as expected.

- Contracts specific for ZkSync network can be found [here](src-zksync)
- Tests specific for ZkSync network can be found [here](test-zksync)

To build and test the contracts use `FOUNDRY_PROFILE=zksync` and the flag `--zksync`
- Example:
```solidity
FOUNDRY_PROFILE=zksync forge test -vvv --zksync
```
21 changes: 21 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ out = 'out'
libs = ['lib']
remappings = []

[profile.zksync]
src = 'src-zksync'
test = 'test-zksync'
libs = ['lib']
solc="0.8.19"

[profile.zksync.zksync]
fallback_oz = true
mode = "3"
zksolc="1.4.1"


# See more config options https://github.com/gakonst/foundry/tree/master/config
[rpc_endpoints]
ethereum = "${RPC_MAINNET}"
Expand All @@ -23,6 +35,8 @@ fantom = "${RPC_FANTOM}"
fantom-testnet = "${RPC_FANTOM_TESTNET}"
binance = "${RPC_BINANCE}"
binance-testnet = "${RPC_BINANCE_TESTNET}"
zksync = "${RPC_ZK_SYNC}"
zksync-testnet = "${RPC_ZK_SYNC_TESTNET}"

[etherscan]
ethereum = { key = "${ETHERSCAN_API_KEY_MAINNET}", chain = 1 }
Expand All @@ -41,3 +55,10 @@ fantom = { key = "${ETHERSCAN_API_KEY_FANTOM}", chain = 250 }
fantom-testnet = { key = "${ETHERSCAN_API_KEY_FANTOM}", chain = 250 }
binance = { key = "${ETHERSCAN_API_KEY_BINANCE}", chain = 56 }
binance-testnet = { key = "${ETHERSCAN_API_KEY_BINANCE}", chain = 56 }
zksync = { key = "${ETHERSCAN_API_KEY_ZK_SYNC}", chain = 324 }
zksync-testnet = { key = "${ETHERSCAN_API_KEY_ZK_SYNC}", chain = 300, url = 'https://api-sepolia-era.zksync.network/api'}

[fuzz]
no_zksync_reserved_addresses = true
[invariant]
no_zksync_reserved_addresses = true
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

import {TransparentProxyFactoryBase, ITransparentProxyFactory} from '../../../src/contracts/transparent-proxy/TransparentProxyFactoryBase.sol';
import {ITransparentProxyFactoryZkSync} from './interfaces/ITransparentProxyFactoryZkSync.sol';

/**
* @title TransparentProxyFactoryZkSync
* @author BGD Labs
* @notice Factory contract to create transparent proxies, both with CREATE and CREATE2
* @dev `create()` and `createDeterministic()` are not unified for clearer interface, and at the same
* time allowing `createDeterministic()` with salt == 0
* @dev Highly recommended to pass as `admin` on creation an OZ ProxyAdmin instance
* @dev This contract needs solc=0.8.19 and zksolc=1.4.1 as codeHashes are specifically made for those versions
**/
contract TransparentProxyFactoryZkSync is
TransparentProxyFactoryBase,
ITransparentProxyFactoryZkSync
{
/// @inheritdoc ITransparentProxyFactoryZkSync
bytes32 public constant TRANSPARENT_UPGRADABLE_PROXY_INIT_CODE_HASH =
0x010001b73fa7f2c39ea2d9c597a419e15436fc9d3e00e032410072fb94ad95e1;

/// @inheritdoc ITransparentProxyFactoryZkSync
bytes32 public constant PROXY_ADMIN_INIT_CODE_HASH =
0x010000e7f9a8b61da13fe7e27804d9f641f5f8db05b07df720973af749a01ac1;

/// @inheritdoc ITransparentProxyFactoryZkSync
bytes32 public constant ZKSYNC_CREATE2_PREFIX = keccak256('zksyncCreate2');

/// @inheritdoc ITransparentProxyFactory
function predictCreateDeterministic(
address logic,
address admin,
bytes calldata data,
bytes32 salt
) public view override returns (address) {
return
_predictCreate2Address(
address(this),
salt,
TRANSPARENT_UPGRADABLE_PROXY_INIT_CODE_HASH,
abi.encode(logic, admin, data)
);
}

/// @inheritdoc ITransparentProxyFactory
function predictCreateDeterministicProxyAdmin(bytes32 salt)
public
view
override
returns (address)
{
return _predictCreate2Address(address(this), salt, PROXY_ADMIN_INIT_CODE_HASH, abi.encode());
}

function _predictCreate2Address(
address sender,
bytes32 salt,
bytes32 creationCodeHash,
bytes memory constructorInput
) internal pure returns (address) {
bytes32 addressHash = keccak256(
bytes.concat(
ZKSYNC_CREATE2_PREFIX,
bytes32(uint256(uint160(sender))),
salt,
creationCodeHash,
keccak256(constructorInput)
)
);

return address(uint160(uint256(addressHash)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

interface ITransparentProxyFactoryZkSync {
/**
* @notice method to get the hash of creation bytecode of the TransparentUpgradableProxy contract
* @return hashed of creation bytecode of the TransparentUpgradableProxy contract
*/
function TRANSPARENT_UPGRADABLE_PROXY_INIT_CODE_HASH() external returns (bytes32);

/**
* @notice method to get the hash of creation bytecode of the ProxyAdmin contract
* @return hashed of creation bytecode of the ProxyAdmin contract
*/
function PROXY_ADMIN_INIT_CODE_HASH() external returns (bytes32);

/**
* @notice method to get the zksync create2 prefix used for create2 address derivation in zksync
* @return create2 prefix used for create2 address derivation
*/
function ZKSYNC_CREATE2_PREFIX() external returns (bytes32);
}
58 changes: 9 additions & 49 deletions src/contracts/transparent-proxy/TransparentProxyFactory.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

import {IOwnable} from './interfaces/IOwnable.sol';
import {ITransparentProxyFactory} from './interfaces/ITransparentProxyFactory.sol';
import {TransparentUpgradeableProxy} from './TransparentUpgradeableProxy.sol';
import {ProxyAdmin} from './ProxyAdmin.sol';
import {TransparentProxyFactoryBase, ITransparentProxyFactory, ProxyAdmin, TransparentUpgradeableProxy} from './TransparentProxyFactoryBase.sol';

/**
* @title TransparentProxyFactory
Expand All @@ -14,56 +11,14 @@ import {ProxyAdmin} from './ProxyAdmin.sol';
* time allowing `createDeterministic()` with salt == 0
* @dev Highly recommended to pass as `admin` on creation an OZ ProxyAdmin instance
**/
contract TransparentProxyFactory is ITransparentProxyFactory {
/// @inheritdoc ITransparentProxyFactory
function create(address logic, address admin, bytes calldata data) external returns (address) {
address proxy = address(new TransparentUpgradeableProxy(logic, admin, data));

emit ProxyCreated(proxy, logic, admin);
return proxy;
}

/// @inheritdoc ITransparentProxyFactory
function createProxyAdmin(address adminOwner) external returns (address) {
address proxyAdmin = address(new ProxyAdmin());
IOwnable(proxyAdmin).transferOwnership(adminOwner);

emit ProxyAdminCreated(proxyAdmin, adminOwner);
return proxyAdmin;
}

/// @inheritdoc ITransparentProxyFactory
function createDeterministic(
address logic,
address admin,
bytes calldata data,
bytes32 salt
) external returns (address) {
address proxy = address(new TransparentUpgradeableProxy{salt: salt}(logic, admin, data));

emit ProxyDeterministicCreated(proxy, logic, admin, salt);
return proxy;
}

/// @inheritdoc ITransparentProxyFactory
function createDeterministicProxyAdmin(
address adminOwner,
bytes32 salt
) external returns (address) {
address proxyAdmin = address(new ProxyAdmin{salt: salt}());
IOwnable(proxyAdmin).transferOwnership(adminOwner);

emit ProxyAdminDeterministicCreated(proxyAdmin, adminOwner, salt);
return proxyAdmin;
}

contract TransparentProxyFactory is TransparentProxyFactoryBase {
/// @inheritdoc ITransparentProxyFactory
function predictCreateDeterministic(
address logic,
address admin,
bytes calldata data,
bytes32 salt
) public view returns (address) {
) public view override returns (address) {
return
_predictCreate2Address(
address(this),
Expand All @@ -74,7 +29,12 @@ contract TransparentProxyFactory is ITransparentProxyFactory {
}

/// @inheritdoc ITransparentProxyFactory
function predictCreateDeterministicProxyAdmin(bytes32 salt) public view returns (address) {
function predictCreateDeterministicProxyAdmin(bytes32 salt)
public
view
override
returns (address)
{
return _predictCreate2Address(address(this), salt, type(ProxyAdmin).creationCode, abi.encode());
}

Expand Down
74 changes: 74 additions & 0 deletions src/contracts/transparent-proxy/TransparentProxyFactoryBase.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

import {IOwnable} from './interfaces/IOwnable.sol';
import {ITransparentProxyFactory} from './interfaces/ITransparentProxyFactory.sol';
import {TransparentUpgradeableProxy} from './TransparentUpgradeableProxy.sol';
import {ProxyAdmin} from './ProxyAdmin.sol';

/**
* @title TransparentProxyFactory
* @author BGD Labs
* @notice Factory contract to create transparent proxies, both with CREATE and CREATE2
* @dev `create()` and `createDeterministic()` are not unified for clearer interface, and at the same
* time allowing `createDeterministic()` with salt == 0
* @dev Highly recommended to pass as `admin` on creation an OZ ProxyAdmin instance
**/
abstract contract TransparentProxyFactoryBase is ITransparentProxyFactory {
/// @inheritdoc ITransparentProxyFactory
function create(
address logic,
address admin,
bytes calldata data
) external returns (address) {
address proxy = address(new TransparentUpgradeableProxy(logic, admin, data));

emit ProxyCreated(proxy, logic, admin);
return proxy;
}

/// @inheritdoc ITransparentProxyFactory
function createProxyAdmin(address adminOwner) external returns (address) {
address proxyAdmin = address(new ProxyAdmin());
IOwnable(proxyAdmin).transferOwnership(adminOwner);

emit ProxyAdminCreated(proxyAdmin, adminOwner);
return proxyAdmin;
}

/// @inheritdoc ITransparentProxyFactory
function createDeterministic(
address logic,
address admin,
bytes calldata data,
bytes32 salt
) external returns (address) {
address proxy = address(new TransparentUpgradeableProxy{salt: salt}(logic, admin, data));

emit ProxyDeterministicCreated(proxy, logic, admin, salt);
return proxy;
}

/// @inheritdoc ITransparentProxyFactory
function createDeterministicProxyAdmin(address adminOwner, bytes32 salt)
external
returns (address)
{
address proxyAdmin = address(new ProxyAdmin{salt: salt}());
IOwnable(proxyAdmin).transferOwnership(adminOwner);

emit ProxyAdminDeterministicCreated(proxyAdmin, adminOwner, salt);
return proxyAdmin;
}

/// @inheritdoc ITransparentProxyFactory
function predictCreateDeterministic(
address logic,
address admin,
bytes calldata data,
bytes32 salt
) public view virtual returns (address);

/// @inheritdoc ITransparentProxyFactory
function predictCreateDeterministicProxyAdmin(bytes32 salt) public view virtual returns (address);
}
Loading
Loading