Skip to content

Commit

Permalink
update modular-contracts dependency, add direct transfer functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
kumaryash90 committed Aug 14, 2024
1 parent 212526c commit 33c274f
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 73 deletions.
2 changes: 1 addition & 1 deletion lib/modular-contracts
Submodule modular-contracts updated 88 files
+10 −10 .gas-snapshot
+2 −2 .github/workflows/benchmark.yml
+1 −1 .github/workflows/formatter.yml
+1 −1 .github/workflows/test.yml
+5 −5 README.md
+104 −104 design-document.md
+14 −4 foundry.toml
+5 −2 script/benchmark-ext/erc721/BenchmarkERC721.s.sol
+4 −0 script/benchmark-ext/erc721/BenchmarkERC721Base.sol
+10 −0 script/benchmark-ext/erc721/BenchmarkERC721Manifold.sol
+6 −0 script/benchmark-ext/erc721/BenchmarkERC721ThirdwebLegacy.sol
+90 −77 src/ModularCore.sol
+0 −8 src/ModularExtension.sol
+10 −0 src/ModularModule.sol
+3 −3 src/Role.sol
+4 −2 src/callback/BeforeApproveCallbackERC20.sol
+4 −2 src/callback/BeforeApproveCallbackERC721.sol
+4 −2 src/callback/BeforeApproveForAllCallback.sol
+4 −2 src/callback/BeforeBatchMintCallbackERC1155.sol
+4 −2 src/callback/BeforeBatchTransferCallbackERC1155.sol
+4 −2 src/callback/BeforeBurnCallbackERC1155.sol
+4 −2 src/callback/BeforeBurnCallbackERC20.sol
+4 −2 src/callback/BeforeBurnCallbackERC721.sol
+4 −2 src/callback/BeforeMintCallbackERC1155.sol
+4 −2 src/callback/BeforeMintCallbackERC20.sol
+4 −2 src/callback/BeforeMintCallbackERC721.sol
+4 −2 src/callback/BeforeTransferCallbackERC1155.sol
+4 −2 src/callback/BeforeTransferCallbackERC20.sol
+4 −2 src/callback/BeforeTransferCallbackERC721.sol
+4 −2 src/callback/OnTokenURICallback.sol
+14 −11 src/core/token/ERC1155Core.sol
+14 −11 src/core/token/ERC1155CoreInitializable.sol
+14 −10 src/core/token/ERC20Core.sol
+13 −10 src/core/token/ERC20CoreInitializable.sol
+24 −11 src/core/token/ERC721Core.sol
+28 −15 src/core/token/ERC721CoreInitializable.sol
+3 −1 src/interface/IERC165.sol
+3 −1 src/interface/IERC20.sol
+5 −0 src/interface/IERC7572.sol
+7 −5 src/interface/IInstallationCallback.sol
+30 −28 src/interface/IModularCore.sol
+0 −15 src/interface/IModularExtension.sol
+17 −0 src/interface/IModularModule.sol
+12 −10 src/interface/IModuleConfig.sol
+6 −4 src/module/token/metadata/BatchMetadataERC1155.sol
+11 −7 src/module/token/metadata/BatchMetadataERC721.sol
+25 −8 src/module/token/metadata/DelayedRevealBatchMetadataERC721.sol
+6 −4 src/module/token/metadata/OpenEditionMetadataERC1155.sol
+12 −7 src/module/token/metadata/OpenEditionMetadataERC721.sol
+6 −4 src/module/token/metadata/SimpleMetadataERC1155.sol
+10 −6 src/module/token/metadata/SimpleMetadataERC721.sol
+39 −10 src/module/token/minting/ClaimableERC1155.sol
+39 −10 src/module/token/minting/ClaimableERC20.sol
+39 −10 src/module/token/minting/ClaimableERC721.sol
+39 −10 src/module/token/minting/MintableERC1155.sol
+39 −13 src/module/token/minting/MintableERC20.sol
+42 −12 src/module/token/minting/MintableERC721.sol
+6 −4 src/module/token/royalty/RoyaltyERC1155.sol
+28 −9 src/module/token/royalty/RoyaltyERC721.sol
+13 −8 src/module/token/transferable/TransferableERC1155.sol
+11 −7 src/module/token/transferable/TransferableERC20.sol
+11 −7 src/module/token/transferable/TransferableERC721.sol
+2 −0 test/Interface.t.sol
+172 −126 test/ModularCore.t.sol
+48 −38 test/benchmark/CoreBenchmark.t.sol
+7 −7 test/core/ERC1155Core.t.sol
+17 −17 test/core/ERC20Core.t.sol
+7 −7 test/core/ERC721Core.t.sol
+15 −11 test/extension/metadata/BatchMetadataERC1155.t.sol
+15 −11 test/extension/metadata/BatchMetadataERC721.t.sol
+15 −11 test/extension/metadata/DelayedRevealBatchMetadataERC721.t.sol
+22 −16 test/extension/metadata/OpenEditionMetadataERC1155.t.sol
+21 −15 test/extension/metadata/OpenEditionMetadataERC721.t.sol
+16 −12 test/extension/metadata/SimpleMetadataERC1155.t.sol
+15 −11 test/extension/metadata/SimpleMetadataERC721.t.sol
+22 −14 test/extension/minting/ClaimableERC1155.t.sol
+22 −14 test/extension/minting/ClaimableERC20.t.sol
+22 −14 test/extension/minting/ClaimableERC721.t.sol
+22 −14 test/extension/minting/MintableERC1155.t.sol
+21 −13 test/extension/minting/MintableERC20.t.sol
+22 −15 test/extension/minting/MintableERC721.t.sol
+21 −17 test/extension/royalty/RoyaltyERC1155.t.sol
+21 −17 test/extension/royalty/RoyaltyERC721.t.sol
+23 −17 test/extension/transferable/TransferableERC1155.t.sol
+23 −17 test/extension/transferable/TransferableERC20.t.sol
+23 −17 test/extension/transferable/TransferableERC721.t.sol
+1 −1 test/utils/ExtensionProxyFactory.sol
+2 −0 test/utils/TestPlus.sol
14 changes: 5 additions & 9 deletions src/PayGateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,13 @@ contract PayGateway is ModularCore, Initializable {
_disableInitializers();
}

function initialize(
address _owner,
address[] memory _extensions,
bytes[] memory _extensionInstallData
) external payable {
function initialize(address _owner, address[] memory _modules, bytes[] memory _moduleInstallData) external payable {
_initializeOwner(_owner);

// Install and initialize extensions
require(_extensions.length == _extensionInstallData.length);
for (uint256 i = 0; i < _extensions.length; i++) {
_installExtension(_extensions[i], _extensionInstallData[i]);
// Install and initialize modules
require(_modules.length == _moduleInstallData.length);
for (uint256 i = 0; i < _modules.length; i++) {
_installModule(_modules[i], _moduleInstallData[i]);
}
}

Expand Down
55 changes: 32 additions & 23 deletions src/PayGatewayExtension.sol → src/PayGatewayModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import { EIP712 } from "lib/solady/src/utils/EIP712.sol";
import { SafeTransferLib } from "lib/solady/src/utils/SafeTransferLib.sol";
import { ReentrancyGuard } from "lib/solady/src/utils/ReentrancyGuard.sol";
import { ECDSA } from "lib/solady/src/utils/ECDSA.sol";
import { ModularExtension } from "lib/modular-contracts/src/ModularExtension.sol";
import { ModularModule } from "lib/modular-contracts/src/ModularModule.sol";
import { Ownable } from "lib/solady/src/auth/Ownable.sol";

library PayGatewayExtensionStorage {
/// @custom:storage-location erc7201:payments.gateway.extension
library PayGatewayModuleStorage {
/// @custom:storage-location erc7201:payments.gateway.module
bytes32 public constant PAYMENTS_GATEWAY_EXTENSION_STORAGE_POSITION =
keccak256(abi.encode(uint256(keccak256("payments.gateway.extension")) - 1)) & ~bytes32(uint256(0xff));
keccak256(abi.encode(uint256(keccak256("payments.gateway.module")) - 1)) & ~bytes32(uint256(0xff));

struct Data {
/// @dev Mapping from pay request UID => whether the pay request is processed.
Expand All @@ -28,7 +28,7 @@ library PayGatewayExtensionStorage {
}
}

contract PayGatewayExtension is EIP712, ModularExtension, ReentrancyGuard {
contract PayGatewayModule is EIP712, ModularModule, ReentrancyGuard {
using ECDSA for bytes32;

/*///////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -78,6 +78,7 @@ contract PayGatewayExtension is EIP712, ModularExtension, ReentrancyGuard {
uint256 expirationTimestamp;
PayoutInfo[] payouts;
address payable forwardAddress;
bool directTransfer;
bytes data;
}

Expand Down Expand Up @@ -124,7 +125,7 @@ contract PayGatewayExtension is EIP712, ModularExtension, ReentrancyGuard {
//////////////////////////////////////////////////////////////*/

/// @notice Returns all implemented callback and fallback functions.
function getExtensionConfig() external pure override returns (ExtensionConfig memory config) {
function getModuleConfig() external pure override returns (ModuleConfig memory config) {
config.fallbackFunctions = new FallbackFunction[](5);

config.fallbackFunctions[0] = FallbackFunction({
Expand Down Expand Up @@ -198,7 +199,7 @@ contract PayGatewayExtension is EIP712, ModularExtension, ReentrancyGuard {
}

// mark the pay request as processed
PayGatewayExtensionStorage.data().processed[req.transactionId] = true;
PayGatewayModuleStorage.data().processed[req.transactionId] = true;

// distribute fees
uint256 totalFeeAmount = _distributeFees(req.tokenAddress, req.payouts);
Expand All @@ -213,23 +214,31 @@ contract PayGatewayExtension is EIP712, ModularExtension, ReentrancyGuard {
}
}

if (_isTokenERC20(req.tokenAddress)) {
// pull user funds
SafeTransferLib.safeTransferFrom(req.tokenAddress, msg.sender, address(this), req.tokenAmount);
SafeTransferLib.safeApprove(req.tokenAddress, req.forwardAddress, req.tokenAmount);
}
if (req.directTransfer) {
if (_isTokenNative(req.tokenAddress)) {
req.forwardAddress.call{ value: sendValue }("");
} else {
SafeTransferLib.safeTransferFrom(req.tokenAddress, msg.sender, req.forwardAddress, req.tokenAmount);
}
} else {
if (_isTokenERC20(req.tokenAddress)) {
// pull user funds
SafeTransferLib.safeTransferFrom(req.tokenAddress, msg.sender, address(this), req.tokenAmount);
SafeTransferLib.safeApprove(req.tokenAddress, req.forwardAddress, req.tokenAmount);
}

{
(bool success, bytes memory response) = req.forwardAddress.call{ value: sendValue }(req.data);
if (!success) {
// If there is return data, the delegate call reverted with a reason or a custom error, which we bubble up.
if (response.length > 0) {
assembly {
let returndata_size := mload(response)
revert(add(32, response), returndata_size)
{
(bool success, bytes memory response) = req.forwardAddress.call{ value: sendValue }(req.data);
if (!success) {
// If there is return data, the delegate call reverted with a reason or a custom error, which we bubble up.
if (response.length > 0) {
assembly {
let returndata_size := mload(response)
revert(add(32, response), returndata_size)
}
} else {
revert PayGatewayFailedToForward();
}
} else {
revert PayGatewayFailedToForward();
}
}
}
Expand Down Expand Up @@ -323,7 +332,7 @@ contract PayGatewayExtension is EIP712, ModularExtension, ReentrancyGuard {
}

function _verifyTransferStart(PayRequest calldata req, bytes calldata signature) private view returns (bool) {
bool processed = PayGatewayExtensionStorage.data().processed[req.transactionId];
bool processed = PayGatewayModuleStorage.data().processed[req.transactionId];

bytes32 payoutsHash = _hashPayoutInfo(req.payouts);
bytes32 structHash = keccak256(
Expand Down
46 changes: 23 additions & 23 deletions test/PayGateway.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ pragma solidity ^0.8.0;
import { Test, console } from "forge-std/Test.sol";

import { PayGateway } from "src/PayGateway.sol";
import { PayGatewayExtension } from "src/PayGatewayExtension.sol";
import { IExtensionConfig } from "lib/modular-contracts/src/interface/IExtensionConfig.sol";
import { PayGatewayModule } from "src/PayGatewayModule.sol";
import { IModuleConfig } from "lib/modular-contracts/src/interface/IModuleConfig.sol";
import { IModularCore } from "lib/modular-contracts/src/interface/IModularCore.sol";
import { LibClone } from "lib/solady/src/utils/LibClone.sol";
import { MockERC20 } from "./utils/MockERC20.sol";
Expand Down Expand Up @@ -39,7 +39,7 @@ contract PayGatewayTest is Test {

event OperatorChanged(address indexed previousOperator, address indexed newOperator);

PayGatewayExtension internal gateway;
PayGatewayModule internal gateway;
MockERC20 internal mockERC20;
MockTarget internal mockTarget;

Expand All @@ -56,7 +56,7 @@ contract PayGatewayTest is Test {
uint256 internal clientFeeAmount;
uint256 internal totalFeeAmount;

PayGatewayExtension.PayoutInfo[] internal payouts;
PayGatewayModule.PayoutInfo[] internal payouts;

bytes32 internal typehashPayRequest;
bytes32 internal typehashPayoutInfo;
Expand All @@ -78,17 +78,17 @@ contract PayGatewayTest is Test {
ownerFeeAmount = 20;
clientFeeAmount = 10;

// deploy and install extension
// deploy and install module
address impl = address(new PayGateway());
address extension = address(new PayGatewayExtension());
address module = address(new PayGatewayModule());

address[] memory extensions = new address[](1);
bytes[] memory extensionData = new bytes[](1);
extensions[0] = address(extension);
extensionData[0] = "";
address[] memory modules = new address[](1);
bytes[] memory moduleData = new bytes[](1);
modules[0] = address(module);
moduleData[0] = "";

gateway = PayGatewayExtension(LibClone.clone(impl));
PayGateway(payable(address(gateway))).initialize(operator, extensions, extensionData);
gateway = PayGatewayModule(LibClone.clone(impl));
PayGateway(payable(address(gateway))).initialize(operator, modules, moduleData);

mockERC20 = new MockERC20("Token", "TKN");
mockTarget = new MockTarget();
Expand All @@ -99,10 +99,10 @@ contract PayGatewayTest is Test {

// build payout info
payouts.push(
PayGatewayExtension.PayoutInfo({ clientId: ownerClientId, payoutAddress: owner, feeAmount: ownerFeeAmount })
PayGatewayModule.PayoutInfo({ clientId: ownerClientId, payoutAddress: owner, feeAmount: ownerFeeAmount })
);
payouts.push(
PayGatewayExtension.PayoutInfo({ clientId: clientId, payoutAddress: client, feeAmount: clientFeeAmount })
PayGatewayModule.PayoutInfo({ clientId: clientId, payoutAddress: client, feeAmount: clientFeeAmount })
);

for (uint256 i = 0; i < payouts.length; i++) {
Expand Down Expand Up @@ -136,7 +136,7 @@ contract PayGatewayTest is Test {
data = abi.encode(_sender, _receiver, _token, _sendValue, _message);
}

function _hashPayoutInfo(PayGatewayExtension.PayoutInfo[] memory _payouts) private view returns (bytes32) {
function _hashPayoutInfo(PayGatewayModule.PayoutInfo[] memory _payouts) private view returns (bytes32) {
bytes32 payoutHash = typehashPayoutInfo;

bytes32[] memory payoutsHashes = new bytes32[](_payouts.length);
Expand All @@ -150,7 +150,7 @@ contract PayGatewayTest is Test {

function _prepareAndSignData(
uint256 _operatorPrivateKey,
PayGatewayExtension.PayRequest memory req
PayGatewayModule.PayRequest memory req
) internal view returns (bytes memory signature) {
bytes memory dataToHash;
{
Expand Down Expand Up @@ -191,7 +191,7 @@ contract PayGatewayTest is Test {
mockERC20.approve(address(gateway), sendValueWithFees);

// create pay request
PayGatewayExtension.PayRequest memory req;
PayGatewayModule.PayRequest memory req;
bytes32 _transactionId = keccak256("transaction ID");

req.clientId = clientId;
Expand Down Expand Up @@ -238,7 +238,7 @@ contract PayGatewayTest is Test {
);

// create pay request
PayGatewayExtension.PayRequest memory req;
PayGatewayModule.PayRequest memory req;
bytes32 _transactionId = keccak256("transaction ID");

req.clientId = clientId;
Expand Down Expand Up @@ -289,7 +289,7 @@ contract PayGatewayTest is Test {
mockERC20.approve(address(gateway), sendValueWithFees);

// create pay request
PayGatewayExtension.PayRequest memory req;
PayGatewayModule.PayRequest memory req;
bytes32 _transactionId = keccak256("transaction ID");

req.clientId = clientId;
Expand Down Expand Up @@ -324,7 +324,7 @@ contract PayGatewayTest is Test {
mockERC20.approve(address(gateway), sendValueWithFees);

// create pay request
PayGatewayExtension.PayRequest memory req;
PayGatewayModule.PayRequest memory req;
bytes32 _transactionId = keccak256("transaction ID");

req.clientId = clientId;
Expand All @@ -344,7 +344,7 @@ contract PayGatewayTest is Test {

// send transaction
vm.prank(sender);
vm.expectRevert(abi.encodeWithSelector(PayGatewayExtension.PayGatewayVerificationFailed.selector));
vm.expectRevert(abi.encodeWithSelector(PayGatewayModule.PayGatewayVerificationFailed.selector));
gateway.initiateTokenPurchase(req, _signature);
}

Expand All @@ -353,7 +353,7 @@ contract PayGatewayTest is Test {
bytes memory targetCalldata = "";

// create pay request
PayGatewayExtension.PayRequest memory req;
PayGatewayModule.PayRequest memory req;
bytes32 _transactionId = keccak256("transaction ID");

req.clientId = clientId;
Expand All @@ -372,7 +372,7 @@ contract PayGatewayTest is Test {
// send transaction
vm.prank(sender);
vm.expectRevert(
abi.encodeWithSelector(PayGatewayExtension.PayGatewayRequestExpired.selector, req.expirationTimestamp)
abi.encodeWithSelector(PayGatewayModule.PayGatewayRequestExpired.selector, req.expirationTimestamp)
);
gateway.initiateTokenPurchase(req, _signature);
}
Expand Down
34 changes: 17 additions & 17 deletions test/benchmarks/BenchmarkPayGateway.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ pragma solidity ^0.8.13;

import { Test, console } from "forge-std/Test.sol";
import { PayGateway } from "src/PayGateway.sol";
import { PayGatewayExtension } from "src/PayGatewayExtension.sol";
import { PayGatewayModule } from "src/PayGatewayModule.sol";
import { LibClone } from "lib/solady/src/utils/LibClone.sol";
import { MockERC20 } from "../utils/MockERC20.sol";
import { MockTarget } from "../utils/MockTarget.sol";

contract BenchmarkPayGatewayTest is Test {
PayGatewayExtension internal gateway;
PayGatewayModule internal gateway;
MockERC20 internal mockERC20;
MockTarget internal mockTarget;

Expand All @@ -26,7 +26,7 @@ contract BenchmarkPayGatewayTest is Test {
uint256 internal clientFeeAmount;
uint256 internal totalFeeAmount;

PayGatewayExtension.PayoutInfo[] internal payouts;
PayGatewayModule.PayoutInfo[] internal payouts;

bytes32 internal typehashPayRequest;
bytes32 internal typehashPayoutInfo;
Expand All @@ -48,17 +48,17 @@ contract BenchmarkPayGatewayTest is Test {
ownerFeeAmount = 20;
clientFeeAmount = 10;

// deploy and install extension
// deploy and install module
address impl = address(new PayGateway());
address extension = address(new PayGatewayExtension());
address module = address(new PayGatewayModule());

address[] memory extensions = new address[](1);
bytes[] memory extensionData = new bytes[](1);
extensions[0] = address(extension);
extensionData[0] = "";
address[] memory modules = new address[](1);
bytes[] memory moduleData = new bytes[](1);
modules[0] = address(module);
moduleData[0] = "";

gateway = PayGatewayExtension(LibClone.clone(impl));
PayGateway(payable(address(gateway))).initialize(operator, extensions, extensionData);
gateway = PayGatewayModule(LibClone.clone(impl));
PayGateway(payable(address(gateway))).initialize(operator, modules, moduleData);

mockERC20 = new MockERC20("Token", "TKN");
mockTarget = new MockTarget();
Expand All @@ -69,10 +69,10 @@ contract BenchmarkPayGatewayTest is Test {

// build payout info
payouts.push(
PayGatewayExtension.PayoutInfo({ clientId: ownerClientId, payoutAddress: owner, feeAmount: ownerFeeAmount })
PayGatewayModule.PayoutInfo({ clientId: ownerClientId, payoutAddress: owner, feeAmount: ownerFeeAmount })
);
payouts.push(
PayGatewayExtension.PayoutInfo({ clientId: clientId, payoutAddress: client, feeAmount: clientFeeAmount })
PayGatewayModule.PayoutInfo({ clientId: clientId, payoutAddress: client, feeAmount: clientFeeAmount })
);

for (uint256 i = 0; i < payouts.length; i++) {
Expand Down Expand Up @@ -106,7 +106,7 @@ contract BenchmarkPayGatewayTest is Test {
data = abi.encode(_sender, _receiver, _token, _sendValue, _message);
}

function _hashPayoutInfo(PayGatewayExtension.PayoutInfo[] memory _payouts) private view returns (bytes32) {
function _hashPayoutInfo(PayGatewayModule.PayoutInfo[] memory _payouts) private view returns (bytes32) {
bytes32 payoutHash = typehashPayoutInfo;

bytes32[] memory payoutsHashes = new bytes32[](_payouts.length);
Expand All @@ -120,7 +120,7 @@ contract BenchmarkPayGatewayTest is Test {

function _prepareAndSignData(
uint256 _operatorPrivateKey,
PayGatewayExtension.PayRequest memory req
PayGatewayModule.PayRequest memory req
) internal view returns (bytes memory signature) {
bytes memory dataToHash;
{
Expand Down Expand Up @@ -162,7 +162,7 @@ contract BenchmarkPayGatewayTest is Test {
mockERC20.approve(address(gateway), sendValueWithFees);

// create pay request
PayGatewayExtension.PayRequest memory req;
PayGatewayModule.PayRequest memory req;
bytes32 _transactionId = keccak256("transaction ID");

req.clientId = clientId;
Expand Down Expand Up @@ -199,7 +199,7 @@ contract BenchmarkPayGatewayTest is Test {
);

// create pay request
PayGatewayExtension.PayRequest memory req;
PayGatewayModule.PayRequest memory req;
bytes32 _transactionId = keccak256("transaction ID");

req.clientId = clientId;
Expand Down

0 comments on commit 33c274f

Please sign in to comment.