@@ -9,11 +9,12 @@ import {
99} from "@superfluid-finance/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol " ;
1010import {SuperAppBase} from "@superfluid-finance/ethereum-contracts/contracts/apps/SuperAppBase.sol " ;
1111import {SuperTokenV1Library} from "@superfluid-finance/ethereum-contracts/contracts/apps/SuperTokenV1Library.sol " ;
12+ import {IRelayRecipient} from "@superfluid-finance/ethereum-contracts/contracts/interfaces/utils/IRelayRecipient.sol " ;
1213import {IVestingSchedulerV3} from "./interface/IVestingSchedulerV3.sol " ;
1314import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol " ;
1415import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol " ;
1516
16- contract VestingSchedulerV3 is IVestingSchedulerV3 , SuperAppBase {
17+ contract VestingSchedulerV3 is IVestingSchedulerV3 , SuperAppBase , IRelayRecipient {
1718 using SuperTokenV1Library for ISuperToken;
1819
1920 ISuperfluid public immutable HOST;
@@ -86,7 +87,7 @@ contract VestingSchedulerV3 is IVestingSchedulerV3, SuperAppBase {
8687 _validateAndCreateVestingSchedule (
8788 ScheduleCreationParams ({
8889 superToken: superToken,
89- sender: msg . sender ,
90+ sender: _msgSender () ,
9091 receiver: receiver,
9192 startDate: _normalizeStartDate (startDate),
9293 claimValidityDate: claimValidityDate,
@@ -172,7 +173,7 @@ contract VestingSchedulerV3 is IVestingSchedulerV3, SuperAppBase {
172173 _validateAndCreateVestingSchedule (
173174 mapCreateVestingScheduleParams (
174175 superToken,
175- msg . sender ,
176+ _msgSender () ,
176177 receiver,
177178 totalAmount,
178179 totalDuration,
@@ -518,7 +519,7 @@ contract VestingSchedulerV3 is IVestingSchedulerV3, SuperAppBase {
518519 VestingSchedule memory schedule = agg.schedule;
519520
520521 // Ensure that the caller is the sender or the receiver if the vesting schedule requires claiming.
521- if (msg . sender != agg.sender && msg . sender != agg.receiver) {
522+ if (_msgSender () != agg.sender && _msgSender () != agg.receiver) {
522523 revert CannotClaimScheduleOnBehalf ();
523524 }
524525
@@ -527,7 +528,7 @@ contract VestingSchedulerV3 is IVestingSchedulerV3, SuperAppBase {
527528 }
528529
529530 delete vestingSchedules[agg.id].claimValidityDate;
530- emit VestingClaimed (agg.superToken, agg.sender, agg.receiver, msg . sender );
531+ emit VestingClaimed (agg.superToken, agg.sender, agg.receiver, _msgSender () );
531532 }
532533
533534 /// @dev IVestingScheduler.executeCliffAndFlow implementation.
@@ -731,7 +732,7 @@ contract VestingSchedulerV3 is IVestingSchedulerV3, SuperAppBase {
731732 if (msg .sender != address (HOST)) revert HostInvalid ();
732733 sender = HOST.decodeCtx (ctx).msgSender;
733734 } else {
734- sender = msg . sender ;
735+ sender = _msgSender () ;
735736 }
736737 // This is an invariant and should never happen.
737738 assert (sender != address (0 ));
@@ -745,4 +746,23 @@ contract VestingSchedulerV3 is IVestingSchedulerV3, SuperAppBase {
745746 function _getId (address superToken , address sender , address receiver ) private pure returns (bytes32 ) {
746747 return keccak256 (abi.encodePacked (superToken, sender, receiver));
747748 }
749+
750+ /// @dev IRelayRecipient.isTrustedForwarder implementation
751+ function isTrustedForwarder (address forwarder ) public view override returns (bool ) {
752+ return forwarder == HOST.getERC2771Forwarder ();
753+ }
754+
755+ /// @dev IRelayRecipient.versionRecipient implementation
756+ function versionRecipient () external override pure returns (string memory ) {
757+ return "v1 " ;
758+ }
759+
760+ /// @dev gets the relayed sender from calldata as specified by EIP-2771, falling back to msg.sender
761+ function _msgSender () internal virtual view returns (address ) {
762+ if (msg .data .length >= 20 && isTrustedForwarder (msg .sender )) {
763+ return address (bytes20 (msg .data [msg .data .length - 20 :]));
764+ } else {
765+ return msg .sender ;
766+ }
767+ }
748768}
0 commit comments