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
Hyperchains Integration #439
base: dev
Are you sure you want to change the base?
Hyperchains Integration #439
Conversation
What ❔This PR introduces invariant tests with fuzzed inputs to test the integration of hyperchains. These tests involve depositing and withdrawing tokens through the bridgehub interface. The primary functionality is based on selecting random calls from the withdraw/deposit functions, executing the calls, and verifying how balances change after each call and if the invariants are kept. Type of deposits:
Type of withdrawals
Calls such as deposit and withdraw are categorized based on the type of token used (ERC20/ETH). Additionally, deposit functions consider whether the token is base or non-base and select the appropriate call. Changed l1 contract deployment base scripts to l1-contract-foundry scripts.
Important!!! forge-std was bump to v1.8.2 Used scripts:
|
address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); | ||
// Create2Factory deterministic bytecode. | ||
// https://github.com/Arachnid/deterministic-deployment-proxy | ||
bytes internal constant CREATE2_FACTORY_BYTECODE = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use Solidity version of create2 factory instead? This way it would be easier for us to migrate zkSync L1 tests when we would use the L1 contract codebase on L2.
bool hasGetName = false; | ||
for (uint256 i = 0; i < selectors.length; i++) { | ||
if (selectors[i] == bytes4(keccak256("getName()"))) { | ||
selectors[i] = selectors[selectors.length - 1]; | ||
hasGetName = true; | ||
break; | ||
} | ||
} | ||
if (hasGetName) { | ||
bytes4[] memory newSelectors = new bytes4[](selectors.length - 1); | ||
for (uint256 i = 0; i < selectors.length - 1; i++) { | ||
newSelectors[i] = selectors[i]; | ||
} | ||
return newSelectors; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bool hasGetName = false; | |
for (uint256 i = 0; i < selectors.length; i++) { | |
if (selectors[i] == bytes4(keccak256("getName()"))) { | |
selectors[i] = selectors[selectors.length - 1]; | |
hasGetName = true; | |
break; | |
} | |
} | |
if (hasGetName) { | |
bytes4[] memory newSelectors = new bytes4[](selectors.length - 1); | |
for (uint256 i = 0; i < selectors.length - 1; i++) { | |
newSelectors[i] = selectors[i]; | |
} | |
return newSelectors; | |
} | |
for (uint256 i = 0; i < selectors.length; i++) { | |
if (selectors[i] == bytes4(keccak256("getName()"))) { | |
selectors[i] = selectors[selectors.length - 1]; | |
// Pop the last element from the array | |
assembly { | |
mstore(selectors, sub(mload(selectors), 1)) | |
} | |
break; | |
} | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we mirror this change to main scripts (in l1-contracts-foundry) in another pr?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can change it in this PR
return selectors; | ||
} | ||
|
||
function getAdminSelectors() public pure returns (bytes4[] memory) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can always use getAllSelectors
over getAdminSelectors
/getExecutorSelectors
/getGettersSelectors
/getMailboxSelectors
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We used it, but this function requires ffi, which has to be set explicitly in test environment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FFI in test is not ideal, maybe we can find middle ground solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is how consensus-shipyard
did it, can we make it similar?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This approach uses command from foundry to inspect the contract, I don't see a way to call foundry command in testing environment without ffi.
@@ -77,7 +77,7 @@ contract DeployErc20Script is Script { | |||
mint: token.mint | |||
}); | |||
console.log("Token deployed at:", tokenAddress); | |||
token.addr = tokenAddress; | |||
config.tokens[i].addr = tokenAddress; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this an intentional change? Why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, because the token
variable is just a copy and does not overwrite the config value. As a result, all token addresses were the default value (address(0)), which was visible in the deployment output configuration.
(bool success, ) = tokenAddress.call( | ||
abi.encodeWithSignature("mint(address,uint256)", config.deployerAddress, mint) | ||
); | ||
(bool success,) = | ||
tokenAddress.call(abi.encodeWithSignature("mint(address,uint256)", config.deployerAddress, mint)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And even better to cast tokenAddress
to Token
type and call mint
there.
return selectors; | ||
} | ||
|
||
function getAdminSelectors() public pure returns (bytes4[] memory) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FFI in test is not ideal, maybe we can find middle ground solution.
return selectors; | ||
} | ||
|
||
function getAdminSelectors() public pure returns (bytes4[] memory) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is how consensus-shipyard
did it, can we make it similar?
import {L1ERC20Bridge} from "contracts/bridge/L1ERC20Bridge.sol"; | ||
import {DiamondProxy} from "contracts/state-transition/chain-deps/DiamondProxy.sol"; | ||
|
||
contract DeployL1Script is Script { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we maybe import this contract directly from the repo to not copy-pasting it?
l1-contracts/test/foundry/integration/_SharedL1ContractDeployer.t.sol
Outdated
Show resolved
Hide resolved
description = RegisterHyperchainsScript.HyperchainDescription({ | ||
hyperchainChainId: __chainId, | ||
baseToken: __baseToken, | ||
bridgehubCreateNewChainSalt: 0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Worth to test it too?
revert changes revert changes revert changes revert changes
57d20fc
to
aaa587f
Compare
No description provided.