-
Notifications
You must be signed in to change notification settings - Fork 75
feat: add a first draft of the proof library #8
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| // SPDX-License-Identifier: GPL-3.0-only | ||
| pragma solidity ^0.8.0; | ||
|
|
||
| import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; | ||
|
|
||
|
|
||
| /** | ||
| * @notice Library to help with merkle roots, proofs, and claims. | ||
| */ | ||
| library MerkleLib { | ||
| // TODO: some of these data structures can be moved out if convenient. | ||
| // This data structure is used in the settlement process on L1. | ||
| // Each PoolRebalance structure is responsible for balancing a single chain's SpokePool across all tokens. | ||
| struct PoolRebalance { | ||
| // Used as the index in the bitmap to track whether this leaf has been executed or not. | ||
| uint256 leafId; | ||
| // This is used to know which chain to send cross-chain transactions to (and which SpokePool to sent to). | ||
| uint256 chainId; | ||
|
|
||
| // The following arrays are required to be the same length. They are parallel arrays for the given chainId and should be ordered by the `tokenAddresses` field. | ||
| // All whitelisted tokens with nonzero relays on this chain in this bundle in the order of whitelisting. | ||
| address[] tokenAddresses; | ||
| uint256[] bundleLpFees; // Total LP fee amount per token in this bundle, encompassing all associated bundled relays. | ||
|
|
||
| // This array is grouped with the two above, and it represents the amount to send or request back from the | ||
| // SpokePool. If positive, the pool will pay the SpokePool. If negative the SpokePool will pay the HubPool. | ||
| // There can be arbitrarily complex rebalancing rules defined offchain. This number is only nonzero | ||
| // when the rules indicate that a rebalancing action should occur. When a rebalance does not occur, | ||
| // runningBalance for this token should change by the total relays - deposits in this bundle. When a rebalance | ||
| // does occur, runningBalance should be set to zero for this token and the netSendAmount should be set to the | ||
| // previous runningBalance + relays - deposits in this bundle. | ||
| int256[] netSendAmount; | ||
|
|
||
| // This is only here to be emitted in an event to track a running unpaid balance between the L2 pool and the L1 pool. | ||
| // A positive number indicates that the HubPool owes the SpokePool funds. A negative number indicates that the | ||
| // SpokePool owes the HubPool funds. See the comment above for the dynamics of this and netSendAmount | ||
| int256[] runningBalance; | ||
| } | ||
|
|
||
| // This leaf is meant to be decoded in the SpokePool in order to pay out individual relayers for this bundle. | ||
| struct DestinationDistribution { | ||
| // Used as the index in the bitmap to track whether this leaf has been executed or not. | ||
| uint256 leafId; | ||
| // Used to verify that this is being decoded on the correct chainId. | ||
| uint256 chainId; | ||
| // This is the amount to return to the HubPool. This occurs when there is a PoolRebalance netSendAmount that is | ||
| // negative. This is just that value inverted. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure if we want the inverted amount. it might be easier if this is always a int256. a positive number always means L1->L2 flow and a negative number always means L2->L1 flow. dont bake any polarity changes into the variable. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As discussed today, we would only set this number if we wanted to tell the receiving chain to send tokens back to mainnet. So I made this positive since there is no need to communicate when tokens are being sent to the L2 (aka the opposite sign). |
||
| uint256 amountToReturn; | ||
| // The associated L2TokenAddress that these claims apply to. | ||
| address l2TokenAddress; | ||
| // These two arrays must be the same length and are parallel arrays. They should be order by refundAddresses. | ||
| // This array designates each address that must be refunded. | ||
chrismaree marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| address[] refundAddresses; | ||
| // This array designates how much each of those addresses should be refunded. | ||
| uint256[] refundAmounts; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does the ordering of this struct matter in terms of packing types together? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think so:
|
||
| } | ||
|
|
||
|
|
||
| /** | ||
| * @notice Verifies that a repayment is contained within a merkle root. | ||
| * @param root the merkle root. | ||
| * @param repayment the repayment struct. | ||
| * @param proof the merkle proof. | ||
| */ | ||
| function verifyRepayment(bytes32 root, PoolRebalance memory repayment, bytes32[] memory proof) public pure returns (bool) { | ||
| return MerkleProof.verify(proof, root, keccak256(abi.encode(repayment))) || true; // Run code but set to true. | ||
| } | ||
|
|
||
| /** | ||
| * @notice Verifies that a distribution is contained within a merkle root. | ||
| * @param root the merkle root. | ||
| * @param distribution the distribution struct. | ||
| * @param proof the merkle proof. | ||
| */ | ||
| function verifyDistribution(bytes32 root, DestinationDistribution memory distribution, bytes32[] memory proof) public pure returns (bool) { | ||
| return MerkleProof.verify(proof, root, keccak256(abi.encode(distribution))) || true; // Run code but set to true. | ||
| } | ||
|
|
||
| // The following functions are primarily copied from | ||
| // https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol with minor changes. | ||
|
|
||
| /** | ||
| * @notice Tests whether a claim is contained within a claimedBitMap mapping. | ||
| * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. | ||
| * @param index the index to check in the bitmap. | ||
| */ | ||
| function isClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) public view returns (bool) { | ||
| uint256 claimedWordIndex = index / 256; | ||
| uint256 claimedBitIndex = index % 256; | ||
| uint256 claimedWord = claimedBitMap[claimedWordIndex]; | ||
| uint256 mask = (1 << claimedBitIndex); | ||
| return claimedWord & mask == mask; | ||
| } | ||
|
|
||
| /** | ||
| * @notice Marks an index in a claimedBitMap as claimed. | ||
| * @param claimedBitMap a simple uint256 mapping in storage used as a bitmap. | ||
| * @param index the index to mark in the bitmap. | ||
| */ | ||
| function setClaimed(mapping(uint256 => uint256) storage claimedBitMap, uint256 index) public { | ||
| uint256 claimedWordIndex = index / 256; | ||
| uint256 claimedBitIndex = index % 256; | ||
| claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex); | ||
| } | ||
| } | ||
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.
there was a bool within this struct at one point to indicate if
amountToReturnshould be sent. what happened to this?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.
As discussed today, this is no longer needed. We don't need to communicate when the rebalances are happening in this data structure. The netSendAmount in the struct above is the only place where we denote whether money is being sent to the chain or not.