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

Pool for native tokens #62

Merged
merged 11 commits into from
Apr 7, 2023
Merged
Show file tree
Hide file tree
Changes from 8 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
4 changes: 4 additions & 0 deletions script/scripts/Env.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,7 @@ address constant uniV3Quoter = 0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6;
uint24 constant fee0 = 500;
address constant usdc = 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174;
uint24 constant fee1 = 500;

// zkbobpool eth
address constant weth = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address constant permit2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;
5 changes: 3 additions & 2 deletions script/scripts/Local.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import "../../test/shared/EIP2470.t.sol";
import "../../src/BobToken.sol";
import "../../src/proxy/EIP1967Proxy.sol";
import "../../src/zkbob/ZkBobPool.sol";
import "../../src/zkbob/ZkBobPoolERC20.sol";
import "../../src/zkbob/manager/MutableOperatorManager.sol";
import "../../src/zkbob/ZkBobDirectDepositQueue.sol";

Expand Down Expand Up @@ -43,7 +44,7 @@ contract DeployLocal is Script {
EIP1967Proxy poolProxy = new EIP1967Proxy(tx.origin, mockImpl, "");
EIP1967Proxy queueProxy = new EIP1967Proxy(tx.origin, mockImpl, "");

ZkBobPool poolImpl = new ZkBobPool(
ZkBobPoolERC20 poolImpl = new ZkBobPoolERC20(
zkBobPoolId,
address(bob),
transferVerifier,
Expand All @@ -65,7 +66,7 @@ contract DeployLocal is Script {
);
poolProxy.upgradeToAndCall(address(poolImpl), initData);
}
ZkBobPool pool = ZkBobPool(address(poolProxy));
ZkBobPoolERC20 pool = ZkBobPoolERC20(address(poolProxy));

ZkBobDirectDepositQueue queueImpl = new ZkBobDirectDepositQueue(address(pool), address(bob));
queueProxy.upgradeTo(address(queueImpl));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ import "./Env.s.sol";
import "../../src/proxy/EIP1967Proxy.sol";
import "../../src/zkbob/ZkBobPool.sol";
import "../../src/zkbob/manager/MutableOperatorManager.sol";
import "../../src/zkbob/ZkBobPoolERC20.sol";

contract DeployNewZkBobPoolImpl is Script {
contract DeployNewZkBobPoolERC20Impl is Script {
function run() external {
vm.startBroadcast();

ZkBobPool pool = ZkBobPool(zkBobPool);
ZkBobPoolERC20 pool = ZkBobPoolERC20(zkBobPool);

ZkBobPool impl = new ZkBobPool(
ZkBobPoolERC20 impl = new ZkBobPoolERC20(
pool.pool_id(),
pool.token(),
pool.transfer_verifier(),
Expand All @@ -25,6 +26,6 @@ contract DeployNewZkBobPoolImpl is Script {

vm.stopBroadcast();

console2.log("ZkBobPool implementation:", address(impl));
console2.log("ZkBobPoolERC20 implementation:", address(impl));
}
}
32 changes: 32 additions & 0 deletions script/scripts/NewZkBobPoolETHImpl.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: CC0-1.0

pragma solidity 0.8.15;

import "forge-std/Script.sol";
import "./Env.s.sol";
import "../../src/proxy/EIP1967Proxy.sol";
import "../../src/zkbob/ZkBobPool.sol";
import "../../src/zkbob/manager/MutableOperatorManager.sol";
import "../../src/zkbob/ZkBobPoolETH.sol";

contract DeployNewZkBobPoolETHImpl is Script {
function run() external {
vm.startBroadcast();

ZkBobPoolETH pool = ZkBobPoolETH(payable(zkBobPool));

ZkBobPoolETH impl = new ZkBobPoolETH(
pool.pool_id(),
pool.token(),
pool.transfer_verifier(),
pool.tree_verifier(),
pool.batch_deposit_verifier(),
address(pool.direct_deposit_queue()),
address(pool.permit2())
);

vm.stopBroadcast();

console2.log("ZkBobPoolETH implementation:", address(impl));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import "../../src/proxy/EIP1967Proxy.sol";
import "../../src/zkbob/ZkBobPool.sol";
import "../../src/zkbob/ZkBobDirectDepositQueue.sol";
import "../../src/zkbob/manager/MutableOperatorManager.sol";
import "../../src/zkbob/ZkBobPoolERC20.sol";

contract DeployZkBobPool is Script {
contract DeployZkBobPoolERC20 is Script {
function run() external {
vm.startBroadcast();

Expand All @@ -32,7 +33,7 @@ contract DeployZkBobPool is Script {
EIP1967Proxy poolProxy = new EIP1967Proxy(tx.origin, mockImpl, "");
EIP1967Proxy queueProxy = new EIP1967Proxy(tx.origin, mockImpl, "");

ZkBobPool poolImpl = new ZkBobPool(
ZkBobPoolERC20 poolImpl = new ZkBobPoolERC20(
zkBobPoolId,
bobVanityAddr,
transferVerifier,
Expand All @@ -52,7 +53,7 @@ contract DeployZkBobPool is Script {
zkBobDirectDepositCap
);
poolProxy.upgradeToAndCall(address(poolImpl), initData);
ZkBobPool pool = ZkBobPool(address(poolProxy));
ZkBobPoolERC20 pool = ZkBobPoolERC20(address(poolProxy));

ZkBobDirectDepositQueue queueImpl = new ZkBobDirectDepositQueue(address(pool), bobVanityAddr);
queueProxy.upgradeTo(address(queueImpl));
Expand Down
98 changes: 98 additions & 0 deletions script/scripts/ZkBobPoolETH.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// SPDX-License-Identifier: CC0-1.0

pragma solidity 0.8.15;

import "forge-std/Script.sol";
import "./Env.s.sol";
import "../../src/proxy/EIP1967Proxy.sol";
import "../../src/zkbob/ZkBobPool.sol";
import "../../src/zkbob/ZkBobDirectDepositQueueETH.sol";
import "../../src/zkbob/manager/MutableOperatorManager.sol";
import "../../src/zkbob/ZkBobPoolETH.sol";

contract DeployZkBobPoolETH is Script {
function run() external {
vm.startBroadcast();

ITransferVerifier transferVerifier;
ITreeVerifier treeVerifier;
IBatchDepositVerifier batchDepositVerifier;
bytes memory code1 =
vm.getCode(string.concat("out/", zkBobVerifiers, "/TransferVerifier.sol/TransferVerifier.json"));
bytes memory code2 =
vm.getCode(string.concat("out/", zkBobVerifiers, "/TreeUpdateVerifier.sol/TreeUpdateVerifier.json"));
bytes memory code3 = vm.getCode(
string.concat("out/", zkBobVerifiers, "/DelegatedDepositVerifier.sol/DelegatedDepositVerifier.json")
);
assembly {
transferVerifier := create(0, add(code1, 0x20), mload(code1))
treeVerifier := create(0, add(code2, 0x20), mload(code2))
batchDepositVerifier := create(0, add(code3, 0x20), mload(code3))
}

EIP1967Proxy poolProxy = new EIP1967Proxy(tx.origin, mockImpl, "");
EIP1967Proxy queueProxy = new EIP1967Proxy(tx.origin, mockImpl, "");

ZkBobPoolETH poolImpl = new ZkBobPoolETH(
zkBobPoolId,
weth,
transferVerifier,
treeVerifier,
batchDepositVerifier,
address(queueProxy),
permit2
);
bytes memory initData = abi.encodeWithSelector(
ZkBobPool.initialize.selector,
zkBobInitialRoot,
zkBobPoolCap,
zkBobDailyDepositCap,
zkBobDailyWithdrawalCap,
zkBobDailyUserDepositCap,
zkBobDepositCap,
zkBobDailyUserDirectDepositCap,
zkBobDirectDepositCap
);
poolProxy.upgradeToAndCall(address(poolImpl), initData);
ZkBobPoolETH pool = ZkBobPoolETH(payable(address(poolProxy)));

ZkBobDirectDepositQueueETH queueImpl = new ZkBobDirectDepositQueueETH(address(pool), weth);
queueProxy.upgradeTo(address(queueImpl));
ZkBobDirectDepositQueueETH queue = ZkBobDirectDepositQueueETH(address(queueProxy));

IOperatorManager operatorManager =
new MutableOperatorManager(zkBobRelayer, zkBobRelayerFeeReceiver, zkBobRelayerURL);
pool.setOperatorManager(operatorManager);
queue.setOperatorManager(operatorManager);

if (owner != address(0)) {
pool.transferOwnership(owner);
queue.transferOwnership(owner);
}

if (admin != tx.origin) {
poolProxy.setAdmin(admin);
queueProxy.setAdmin(admin);
}

vm.stopBroadcast();

require(poolProxy.implementation() == address(poolImpl), "Invalid implementation address");
require(poolProxy.admin() == admin, "Proxy admin is not configured");
require(pool.owner() == owner, "Owner is not configured");
require(queueProxy.implementation() == address(queueImpl), "Invalid implementation address");
require(queueProxy.admin() == admin, "Proxy admin is not configured");
require(queue.owner() == owner, "Owner is not configured");
require(pool.transfer_verifier() == transferVerifier, "Transfer verifier is not configured");
require(pool.tree_verifier() == treeVerifier, "Tree verifier is not configured");
require(pool.batch_deposit_verifier() == batchDepositVerifier, "Batch deposit verifier is not configured");

console2.log("ZkBobPool:", address(pool));
console2.log("ZkBobPool implementation:", address(poolImpl));
console2.log("ZkBobDirectDepositQueue:", address(queue));
console2.log("ZkBobDirectDepositQueue implementation:", address(queueImpl));
console2.log("TransferVerifier:", address(transferVerifier));
console2.log("TreeUpdateVerifier:", address(treeVerifier));
console2.log("BatchDepositVierifier:", address(batchDepositVerifier));
}
}
62 changes: 62 additions & 0 deletions src/interfaces/IPermit2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title Uniswap Permit2
/// @notice Handles ERC20 token transfers through signature based actions
/// @dev Requires user's token approval on the Permit2 contract
interface IPermit2 {
/// @notice Thrown when the requested amount for a transfer is larger than the permissioned amount
/// @param maxAmount The maximum amount a spender can request to transfer
error InvalidAmount(uint256 maxAmount);

/// @notice Thrown when the number of tokens permissioned to a spender does not match the number of tokens being transferred
/// @dev If the spender does not need to transfer the number of tokens permitted, the spender can request amount 0 to be transferred
error LengthMismatch();

/// @notice Emits an event when the owner successfully invalidates an unordered nonce.
event UnorderedNonceInvalidation(address indexed owner, uint256 word, uint256 mask);

/// @notice Domain separator
function DOMAIN_SEPARATOR() external view returns (bytes32);

/// @notice The token and amount details for a transfer signed in the permit transfer signature
struct TokenPermissions {
// ERC20 token address
address token;
// the maximum amount that can be spent
uint256 amount;
}

/// @notice The signed permit message for a single token transfer
struct PermitTransferFrom {
TokenPermissions permitted;
// a unique value for every token owner's signature to prevent signature replays
uint256 nonce;
// deadline on the permit signature
uint256 deadline;
}

/// @notice Specifies the recipient address and amount for batched transfers.
/// @dev Recipients and amounts correspond to the index of the signed token permissions array.
/// @dev Reverts if the requested amount is greater than the permitted signed amount.
struct SignatureTransferDetails {
// recipient address
address to;
// spender requested amount
uint256 requestedAmount;
}

/// @notice Transfers a token using a signed permit message
/// @dev Reverts if the requested amount is greater than the permitted signed amount
/// @param permit The permit data signed over by the owner
/// @param owner The owner of the tokens to transfer
/// @param transferDetails The spender's requested transfer details for the permitted token
/// @param signature The signature to verify
function permitTransferFrom(
PermitTransferFrom memory permit,
SignatureTransferDetails calldata transferDetails,
address owner,
bytes calldata signature
)
external;
}
37 changes: 37 additions & 0 deletions src/interfaces/IZkBobDirectDepositsETH.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: CC0-1.0

pragma solidity ^0.8.0;

import "./IZkBobDirectDeposits.sol";

interface IZkBobDirectDepositsETH is IZkBobDirectDeposits {
/**
* @notice Performs a direct deposit to the specified zk address in native token.
* In case the deposit cannot be processed, it can be refunded later to the fallbackReceiver address.
* @param fallbackReceiver receiver of deposit refund.
* @param zkAddress receiver zk address.
* @return depositId id of the submitted deposit to query status for.
*/
function directNativeDeposit(
address fallbackReceiver,
bytes memory zkAddress
)
external
payable
returns (uint256 depositId);

/**
* @notice Performs a direct deposit to the specified zk address in native token.
* In case the deposit cannot be processed, it can be refunded later to the fallbackReceiver address.
* @param fallbackReceiver receiver of deposit refund.
* @param zkAddress receiver zk address.
* @return depositId id of the submitted deposit to query status for.
*/
function directNativeDeposit(
address fallbackReceiver,
string memory zkAddress
)
external
payable
returns (uint256 depositId);
}
43 changes: 43 additions & 0 deletions src/zkbob/ZkBobDirectDepositQueueETH.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.15;

import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@uniswap/v3-periphery/contracts/interfaces/external/IWETH9.sol";
import "../libraries/ZkAddress.sol";
import "../interfaces/IOperatorManager.sol";
import "../interfaces/IZkBobDirectDepositsETH.sol";
import "../interfaces/IZkBobDirectDepositQueue.sol";
import "../interfaces/IZkBobPool.sol";
import "../utils/Ownable.sol";
import "../proxy/EIP1967Admin.sol";
import "./ZkBobDirectDepositQueue.sol";

/**
* @title ZkBobDirectDepositQueueETH
* Queue for zkBob ETH direct deposits.
*/
contract ZkBobDirectDepositQueueETH is IZkBobDirectDepositsETH, ZkBobDirectDepositQueue {
constructor(address _pool, address _token) ZkBobDirectDepositQueue(_pool, _token) {}

/// @inheritdoc IZkBobDirectDepositsETH
function directNativeDeposit(
address _fallbackUser,
string calldata _zkAddress
)
external
payable
returns (uint256)
{
return directNativeDeposit(_fallbackUser, bytes(_zkAddress));
}

/// @inheritdoc IZkBobDirectDepositsETH
function directNativeDeposit(address _fallbackUser, bytes memory _rawZkAddress) public payable returns (uint256) {
uint256 amount = msg.value;
IWETH9(token).deposit{value: amount}();
return _recordDirectDeposit(msg.sender, _fallbackUser, amount, _rawZkAddress);
}
}
Loading