-
Notifications
You must be signed in to change notification settings - Fork 75
feat(SpokePool): Introduce opt-in deterministic relay data hashes #583
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
Conversation
## Motivation We should allow a depositor to pre-compute their relay data hash so that they can work with a filler to more quickly fill their deposit while avoiding re-org risk (which could change the ordering of V3FundsDeposited events and change a depositor's expected `depositId`) and race conditions with another innocent or malicious depositor who front-runs their depositId. The advantage of using the global `depositId` as a nonce today is gas cost savings since we don't need to store a new value in a new slot on each deposit. We should not add gas cost to deposits. Secondly, incrementing the global `depositId` after each deposit guarantees that each `depositV3()` produces a unique deposit. This means that a depositor does not have to worry about accidentally producing a relay hash collision that means their deposit would be unfillable. Fortunately, unfillable deposits are refunded on the origin chain to the depositor but this possibility is undesirable for many depositors. Therefore, any implementation of deterministic relay hashes should ideally be opt-in. ## Implementation Introduces a new function: `unsafeDepositV3()` which gives the msg.sender 12 bytes with which to set a deposit nonce. It is marked unsafe because there is no protection given by the contract that the resultant relay data hash produced will be unique. The 12 byte deposit nonce is combined with the msg.sender's address, allowing each msg.sender to only track their own deposit nonces to avoid collisions. This also protects depositors from being griefed by malicious actors who might try to front-run their unsafe relay data hashes. `unsafeDepositV3()` is no more expensive than `depositV3` from a gas-cost perspective. The existing `depositV3()` function's implementation is untouched. ## Changes to V3RelayData struct Changes the `depositId` parameter in the `V3RelayData` struct from uint32 to uint256. In storage, this parameter is stored as a uint256 so at the low-level, this changes nothing. Moreover, in practice until now, depositId's were always set as uint32 meaning that the first 24 bytes of the uint256 `depositId` slot are currently set to 0. This change is made because this PR introduces a new function: `unsafeDepositV3()` which allows someone to set a `depositId` with non-zero bytes in the first 24 bytes.
|
Some off chain work related to this pr: It will be necessary to change all offchain code that tries to query deposits using deposit Id since we can no longer assume that deposit id is monotonically increasing for each deposit |
| * all parameters to this function along with this chain's chainId(). Relayers are only refunded for filling | ||
| * deposits with deposit hashes that map exactly to the one emitted by this contract. | ||
| * @param depositNonce The nonce that uniquely identifies this deposit. This function will combine this parameter | ||
| * with the msg.sender address to create a unique uint256 depositNonce and ensure that the msg.sender cannot |
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.
if the deposit is being made via a 4337 bundler, then the msg.sender will be the bundler address?
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'm not super familiar with 4337 but that sounds right. I think that might be a feature that allows the bundler to ensure that its own deposit hashes are all unique. The alternative instead of msg.sender is using the depositor address but that allows the msg.sender to manipulate the hashes and try to front-run honest msg.senders.
contracts/SpokePool.sol
Outdated
| // this is unlikely and we also should consider not checking it and incurring the extra gas cost: | ||
| // if (msg.sender == address()) revert InvalidUnsafeDepositor(); | ||
|
|
||
| uint256 depositHash = uint256((uint160(msg.sender) << 12) | depositNonce); |
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.
nit: not sure if "hash" is the correct word here. Probably "id" would be better, like in "speedUpV3Deposit"
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.
good point
contracts/SpokePool.sol
Outdated
| uint256 outputAmount, | ||
| uint256 destinationChainId, | ||
| address exclusiveRelayer, | ||
| uint256 depositNonce, |
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.
nit: "nonce" is overloaded as "uint96" provided by the user and also as "uint256" (msg.sender + value provided by the user). Perhaps "id" would be fitting here as well
|
I've updated the algorithm to derive the |
| destinationChainId, | ||
| exclusiveRelayer, | ||
| // Increment count of deposits so that deposit ID for this spoke pool is unique. | ||
| // @dev Implicitly casts from uint32 to uint256 by padding the left-most bytes with zeros. Guarantees |
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.
Something to verify for the reviewer: We want to guarantee that any caller of depositV3 will never produce a uint256 depositId that could collide with one produced by a caller of unsafeDepositV3. I think this is true because numberOfDeposits is a uint32 while the way unsafeDepositV3 produces a depositId is by packing the 20 byte address of the msg.sender with the uint96 depositId which guarantees that the resultant 32 byte value when casted into a uint256 will always be greater than the MAX_UINT32 if the address is non-0
UPDATED: packing the address with a depositId input by the caller and then hashing the resultant bytes. The chance that a resultant hash collides with a uint32 is less than the chance that the first 28 bytes of the hash are equal to 0 which is extremely small. I don't think this is a realistic possibility we need to guard against.
The keccak256 hashing of the packed 32 bytes removes the guarantee that unsafe and safe deposits can't collide. This is because the resultanthash might produce a number less than uint32.max
mrice32
left a comment
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.
A few comments! Looks awesome
contracts/SpokePool.sol
Outdated
| // this is unlikely and we choose to not check it and incur the extra gas cost: | ||
| // e.g. if (msg.sender == address(0)) revert InvalidUnsafeDepositor(); | ||
|
|
||
| uint256 depositId = uint256(bytes32(abi.encodePacked(msg.sender, depositNonce))); |
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 could flip the ordering and require that depositNonce > 0, making every custom nonce a very large number regardless of address. That would mean that any address would work, which would remove any concerns around precompiles that are at address 0x1, 0x2, 0x3 (not sure if anybody does this, but would prefer to avoid building our noncing around it).
Thoughts?
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.
require that depositNonce > 0,
Ideally I was trying to avoid an additional require statement here but I agree this would be a good algorithm. This is why I wanted to avoid require(msg.sender != address(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.
I think this comment is irrelevant now that we hash the packed data: 19a3380
contracts/SpokePool.sol
Outdated
| // we might want to consider explicitly checking that the msg.sender is not the zero address. However, | ||
| // this is unlikely and we choose to not check it and incur the extra gas cost: | ||
| // e.g. if (msg.sender == address(0)) revert InvalidUnsafeDepositor(); | ||
|
|
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.
OOC, what's the reasoning behind not wrapping all this in a hash? Simplicity for the integrator to predict the deposit hash?
Hash advantages:
- We can use full 256 bit depositNonces (might improve cross compatibility with things like permit2 or other noncing systems that may be used concurrently).
- No matter how we concat the data, there is no concern about creating collisions with normal depositIds.
- We could add more parameters that get baked into the depositId. For instance, this could be called by a contract that passes its msg.sender as the depositor. Adding the depositor to the depositId hash would mean that different depositors wouldn't collide.
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 is no concern about creating collisions with normal depositIds.
Is this true? What if the hash produces some value where the first 28 bytes are 0 (miraculously)? Wouldn't that then translate into a valid uint32 value?
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.
Otherwise I totally agree with all the reasons FOR hashing 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.
Did the math on this.
The probability of finding 28 bytes of leading zeros is 1 - (1 - (1/2^224))^num_tries.
You get to about 0.3% after 1e65 tries (screenshot below). For reference, Bitcoin produces about 2e28 hashes per year, meaning it would take about 5e36 years for the entire bitcoin network to have a 0.3% chance of cracking this.
|
@mrice32 just one question: do you think we should add more params to the hashed struct?
|
| * INTERNAL FUNCTIONS * | ||
| **************************************/ | ||
|
|
||
| function _depositV3( |
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 should be copied from the existing depositV3 logic
Yeah, I think msg.sender and depositor should both be in there to handle interactions from both regular users and passthrough contracts. |
contracts/SpokePool.sol
Outdated
| * @dev msg.sender and depositor are both used as inputs to allow passthrough depositors to create unique | ||
| * deposit hash spaces for unique depositors. | ||
| * @param sender The msg.sender address used as input to produce the deposit ID. |
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 wording is a bit counter-intuitive for me because it's relying on the implementation details of another function (unsafeDepositV3()). i.e. it's confusing that msg.sender is referenced in the comment, but sender is an input argument and can be any address.
Is relayer a candidate variable name? It implies that the relayer's address is needed to produce the deterministic deposit ID. In context of a relayer filling via a contract it would be the contract address, not the EOA, so idk whether that introduces a possible additional source of confusion.
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 msgSender maybe is a better variable name
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.
Because maybe an aggregator also wants to use the unsafeDeposit method but there would be no natural "relayer" to fill in, right? Maybe i'm over thinking it
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.
mrice32
left a comment
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.
LGTM!
…n offset, or a timestamp (#670) * Revert "feat(SpokePool): Introduce opt-in deterministic relay data hashes (#583)" This reverts commit 9d21d1b. * Reapply "feat(SpokePool): Introduce opt-in deterministic relay data hashes (#583)" This reverts commit d363bf0. * add deposit nonces to 7683 Signed-off-by: Matt Rice <[email protected]> * fix Signed-off-by: Matt Rice <[email protected]> * WIP Signed-off-by: Matt Rice <[email protected]> * feat(SpokePool): Introduce opt-in deterministic relay data hashes (#583) * fix(SpokePool): Apply exclusivity consistently The new relative exclusivity check has not been propagated to fillV3RelayWithUpdatedDeposit(). Identified via test case failures in the relayer. Signed-off-by: Paul <[email protected]> * Also check on slow fill requests * Update contracts/SpokePool.sol * lint * Update * Add pure * Fix * Add tests * improve(SpokePool): _depositV3 interprets `exclusivityParameter` as 0, an offset, or a timestamp There should be a way for the deposit transaction to remove chain re-org risk affecting the block.timestamp by allowing the caller to set a fixed `exclusivityDeadline` value. This supports the existing behavior where the `exclusivityDeadline` is always emitted as its passed in. The new behavior is that if the `exclusivityParameter`, which replaces the `exclusivityDeadlineOffset` parameter, is 0 or greater than 1 year in seconds, then the `exclusivityDeadline` is equal to this parameter. Otherwise, its interpreted by `_depositV3()` as an offset. The offset would be useful in cases where the origin chain will not re-org, for example. * Update SpokePool.sol * Update SpokePool.Relay.ts * Update SpokePool.SlowRelay.ts * Update contracts/SpokePool.sol Co-authored-by: Paul <[email protected]> * Update SpokePool.sol * Update contracts/SpokePool.sol * rebase * Update SpokePool.sol --------- Signed-off-by: Matt Rice <[email protected]> Signed-off-by: Paul <[email protected]> Co-authored-by: Matt Rice <[email protected]> Co-authored-by: Paul <[email protected]>
* Revert "feat(SpokePool): Introduce opt-in deterministic relay data hashes (#583)" This reverts commit 9d21d1b. * Reapply "feat(SpokePool): Introduce opt-in deterministic relay data hashes (#583)" This reverts commit d363bf0. * add deposit nonces to 7683 Signed-off-by: Matt Rice <[email protected]> * fix Signed-off-by: Matt Rice <[email protected]> * WIP Signed-off-by: Matt Rice <[email protected]> * feat(SpokePool): Introduce opt-in deterministic relay data hashes (#583) * fix(SpokePool): Apply exclusivity consistently The new relative exclusivity check has not been propagated to fillV3RelayWithUpdatedDeposit(). Identified via test case failures in the relayer. Signed-off-by: Paul <[email protected]> * Also check on slow fill requests * Update contracts/SpokePool.sol * lint * Update * Add pure * Fix * Add tests * improve(SpokePool): _depositV3 interprets `exclusivityParameter` as 0, an offset, or a timestamp There should be a way for the deposit transaction to remove chain re-org risk affecting the block.timestamp by allowing the caller to set a fixed `exclusivityDeadline` value. This supports the existing behavior where the `exclusivityDeadline` is always emitted as its passed in. The new behavior is that if the `exclusivityParameter`, which replaces the `exclusivityDeadlineOffset` parameter, is 0 or greater than 1 year in seconds, then the `exclusivityDeadline` is equal to this parameter. Otherwise, its interpreted by `_depositV3()` as an offset. The offset would be useful in cases where the origin chain will not re-org, for example. * Update SpokePool.sol * Update SpokePool.Relay.ts * Update SpokePool.SlowRelay.ts * Update contracts/SpokePool.sol Co-authored-by: Paul <[email protected]> * Update SpokePool.sol * Update contracts/SpokePool.sol * rebase * Update SpokePool.sol * Revert "Merge branch 'npai/exclusivity-switch' into mrice32/deterministic-new" This reverts commit 2432944, reversing changes made to 6fe3534. * Revert "Merge branch 'npai/exclusivity-switch' into mrice32/deterministic-new" This reverts commit 2432944, reversing changes made to 6fe3534. * revert * Update SpokePool.sol * Fix * Update SpokePool.sol Co-authored-by: Chris Maree <[email protected]> * WIP * WIP * wip * Update SpokePool.Relay.ts * Fix * Update SpokePool.sol * Update SpokePool.sol --------- Signed-off-by: Matt Rice <[email protected]> Signed-off-by: Paul <[email protected]> Co-authored-by: nicholaspai <[email protected]> Co-authored-by: nicholaspai <[email protected]> Co-authored-by: Paul <[email protected]> Co-authored-by: Chris Maree <[email protected]>
…h on "unsafe" deposit ID's I'm combing through the SDK for any functions that will need to change once this contracts [PR](across-protocol/contracts#583) is merged and here are some changes: - Added comments to BundleDataClient - Export useful constant `MAX_SAFE_DEPOSIT_ID` - Export useful utility `isUnsafeDepositId()` - Delete unused functions that wouldn't work post spoke pool upgrade because the `V3RelayData.depositId` type will change to uint256
* feat(chain-adapters): add solana adapter (#641) * feat(chain-adapters): add solana adapter Signed-off-by: Reinis Martinsons <[email protected]> * fix: comments Signed-off-by: Reinis Martinsons <[email protected]> * test: solana adapter Signed-off-by: Reinis Martinsons <[email protected]> * Update contracts/chain-adapters/Solana_Adapter.sol Co-authored-by: Chris Maree <[email protected]> * fix: do not hash bytes32 svm address Signed-off-by: Reinis Martinsons <[email protected]> --------- Signed-off-by: Reinis Martinsons <[email protected]> Co-authored-by: Chris Maree <[email protected]> * feat: address to bytes32 contract changes (#650) * feat: add address to bytes32 contract changes Signed-off-by: Pablo Maldonado <[email protected]> * refactor: remove todos Signed-off-by: Pablo Maldonado <[email protected]> * refactor: imports Signed-off-by: Pablo Maldonado <[email protected]> * Update contracts/SpokePool.sol Co-authored-by: Reinis Martinsons <[email protected]> * feat: bytes 32 comparisons Signed-off-by: Pablo Maldonado <[email protected]> * refactor: format code Signed-off-by: Pablo Maldonado <[email protected]> * fix: tests Signed-off-by: Pablo Maldonado <[email protected]> * feat: bytes 32 check Signed-off-by: Pablo Maldonado <[email protected]> * fix: ts Signed-off-by: Pablo Maldonado <[email protected]> * feat: reuse lib in cctp adapter Signed-off-by: Pablo Maldonado <[email protected]> * feat: _preExecuteLeafHook Signed-off-by: Pablo Maldonado <[email protected]> * refactor: comments Signed-off-by: Pablo Maldonado <[email protected]> * feat: _verifyUpdateV3DepositMessage Signed-off-by: Pablo Maldonado <[email protected]> * feat: backward compatibility Signed-off-by: Pablo Maldonado <[email protected]> * feat: backwards compatibility tests Signed-off-by: Pablo Maldonado <[email protected]> * feat: change comparison casting address bytes32 Signed-off-by: Pablo Maldonado <[email protected]> * fix: test Signed-off-by: Pablo Maldonado <[email protected]> * feat: merkle tree leaf to bytes32 Signed-off-by: Pablo Maldonado <[email protected]> * test: leaf type update fixes Signed-off-by: Pablo Maldonado <[email protected]> * feat: remove helper Signed-off-by: Pablo Maldonado <[email protected]> --------- Signed-off-by: Pablo Maldonado <[email protected]> Co-authored-by: Reinis Martinsons <[email protected]> * feat: Add relayer repayment address (#653) * WIP Signed-off-by: chrismaree <[email protected]> * WIP Signed-off-by: chrismaree <[email protected]> * WIP Signed-off-by: chrismaree <[email protected]> * WIP Signed-off-by: chrismaree <[email protected]> * WIP Signed-off-by: chrismaree <[email protected]> --------- Signed-off-by: chrismaree <[email protected]> * fix: clean up cast utilities (#676) * WIP Signed-off-by: chrismaree <[email protected]> * WIP Signed-off-by: chrismaree <[email protected]> * WIP Signed-off-by: chrismaree <[email protected]> * WIP Signed-off-by: chrismaree <[email protected]> * WIP Signed-off-by: chrismaree <[email protected]> * WIP Signed-off-by: chrismaree <[email protected]> --------- Signed-off-by: chrismaree <[email protected]> * feat: update spokepool relayer refund to handle blocked transfers (#675) Co-authored-by: Matt Rice <[email protected]> * WIP Signed-off-by: chrismaree <[email protected]> * fix(evm): merkle tree tests bytes32 Signed-off-by: Pablo Maldonado <[email protected]> * WIP Signed-off-by: chrismaree <[email protected]> * feat(svm): svm-dev fixes from review (#727) * refactor(svm): reuse bytes32 to address lib in svm adapter Signed-off-by: Pablo Maldonado <[email protected]> * feat: custom errors Signed-off-by: Pablo Maldonado <[email protected]> * feat: fix test Signed-off-by: Pablo Maldonado <[email protected]> --------- Signed-off-by: Pablo Maldonado <[email protected]> * test: fix forge tests Signed-off-by: Pablo Maldonado <[email protected]> * proposal: ensure that EVM errors are always consistant on underflows (#720) * feat: revert bytes32 conversion for internal functions (#755) * Discard changes to contracts/Ovm_SpokePool.sol * fix: stack too deep (#766) * WIP Signed-off-by: chrismaree <[email protected]> * WIP Signed-off-by: chrismaree <[email protected]> * Revert "feat: update depositor to bytes32" (#764) This reverts commit 85f0001. * Discard changes to contracts/PolygonZkEVM_SpokePool.sol * Discard changes to contracts/Polygon_SpokePool.sol * fix: make event case consistant between evm & svm (#760) * feat(SpokePool): Remove depositExclusive (#642) This function was used to express exclusivity as a period but its no longer useful since depositV3 now allows caller to express exclusivityPeriod instead of exclusivityDeadline * feat: Introduce opt-in deterministic relay data hashes (again) (#639) * Revert "feat(SpokePool): Introduce opt-in deterministic relay data hashes (#583)" This reverts commit 9d21d1b. * Reapply "feat(SpokePool): Introduce opt-in deterministic relay data hashes (#583)" This reverts commit d363bf0. * add deposit nonces to 7683 Signed-off-by: Matt Rice <[email protected]> * fix Signed-off-by: Matt Rice <[email protected]> * WIP Signed-off-by: Matt Rice <[email protected]> * feat(SpokePool): Introduce opt-in deterministic relay data hashes (#583) * fix(SpokePool): Apply exclusivity consistently The new relative exclusivity check has not been propagated to fillV3RelayWithUpdatedDeposit(). Identified via test case failures in the relayer. Signed-off-by: Paul <[email protected]> * Also check on slow fill requests * Update contracts/SpokePool.sol * lint * Update * Add pure * Fix * Add tests * improve(SpokePool): _depositV3 interprets `exclusivityParameter` as 0, an offset, or a timestamp There should be a way for the deposit transaction to remove chain re-org risk affecting the block.timestamp by allowing the caller to set a fixed `exclusivityDeadline` value. This supports the existing behavior where the `exclusivityDeadline` is always emitted as its passed in. The new behavior is that if the `exclusivityParameter`, which replaces the `exclusivityDeadlineOffset` parameter, is 0 or greater than 1 year in seconds, then the `exclusivityDeadline` is equal to this parameter. Otherwise, its interpreted by `_depositV3()` as an offset. The offset would be useful in cases where the origin chain will not re-org, for example. * Update SpokePool.sol * Update SpokePool.Relay.ts * Update SpokePool.SlowRelay.ts * Update contracts/SpokePool.sol Co-authored-by: Paul <[email protected]> * Update SpokePool.sol * Update contracts/SpokePool.sol * rebase * Update SpokePool.sol * Revert "Merge branch 'npai/exclusivity-switch' into mrice32/deterministic-new" This reverts commit 2432944, reversing changes made to 6fe3534. * Revert "Merge branch 'npai/exclusivity-switch' into mrice32/deterministic-new" This reverts commit 2432944, reversing changes made to 6fe3534. * revert * Update SpokePool.sol * Fix * Update SpokePool.sol Co-authored-by: Chris Maree <[email protected]> * WIP * WIP * wip * Update SpokePool.Relay.ts * Fix * Update SpokePool.sol * Update SpokePool.sol --------- Signed-off-by: Matt Rice <[email protected]> Signed-off-by: Paul <[email protected]> Co-authored-by: nicholaspai <[email protected]> Co-authored-by: nicholaspai <[email protected]> Co-authored-by: Paul <[email protected]> Co-authored-by: Chris Maree <[email protected]> * docs: fix comment duplication (#775) Signed-off-by: Pablo Maldonado <[email protected]> * fix: emit hashed message in evm fill events (#772) * fix: emit hashed message in evm fill events Signed-off-by: Reinis Martinsons <[email protected]> * WIP Signed-off-by: chrismaree <[email protected]> * fix: linting Signed-off-by: Reinis Martinsons <[email protected]> --------- Signed-off-by: Reinis Martinsons <[email protected]> Signed-off-by: chrismaree <[email protected]> Co-authored-by: chrismaree <[email protected]> * fix: linting Signed-off-by: Reinis Martinsons <[email protected]> * feat: improve _getV3RelayHash method (#779) * WIP Signed-off-by: chrismaree <[email protected]> * WIP Signed-off-by: chrismaree <[email protected]> * fix: Address Storage layout issue in CI (#836) * add new storage layout Signed-off-by: Chris Maree <[email protected]> * Discard changes to storage-layouts/PolygonZkEVM_SpokePool.json * Discard changes to storage-layouts/Redstone_SpokePool.json * Discard changes to storage-layouts/Scroll_SpokePool.json * Discard changes to storage-layouts/Zora_SpokePool.json * Discard changes to storage-layouts/WorldChain_SpokePool.json * add new storage layout Signed-off-by: Chris Maree <[email protected]> --------- Signed-off-by: Chris Maree <[email protected]> * fix(evm): C01 - Address incorrect use of relayerRefund over msg.sender in claimRelayerRefund function (#826) Signed-off-by: Chris Maree <[email protected]> * fix(evm): L01 - Update function from public to external (#827) Signed-off-by: Chris Maree <[email protected]> * fix(evm): L03 - Address incorrect Right Shift in AddressConverters Lib (#828) Signed-off-by: Chris Maree <[email protected]> * fix(evm): L04 - Remove repeated function (#829) Signed-off-by: Chris Maree <[email protected]> * fix(evm): N01 - Add missing docstring for repaymentAddress (#830) Signed-off-by: Chris Maree <[email protected]> * fix(evm): N02 - Address typographical Errors in spoke pool (#831) * WIP Signed-off-by: Chris Maree <[email protected]> * Update contracts/SpokePool.sol --------- Signed-off-by: Chris Maree <[email protected]> Co-authored-by: Matt Rice <[email protected]> * feat: update function and event naming for backwards compatibility (#805) * WIP Signed-off-by: Chris Maree <[email protected]> * WIP Signed-off-by: Chris Maree <[email protected]> * WIP Signed-off-by: Chris Maree <[email protected]> * WIP Signed-off-by: Chris Maree <[email protected]> * refined overfloaded function structure Signed-off-by: Chris Maree <[email protected]> * Discard changes to test/evm/hardhat/chain-specific-spokepools/Polygon_SpokePool.ts * WIP Signed-off-by: Chris Maree <[email protected]> * WIP Signed-off-by: Chris Maree <[email protected]> * WIP Signed-off-by: Chris Maree <[email protected]> * WIP Signed-off-by: Chris Maree <[email protected]> * WIP Signed-off-by: Matt Rice <[email protected]> * WIP Signed-off-by: Matt Rice <[email protected]> * WIP Signed-off-by: Matt Rice <[email protected]> * WIP Signed-off-by: Matt Rice <[email protected]> * update event names Signed-off-by: Matt Rice <[email protected]> * fix tests Signed-off-by: Matt Rice <[email protected]> * update function Signed-off-by: Matt Rice <[email protected]> * update naming Signed-off-by: Matt Rice <[email protected]> * drop unintended svm changes Signed-off-by: Matt Rice <[email protected]> * WIP Signed-off-by: Chris Maree <[email protected]> * WIP Signed-off-by: Chris Maree <[email protected]> * WIP Signed-off-by: Chris Maree <[email protected]> * feat: extend current add-legacy-fill-method-svm-dev (#864) * WIP Signed-off-by: Chris Maree <[email protected]> --------- Signed-off-by: Chris Maree <[email protected]> Signed-off-by: Chris Maree <[email protected]> Signed-off-by: Matt Rice <[email protected]> Co-authored-by: Chris Maree <[email protected]> Co-authored-by: Matt Rice <[email protected]> * fix: update legacy FilledV3Relay event to match old event signature (#873) * fix: update legacy event to match old event signature Signed-off-by: Matt Rice <[email protected]> * WIP Signed-off-by: Matt Rice <[email protected]> * WIP Signed-off-by: Matt Rice <[email protected]> --------- Signed-off-by: Matt Rice <[email protected]> * fix: use entire message when calculating relay hash for evm chains (#867) * fix: hash entire message when calculating relay hash for evm chains Signed-off-by: bennett <[email protected]> * make getV3RelayHash public Signed-off-by: bennett <[email protected]> * update fixture with relay hash change Signed-off-by: bennett <[email protected]> --------- Signed-off-by: bennett <[email protected]> * feat(SpokePool): Permit historical fillDeadline on deposit (#870) * feat(SpokePool): Permit historical fillDeadline on deposit This removes a sharp edge for pre-fill deposits, where the deposit comes after the fill. Permitting a historical fillDeadline gives more flexibility to the relayer around when they submit the deposit on the origin chain. * fix test * restore test * Bump approvals * fix: add check to ensure depositor is a valid EVM address (#874) Signed-off-by: Matt Rice <[email protected]> * fix(evm): L02 _destinationSettler Can Return Zero Address (#834) * fix: L02 _destinationSettler Can Return Zero Address * updated implementation to be in internal function Signed-off-by: Chris Maree <[email protected]> --------- Signed-off-by: Chris Maree <[email protected]> Co-authored-by: Chris Maree <[email protected]> Co-authored-by: nicholaspai <[email protected]> * improve: Verify relay hashes are the same pre and post upgrade (#878) * fix: hash entire message when calculating relay hash for evm chains Signed-off-by: bennett <[email protected]> * make getV3RelayHash public Signed-off-by: bennett <[email protected]> * update fixture with relay hash change Signed-off-by: bennett <[email protected]> * improve: Verify relay hashes are the same pre and post upgrade Adds a simple unit test to check that the same data hash is constructed * fix * Update test/evm/hardhat/MerkleLib.Proofs.ts * Update test/evm/hardhat/SpokePool.Relay.ts * Update SpokePool.Relay.ts --------- Signed-off-by: bennett <[email protected]> Co-authored-by: bennett <[email protected]> * Fix merge conflict that removed exclusivity parameter * Fix SwapAndBridge merge conflict * reorder stack variables Signed-off-by: bennett <[email protected]> * export test functions Signed-off-by: bennett <[email protected]> * bump package Signed-off-by: bennett <[email protected]> * fix: simpler solution to stack too deep --------- Signed-off-by: Reinis Martinsons <[email protected]> Signed-off-by: Pablo Maldonado <[email protected]> Signed-off-by: chrismaree <[email protected]> Signed-off-by: Matt Rice <[email protected]> Signed-off-by: Paul <[email protected]> Signed-off-by: Chris Maree <[email protected]> Signed-off-by: Chris Maree <[email protected]> Signed-off-by: bennett <[email protected]> Co-authored-by: Reinis Martinsons <[email protected]> Co-authored-by: Pablo Maldonado <[email protected]> Co-authored-by: Matt Rice <[email protected]> Co-authored-by: nicholaspai <[email protected]> Co-authored-by: nicholaspai <[email protected]> Co-authored-by: Paul <[email protected]> Co-authored-by: Reinis Martinsons <[email protected]> Co-authored-by: Chris Maree <[email protected]> Co-authored-by: bmzig <[email protected]> Co-authored-by: bennett <[email protected]>

Motivation
We should allow a depositor to pre-compute their relay data hash so that they can work with a filler to more quickly fill their deposit while avoiding re-org risk (which could change the ordering of V3FundsDeposited events and change a depositor's expected
depositId) and race conditions with another innocent or malicious depositor who front-runs their depositId.The advantage of using the global
depositIdas a nonce today is gas cost savings since we don't need to store a new value in a new slot on each deposit. We should not add gas cost to deposits.Secondly, incrementing the global
depositIdafter each deposit guarantees that eachdepositV3()produces a unique deposit. This means that a depositor does not have to worry about accidentally producing a relay hash collision that means their deposit would be unfillable. Fortunately, unfillable deposits are refunded on the origin chain to the depositor but this possibility is undesirable for many depositors.Therefore, any implementation of deterministic relay hashes should ideally be opt-in.
Implementation
Introduces a new function:
unsafeDepositV3()which gives the msg.sender 12 bytes with which to set a deposit nonce. It is marked unsafe because there is no protection given by the contract that the resultant relay data hash produced will be unique. The 12 byte deposit nonce is combined with the msg.sender's address, allowing each msg.sender to only track their own deposit nonces to avoid collisions. This also protects depositors from being griefed by malicious actors who might try to front-run their unsafe relay data hashes.unsafeDepositV3()is slightly more expensive thandepositV3from a gas-cost perspective because it adds a keccak256 + abi.encodePacked operation but it removes a SSTOREThe existing
depositV3()function's implementation is untouched.Changes to V3RelayData struct
Changes the
depositIdparameter in theV3RelayDatastruct from uint32 to uint256. In storage, this parameter is stored as a uint256 so at the low-level, this changes nothing. Moreover, in practice until now, depositId's were always set as uint32 meaning that the first 24 bytes of the uint256depositIdslot are currently set to 0.This change is made because this PR introduces a new function:
unsafeDepositV3()which allows someone to set adepositIdwith non-zero bytes in the first 24 bytes.Implications for clients
Any logic that assumes that depositId's will always be monotonically increasing now needs to be changed. For example, the
queryHistoricalDepositForFillfunction performs a binary search on V3FundsDeposited events' depositId values to locate historical fills. This clearly will no longer work following this PR, so this corresponding change in therelayerclient skips this function in all cases unless the deposit was sent via a legacy function where all deposit ID's are produced "safely": across-protocol/relayer#1769