Skip to content

Commit

Permalink
Merge pull request #2129 from matter-labs/vb-smart-contracts-v8-store…
Browse files Browse the repository at this point in the history
…-or-complete-withdraw

(Smart contracts v8) Remove withdrawals from execute blocks
  • Loading branch information
vladbochok authored Jan 17, 2022
2 parents 9a060ae + 52e2012 commit 053ede0
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 22 deletions.
2 changes: 1 addition & 1 deletion contracts/contracts/AdditionalZkSync.sol
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ contract AdditionalZkSync is Storage, Config, Events, ReentrancyGuard {
if (_tokenId <= MAX_FUNGIBLE_TOKEN_ID) {
bytes22 packedBalanceKey = packAddressAndTokenId(_owner, uint16(_tokenId));
increaseBalanceToWithdraw(packedBalanceKey, _amount);
emit WithdrawalPending(uint16(_tokenId), _amount);
emit WithdrawalPending(uint16(_tokenId), _owner, _amount);
} else {
require(_amount != 0, "Z"); // Unsupported nft amount
Operations.WithdrawNFT memory withdrawNftOp = Operations.WithdrawNFT(
Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/Events.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ interface Events {
event Withdrawal(uint16 indexed tokenId, uint128 amount);

/// @notice Event emitted when user funds are withdrawn from the zkSync state but not from contract
event WithdrawalPending(uint16 indexed tokenId, uint128 amount);
event WithdrawalPending(uint16 indexed tokenId, address recepient, uint128 amount);

/// @notice Event emitted when user NFT is withdrawn from the zkSync state and contract
event WithdrawalNFT(uint32 indexed tokenId);
Expand Down
69 changes: 55 additions & 14 deletions contracts/contracts/ZkSync.sol
Original file line number Diff line number Diff line change
Expand Up @@ -459,8 +459,7 @@ contract ZkSync is UpgradeableMaster, Storage, Config, Events, ReentrancyGuard {
withdrawnNFTs[op.tokenId] = address(_factory);
emit WithdrawalNFT(op.tokenId);
} catch {
pendingWithdrawnNFTs[op.tokenId] = op;
emit WithdrawalNFTPending(op.tokenId);
storePendingNFT(op);
}
}

Expand Down Expand Up @@ -489,17 +488,59 @@ contract ZkSync is UpgradeableMaster, Storage, Config, Events, ReentrancyGuard {
if (sent) {
emit Withdrawal(_tokenId, _amount);
} else {
bytes22 packedBalanceKey = packAddressAndTokenId(_recipient, _tokenId);
increaseBalanceToWithdraw(packedBalanceKey, _amount);
emit WithdrawalPending(_tokenId, _amount);
storePendingBalance(_tokenId, _recipient, _amount);
}
}

/// @dev Save NFT as pending to withdraw
function storePendingNFT(Operations.WithdrawNFT memory op) internal {
pendingWithdrawnNFTs[op.tokenId] = op;
emit WithdrawalNFTPending(op.tokenId);
}

/// @dev Increment `_recipient` balance to withdraw
function storePendingBalance(
uint16 _tokenId,
address _recipient,
uint128 _amount
) internal {
bytes22 packedBalanceKey = packAddressAndTokenId(_recipient, _tokenId);
increaseBalanceToWithdraw(packedBalanceKey, _amount);
emit WithdrawalPending(_tokenId, _recipient, _amount);
}

/// @dev helper function to process ETH/ERC20 withdrawal
function handleWithdrawFT(
bool _completeWithdrawals,
uint16 _tokenId,
address _addr,
uint128 _amount
) internal {
if (_completeWithdrawals) {
withdrawOrStore(_tokenId, _addr, _amount);
} else {
storePendingBalance(_tokenId, _addr, _amount);
}
}

/// @dev helper function to process NFT withdrawal
function handleWithdrawNFT(bool _completeWithdrawals, Operations.WithdrawNFT memory _op) internal {
if (_completeWithdrawals) {
withdrawOrStoreNFT(_op);
} else {
storePendingNFT(_op);
}
}

/// @dev Executes one block
/// @dev 1. Processes all pending operations (Send Exits, Complete priority requests)
/// @dev 1. Processes all priority operations or save them as pending
/// @dev 2. Finalizes block on Ethereum
/// @dev _executedBlockIdx is index in the array of the blocks that we want to execute together
function executeOneBlock(ExecuteBlockInfo memory _blockExecuteData, uint32 _executedBlockIdx) internal {
function executeOneBlock(
ExecuteBlockInfo memory _blockExecuteData,
uint32 _executedBlockIdx,
bool _completeWithdrawals
) internal {
// Ensure block was committed
require(
hashStoredBlockInfo(_blockExecuteData.storedBlock) ==
Expand All @@ -518,16 +559,16 @@ contract ZkSync is UpgradeableMaster, Storage, Config, Events, ReentrancyGuard {
Operations.PartialExit memory op = Operations.readPartialExitPubdata(pubData);
// Circuit guarantees that partial exits are available only for fungible tokens
require(op.tokenId <= MAX_FUNGIBLE_TOKEN_ID, "mf1");
withdrawOrStore(uint16(op.tokenId), op.owner, op.amount);
handleWithdrawFT(_completeWithdrawals, uint16(op.tokenId), op.owner, op.amount);
} else if (opType == Operations.OpType.ForcedExit) {
Operations.ForcedExit memory op = Operations.readForcedExitPubdata(pubData);
// Circuit guarantees that forced exits are available only for fungible tokens
require(op.tokenId <= MAX_FUNGIBLE_TOKEN_ID, "mf2");
withdrawOrStore(uint16(op.tokenId), op.target, op.amount);
handleWithdrawFT(_completeWithdrawals, uint16(op.tokenId), op.target, op.amount);
} else if (opType == Operations.OpType.FullExit) {
Operations.FullExit memory op = Operations.readFullExitPubdata(pubData);
if (op.tokenId <= MAX_FUNGIBLE_TOKEN_ID) {
withdrawOrStore(uint16(op.tokenId), op.owner, op.amount);
handleWithdrawFT(_completeWithdrawals, uint16(op.tokenId), op.owner, op.amount);
} else {
if (op.amount == 1) {
Operations.WithdrawNFT memory withdrawNftOp = Operations.WithdrawNFT(
Expand All @@ -538,12 +579,12 @@ contract ZkSync is UpgradeableMaster, Storage, Config, Events, ReentrancyGuard {
op.owner,
op.tokenId
);
withdrawOrStoreNFT(withdrawNftOp);
handleWithdrawNFT(_completeWithdrawals, withdrawNftOp);
}
}
} else if (opType == Operations.OpType.WithdrawNFT) {
Operations.WithdrawNFT memory op = Operations.readWithdrawNFTPubdata(pubData);
withdrawOrStoreNFT(op);
handleWithdrawNFT(_completeWithdrawals, op);
} else {
revert("l"); // unsupported op in block execution
}
Expand All @@ -556,14 +597,14 @@ contract ZkSync is UpgradeableMaster, Storage, Config, Events, ReentrancyGuard {
/// @notice Execute blocks, completing priority operations and processing withdrawals.
/// @notice 1. Processes all pending operations (Send Exits, Complete priority requests)
/// @notice 2. Finalizes block on Ethereum
function executeBlocks(ExecuteBlockInfo[] memory _blocksData) external nonReentrant {
function executeBlocks(ExecuteBlockInfo[] memory _blocksData, bool _completeWithdrawals) external nonReentrant {
requireActive();
governance.requireActiveValidator(msg.sender);

uint64 priorityRequestsExecuted = 0;
uint32 nBlocks = uint32(_blocksData.length);
for (uint32 i = 0; i < nBlocks; ++i) {
executeOneBlock(_blocksData[i], i);
executeOneBlock(_blocksData[i], i, _completeWithdrawals);
priorityRequestsExecuted += _blocksData[i].storedBlock.priorityOperations;
emit BlockVerification(_blocksData[i].storedBlock.blockNumber);
}
Expand Down
17 changes: 11 additions & 6 deletions core/lib/types/src/aggregated_operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,17 @@ impl BlocksExecuteOperation {
}

pub fn get_eth_tx_args(&self) -> Vec<Token> {
vec![Token::Array(
self.blocks
.iter()
.map(BlocksExecuteOperation::get_eth_tx_args_for_block)
.collect(),
)]
// make withdrawals in execute operation until the server and frontend are not updated
let complete_withdrawals = Token::Bool(true);
vec![
Token::Array(
self.blocks
.iter()
.map(BlocksExecuteOperation::get_eth_tx_args_for_block)
.collect(),
),
complete_withdrawals,
]
}

pub fn block_range(&self) -> (BlockNumber, BlockNumber) {
Expand Down

0 comments on commit 053ede0

Please sign in to comment.