Skip to content

Commit

Permalink
WIP: Add feature unset claimMap
Browse files Browse the repository at this point in the history
  • Loading branch information
ignasirv committed Nov 21, 2024
1 parent 42e97e8 commit ce1d428
Show file tree
Hide file tree
Showing 10 changed files with 238 additions and 103 deletions.
5 changes: 5 additions & 0 deletions contracts/interfaces/IBasePolygonZkEVMGlobalExitRoot.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ interface IBasePolygonZkEVMGlobalExitRoot {
*/
error OnlyGlobalExitRootUpdater();

/**
* @dev Thrown when the caller is not the globalExitRootRemover
*/
error OnlyGlobalExitRootRemover();

/**
* @dev Thrown when trying to insert a global exit root that is already set
*/
Expand Down
71 changes: 32 additions & 39 deletions contracts/v2/PolygonZkEVMBridgeV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ contract PolygonZkEVMBridgeV2 is
bytes4 private constant _PERMIT_SIGNATURE_DAI = 0x8fcbaf0c;

// Mainnet identifier
uint32 private constant _MAINNET_NETWORK_ID = 0;
uint32 internal constant _MAINNET_NETWORK_ID = 0;

// ZkEVM identifier
uint32 private constant _ZKEVM_NETWORK_ID = 1;
uint32 internal constant _ZKEVM_NETWORK_ID = 1;

// Leaf type asset
uint8 private constant _LEAF_TYPE_ASSET = 0;
Expand All @@ -48,7 +48,7 @@ contract PolygonZkEVMBridgeV2 is
uint8 private constant _LEAF_TYPE_MESSAGE = 1;

// Nullifier offset
uint256 private constant _MAX_LEAFS_PER_NETWORK = 2 ** 32;
uint256 internal constant _MAX_LEAFS_PER_NETWORK = 2 ** 32;

// Indicate where's the mainnet flag bit in the global index
uint256 private constant _GLOBAL_INDEX_MAINNET_FLAG = 2 ** 64;
Expand Down Expand Up @@ -840,21 +840,10 @@ contract PolygonZkEVMBridgeV2 is
uint32 leafIndex,
uint32 sourceBridgeNetwork
) external view returns (bool) {
uint256 globalIndex;

// For consistency with the previous setted nullifiers
if (
networkID == _MAINNET_NETWORK_ID &&
sourceBridgeNetwork == _ZKEVM_NETWORK_ID
) {
globalIndex = uint256(leafIndex);
} else {
globalIndex =
uint256(leafIndex) +
uint256(sourceBridgeNetwork) *
_MAX_LEAFS_PER_NETWORK;
}
(uint256 wordPos, uint256 bitPos) = _bitmapPositions(globalIndex);
(uint256 wordPos, uint256 bitPos) = _bitmapPositions(
leafIndex,
sourceBridgeNetwork
);
uint256 mask = (1 << bitPos);
return (claimedBitMap[wordPos] & mask) == mask;
}
Expand All @@ -868,21 +857,10 @@ contract PolygonZkEVMBridgeV2 is
uint32 leafIndex,
uint32 sourceBridgeNetwork
) private {
uint256 globalIndex;

// For consistency with the previous setted nullifiers
if (
networkID == _MAINNET_NETWORK_ID &&
sourceBridgeNetwork == _ZKEVM_NETWORK_ID
) {
globalIndex = uint256(leafIndex);
} else {
globalIndex =
uint256(leafIndex) +
uint256(sourceBridgeNetwork) *
_MAX_LEAFS_PER_NETWORK;
}
(uint256 wordPos, uint256 bitPos) = _bitmapPositions(globalIndex);
(uint256 wordPos, uint256 bitPos) = _bitmapPositions(
leafIndex,
sourceBridgeNetwork
);
uint256 mask = 1 << bitPos;
uint256 flipped = claimedBitMap[wordPos] ^= mask;
if (flipped & mask == 0) {
Expand Down Expand Up @@ -938,14 +916,29 @@ contract PolygonZkEVMBridgeV2 is
}

/**
* @notice Function decode an index into a wordPos and bitPos
* @param index Index
* @notice Computes globalIndex and decodes it into a wordPos and bitPos
* @param _leafIndex Index
* @param _sourceBridgeNetwork Origin network
*/
function _bitmapPositions(
uint256 index
) private pure returns (uint256 wordPos, uint256 bitPos) {
wordPos = uint248(index >> 8);
bitPos = uint8(index);
uint32 _leafIndex,
uint32 _sourceBridgeNetwork
) internal view returns (uint256 wordPos, uint256 bitPos) {
uint256 globalIndex;
// For consistency with the previous setted nullifiers
if (
networkID == _MAINNET_NETWORK_ID &&
_sourceBridgeNetwork == _ZKEVM_NETWORK_ID
) {
globalIndex = uint256(_leafIndex);
} else {
globalIndex =
uint256(_leafIndex) +
uint256(_sourceBridgeNetwork) *
_MAX_LEAFS_PER_NETWORK;
}
wordPos = uint248(globalIndex >> 8);
bitPos = uint8(globalIndex);
}

/**
Expand Down
12 changes: 11 additions & 1 deletion contracts/v2/interfaces/IBridgeL2SovereignChains.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ interface IBridgeL2SovereignChains is IPolygonZkEVMBridgeV2 {
*/
error OnlyBridgeManager();

/**
* @dev Thrown when sender is not the claims updater
*/
error OnlyClaimsUpdater();

/**
* @dev Thrown when bridge manager address is invalid
*/
Expand Down Expand Up @@ -71,6 +76,10 @@ interface IBridgeL2SovereignChains is IPolygonZkEVMBridgeV2 {
*/
error EmergencyStateNotAllowed();

/**
* @dev Thrown when trying to unset a not setted claim
*/
error ClaimNotSet();

function initialize(
uint32 _networkID,
Expand All @@ -81,6 +90,7 @@ interface IBridgeL2SovereignChains is IPolygonZkEVMBridgeV2 {
bytes memory _gasTokenMetadata,
address _bridgeManager,
address sovereignWETHAddress,
bool _sovereignWETHAddressIsNotMintable
bool _sovereignWETHAddressIsNotMintable,
address _claimsUpdater
) external;
}
112 changes: 81 additions & 31 deletions contracts/v2/sovereignChains/BridgeL2SovereignChain.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ pragma solidity 0.8.20;
import "../interfaces/IBridgeL2SovereignChains.sol";
import "../PolygonZkEVMBridgeV2.sol";

// WARNING: not audited

/**
* Sovereign chains bridge that will be deployed on all Sovereign chains
* Contract responsible to manage the token interactions with other networks
Expand All @@ -24,11 +22,25 @@ contract BridgeL2SovereignChain is
// Bridge manager address; can set custom mapping for any token
address public bridgeManager;

// Claims updater address; can unset claims from claimedBitmap.
// In case of initializing a chain with Full execution proofs, this address should be set to zero, otherwise, some malicious sequencer could insert invalid global exit roots, claim, go back and the execution would be correctly proved.
address public claimsUpdater;

/**
* @dev Emitted when a bridge manager is updated
*/
event SetBridgeManager(address bridgeManager);

/**
* @dev Emitted when a bridge manager is updated
*/
event SetClaimsUpdater(address claimsUpdater);

/**
* @dev Emitted when a claim is unset
*/
event UnsetClaim(uint32 leafIndex, uint32 sourceBridgeNetwork);

/**
* @dev Emitted when a token address is remapped by a sovereign token address
*/
Expand Down Expand Up @@ -81,6 +93,7 @@ contract BridgeL2SovereignChain is
* @param _bridgeManager bridge manager address
* @param _sovereignWETHAddress sovereign WETH address
* @param _sovereignWETHAddressIsNotMintable Flag to indicate if the wrapped ETH is not mintable
* @param _claimsUpdater Address that can unset claims from claimedBitmap. In case of initializing a chain with Full execution proofs, this address should be set to zero, otherwise, some malicious sequencer could insert invalid global exit roots, claim, go back and the execution would be correctly proved.
*/
function initialize(
uint32 _networkID,
Expand All @@ -91,12 +104,14 @@ contract BridgeL2SovereignChain is
bytes memory _gasTokenMetadata,
address _bridgeManager,
address _sovereignWETHAddress,
bool _sovereignWETHAddressIsNotMintable
bool _sovereignWETHAddressIsNotMintable,
address _claimsUpdater
) public virtual initializer {
networkID = _networkID;
globalExitRootManager = _globalExitRootManager;
polygonRollupManager = _polygonRollupManager;
bridgeManager = _bridgeManager;
claimsUpdater = _claimsUpdater;

// Set gas token
if (_gasTokenAddress == address(0)) {
Expand Down Expand Up @@ -167,10 +182,20 @@ contract BridgeL2SovereignChain is
_;
}

modifier onlyClaimsUpdater() {
if (claimsUpdater != msg.sender) {
revert OnlyClaimsUpdater();
}
_;
}

/**
* @notice Remap multiple wrapped tokens to a new sovereign token address
* @dev This function is a "multi/batch call" to `setSovereignTokenAddress`
* @param sovereignTokenAddresses Array of SovereignTokenAddress to remap
* @param originNetworks Array of Origin networks
* @param originTokenAddresses Array od Origin token addresses, 0 address is reserved for ether
* @param sovereignTokenAddresses Array of Addresses of the sovereign wrapped token
* @param isNotMintable Array of Flags to indicate if the wrapped token is not mintable
*/
function setMultipleSovereignTokenAddress(
uint32[] memory originNetworks,
Expand All @@ -197,32 +222,6 @@ contract BridgeL2SovereignChain is
}
}

/**
* @notice Remap a wrapped token to a new sovereign token address
* @dev This function is used to allow any existing token to be mapped with
* origin token.
* @notice If this function is called multiple times for the same existingTokenAddress,
* this will override the previous calls and only keep the last sovereignTokenAddress.
* @notice The tokenInfoToWrappedToken mapping value is replaced by the new sovereign address but it's not the case for the wrappedTokenToTokenInfo map where the value is added, this way user will always be able to withdraw their tokens
* @param originNetwork Origin network
* @param originTokenAddress Origin token address, 0 address is reserved for ether
* @param sovereignTokenAddress Address of the sovereign wrapped token
* @param isNotMintable Flag to indicate if the wrapped token is not mintable
*/
function setSovereignTokenAddress(
uint32 originNetwork,
address originTokenAddress,
address sovereignTokenAddress,
bool isNotMintable
) external onlyBridgeManager {
_setSovereignTokenAddress(
originNetwork,
originTokenAddress,
sovereignTokenAddress,
isNotMintable
);
}

/**
* @notice Remap a wrapped token to a new sovereign token address
* @dev This function is used to allow any existing token to be mapped with
Expand Down Expand Up @@ -304,7 +303,8 @@ contract BridgeL2SovereignChain is

if (
tokenInfoToWrappedToken[tokenInfoHash] == address(0) ||
tokenInfoToWrappedToken[tokenInfoHash] == legacySovereignTokenAddress
tokenInfoToWrappedToken[tokenInfoHash] ==
legacySovereignTokenAddress
) {
revert TokenNotRemapped();
}
Expand Down Expand Up @@ -379,6 +379,25 @@ contract BridgeL2SovereignChain is
);
}

/**
* @notice unset multiple claims from the claimedBitmap
* @dev This function is a "multi/batch call" to `unsetClaimedBitmap`
* @param leafIndexes Array of Index
* @param sourceBridgeNetworks Array of Origin networks
*/
function unsetMultipleClaimedBitmap(
uint32[] memory leafIndexes,
uint32[] memory sourceBridgeNetworks
) external onlyClaimsUpdater {
if (leafIndexes.length != sourceBridgeNetworks.length) {
revert InputArraysLengthMismatch();
}

for (uint256 i = 0; i < leafIndexes.length; i++) {
_unsetClaimedBitmap(leafIndexes[i], sourceBridgeNetworks[i]);
}
}

/**
* @notice Updated bridge manager address
* @param _bridgeManager Bridge manager address
Expand All @@ -391,6 +410,17 @@ contract BridgeL2SovereignChain is
emit SetBridgeManager(bridgeManager);
}

/**
* @notice Updated bridge manager address
* @param _claimsUpdater Bridge manager address
*/
function setClaimsUpdater(
address _claimsUpdater
) external onlyClaimsUpdater {
claimsUpdater = _claimsUpdater;
emit SetClaimsUpdater(claimsUpdater);
}

/**
* @notice Burn tokens from wrapped token to execute the bridge, if the token is not mintable it will be transferred
* note This function has been extracted to be able to override it by other contracts like Bridge2SovereignChain
Expand Down Expand Up @@ -441,6 +471,26 @@ contract BridgeL2SovereignChain is
}
}

/*
* @notice unset a claim from the claimedBitmap
* @param leafIndex Index
* @param sourceBridgeNetwork Origin network
*/
function _unsetClaimedBitmap(
uint32 leafIndex,
uint32 sourceBridgeNetwork
) private {
(uint256 wordPos, uint256 bitPos) = _bitmapPositions(leafIndex, sourceBridgeNetwork);
uint256 mask = ~(1 << bitPos);
// Check if the bit is already unset
if ((claimedBitMap[wordPos] & (1 << bitPos)) == 0) {
revert ClaimNotSet();
}
// Use bitwise AND with the negated mask to unset the bit
claimedBitMap[wordPos] &= mask;
emit UnsetClaim(leafIndex, sourceBridgeNetwork);
}

// @note This function is not used in the current implementation. We overwrite it to improve deployed bytecode size
function activateEmergencyState()
external
Expand Down
Loading

0 comments on commit ce1d428

Please sign in to comment.