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

feat(protocol): Additional integration tests, solidity bump, reduce TokenVault contract size #13155

Merged
merged 17 commits into from
Feb 16, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
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
3 changes: 2 additions & 1 deletion packages/protocol/.prettierrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
{
"files": ["*.sol", "*.ts"],
"options": {
"tabWidth": 4
"tabWidth": 4,
"compiler": "^0.8.18"
}
}
],
Expand Down
2 changes: 1 addition & 1 deletion packages/protocol/.solhint.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"extends": "solhint:recommended",
"rules": {
"avoid-low-level-calls": "off",
"compiler-version": ["error", "^0.8.0"],
"compiler-version": ["error", "^0.8.18"],
"func-visibility": ["warn", { "ignoreConstructors": true }],
"max-line-length": ["warn", 80],
"no-empty-blocks": "off",
Expand Down
15 changes: 6 additions & 9 deletions packages/protocol/contracts/L1/TaikoData.sol
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,12 @@ library TaikoData {

// This struct takes 9 slots.
struct State {
// block id => block hash (some blocks' hashes won't be persisted,
// only the latest one if verified in a batch)
mapping(uint256 => bytes32) l2Hashes;
// block id => ProposedBlock
mapping(uint256 => ProposedBlock) proposedBlocks;
// block id => parent hash => fork choice
mapping(uint256 => mapping(bytes32 => ForkChoice)) forkChoices;
// proposer => commitSlot => hash(commitHash, commitHeight)
mapping(address => mapping(uint256 => bytes32)) commits;
// some blocks' hashes won't be persisted,
// only the latest one if verified in a batch
mapping(uint256 blockId => bytes32 blockHash) l2Hashes;
mapping(uint256 blockId => ProposedBlock proposedBlock) proposedBlocks;
mapping(uint256 blockId => mapping(bytes32 parentHash => ForkChoice forkChoice)) forkChoices;
mapping(address proposerAddress => mapping(uint256 commitSlot => bytes32 commitHash)) commits;
// Never or rarely changed
uint64 genesisHeight;
uint64 genesisTimestamp;
Expand Down
2 changes: 1 addition & 1 deletion packages/protocol/contracts/L1/TaikoL1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ contract TaikoL1 is EssentialContract, IHeaderSync, TaikoEvents {
});
LibVerifying.verifyBlocks({
state: state,
config: getConfig(),
config: config,
resolver: AddressResolver(this),
maxBlocks: config.maxVerificationsPerTx,
checkHalt: false
Expand Down
3 changes: 2 additions & 1 deletion packages/protocol/contracts/L1/libs/LibProving.sol
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ library LibProving {
error L1_ANCHOR_RECEIPT_ADDR();
error L1_ANCHOR_RECEIPT_TOPICS();
error L1_ANCHOR_RECEIPT_DATA();
error L1_HALTED();

function proveBlock(
TaikoData.State storage state,
Expand All @@ -81,7 +82,7 @@ library LibProving {
uint256 blockId,
bytes[] calldata inputs
) public {
assert(!LibUtils.isHalted(state));
if (LibUtils.isHalted(state)) revert L1_HALTED();

// Check and decode inputs
if (inputs.length != 3) revert L1_INPUT_SIZE();
Expand Down
4 changes: 2 additions & 2 deletions packages/protocol/contracts/L2/TaikoL2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ contract TaikoL2 is AddressResolver, ReentrancyGuard, IHeaderSync {

// Mapping from L2 block numbers to their block hashes.
// All L2 block hashes will be saved in this mapping.
mapping(uint256 => bytes32) private _l2Hashes;
mapping(uint256 blockNumber => bytes32 blockHash) private _l2Hashes;

// Mapping from L1 block numbers to their block hashes.
// Note that only hashes of L1 blocks where at least one L2
// block has been proposed will be saved in this mapping.
mapping(uint256 => bytes32) private _l1Hashes;
mapping(uint256 blockNumber => bytes32 blockHash) private _l1Hashes;

// A hash to check te integrity of public inputs.
bytes32 private _publicInputHash;
Expand Down
2 changes: 1 addition & 1 deletion packages/protocol/contracts/bridge/EtherVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ contract EtherVault is EssentialContract {
* State Variables *
*********************/

mapping(address => bool) private _authorizedAddrs;
mapping(address addr => bool isAuthorized) private _authorizedAddrs;
uint256[49] private __gap;

/*********************
Expand Down
83 changes: 48 additions & 35 deletions packages/protocol/contracts/bridge/TokenVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,20 @@ contract TokenVault is EssentialContract {
*********************/

// Tracks if a token on the current chain is a canonical or bridged token.
mapping(address => bool) public isBridgedToken;
mapping(address tokenAddress => bool isBridged) public isBridgedToken;

// Mappings from bridged tokens to their canonical tokens.
mapping(address => CanonicalERC20) public bridgedToCanonical;
mapping(address bridgedAddress => CanonicalERC20 canonicalErc20)
public bridgedToCanonical;

// Mappings from canonical tokens to their bridged tokens.
// Also storing chainId for tokens across other chains aside from Ethereum.
// chainId => canonical address => bridged address
mapping(uint256 => mapping(address => address)) public canonicalToBridged;
mapping(uint256 chainId => mapping(address canonicalAddress => address bridgedAddress))
public canonicalToBridged;

// Tracks the token and amount associated with a message hash.
mapping(bytes32 => MessageDeposit) public messageDeposits;
mapping(bytes32 msgHash => MessageDeposit messageDeposit)
public messageDeposits;

uint256[47] private __gap;

Expand Down Expand Up @@ -108,6 +110,21 @@ contract TokenVault is EssentialContract {
uint256 amount
);

/*********************
* Custom Errors*
*********************/

error TOKENVAULT_INVALID_TO();
error TOKENVAULT_INVALID_VALUE();
error TOKENVAULT_INVALID_CALL_VALUE();
error TOKENVAULT_INVALID_TOKEN();
error TOKENVAULT_INVALID_AMOUNT();
error TOKENVAULT_CANONICAL_TOKEN_NOT_FOUND();
error TOKENVAULT_INVALID_OWNER();
error TOKENVAULT_INVALID_SRC_CHAIN_ID();
error TOKENVAULT_MESSAGE_NOT_FAILED();
error TOKENVAULT_INVALID_SENDER();

/*********************
* External Functions*
*********************/
Expand All @@ -134,12 +151,11 @@ contract TokenVault is EssentialContract {
address refundAddress,
string memory memo
) external payable nonReentrant {
require(
to != address(0) &&
to != resolve(destChainId, "token_vault", false),
"V:to"
);
require(msg.value > processingFee, "V:msgValue");
if (
to == address(0) || to == resolve(destChainId, "token_vault", false)
) revert TOKENVAULT_INVALID_TO();

if (msg.value <= processingFee) revert TOKENVAULT_INVALID_VALUE();

IBridge.Message memory message;
message.destChainId = destChainId;
Expand All @@ -152,7 +168,7 @@ contract TokenVault is EssentialContract {
message.memo = memo;

// prevent future PRs from changing the callValue when it must be zero
require(message.callValue == 0, "V:callValue");
if (message.callValue != 0) revert TOKENVAULT_INVALID_CALL_VALUE();

bytes32 msgHash = IBridge(resolve("bridge", false)).sendMessage{
value: msg.value
Expand Down Expand Up @@ -191,13 +207,13 @@ contract TokenVault is EssentialContract {
address refundAddress,
string memory memo
) external payable nonReentrant {
require(
to != address(0) &&
to != resolve(destChainId, "token_vault", false),
"V:to"
);
require(token != address(0), "V:token");
require(amount > 0, "V:amount");
if (
to == address(0) || to == resolve(destChainId, "token_vault", false)
) revert TOKENVAULT_INVALID_TO();

if (token == address(0)) revert TOKENVAULT_INVALID_TOKEN();

if (amount == 0) revert TOKENVAULT_INVALID_AMOUNT();

CanonicalERC20 memory canonicalToken;
uint256 _amount;
Expand All @@ -206,7 +222,8 @@ contract TokenVault is EssentialContract {
if (isBridgedToken[token]) {
BridgedERC20(token).bridgeBurnFrom(msg.sender, amount);
canonicalToken = bridgedToCanonical[token];
require(canonicalToken.addr != address(0), "V:canonicalToken");
if (canonicalToken.addr == address(0))
revert TOKENVAULT_CANONICAL_TOKEN_NOT_FOUND();
_amount = amount;
} else {
// is a canonical token, meaning, it lives on this chain
Expand Down Expand Up @@ -271,20 +288,19 @@ contract TokenVault is EssentialContract {
IBridge.Message calldata message,
bytes calldata proof
) external nonReentrant {
require(message.owner != address(0), "B:owner");
require(message.srcChainId == block.chainid, "B:srcChainId");
if (message.owner == address(0)) revert TOKENVAULT_INVALID_OWNER();
if (message.srcChainId != block.chainid)
revert TOKENVAULT_INVALID_SRC_CHAIN_ID();

IBridge bridge = IBridge(resolve("bridge", false));
bytes32 msgHash = bridge.hashMessage(message);

address token = messageDeposits[msgHash].token;
uint256 amount = messageDeposits[msgHash].amount;
require(token != address(0), "B:ERC20Released");
require(
bridge.isMessageFailed(msgHash, message.destChainId, proof),
"V:notFailed"
);
if (token == address(0)) revert TOKENVAULT_INVALID_TOKEN();

if (!bridge.isMessageFailed(msgHash, message.destChainId, proof))
revert TOKENVAULT_MESSAGE_NOT_FAILED();
messageDeposits[msgHash] = MessageDeposit(address(0), 0);

if (amount > 0) {
Expand Down Expand Up @@ -321,10 +337,8 @@ contract TokenVault is EssentialContract {
uint256 amount
) external nonReentrant onlyFromNamed("bridge") {
IBridge.Context memory ctx = IBridge(msg.sender).context();
require(
ctx.sender == resolve(ctx.srcChainId, "token_vault", false),
"V:sender"
);
if (ctx.sender != resolve(ctx.srcChainId, "token_vault", false))
revert TOKENVAULT_INVALID_SENDER();

address token;
if (canonicalToken.chainId == block.chainid) {
Expand Down Expand Up @@ -367,12 +381,11 @@ contract TokenVault is EssentialContract {
function _deployBridgedToken(
CanonicalERC20 calldata canonicalToken
) private returns (address bridgedToken) {
bytes32 salt = keccak256(
abi.encodePacked(canonicalToken.chainId, canonicalToken.addr)
);
bridgedToken = Create2Upgradeable.deploy(
0, // amount of Ether to send
salt,
keccak256(
abi.encodePacked(canonicalToken.chainId, canonicalToken.addr)
),
type(BridgedERC20).creationCode
);

Expand Down
2 changes: 1 addition & 1 deletion packages/protocol/contracts/bridge/libs/LibBridgeData.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ library LibBridgeData {
struct State {
uint256 nextMessageId;
IBridge.Context ctx; // 3 slots
mapping(bytes32 => bool) etherReleased;
mapping(bytes32 msgHash => bool released) etherReleased;
uint256[45] __gap;
}

Expand Down
3 changes: 2 additions & 1 deletion packages/protocol/contracts/test/libs/TestLibProving.sol
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ library TestLibProving {
error L1_ANCHOR_RECEIPT_ADDR();
error L1_ANCHOR_RECEIPT_TOPICS();
error L1_ANCHOR_RECEIPT_DATA();
error L1_HALTED();

function proveBlock(
TaikoData.State storage state,
Expand All @@ -87,7 +88,7 @@ library TestLibProving {
uint256 blockId,
bytes[] calldata inputs
) public {
assert(!LibUtils.isHalted(state));
if (LibUtils.isHalted(state)) revert L1_HALTED();

// Check and decode inputs
if (inputs.length != 3) revert L1_INPUT_SIZE();
Expand Down
2 changes: 1 addition & 1 deletion packages/protocol/contracts/thirdparty/AddressManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ contract AddressManager is OwnableUpgradeable {
* Variables *
*************/

mapping(bytes32 => address) private addresses;
mapping(bytes32 nameHash => address addr) private addresses;

/**********
* Events *
Expand Down
5 changes: 3 additions & 2 deletions packages/protocol/contracts/thirdparty/ERC20Upgradeable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,10 @@ contract ERC20Upgradeable is
IERC20Upgradeable,
IERC20MetadataUpgradeable
{
mapping(address => uint256) private _balances;
mapping(address owner => uint256 balance) private _balances;

mapping(address => mapping(address => uint256)) private _allowances;
mapping(address owner => mapping(address spender => uint256 allowance))
private _allowances;

uint256 private _totalSupply;

Expand Down
3 changes: 2 additions & 1 deletion packages/protocol/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import "@openzeppelin/hardhat-upgrades";
import "@typechain/hardhat";
import "hardhat-abi-exporter";
import "hardhat-gas-reporter";
import "hardhat-contract-sizer";
import { HardhatUserConfig } from "hardhat/config";
import "solidity-coverage";
import "solidity-docgen";
Expand Down Expand Up @@ -133,7 +134,7 @@ const config: HardhatUserConfig = {
},
},
},
version: "0.8.9",
version: "0.8.18",
},
};

Expand Down
12 changes: 7 additions & 5 deletions packages/protocol/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"export:abi": "pnpm hardhat clear-abi && pnpm hardhat export-abi",
"export:docs": "pnpm hardhat docgen && pnpm prettier --write ../website/pages/docs/reference/contract-documentation/**/*.md",
"clean": "rm -rf abis cache && pnpm hardhat clean",
"lint:sol": "pnpm prettier '**/*.sol' --write && pnpm solhint 'contracts/**/*.sol' --fix",
"lint:sol": "pnpm prettier '**/*.sol' --write",
"eslint": "pnpm exec eslint --ignore-path .eslintignore --ext .js,.ts .",
"eslint:fix": "pnpm exec eslint --ignore-path .eslintignore --ext .js,.ts . --fix",
"test": "pnpm hardhat test --grep '^[^integration]'",
Expand All @@ -18,9 +18,10 @@
"test:genesis": "./test/genesis/generate_genesis.test.sh",
"test:integration": "TEST_TYPE=integration ./test/test_integration.sh",
"test:tokenomics": "TEST_TYPE=tokenomics ./test/test_integration.sh",
"test:all": "pnpm run test && pnpm run test:integration && pnpm run test:tokenomics",
"test:all": "pnpm run test && pnpm run test:integration && pnpm run test:tokenomics && pnpm run test:genesis",
"deploy:hardhat": "./scripts/download_solc.sh && LOG_LEVEL=debug pnpm hardhat deploy_L1 --network hardhat --dao-vault 0xdf08f82de32b8d460adbe8d72043e3a7e25a3b39 --team-vault 0xdf08f82de32b8d460adbe8d72043e3a7e25a3b39 --l2-genesis-block-hash 0xee1950562d42f0da28bd4550d88886bc90894c77c9c9eaefef775d4c8223f259 --bridge-funder-private-key ddbf12f72c946bb1e6de5eaf580c51db51828ba198d9b0dba9c7d48ec748dc04 --bridge-fund 0xff --oracle-prover 0xdf08f82de32b8d460adbe8d72043e3a7e25a3b39 --confirmations 1",
"lint-staged": "lint-staged --allow-empty"
"lint-staged": "lint-staged --allow-empty",
"sizer": "pnpm hardhat size-contracts"
},
"lint-staged": {
"*.sol": "pnpm lint:sol",
Expand Down Expand Up @@ -66,14 +67,15 @@
"glob": "^8.1.0",
"hardhat": "^2.8.3",
"hardhat-abi-exporter": "^2.10.0",
"hardhat-contract-sizer": "^2.8.0",
"hardhat-docgen": "^1.3.0",
"hardhat-gas-reporter": "^1.0.7",
"lint-staged": "^12.3.4",
"merkle-patricia-tree": "^4.2.4",
"prettier": "^2.5.1",
"prettier-plugin-solidity": "^1.0.0-beta.19",
"prettier-plugin-solidity": "^1.1.2",
"rlp": "^3.0.0",
"solhint": "^3.3.7",
"solhint": "^3.3.8",
"solidity-coverage": "^0.8.2",
"solidity-docgen": "^0.6.0-beta.34",
"ts-node": "^10.5.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/protocol/scripts/download_solc.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ if [ -f "solc" ]; then
exit 0
fi

VERSION=v0.8.9
VERSION=v0.8.18

if [ "$(uname)" = 'Darwin' ]; then
SOLC_FILE_NAME=solc-macos
Expand Down
Loading