From 16993cdb081b831420c7e86d981afd11726197d1 Mon Sep 17 00:00:00 2001
From: Daniel Wang <99078276+dantaik@users.noreply.github.com>
Date: Wed, 22 Feb 2023 11:42:23 +0800
Subject: [PATCH] feat(protocol): partially randomize prover reward (#13184)

Co-authored-by: dave | d1onys1us <13951458+d1onys1us@users.noreply.github.com>
Co-authored-by: David <david@taiko.xyz>
---
 packages/protocol/contracts/L1/TaikoData.sol  |  1 +
 packages/protocol/contracts/L1/TaikoL1.sol    |  6 ++
 .../protocol/contracts/L1/libs/LibProving.sol |  5 +-
 .../protocol/contracts/L1/libs/LibUtils.sol   |  2 +-
 .../contracts/L1/libs/LibVerifying.sol        | 90 +++++++++++++++----
 packages/protocol/contracts/L2/TaikoL2.sol    |  2 +-
 .../contracts/libs/LibReceiptDecoder.sol      |  4 +-
 .../contracts/libs/LibSharedConfig.sol        |  1 +
 .../protocol/contracts/libs/LibTxDecoder.sol  |  8 +-
 .../protocol/contracts/libs/LibTxUtils.sol    |  2 +-
 .../contracts/test/L1/TestTaikoL1.sol         |  1 +
 .../test/L1/TestTaikoL1EnableTokenomics.sol   |  1 +
 .../contracts/test/L1/TestTaikoL2.sol         |  1 +
 .../L1/TestTaikoL2EnablePublicInputsCheck.sol |  1 +
 .../contracts/test/libs/TestLibProving.sol    |  5 +-
 .../test/thirdparty/TestLibRLPReader.sol      |  2 +-
 .../contracts/thirdparty/LibBytesUtils.sol    |  4 +-
 .../contracts/thirdparty/LibMerkleTrie.sol    |  8 +-
 .../contracts/thirdparty/LibRLPReader.sol     |  4 +-
 .../contracts/thirdparty/LibRLPWriter.sol     | 10 +--
 20 files changed, 113 insertions(+), 45 deletions(-)

diff --git a/packages/protocol/contracts/L1/TaikoData.sol b/packages/protocol/contracts/L1/TaikoData.sol
index 41886b9bcea..8843adfaada 100644
--- a/packages/protocol/contracts/L1/TaikoData.sol
+++ b/packages/protocol/contracts/L1/TaikoData.sol
@@ -38,6 +38,7 @@ library TaikoData {
         uint64 proofTimeCap;
         uint64 bootstrapDiscountHalvingPeriod;
         uint64 initialUncleDelay;
+        uint64 proverRewardRandomizedPercentage;
         bool enableTokenomics;
         bool enablePublicInputsCheck;
         bool enableProofValidation;
diff --git a/packages/protocol/contracts/L1/TaikoL1.sol b/packages/protocol/contracts/L1/TaikoL1.sol
index 2e199096adb..63593e53758 100644
--- a/packages/protocol/contracts/L1/TaikoL1.sol
+++ b/packages/protocol/contracts/L1/TaikoL1.sol
@@ -287,6 +287,12 @@ contract TaikoL1 is
         return LibUtils.getUncleProofDelay(state, getConfig(), blockId);
     }
 
+    function getProverRewardBips(
+        uint256 numProvers
+    ) public view returns (uint256[] memory) {
+        return LibVerifying.getProverRewardBips(getConfig(), numProvers);
+    }
+
     function getConfig() public pure virtual returns (TaikoData.Config memory) {
         return LibSharedConfig.getConfig();
     }
diff --git a/packages/protocol/contracts/L1/libs/LibProving.sol b/packages/protocol/contracts/L1/libs/LibProving.sol
index 3614fa5c75d..1f99af5003a 100644
--- a/packages/protocol/contracts/L1/libs/LibProving.sol
+++ b/packages/protocol/contracts/L1/libs/LibProving.sol
@@ -284,7 +284,7 @@ library LibProving {
         bytes32 blockHash = evidence.header.hashBlockHeader();
 
         if (!skipZKPVerification) {
-            for (uint256 i = 0; i < config.zkProofsPerBlock; ++i) {
+            for (uint256 i; i < config.zkProofsPerBlock; ++i) {
                 bytes32 instance = keccak256(
                     abi.encode(
                         blockHash,
@@ -292,6 +292,7 @@ library LibProving {
                         evidence.meta.txListHash
                     )
                 );
+
                 if (
                     !proofVerifier.verifyZKP({
                         verifierId: string(
@@ -357,7 +358,7 @@ library LibProving {
                 })
             ) revert L1_TOO_LATE();
 
-            for (uint256 i = 0; i < fc.provers.length; ++i) {
+            for (uint256 i; i < fc.provers.length; ++i) {
                 if (fc.provers[i] == prover) revert L1_DUP_PROVERS();
             }
 
diff --git a/packages/protocol/contracts/L1/libs/LibUtils.sol b/packages/protocol/contracts/L1/libs/LibUtils.sol
index a5d8749093d..58073f30e9f 100644
--- a/packages/protocol/contracts/L1/libs/LibUtils.sol
+++ b/packages/protocol/contracts/L1/libs/LibUtils.sol
@@ -98,7 +98,7 @@ library LibUtils {
     ) internal view returns (uint256 newFeeBase, uint256 tRelBp) {
         if (tAvg == 0) {
             newFeeBase = state.feeBase;
-            tRelBp = 0;
+            // tRelBp = 0;
         } else {
             uint256 _tAvg = tAvg > config.proofTimeCap
                 ? config.proofTimeCap
diff --git a/packages/protocol/contracts/L1/libs/LibVerifying.sol b/packages/protocol/contracts/L1/libs/LibVerifying.sol
index 8b18be76b55..13b4d884335 100644
--- a/packages/protocol/contracts/L1/libs/LibVerifying.sol
+++ b/packages/protocol/contracts/L1/libs/LibVerifying.sol
@@ -62,7 +62,7 @@ library LibVerifying {
         bytes32 latestL2Hash = state.l2Hashes[
             latestL2Height % config.blockHashHistory
         ];
-        uint64 processed = 0;
+        uint64 processed;
 
         for (
             uint256 i = state.latestVerifiedId + 1;
@@ -144,6 +144,63 @@ library LibVerifying {
         reward = (reward * (10000 - config.rewardBurnBips)) / 10000;
     }
 
+    /**
+     * A function that calculates the weight for each prover based on the number
+     * of provers and a random seed. The weight is a number between 0 and 100.
+     * The sum of the weights will be 100. The weight is calculated in bips,
+     * so the weight of 1 will be 0.01%.
+     *
+     * @param config The config of the Taiko protocol (stores the randomized percentage)
+     * @param numProvers The number of provers
+     * @return bips The weight of each prover in bips
+     */
+    function getProverRewardBips(
+        TaikoData.Config memory config,
+        uint256 numProvers
+    ) public view returns (uint256[] memory bips) {
+        bips = new uint256[](numProvers);
+
+        uint256 randomized = config.proverRewardRandomizedPercentage;
+        if (randomized > 100) {
+            randomized = 100;
+        }
+
+        uint256 sum;
+        uint256 i;
+
+        // Calculate the randomized weight
+        if (randomized > 0) {
+            unchecked {
+                uint256 seed = block.prevrandao;
+                for (i = 0; i < numProvers; ++i) {
+                    // Get an uint16, note that smart provers may
+                    // choose the right timing to maximize their rewards
+                    // which helps blocks to be verified sooner.
+                    bips[i] = uint16(seed * (1 + i));
+                    sum += bips[i];
+                }
+                for (i = 0; i < numProvers; ++i) {
+                    bips[i] = (bips[i] * 100 * randomized) / sum;
+                }
+            }
+        }
+
+        // Add the fixed weight. If there are 5 provers, then their
+        // weight will be:
+        // 1<<4=16, 1<<3=8, 1<<2=4, 1<<1=2, 1<<0=1
+        if (randomized != 100) {
+            unchecked {
+                sum = (1 << numProvers) - 1;
+                uint256 fix = 100 - randomized;
+                uint256 weight = 1 << (numProvers - 1);
+                for (i = 0; i < numProvers; ++i) {
+                    bips[i] += (weight * 100 * fix) / sum;
+                    weight >>= 1;
+                }
+            }
+        }
+    }
+
     function _refundProposerDeposit(
         TaikoData.ProposedBlock storage target,
         uint256 tRelBp,
@@ -162,30 +219,27 @@ library LibVerifying {
         uint256 reward,
         TkoToken tkoToken
     ) private {
-        uint256 start;
+        uint256 offset;
         uint256 count = fc.provers.length;
 
         if (config.enableOracleProver) {
-            start = 1;
+            offset = 1;
             count -= 1;
         }
 
-        uint256 sum = (1 << count) - 1;
-        uint256 weight = 1 << (count - 1);
-        for (uint i = 0; i < count; ++i) {
-            uint256 proverReward = (reward * weight) / sum;
-            if (proverReward == 0) {
-                break;
-            }
+        uint256[] memory bips = getProverRewardBips(config, count);
 
-            if (tkoToken.balanceOf(fc.provers[start + i]) == 0) {
-                // Reduce reward to 1 wei as a penalty if the prover
-                // has 0 TKO balance. This allows the next prover reward
-                // to be fully paid.
-                proverReward = uint256(1);
+        for (uint256 i; i < count; ++i) {
+            uint256 proverReward = (reward * bips[i]) / 10000;
+            if (proverReward != 0) {
+                if (tkoToken.balanceOf(fc.provers[offset + i]) == 0) {
+                    // Reduce reward to 1 wei as a penalty if the prover
+                    // has 0 TKO balance. This allows the next prover reward
+                    // to be fully paid.
+                    proverReward = uint256(1);
+                }
+                tkoToken.mint(fc.provers[offset + i], proverReward);
             }
-            tkoToken.mint(fc.provers[start + i], proverReward);
-            weight = weight >> 1;
         }
     }
 
@@ -245,7 +299,7 @@ library LibVerifying {
     function _cleanUp(TaikoData.ForkChoice storage fc) private {
         fc.blockHash = 0;
         fc.provenAt = 0;
-        for (uint i = 0; i < fc.provers.length; ++i) {
+        for (uint256 i; i < fc.provers.length; ++i) {
             fc.provers[i] = address(0);
         }
         delete fc.provers;
diff --git a/packages/protocol/contracts/L2/TaikoL2.sol b/packages/protocol/contracts/L2/TaikoL2.sol
index 4a61c1d33ca..20841415adf 100644
--- a/packages/protocol/contracts/L2/TaikoL2.sol
+++ b/packages/protocol/contracts/L2/TaikoL2.sol
@@ -64,7 +64,7 @@ contract TaikoL2 is AddressResolver, ReentrancyGuard, IHeaderSync {
 
         bytes32[255] memory ancestors;
         uint256 number = block.number;
-        for (uint256 i = 0; i < 255 && number >= i + 2; ++i) {
+        for (uint256 i; i < 255 && number >= i + 2; ++i) {
             ancestors[i] = blockhash(number - i - 2);
         }
 
diff --git a/packages/protocol/contracts/libs/LibReceiptDecoder.sol b/packages/protocol/contracts/libs/LibReceiptDecoder.sol
index d14e9197379..87174c9d54e 100644
--- a/packages/protocol/contracts/libs/LibReceiptDecoder.sol
+++ b/packages/protocol/contracts/libs/LibReceiptDecoder.sol
@@ -60,7 +60,7 @@ library LibReceiptDecoder {
     ) internal pure returns (Log[] memory) {
         Log[] memory logs = new Log[](logsRlp.length);
 
-        for (uint256 i = 0; i < logsRlp.length; ++i) {
+        for (uint256 i; i < logsRlp.length; ++i) {
             LibRLPReader.RLPItem[] memory rlpItems = LibRLPReader.readList(
                 logsRlp[i]
             );
@@ -77,7 +77,7 @@ library LibReceiptDecoder {
     ) internal pure returns (bytes32[] memory) {
         bytes32[] memory topics = new bytes32[](topicsRlp.length);
 
-        for (uint256 i = 0; i < topicsRlp.length; ++i) {
+        for (uint256 i; i < topicsRlp.length; ++i) {
             topics[i] = LibRLPReader.readBytes32(topicsRlp[i]);
         }
 
diff --git a/packages/protocol/contracts/libs/LibSharedConfig.sol b/packages/protocol/contracts/libs/LibSharedConfig.sol
index bfde1b6d260..9770762f539 100644
--- a/packages/protocol/contracts/libs/LibSharedConfig.sol
+++ b/packages/protocol/contracts/libs/LibSharedConfig.sol
@@ -41,6 +41,7 @@ library LibSharedConfig {
                 proofTimeCap: 60 minutes,
                 bootstrapDiscountHalvingPeriod: 180 days,
                 initialUncleDelay: 60 minutes,
+                proverRewardRandomizedPercentage: 0,
                 enableTokenomics: false,
                 enablePublicInputsCheck: true,
                 enableProofValidation: false,
diff --git a/packages/protocol/contracts/libs/LibTxDecoder.sol b/packages/protocol/contracts/libs/LibTxDecoder.sol
index edbd1973146..c92e0160d86 100644
--- a/packages/protocol/contracts/libs/LibTxDecoder.sol
+++ b/packages/protocol/contracts/libs/LibTxDecoder.sol
@@ -82,7 +82,7 @@ library LibTxDecoder {
         LibRLPReader.RLPItem[] memory txs = LibRLPReader.readList(encoded);
 
         Tx[] memory _txList = new Tx[](txs.length);
-        for (uint256 i = 0; i < txs.length; ++i) {
+        for (uint256 i; i < txs.length; ++i) {
             _txList[i] = decodeTx(chainId, LibRLPReader.readBytes(txs[i]));
         }
 
@@ -211,7 +211,7 @@ library LibTxDecoder {
         LibRLPReader.RLPItem[] memory accessListRLP
     ) internal pure returns (AccessItem[] memory accessList) {
         accessList = new AccessItem[](accessListRLP.length);
-        for (uint256 i = 0; i < accessListRLP.length; ++i) {
+        for (uint256 i; i < accessListRLP.length; ++i) {
             LibRLPReader.RLPItem[] memory items = LibRLPReader.readList(
                 accessListRLP[i]
             );
@@ -220,7 +220,7 @@ library LibTxDecoder {
                 items[1]
             );
             bytes32[] memory slots = new bytes32[](slotListRLP.length);
-            for (uint256 j = 0; j < slotListRLP.length; ++j) {
+            for (uint256 j; j < slotListRLP.length; ++j) {
                 slots[j] = LibRLPReader.readBytes32(slotListRLP[j]);
             }
             accessList[i] = AccessItem(addr, slots);
@@ -231,7 +231,7 @@ library LibTxDecoder {
         TxList memory txList
     ) internal pure returns (uint256 sum) {
         Tx[] memory items = txList.items;
-        for (uint256 i = 0; i < items.length; ++i) {
+        for (uint256 i; i < items.length; ++i) {
             sum += items[i].gasLimit;
         }
     }
diff --git a/packages/protocol/contracts/libs/LibTxUtils.sol b/packages/protocol/contracts/libs/LibTxUtils.sol
index c7ef36419a2..d316a763bfb 100644
--- a/packages/protocol/contracts/libs/LibTxUtils.sol
+++ b/packages/protocol/contracts/libs/LibTxUtils.sol
@@ -55,7 +55,7 @@ library LibTxUtils {
             transaction.txType == 0 ? txRLPItems.length : txRLPItems.length - 3
         );
 
-        for (uint256 i = 0; i < list.length; ++i) {
+        for (uint256 i; i < list.length; ++i) {
             // For Non-legacy transactions, accessList is always the
             // fourth to last item.
             if (transaction.txType != 0 && i == list.length - 1) {
diff --git a/packages/protocol/contracts/test/L1/TestTaikoL1.sol b/packages/protocol/contracts/test/L1/TestTaikoL1.sol
index a4bde07d5e5..06024663730 100644
--- a/packages/protocol/contracts/test/L1/TestTaikoL1.sol
+++ b/packages/protocol/contracts/test/L1/TestTaikoL1.sol
@@ -47,6 +47,7 @@ contract TestTaikoL1 is TaikoL1, IProofVerifier {
         config.proofTimeCap = 4 seconds;
         config.bootstrapDiscountHalvingPeriod = 180 days;
         config.initialUncleDelay = 1 seconds;
+        config.proverRewardRandomizedPercentage = 0;
         config.enableTokenomics = false;
         config.enablePublicInputsCheck = false;
         config.enableOracleProver = false;
diff --git a/packages/protocol/contracts/test/L1/TestTaikoL1EnableTokenomics.sol b/packages/protocol/contracts/test/L1/TestTaikoL1EnableTokenomics.sol
index 68f634b48c9..8191bfca592 100644
--- a/packages/protocol/contracts/test/L1/TestTaikoL1EnableTokenomics.sol
+++ b/packages/protocol/contracts/test/L1/TestTaikoL1EnableTokenomics.sol
@@ -47,6 +47,7 @@ contract TestTaikoL1EnableTokenomics is TaikoL1, IProofVerifier {
         config.proofTimeCap = 5 seconds;
         config.bootstrapDiscountHalvingPeriod = 1 seconds;
         config.initialUncleDelay = 1 seconds;
+        config.proverRewardRandomizedPercentage = 0;
         config.enableTokenomics = true;
         config.enablePublicInputsCheck = false;
         config.enableProofValidation = false;
diff --git a/packages/protocol/contracts/test/L1/TestTaikoL2.sol b/packages/protocol/contracts/test/L1/TestTaikoL2.sol
index ae786c018e1..648cea4b244 100644
--- a/packages/protocol/contracts/test/L1/TestTaikoL2.sol
+++ b/packages/protocol/contracts/test/L1/TestTaikoL2.sol
@@ -48,6 +48,7 @@ contract TestTaikoL2 is TaikoL2 {
         config.proofTimeCap = 60 minutes;
         config.bootstrapDiscountHalvingPeriod = 180 days;
         config.initialUncleDelay = 1 minutes;
+        config.proverRewardRandomizedPercentage = 0;
         config.enableTokenomics = true;
         config.enablePublicInputsCheck = false;
         config.enableProofValidation = false;
diff --git a/packages/protocol/contracts/test/L1/TestTaikoL2EnablePublicInputsCheck.sol b/packages/protocol/contracts/test/L1/TestTaikoL2EnablePublicInputsCheck.sol
index 7f479f97bbc..052e9bd38a6 100644
--- a/packages/protocol/contracts/test/L1/TestTaikoL2EnablePublicInputsCheck.sol
+++ b/packages/protocol/contracts/test/L1/TestTaikoL2EnablePublicInputsCheck.sol
@@ -48,6 +48,7 @@ contract TestTaikoL2EnablePublicInputsCheck is TaikoL2 {
         config.proofTimeCap = 60 minutes;
         config.bootstrapDiscountHalvingPeriod = 180 days;
         config.initialUncleDelay = 1 minutes;
+        config.proverRewardRandomizedPercentage = 0;
         config.enableTokenomics = true;
         config.enablePublicInputsCheck = true;
         config.enableProofValidation = true;
diff --git a/packages/protocol/contracts/test/libs/TestLibProving.sol b/packages/protocol/contracts/test/libs/TestLibProving.sol
index 24e5f87279d..7062c672722 100644
--- a/packages/protocol/contracts/test/libs/TestLibProving.sol
+++ b/packages/protocol/contracts/test/libs/TestLibProving.sol
@@ -290,7 +290,7 @@ library TestLibProving {
         bytes32 blockHash = evidence.header.hashBlockHeader();
 
         if (!skipZKPVerification) {
-            for (uint256 i = 0; i < config.zkProofsPerBlock; ++i) {
+            for (uint256 i; i < config.zkProofsPerBlock; ++i) {
                 bytes32 instance = keccak256(
                     abi.encode(
                         blockHash,
@@ -298,6 +298,7 @@ library TestLibProving {
                         evidence.meta.txListHash
                     )
                 );
+
                 if (
                     !proofVerifier.verifyZKP({
                         verifierId: string(
@@ -363,7 +364,7 @@ library TestLibProving {
                 })
             ) revert L1_TOO_LATE();
 
-            for (uint256 i = 0; i < fc.provers.length; ++i) {
+            for (uint256 i; i < fc.provers.length; ++i) {
                 if (fc.provers[i] == prover) revert L1_DUP_PROVERS();
             }
 
diff --git a/packages/protocol/contracts/test/thirdparty/TestLibRLPReader.sol b/packages/protocol/contracts/test/thirdparty/TestLibRLPReader.sol
index 9b665fba2f7..7de89cae7c3 100644
--- a/packages/protocol/contracts/test/thirdparty/TestLibRLPReader.sol
+++ b/packages/protocol/contracts/test/thirdparty/TestLibRLPReader.sol
@@ -11,7 +11,7 @@ contract TestLibRLPReader {
     function readList(bytes memory _in) public pure returns (bytes[] memory) {
         LibRLPReader.RLPItem[] memory decoded = LibRLPReader.readList(_in);
         bytes[] memory out = new bytes[](decoded.length);
-        for (uint256 i = 0; i < out.length; ++i) {
+        for (uint256 i; i < out.length; ++i) {
             out[i] = LibRLPReader.readRawBytes(decoded[i]);
         }
         return out;
diff --git a/packages/protocol/contracts/thirdparty/LibBytesUtils.sol b/packages/protocol/contracts/thirdparty/LibBytesUtils.sol
index 69f27184251..54e082a9cdc 100644
--- a/packages/protocol/contracts/thirdparty/LibBytesUtils.sol
+++ b/packages/protocol/contracts/thirdparty/LibBytesUtils.sol
@@ -142,7 +142,7 @@ library LibBytesUtils {
     ) internal pure returns (bytes memory) {
         bytes memory nibbles = new bytes(_bytes.length * 2);
 
-        for (uint256 i = 0; i < _bytes.length; ++i) {
+        for (uint256 i; i < _bytes.length; ++i) {
             nibbles[i * 2] = _bytes[i] >> 4;
             nibbles[i * 2 + 1] = bytes1(uint8(_bytes[i]) % 16);
         }
@@ -155,7 +155,7 @@ library LibBytesUtils {
     ) internal pure returns (bytes memory) {
         bytes memory ret = new bytes(_bytes.length / 2);
 
-        for (uint256 i = 0; i < ret.length; ++i) {
+        for (uint256 i; i < ret.length; ++i) {
             ret[i] = (_bytes[i * 2] << 4) | (_bytes[i * 2 + 1]);
         }
 
diff --git a/packages/protocol/contracts/thirdparty/LibMerkleTrie.sol b/packages/protocol/contracts/thirdparty/LibMerkleTrie.sol
index 5c5446858d3..5f893543262 100644
--- a/packages/protocol/contracts/thirdparty/LibMerkleTrie.sol
+++ b/packages/protocol/contracts/thirdparty/LibMerkleTrie.sol
@@ -158,7 +158,7 @@ library LibMerkleTrie {
             bool _isFinalNode
         )
     {
-        uint256 pathLength = 0;
+        uint256 pathLength;
         bytes memory key = LibBytesUtils.toNibbles(_key);
 
         bytes32 currentNodeID = _root;
@@ -167,7 +167,7 @@ library LibMerkleTrie {
         TrieNode memory currentNode;
 
         // Proof is top-down, so we start at the first element (root).
-        for (uint256 i = 0; i < _proof.length; ++i) {
+        for (uint256 i; i < _proof.length; ++i) {
             currentNode = _proof[i];
             currentKeyIndex += currentKeyIncrement;
 
@@ -286,7 +286,7 @@ library LibMerkleTrie {
         LibRLPReader.RLPItem[] memory nodes = LibRLPReader.readList(_proof);
         TrieNode[] memory proof = new TrieNode[](nodes.length);
 
-        for (uint256 i = 0; i < nodes.length; ++i) {
+        for (uint256 i; i < nodes.length; ++i) {
             bytes memory encoded = LibRLPReader.readBytes(nodes[i]);
             proof[i] = TrieNode({
                 encoded: encoded,
@@ -354,7 +354,7 @@ library LibMerkleTrie {
         bytes memory _a,
         bytes memory _b
     ) private pure returns (uint256 _shared) {
-        uint256 i = 0;
+        uint256 i;
         while (_a.length > i && _b.length > i && _a[i] == _b[i]) {
             ++i;
         }
diff --git a/packages/protocol/contracts/thirdparty/LibRLPReader.sol b/packages/protocol/contracts/thirdparty/LibRLPReader.sol
index 3df840372c8..09c51a04006 100644
--- a/packages/protocol/contracts/thirdparty/LibRLPReader.sol
+++ b/packages/protocol/contracts/thirdparty/LibRLPReader.sol
@@ -93,7 +93,7 @@ library LibRLPReader {
         // simply set a reasonable maximum list length and decrease the size before we finish.
         RLPItem[] memory out = new RLPItem[](MAX_LIST_LENGTH);
 
-        uint256 itemCount = 0;
+        uint256 itemCount;
         uint256 offset = listOffset;
         while (offset < _in.length) {
             require(
@@ -424,7 +424,7 @@ library LibRLPReader {
         }
 
         // Copy over as many complete words as we can.
-        for (uint256 i = 0; i < _length / 32; ++i) {
+        for (uint256 i; i < _length / 32; ++i) {
             assembly {
                 mstore(dest, mload(src))
             }
diff --git a/packages/protocol/contracts/thirdparty/LibRLPWriter.sol b/packages/protocol/contracts/thirdparty/LibRLPWriter.sol
index ae256de5e78..58934a53c16 100644
--- a/packages/protocol/contracts/thirdparty/LibRLPWriter.sol
+++ b/packages/protocol/contracts/thirdparty/LibRLPWriter.sol
@@ -172,7 +172,7 @@ library LibRLPWriter {
     function _toBinary(uint256 _x) private pure returns (bytes memory) {
         bytes memory b = abi.encodePacked(_x);
 
-        uint256 i = 0;
+        uint256 i;
         for (; i < 32; ++i) {
             if (b[i] != 0) {
                 break;
@@ -180,7 +180,7 @@ library LibRLPWriter {
         }
 
         bytes memory res = new bytes(32 - i);
-        for (uint256 j = 0; j < res.length; ++j) {
+        for (uint256 j; j < res.length; ++j) {
             res[j] = b[i++];
         }
 
@@ -198,10 +198,10 @@ library LibRLPWriter {
     ) private pure returns (bytes memory) {
         bytes memory b = abi.encodePacked(_x);
 
-        uint256 i = 0;
+        uint256 i;
 
         bytes memory res = new bytes(32);
-        for (uint256 j = 0; j < res.length; ++j) {
+        for (uint256 j; j < res.length; ++j) {
             res[j] = b[i++];
         }
 
@@ -253,7 +253,7 @@ library LibRLPWriter {
         }
 
         uint256 len;
-        uint256 i = 0;
+        uint256 i;
         for (; i < _list.length; ++i) {
             len += _list[i].length;
         }