From 8e6a20aa0de6faccd2eea4e354680354e379dfb9 Mon Sep 17 00:00:00 2001 From: didi Date: Tue, 5 Nov 2024 18:42:30 +0100 Subject: [PATCH] make SuperToken 2771 recipient which trusts DMZForwarder, example use with increaseAllowance --- .../interfaces/superfluid/ISuperfluid.sol | 5 +++ .../contracts/superfluid/SuperToken.sol | 32 +++++++++++++++++-- .../contracts/superfluid/Superfluid.sol | 4 +++ .../superfluid/Superfluid.BatchCall.t.sol | 14 ++++++++ 4 files changed, 52 insertions(+), 3 deletions(-) diff --git a/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol b/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol index b698648111..388c253217 100644 --- a/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol +++ b/packages/ethereum-contracts/contracts/interfaces/superfluid/ISuperfluid.sol @@ -645,6 +645,11 @@ interface ISuperfluid { */ function forwardBatchCall(Operation[] calldata operations) external payable; + /** + * @dev Get the current DMZForwarder + */ + function getDMZForwarder() external view returns(address); + /************************************************************************** * Function modifiers for access control and parameter validations * diff --git a/packages/ethereum-contracts/contracts/superfluid/SuperToken.sol b/packages/ethereum-contracts/contracts/superfluid/SuperToken.sol index dbb0db043f..905901acbb 100644 --- a/packages/ethereum-contracts/contracts/superfluid/SuperToken.sol +++ b/packages/ethereum-contracts/contracts/superfluid/SuperToken.sol @@ -14,6 +14,7 @@ import { } from "../interfaces/superfluid/ISuperfluid.sol"; import { SuperfluidToken } from "./SuperfluidToken.sol"; import { ERC777Helper } from "../libs/ERC777Helper.sol"; +import { IRelayRecipient } from "../interfaces/utils/IRelayRecipient.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { SafeMath } from "@openzeppelin/contracts/utils/math/SafeMath.sol"; import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol"; @@ -35,7 +36,8 @@ interface IConstantInflowNFT {} contract SuperToken is UUPSProxiable, SuperfluidToken, - ISuperToken + ISuperToken, + IRelayRecipient { using SafeMath for uint256; @@ -543,8 +545,10 @@ contract SuperToken is } function increaseAllowance(address spender, uint256 addedValue) - public virtual override returns (bool) { - _approve(msg.sender, spender, _allowances[msg.sender][spender] + addedValue); + public virtual override returns (bool) + { + address msgSender = _msgSender(); + _approve(msgSender, spender, _allowances[msgSender][spender] + addedValue); return true; } @@ -886,6 +890,28 @@ contract SuperToken is _downgrade(msg.sender, account, to, amount, "", ""); } + /************************************************************************** + * IRelayRecipient + *************************************************************************/ + + /// @dev IRelayRecipient.isTrustedForwarder implementation + function isTrustedForwarder(address forwarder) public view override returns(bool) { + return forwarder == _host.getDMZForwarder(); + } + + /// @dev IRelayRecipient.versionRecipient implementation + function versionRecipient() external override pure returns (string memory) { + return "v1"; + } + + function _msgSender() internal virtual view returns (address) { + if(msg.data.length >= 20 && isTrustedForwarder(msg.sender)) { + return address(bytes20(msg.data[msg.data.length - 20:])); + } else { + return msg.sender; + } + } + /************************************************************************** * Modifiers *************************************************************************/ diff --git a/packages/ethereum-contracts/contracts/superfluid/Superfluid.sol b/packages/ethereum-contracts/contracts/superfluid/Superfluid.sol index 9528c99748..06e9fb72fc 100644 --- a/packages/ethereum-contracts/contracts/superfluid/Superfluid.sol +++ b/packages/ethereum-contracts/contracts/superfluid/Superfluid.sol @@ -949,6 +949,10 @@ contract Superfluid is return "v1"; } + function getDMZForwarder() external view override returns(address) { + return address(DMZ_FORWARDER); + } + /************************************************************************** * Internal **************************************************************************/ diff --git a/packages/ethereum-contracts/test/foundry/superfluid/Superfluid.BatchCall.t.sol b/packages/ethereum-contracts/test/foundry/superfluid/Superfluid.BatchCall.t.sol index ad56918876..5352396efb 100644 --- a/packages/ethereum-contracts/test/foundry/superfluid/Superfluid.BatchCall.t.sol +++ b/packages/ethereum-contracts/test/foundry/superfluid/Superfluid.BatchCall.t.sol @@ -628,4 +628,18 @@ contract SuperfluidBatchCallTest is FoundrySuperfluidTester { assertEq(address(forwarder).balance, 0, "DMZForwarder: balance still not 0"); assertEq(bob.balance, amount, "DMZForwarder: where did the money go?"); } + + function testIncreaseAllowanceUsing2771ForwardCall(uint256 allowanceAmount) public { + ISuperfluid.Operation[] memory ops = new ISuperfluid.Operation[](1); + uint256 aliceToBobAllowanceBefore = superToken.allowance(alice, bob); + ops[0] = ISuperfluid.Operation({ + operationType: BatchOperation.OPERATION_TYPE_ERC2771_FORWARD_CALL, + target: address(superToken), + data: abi.encodeCall(superToken.increaseAllowance, (bob, allowanceAmount)) + }); + vm.prank(alice); + sf.host.batchCall(ops); + uint256 aliceToBobAllowanceAfter = superToken.allowance(alice, bob); + assertEq(aliceToBobAllowanceAfter, aliceToBobAllowanceBefore + allowanceAmount); + } }