Skip to content

Commit 19a3380

Browse files
committed
Hash packed deterministic deposit id
1 parent 751ddf8 commit 19a3380

File tree

2 files changed

+12
-19
lines changed

2 files changed

+12
-19
lines changed

contracts/SpokePool.sol

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -574,12 +574,11 @@ abstract contract SpokePool is
574574
* function is designed to be used by anyone who wants to pre-compute their resultant relay data hash, which
575575
* could be useful for filling a deposit faster and avoiding any risk of a relay hash unexpectedly changing
576576
* due to another deposit front-running this one and incrementing the global deposit ID counter.
577-
* @dev This is labeled "unsafe" because there is no guarantee that the depositId is unique which means that the
577+
* @dev This is labeled "unsafe" because there is no guarantee that the depositId emitted in the resultant
578+
* V3FundsDeposited event is unique which means that the
578579
* corresponding fill might collide with an existing relay hash on the destination chain SpokePool,
579580
* which would make this deposit unfillable. In this case, the depositor would subsequently receive a refund
580581
* of `inputAmount` of `inputToken` on the origin chain after the fill deadline.
581-
* @dev This is slightly more gas efficient than the depositV3() function because it doesn't
582-
* increment the global deposit count.
583582
* @dev On the destination chain, the hash of the deposit data will be used to uniquely identify this deposit, so
584583
* modifying any params in it will result in a different hash and a different deposit. The hash will comprise
585584
* all parameters to this function along with this chain's chainId(). Relayers are only refunded for filling
@@ -610,24 +609,18 @@ abstract contract SpokePool is
610609
uint256 outputAmount,
611610
uint256 destinationChainId,
612611
address exclusiveRelayer,
613-
uint96 depositNonce,
612+
uint256 depositNonce,
614613
uint32 quoteTimestamp,
615614
uint32 fillDeadline,
616615
uint32 exclusivityPeriod,
617616
bytes calldata message
618617
) public payable nonReentrant unpausedDeposits {
619-
// @dev Create the uint256 deposit ID by concatenating the address (which is 20 bytes) with the 12 byte
618+
// @dev Create the uint256 deposit ID by concatenating the address with the inputted
620619
// depositNonce parameter. The resultant 32 byte string can be casted to an "unsafe" uint256 deposit ID.
621-
// This guarantees the resultant ID won't collide with a "safe" deposit ID which is set by
622-
// implicitly casting a uint32 to a uint256, where the left-most 24 bytes are set to 0. We guarantee
623-
// that there are no collisions between "unsafe" and "safe" deposit ID's as long as the msg.sender's address
624-
// is not the zero address.
625-
626-
// @dev For some L2's, it could be possible that the zero address can be the msg.sender which might
627-
// make it possible for an unsafe deposit hash to collide with a safe deposit nonce. To prevent these cases,
628-
// we might want to consider explicitly checking that the msg.sender is not the zero address. However,
629-
// this is unlikely and we choose to not check it and incur the extra gas cost:
630-
// e.g. if (msg.sender == address(0)) revert InvalidUnsafeDepositor();
620+
// This probability that the resultant ID collides with a "safe" deposit ID is equal to the chance that the
621+
// first 28 bytes of the hash are 0, which is too small for us to consider. Moreover, if the depositId collided
622+
// with an already emitted safe deposit ID, then the deposit would only be unfillable if the rest of the
623+
// deposit data also matched, which would be very unlikely.
631624

632625
uint256 depositId = getUnsafeDepositId(msg.sender, depositNonce);
633626
_depositV3(
@@ -1114,8 +1107,8 @@ abstract contract SpokePool is
11141107
* @param depositNonce The nonce used as input to produce the deposit ID.
11151108
* @return The deposit ID for the unsafe deposit.
11161109
*/
1117-
function getUnsafeDepositId(address depositor, uint96 depositNonce) public pure returns (uint256) {
1118-
return uint256(bytes32(abi.encodePacked(depositor, depositNonce)));
1110+
function getUnsafeDepositId(address depositor, uint256 depositNonce) public pure returns (uint256) {
1111+
return uint256(keccak256(abi.encodePacked(depositor, depositNonce)));
11191112
}
11201113

11211114
/**************************************

test/evm/hardhat/SpokePool.Deposit.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,7 @@ describe("SpokePool Depositor Logic", async function () {
602602
const currentTime = (await spokePool.getCurrentTime()).toNumber();
603603
// new deposit ID should be the uint256 equivalent of the keccak256 hash of packed {address, forcedDepositId}.
604604
const forcedDepositId = "99";
605-
const expectedDepositId = ethers.utils.solidityPack(["address", "uint96"], [depositor.address, forcedDepositId]);
605+
const expectedDepositId = BigNumber.from(ethers.utils.solidityKeccak256(["address", "uint256"], [depositor.address, forcedDepositId]));
606606
expect(await spokePool.getUnsafeDepositId(depositor.address, forcedDepositId)).to.equal(expectedDepositId);
607607
await expect(
608608
spokePool
@@ -616,7 +616,7 @@ describe("SpokePool Depositor Logic", async function () {
616616
relayData.inputAmount,
617617
relayData.outputAmount,
618618
destinationChainId,
619-
BigNumber.from(expectedDepositId),
619+
expectedDepositId,
620620
quoteTimestamp,
621621
relayData.fillDeadline,
622622
currentTime,

0 commit comments

Comments
 (0)