Skip to content

Commit f56146a

Browse files
nicholaspaimrice32pxrl
authored
feat(SpokePool): Specify exclusivityDeadlineOffset by default (#584)
* feat(SpokePool): Specify exclusivityDeadlineOffset by default Better depositor UX if they can specify an offset that is relative to the time that their deposit mines, so they do not have to account for any off-chain latency * Update SpokePool.sol * add clause * add back depositExclusive Signed-off-by: Matt Rice <matthewcrice32@gmail.com> * Update contracts/SpokePool.sol Co-authored-by: Paul <108695806+pxrl@users.noreply.github.com> * Update SpokePool.sol * fux tests * Update SpokePool.Deposit.ts * Update SpokePool.Deposit.ts * fix tests * Update contracts/SpokePool.sol Co-authored-by: Paul <108695806+pxrl@users.noreply.github.com> * Rmove check in deposit * Update contracts/SpokePool.sol Co-authored-by: Matt Rice <matthewcrice32@gmail.com> --------- Signed-off-by: Matt Rice <matthewcrice32@gmail.com> Co-authored-by: Matt Rice <matthewcrice32@gmail.com> Co-authored-by: Paul <108695806+pxrl@users.noreply.github.com>
1 parent 266fee0 commit f56146a

File tree

3 files changed

+45
-122
lines changed

3 files changed

+45
-122
lines changed

contracts/SpokePool.sol

Lines changed: 19 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -523,9 +523,9 @@ abstract contract SpokePool is
523523
* @param fillDeadline The deadline for the relayer to fill the deposit. After this destination chain timestamp,
524524
* the fill will revert on the destination chain. Must be set between [currentTime, currentTime + fillDeadlineBuffer]
525525
* where currentTime is block.timestamp on this chain or this transaction will revert.
526-
* @param exclusivityDeadline The deadline for the exclusive relayer to fill the deposit. After this
527-
* destination chain timestamp, anyone can fill this deposit on the destination chain. If exclusiveRelayer is set
528-
* to address(0), then this also must be set to 0, (and vice versa), otherwise this must be set >= current time.
526+
* @param exclusivityPeriod Added to the current time to set the exclusive reayer deadline,
527+
* which is the deadline for the exclusiveRelayer to fill the deposit. After this destination chain timestamp,
528+
* anyone can fill the deposit.
529529
* @param message The message to send to the recipient on the destination chain if the recipient is a contract.
530530
* If the message is not empty, the recipient contract must implement handleV3AcrossMessage() or the fill will revert.
531531
*/
@@ -540,7 +540,7 @@ abstract contract SpokePool is
540540
address exclusiveRelayer,
541541
uint32 quoteTimestamp,
542542
uint32 fillDeadline,
543-
uint32 exclusivityDeadline,
543+
uint32 exclusivityPeriod,
544544
bytes calldata message
545545
) public payable override nonReentrant unpausedDeposits {
546546
// Check that deposit route is enabled for the input token. There are no checks required for the output token
@@ -567,22 +567,6 @@ abstract contract SpokePool is
567567
// situation won't be a problem for honest users.
568568
if (fillDeadline < currentTime || fillDeadline > currentTime + fillDeadlineBuffer) revert InvalidFillDeadline();
569569

570-
// As a safety measure, prevent caller from inadvertently locking funds during exclusivity period
571-
// by forcing them to specify an exclusive relayer if the exclusivity period
572-
// is in the future. If this deadline is 0, then the exclusive relayer must also be address(0).
573-
// @dev Checks if either are > 0 by bitwise or-ing.
574-
if (uint256(uint160(exclusiveRelayer)) | exclusivityDeadline != 0) {
575-
// Now that we know one is nonzero, we need to perform checks on each.
576-
// Check that exclusive relayer is nonzero.
577-
if (exclusiveRelayer == address(0)) revert InvalidExclusiveRelayer();
578-
579-
// Check that deadline is in the future.
580-
if (exclusivityDeadline < currentTime) revert InvalidExclusivityDeadline();
581-
}
582-
583-
// No need to sanity check exclusivityDeadline because if its bigger than fillDeadline, then
584-
// there the full deadline is exclusive, and if its too small, then there is no exclusivity period.
585-
586570
// If the address of the origin token is a wrappedNativeToken contract and there is a msg.value with the
587571
// transaction then the user is sending the native token. In this case, the native token should be
588572
// wrapped.
@@ -608,7 +592,7 @@ abstract contract SpokePool is
608592
numberOfDeposits++,
609593
quoteTimestamp,
610594
fillDeadline,
611-
exclusivityDeadline,
595+
uint32(getCurrentTime()) + exclusivityPeriod,
612596
depositor,
613597
recipient,
614598
exclusiveRelayer,
@@ -642,9 +626,9 @@ abstract contract SpokePool is
642626
* @param fillDeadlineOffset Added to the current time to set the fill deadline, which is the deadline for the
643627
* relayer to fill the deposit. After this destination chain timestamp, the fill will revert on the
644628
* destination chain.
645-
* @param exclusivityDeadline The latest timestamp that only the exclusive relayer can fill the deposit. After this
646-
* destination chain timestamp, anyone can fill this deposit on the destination chain. Should be 0 if
647-
* exclusive relayer is 0.
629+
* @param exclusivityPeriod Added to the current time to set the exclusive relayer deadline,
630+
* which is the deadline for the exclusiveRelayer to fill the deposit. After this destination chain timestamp,
631+
* anyone can fill the deposit up to the fillDeadline timestamp.
648632
* @param message The message to send to the recipient on the destination chain if the recipient is a contract.
649633
* If the message is not empty, the recipient contract must implement handleV3AcrossMessage() or the fill will revert.
650634
*/
@@ -658,7 +642,7 @@ abstract contract SpokePool is
658642
uint256 destinationChainId,
659643
address exclusiveRelayer,
660644
uint32 fillDeadlineOffset,
661-
uint32 exclusivityDeadline,
645+
uint32 exclusivityPeriod,
662646
bytes calldata message
663647
) external payable {
664648
depositV3(
@@ -672,12 +656,13 @@ abstract contract SpokePool is
672656
exclusiveRelayer,
673657
uint32(getCurrentTime()),
674658
uint32(getCurrentTime()) + fillDeadlineOffset,
675-
exclusivityDeadline,
659+
exclusivityPeriod,
676660
message
677661
);
678662
}
679663

680664
/**
665+
* @notice DEPRECATED. Use depositV3() instead.
681666
* @notice Submits deposit and sets exclusivityDeadline to current time plus some offset. This function is
682667
* designed to be called by users who want to set an exclusive relayer for some amount of time after their deposit
683668
* transaction is mined.
@@ -708,7 +693,7 @@ abstract contract SpokePool is
708693
* @param fillDeadline The deadline for the relayer to fill the deposit. After this destination chain timestamp,
709694
* the fill will revert on the destination chain. Must be set between [currentTime, currentTime + fillDeadlineBuffer]
710695
* where currentTime is block.timestamp on this chain or this transaction will revert.
711-
* @param exclusivityDeadlineOffset Added to the current time to set the exclusive reayer deadline,
696+
* @param exclusivityPeriod Added to the current time to set the exclusive reayer deadline,
712697
* which is the deadline for the exclusiveRelayer to fill the deposit. After this destination chain timestamp,
713698
* anyone can fill the deposit.
714699
* @param message The message to send to the recipient on the destination chain if the recipient is a contract.
@@ -725,7 +710,7 @@ abstract contract SpokePool is
725710
address exclusiveRelayer,
726711
uint32 quoteTimestamp,
727712
uint32 fillDeadline,
728-
uint32 exclusivityDeadlineOffset,
713+
uint32 exclusivityPeriod,
729714
bytes calldata message
730715
) public payable {
731716
depositV3(
@@ -739,7 +724,7 @@ abstract contract SpokePool is
739724
exclusiveRelayer,
740725
quoteTimestamp,
741726
fillDeadline,
742-
uint32(getCurrentTime()) + exclusivityDeadlineOffset,
727+
exclusivityPeriod,
743728
message
744729
);
745730
}
@@ -845,7 +830,11 @@ abstract contract SpokePool is
845830
{
846831
// Exclusivity deadline is inclusive and is the latest timestamp that the exclusive relayer has sole right
847832
// to fill the relay.
848-
if (relayData.exclusivityDeadline >= getCurrentTime() && relayData.exclusiveRelayer != msg.sender) {
833+
if (
834+
relayData.exclusiveRelayer != msg.sender &&
835+
relayData.exclusivityDeadline >= getCurrentTime() &&
836+
relayData.exclusiveRelayer != address(0)
837+
) {
849838
revert NotExclusiveRelayer();
850839
}
851840

test/SpokePool.Deposit.ts

Lines changed: 6 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -434,56 +434,6 @@ describe("SpokePool Depositor Logic", async function () {
434434
)
435435
).to.not.be.reverted;
436436
});
437-
it("invalid exclusivity params", async function () {
438-
const currentTime = await spokePool.getCurrentTime();
439-
440-
// Both exclusive deadline and exclusive relayer must be 0 or non-zero (and the deadline is in the future).
441-
await expect(
442-
spokePool.connect(depositor).depositV3(
443-
...getDepositArgsFromRelayData({
444-
...relayData,
445-
exclusiveRelayer: depositor.address,
446-
exclusivityDeadline: 0,
447-
})
448-
)
449-
).to.be.revertedWith("InvalidExclusivityDeadline");
450-
await expect(
451-
spokePool.connect(depositor).depositV3(
452-
...getDepositArgsFromRelayData({
453-
...relayData,
454-
exclusiveRelayer: depositor.address,
455-
exclusivityDeadline: currentTime.sub(1),
456-
})
457-
)
458-
).to.be.revertedWith("InvalidExclusivityDeadline");
459-
await expect(
460-
spokePool.connect(depositor).depositV3(
461-
...getDepositArgsFromRelayData({
462-
...relayData,
463-
exclusiveRelayer: zeroAddress,
464-
exclusivityDeadline: currentTime,
465-
})
466-
)
467-
).to.be.revertedWith("InvalidExclusiveRelayer");
468-
await expect(
469-
spokePool.connect(depositor).depositV3(
470-
...getDepositArgsFromRelayData({
471-
...relayData,
472-
exclusiveRelayer: depositor.address,
473-
exclusivityDeadline: currentTime,
474-
})
475-
)
476-
).to.not.be.reverted;
477-
});
478-
it("exclusive deadline and relayer can both be 0", async function () {
479-
await expect(
480-
spokePool
481-
.connect(depositor)
482-
.depositV3(
483-
...getDepositArgsFromRelayData({ ...relayData, exclusiveRelayer: zeroAddress, exclusivityDeadline: 0 })
484-
)
485-
).to.not.be.reverted;
486-
});
487437
it("if input token is WETH and msg.value > 0, msg.value must match inputAmount", async function () {
488438
await expect(
489439
spokePool
@@ -525,8 +475,7 @@ describe("SpokePool Depositor Logic", async function () {
525475
it("depositV3Now uses current time as quote time", async function () {
526476
const currentTime = (await spokePool.getCurrentTime()).toNumber();
527477
const fillDeadlineOffset = 1000;
528-
const exclusivityDeadline = 0; // Should be zero since
529-
// exclusive relayer is zero address
478+
const exclusivityDeadline = 0;
530479
await expect(
531480
spokePool
532481
.connect(depositor)
@@ -555,51 +504,15 @@ describe("SpokePool Depositor Logic", async function () {
555504
0,
556505
currentTime, // quoteTimestamp should be current time
557506
currentTime + fillDeadlineOffset, // fillDeadline should be current time + offset
558-
exclusivityDeadline,
559-
relayData.depositor,
560-
relayData.recipient,
561-
relayData.exclusiveRelayer,
562-
relayData.message
563-
);
564-
});
565-
it("depositExclusive sets exclusive deadline correctly", async function () {
566-
const currentTime = (await spokePool.getCurrentTime()).toNumber();
567-
const exclusivityDeadlineOffset = 1000;
568-
await expect(
569-
spokePool.connect(depositor).depositExclusive(
570-
relayData.depositor,
571-
relayData.recipient,
572-
relayData.inputToken,
573-
relayData.outputToken,
574-
relayData.inputAmount,
575-
relayData.outputAmount,
576-
destinationChainId,
577-
relayData.depositor, // non-zero exclusive relayer
578507
currentTime,
579-
relayData.fillDeadline,
580-
exclusivityDeadlineOffset,
581-
relayData.message
582-
)
583-
)
584-
.to.emit(spokePool, "V3FundsDeposited")
585-
.withArgs(
586-
relayData.inputToken,
587-
relayData.outputToken,
588-
relayData.inputAmount,
589-
relayData.outputAmount,
590-
destinationChainId,
591-
// deposit ID is 0 for first deposit
592-
0,
593-
currentTime, // quoteTimestamp should be current time
594-
relayData.fillDeadline,
595-
currentTime + exclusivityDeadlineOffset, // should be current time + offset
596508
relayData.depositor,
597509
relayData.recipient,
598-
relayData.depositor, // non-zero exclusive relayer
510+
relayData.exclusiveRelayer,
599511
relayData.message
600512
);
601513
});
602514
it("emits V3FundsDeposited event with correct deposit ID", async function () {
515+
const currentTime = (await spokePool.getCurrentTime()).toNumber();
603516
await expect(spokePool.connect(depositor).depositV3(...depositArgs))
604517
.to.emit(spokePool, "V3FundsDeposited")
605518
.withArgs(
@@ -612,7 +525,7 @@ describe("SpokePool Depositor Logic", async function () {
612525
0,
613526
quoteTimestamp,
614527
relayData.fillDeadline,
615-
relayData.exclusivityDeadline,
528+
currentTime,
616529
relayData.depositor,
617530
relayData.recipient,
618531
relayData.exclusiveRelayer,
@@ -624,6 +537,7 @@ describe("SpokePool Depositor Logic", async function () {
624537
expect(await spokePool.numberOfDeposits()).to.equal(1);
625538
});
626539
it("tokens are always pulled from caller, even if different from specified depositor", async function () {
540+
const currentTime = (await spokePool.getCurrentTime()).toNumber();
627541
const balanceBefore = await erc20.balanceOf(depositor.address);
628542
const newDepositor = randomAddress();
629543
await expect(
@@ -641,7 +555,7 @@ describe("SpokePool Depositor Logic", async function () {
641555
0,
642556
quoteTimestamp,
643557
relayData.fillDeadline,
644-
relayData.exclusivityDeadline,
558+
currentTime,
645559
// New depositor
646560
newDepositor,
647561
relayData.recipient,

test/SpokePool.Relay.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,26 @@ describe("SpokePool Relayer Logic", async function () {
349349
)
350350
).to.not.be.reverted;
351351
});
352+
it("if no exclusive relayer is set, exclusivity deadline can be in future", async function () {
353+
const _relayData = {
354+
...relayData,
355+
// Overwrite exclusivity deadline
356+
exclusivityDeadline: relayData.fillDeadline,
357+
};
358+
359+
// Can send it after exclusivity deadline
360+
await expect(spokePool.connect(relayer).fillV3Relay(_relayData, consts.repaymentChainId)).to.not.be.reverted;
361+
});
362+
it("can have empty exclusive relayer before exclusivity deadline", async function () {
363+
const _relayData = {
364+
...relayData,
365+
// Overwrite exclusivity deadline
366+
exclusivityDeadline: relayData.fillDeadline,
367+
};
368+
369+
// Can send it before exclusivity deadline if exclusive relayer is empty
370+
await expect(spokePool.connect(relayer).fillV3Relay(_relayData, consts.repaymentChainId)).to.not.be.reverted;
371+
});
352372
it("calls _fillRelayV3 with expected params", async function () {
353373
await expect(spokePool.connect(relayer).fillV3Relay(relayData, consts.repaymentChainId))
354374
.to.emit(spokePool, "FilledV3Relay")

0 commit comments

Comments
 (0)