Skip to content

Commit be3c91d

Browse files
authored
feat: allow relayers to submit deposit transactions (#217)
## Summary This PR enables transaction relayers to submit deposit transactions on behalf of users by removing the restriction that the permit recipient must be the message sender. ## Changes - Update `Payments` contract to allow relayers to submit permit signed by a user - Add tests It'll improve UX by cutting down signatures from two to one as relayer / operators can accept permit and submit on users behalf. Demo (deployment address: `0xa883569439A2E11482197d93526d64e598089DeD`): 1. Generate permit: https://eip2612.hashchainprotocol.com/generate-permit.html 2. Submit permit value + token address + signer address at https://eip2612.hashchainprotocol.com/ Closes #146
1 parent f9b8844 commit be3c91d

File tree

5 files changed

+73
-16
lines changed

5 files changed

+73
-16
lines changed

src/Payments.sol

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -494,13 +494,7 @@ contract Payments is ReentrancyGuard {
494494
uint8 v,
495495
bytes32 r,
496496
bytes32 s
497-
)
498-
external
499-
nonReentrant
500-
validateNonZeroAddress(to, "to")
501-
validatePermitRecipient(to)
502-
settleAccountLockupBeforeAndAfter(token, to, false)
503-
{
497+
) external nonReentrant validateNonZeroAddress(to, "to") settleAccountLockupBeforeAndAfter(token, to, false) {
504498
_depositWithPermit(token, to, amount, deadline, v, r, s);
505499
}
506500

test/AccountManagement.t.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ contract AccountManagementTest is Test, BaseTestHelper {
7070
helper.expectInvalidPermitToRevert(user1Sk, USER1, DEPOSIT_AMOUNT);
7171
}
7272

73-
function testDepositWithPermitToAnotherUserReverts() public {
74-
helper.expectDepositWithPermitToAnotherUserToRevert(user1Sk, USER2, DEPOSIT_AMOUNT);
73+
function testDepositWithPermitToAnotherUser() public {
74+
helper.makeDepositWithPermitToAnotherUser(user1Sk, RELAYER, DEPOSIT_AMOUNT);
7575
}
7676

7777
function testNativeDepositWithInsufficientNativeTokens() public {

test/DepositWithPermitAndOperatorApproval.t.sol

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,33 @@ contract DepositWithPermitAndOperatorApproval is Test, BaseTestHelper {
5959
);
6060
}
6161

62+
function testDepositWithPermitAndOperatorApproval_Revert_DifferentSender() public {
63+
address from = USER1;
64+
address to = from;
65+
uint256 deadline = block.timestamp + 1 hours;
66+
67+
// get signature for permit
68+
(uint8 v, bytes32 r, bytes32 s) =
69+
helper.getPermitSignature(user1Sk, from, address(payments), DEPOSIT_AMOUNT, deadline);
70+
71+
vm.startPrank(RELAYER);
72+
vm.expectRevert(abi.encodeWithSelector(Errors.PermitRecipientMustBeMsgSender.selector, RELAYER, from));
73+
payments.depositWithPermitAndApproveOperator(
74+
address(testToken),
75+
from,
76+
DEPOSIT_AMOUNT,
77+
deadline,
78+
v,
79+
r,
80+
s,
81+
OPERATOR,
82+
RATE_ALLOWANCE,
83+
LOCKUP_ALLOWANCE,
84+
MAX_LOCKUP_PERIOD
85+
);
86+
vm.stopPrank();
87+
}
88+
6289
// SECTION: Deposit With Permit And Increase Operator Approval Tests
6390

6491
function testDepositWithPermitAndIncreaseOperatorApproval_HappyPath() public {
@@ -241,4 +268,40 @@ contract DepositWithPermitAndOperatorApproval is Test, BaseTestHelper {
241268
assertEq(finalRateUsage, preRateUsage); // Usage unchanged
242269
assertEq(finalLockupUsage, preLockupUsage); // Usage unchanged
243270
}
271+
272+
function testDepositWithPermitAndIncreaseOperatorApproval_Revert_DifferentSender() public {
273+
address from = USER1;
274+
275+
// Step 1: First establish initial operator approval with deposit
276+
helper.makeDepositWithPermitAndOperatorApproval(
277+
user1Sk, DEPOSIT_AMOUNT, OPERATOR, RATE_ALLOWANCE, LOCKUP_ALLOWANCE, MAX_LOCKUP_PERIOD
278+
);
279+
280+
// Step 2: Verify initial approval state
281+
(bool isApproved, uint256 initialRateAllowance, uint256 initialLockupAllowance,,,) =
282+
payments.operatorApprovals(address(testToken), USER1, OPERATOR);
283+
assertEq(isApproved, true);
284+
assertEq(initialRateAllowance, RATE_ALLOWANCE);
285+
assertEq(initialLockupAllowance, LOCKUP_ALLOWANCE);
286+
287+
// Step 3: Prepare for the increase operation
288+
uint256 additionalDeposit = 500 ether;
289+
uint256 rateIncrease = 50 ether;
290+
uint256 lockupIncrease = 500 ether;
291+
292+
// Give USER1 more tokens for the additional deposit
293+
testToken.mint(USER1, additionalDeposit);
294+
295+
// Get permit signature for the additional deposit
296+
uint256 deadline = block.timestamp + 1 hours;
297+
(uint8 v, bytes32 r, bytes32 s) =
298+
helper.getPermitSignature(user1Sk, USER1, address(payments), additionalDeposit, deadline);
299+
300+
vm.startPrank(RELAYER);
301+
vm.expectRevert(abi.encodeWithSelector(Errors.PermitRecipientMustBeMsgSender.selector, RELAYER, from));
302+
payments.depositWithPermitAndIncreaseOperatorApproval(
303+
address(testToken), USER1, additionalDeposit, deadline, v, r, s, OPERATOR, rateIncrease, lockupIncrease
304+
);
305+
vm.stopPrank();
306+
}
244307
}

test/helpers/BaseTestHelper.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ contract BaseTestHelper is Test {
1111
uint256 internal operator2Sk = 5;
1212
uint256 internal validatorSk = 6;
1313
uint256 internal serviceFeeRecipientSk = 7;
14+
uint256 internal relayerSk = 8;
1415

1516
address public immutable OWNER = vm.addr(ownerSk);
1617
address public immutable USER1 = vm.addr(user1Sk);
@@ -19,4 +20,5 @@ contract BaseTestHelper is Test {
1920
address public immutable OPERATOR2 = vm.addr(operator2Sk);
2021
address public immutable VALIDATOR = vm.addr(validatorSk);
2122
address public immutable SERVICE_FEE_RECIPIENT = vm.addr(serviceFeeRecipientSk);
23+
address public immutable RELAYER = vm.addr(relayerSk);
2224
}

test/helpers/PaymentsTestHelpers.sol

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -837,16 +837,14 @@ contract PaymentsTestHelpers is Test, BaseTestHelper {
837837
verifyOperatorAllowances(from, operator, false, 0, 0, 0, 0, 0); // No values should have been set due to revert - expect defaults
838838
}
839839

840-
function expectDepositWithPermitToAnotherUserToRevert(uint256 senderSk, address to, uint256 amount) public {
841-
address from = vm.addr(senderSk);
840+
function makeDepositWithPermitToAnotherUser(uint256 senderSk, address depositer, uint256 amount) public {
841+
address to = vm.addr(senderSk);
842842
uint256 deadline = block.timestamp + 1 hours;
843843

844-
// Get permit signature for the sender
845-
(uint8 v, bytes32 r, bytes32 s) = getPermitSignature(senderSk, from, address(payments), amount, deadline);
844+
// Get permit signature for 'to' address
845+
(uint8 v, bytes32 r, bytes32 s) = getPermitSignature(senderSk, to, address(payments), amount, deadline);
846846

847-
// Expect revert when trying to deposit to a different address than msg.sender
848-
vm.startPrank(from);
849-
vm.expectRevert(abi.encodeWithSelector(Errors.PermitRecipientMustBeMsgSender.selector, from, to));
847+
vm.startPrank(depositer);
850848
payments.depositWithPermit(address(testToken), to, amount, deadline, v, r, s);
851849
vm.stopPrank();
852850
}

0 commit comments

Comments
 (0)