Skip to content

Checkout plugin and proxy #598

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@
[submodule "lib/dynamic-contracts"]
path = lib/dynamic-contracts
url = https://github.com/thirdweb-dev/dynamic-contracts
[submodule "lib/prb-proxy"]
path = lib/prb-proxy
url = https://github.com/PaulRBerg/prb-proxy
251 changes: 251 additions & 0 deletions contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.18;

Check warning

Code scanning / Slither

Different pragma directives are used

Different versions of Solidity are used: - Version used: ['>=0.8.18', '>=0.8.4', '^0.8.0', '^0.8.1', '^0.8.10', '^0.8.11', '^0.8.12', '^0.8.2', '^0.8.4', '^0.8.8', '^0.8.9'] - >=0.8.18 (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#2) - >=0.8.18 (lib/prb-proxy/src/PRBProxy.sol#2) - >=0.8.4 (lib/prb-proxy/src/interfaces/IPRBProxy.sol#2) - >=0.8.4 (lib/prb-proxy/src/interfaces/IPRBProxyPlugin.sol#2) - >=0.8.4 (lib/prb-proxy/src/interfaces/IPRBProxyRegistry.sol#2) - ^0.8.0 (contracts/base/ERC1155Base.sol#2) - ^0.8.0 (contracts/base/ERC1155DelayedReveal.sol#2) - ^0.8.0 (contracts/base/ERC1155Drop.sol#2) - ^0.8.0 (contracts/base/ERC1155LazyMint.sol#2) - ^0.8.0 (contracts/base/ERC1155SignatureMint.sol#2) - ^0.8.0 (contracts/base/ERC20Base.sol#2) - ^0.8.0 (contracts/base/ERC20Drop.sol#2) - ^0.8.0 (contracts/base/ERC20DropVote.sol#2) - ^0.8.0 (contracts/base/ERC20SignatureMint.sol#2) - ^0.8.0 (contracts/base/ERC20SignatureMintVote.sol#2) - ^0.8.0 (contracts/base/ERC20Vote.sol#2) - ^0.8.0 (contracts/base/ERC721Base.sol#2) - ^0.8.0 (contracts/base/ERC721DelayedReveal.sol#2) - ^0.8.0 (contracts/base/ERC721Drop.sol#2) - ^0.8.0 (contracts/base/ERC721LazyMint.sol#2) - ^0.8.0 (contracts/base/ERC721Multiwrap.sol#2) - ^0.8.0 (contracts/base/ERC721SignatureMint.sol#2) - ^0.8.0 (contracts/base/Staking1155Base.sol#2) - ^0.8.0 (contracts/base/Staking20Base.sol#2) - ^0.8.0 (contracts/base/Staking721Base.sol#2) - ^0.8.0 (contracts/eip/ERC1155.sol#2) - ^0.8.0 (contracts/eip/ERC1271.sol#2) - ^0.8.0 (contracts/eip/ERC165.sol#4) - ^0.8.0 (contracts/eip/interface/IERC1155.sol#2) - ^0.8.0 (contracts/eip/interface/IERC1155Enumerable.sol#2) - ^0.8.0 (contracts/eip/interface/IERC1155Metadata.sol#2) - ^0.8.0 (contracts/eip/interface/IERC1155Receiver.sol#4) - ^0.8.0 (contracts/eip/interface/IERC1155Supply.sol#2) - ^0.8.0 (contracts/eip/interface/IERC165.sol#4) - ^0.8.0 (contracts/eip/interface/IERC20.sol#2) - ^0.8.0 (contracts/eip/interface/IERC20Metadata.sol#2) - ^0.8.0 (contracts/eip/interface/IERC20Permit.sol#4) - ^0.8.0 (contracts/eip/interface/IERC2981.sol#2) - ^0.8.0 (contracts/eip/interface/IERC721.sol#4) - ^0.8.0 (contracts/eip/interface/IERC721Enumerable.sol#2) - ^0.8.0 (contracts/eip/interface/IERC721Metadata.sol#2) - ^0.8.0 (contracts/eip/interface/IERC721Receiver.sol#4) - ^0.8.0 (contracts/eip/interface/IERC721Supply.sol#2) - ^0.8.0 (contracts/eip/queryable/ERC721AStorage.sol#3) - ^0.8.0 (contracts/eip/queryable/ERC721A__Initializable.sol#2) - ^0.8.0 (contracts/eip/queryable/ERC721A__InitializableStorage.sol#3) - ^0.8.0 (contracts/extension/AppURI.sol#2) - ^0.8.0 (contracts/extension/BatchMintMetadata.sol#2) - ^0.8.0 (contracts/extension/BurnToClaim.sol#2) - ^0.8.0 (contracts/extension/ContractMetadata.sol#2) - ^0.8.0 (contracts/extension/DelayedReveal.sol#2) - ^0.8.0 (contracts/extension/Drop.sol#2) - ^0.8.0 (contracts/extension/Drop1155.sol#2) - ^0.8.0 (contracts/extension/DropSinglePhase.sol#2) - ^0.8.0 (contracts/extension/DropSinglePhase1155.sol#2) - ^0.8.0 (contracts/extension/Initializable.sol#2) - ^0.8.0 (contracts/extension/LazyMint.sol#2) - ^0.8.0 (contracts/extension/LazyMintWithTier.sol#2) - ^0.8.0 (contracts/extension/Multicall.sol#2) - ^0.8.0 (contracts/extension/NFTMetadata.sol#2) - ^0.8.0 (contracts/extension/OperatorFilterToggle.sol#2) - ^0.8.0 (contracts/extension/OperatorFilterer.sol#2) - ^0.8.0 (contracts/extension/OperatorFiltererUpgradeable.sol#2) - ^0.8.0 (contracts/extension/Ownable.sol#2) - ^0.8.0 (contracts/extension/Permissions.sol#2) - ^0.8.0 (contracts/extension/PermissionsEnumerable.sol#2) - ^0.8.0 (contracts/extension/PlatformFee.sol#2) - ^0.8.0 (contracts/extension/PrimarySale.sol#2) - ^0.8.0 (contracts/extension/Proxy.sol#2) - ^0.8.0 (contracts/extension/ProxyForUpgradeable.sol#2) - ^0.8.0 (contracts/extension/Royalty.sol#2) - ^0.8.0 (contracts/extension/SignatureAction.sol#2) - ^0.8.0 (contracts/extension/SignatureActionUpgradeable.sol#2) - ^0.8.0 (contracts/extension/SignatureMintERC1155.sol#2) - ^0.8.0 (contrac

import { IPRBProxy } from "@prb/proxy/src/interfaces/IPRBProxy.sol";
import { IPRBProxyPlugin } from "@prb/proxy/src/interfaces/IPRBProxyPlugin.sol";
import { IPRBProxyRegistry } from "@prb/proxy/src/interfaces/IPRBProxyRegistry.sol";
import { PRBProxy } from "@prb/proxy/src/PRBProxy.sol";

/// @author Modified from prb-proxy (https://github.com/PaulRBerg/prb-proxy/blob/main/src/PRBProxyRegistry.sol)
/// @title PRBProxyRegistry
/// @dev See the documentation in {IPRBProxyRegistry}.
contract PRBProxyRegistryModified is IPRBProxyRegistry {
/*//////////////////////////////////////////////////////////////////////////
CONSTANTS
//////////////////////////////////////////////////////////////////////////*/

/// @inheritdoc IPRBProxyRegistry
string public constant override VERSION = "4.0.2";

/// @dev Magic value to override target permissions. Holders can execute on any target.
address public constant MAGIC_TARGET = address(0x42);

/*//////////////////////////////////////////////////////////////////////////
USER-FACING STORAGE
//////////////////////////////////////////////////////////////////////////*/

/// @inheritdoc IPRBProxyRegistry
ConstructorParams public override constructorParams;

/*//////////////////////////////////////////////////////////////////////////
INTERNAL STORAGE
//////////////////////////////////////////////////////////////////////////*/

mapping(address owner => mapping(IPRBProxyPlugin plugin => bytes4[] methods)) internal _methods;

mapping(address owner => mapping(address envoy => mapping(address target => bool permission)))
internal _permissions;

mapping(address owner => mapping(bytes4 method => IPRBProxyPlugin plugin)) internal _plugins;

mapping(address owner => IPRBProxy proxy) internal _proxies;

/*//////////////////////////////////////////////////////////////////////////
MODIFIERS
//////////////////////////////////////////////////////////////////////////*/

/// @notice Checks that the caller has a proxy.
modifier onlyCallerWithProxy() {
if (address(_proxies[msg.sender]) == address(0)) {
revert PRBProxyRegistry_UserDoesNotHaveProxy(msg.sender);
}
_;
}

/// @notice Check that the user does not have a proxy.
modifier onlyNonProxyOwner(address user) {
IPRBProxy proxy = _proxies[user];
if (address(proxy) != address(0)) {
revert PRBProxyRegistry_UserHasProxy(user, proxy);
}
_;
}

/*//////////////////////////////////////////////////////////////////////////
USER-FACING CONSTANT FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/

/// @inheritdoc IPRBProxyRegistry
function getMethodsByOwner(address owner, IPRBProxyPlugin plugin) external view returns (bytes4[] memory methods) {
methods = _methods[owner][plugin];
}

/// @inheritdoc IPRBProxyRegistry
function getMethodsByProxy(
IPRBProxy proxy,
IPRBProxyPlugin plugin
) external view returns (bytes4[] memory methods) {
methods = _methods[proxy.owner()][plugin];
}

/// @inheritdoc IPRBProxyRegistry
function getPermissionByOwner(
address owner,
address envoy,
address target
) external view returns (bool permission) {
permission = _permissions[owner][envoy][target] || _permissions[owner][envoy][MAGIC_TARGET];
}

/// @inheritdoc IPRBProxyRegistry
function getPermissionByProxy(
IPRBProxy proxy,
address envoy,
address target
) external view returns (bool permission) {
permission = _permissions[proxy.owner()][envoy][target] || _permissions[proxy.owner()][envoy][MAGIC_TARGET];
}

/// @inheritdoc IPRBProxyRegistry
function getPluginByOwner(address owner, bytes4 method) external view returns (IPRBProxyPlugin plugin) {
plugin = _plugins[owner][method];
}

/// @inheritdoc IPRBProxyRegistry
function getPluginByProxy(IPRBProxy proxy, bytes4 method) external view returns (IPRBProxyPlugin plugin) {
plugin = _plugins[proxy.owner()][method];
}

/// @inheritdoc IPRBProxyRegistry
function getProxy(address user) external view returns (IPRBProxy proxy) {
proxy = _proxies[user];
}

/*//////////////////////////////////////////////////////////////////////////
USER-FACING NON-CONSTANT FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/

/// @inheritdoc IPRBProxyRegistry
function deploy() external override onlyNonProxyOwner(msg.sender) returns (IPRBProxy proxy) {
proxy = _deploy({ owner: msg.sender, target: address(0), data: "" });
}

/// @inheritdoc IPRBProxyRegistry
function deployAndExecute(
address target,
bytes calldata data
) external override onlyNonProxyOwner(msg.sender) returns (IPRBProxy proxy) {
proxy = _deploy({ owner: msg.sender, target: target, data: data });
}

/// @inheritdoc IPRBProxyRegistry
function deployFor(address user) external override onlyNonProxyOwner(user) returns (IPRBProxy proxy) {
proxy = _deploy({ owner: user, target: address(0), data: "" });
}

/// @inheritdoc IPRBProxyRegistry
function deployAndExecuteAndInstallPlugin(
address target,
bytes calldata data,
IPRBProxyPlugin plugin
) external override onlyNonProxyOwner(msg.sender) returns (IPRBProxy proxy) {
proxy = _deploy({ owner: msg.sender, target: target, data: data });
_installPlugin(plugin);
}
Comment on lines +137 to +144

Check notice

Code scanning / Slither

Reentrancy vulnerabilities

Reentrancy in PRBProxyRegistryModified.deployAndExecuteAndInstallPlugin(address,bytes,IPRBProxyPlugin) (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#137-144): External calls: - proxy = _deploy({owner:msg.sender,target:target,data:data}) (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#142) - proxy = new PRBProxy() (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#206) - _installPlugin(plugin) (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#143) - methods = plugin.getMethods() (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#219) State variables written after the call(s): - _installPlugin(plugin) (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#143) - _methods[owner][plugin] = methods (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#246)
Comment on lines +137 to +144

Check notice

Code scanning / Slither

Reentrancy vulnerabilities

Reentrancy in PRBProxyRegistryModified.deployAndExecuteAndInstallPlugin(address,bytes,IPRBProxyPlugin) (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#137-144): External calls: - proxy = _deploy({owner:msg.sender,target:target,data:data}) (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#142) - proxy = new PRBProxy() (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#206) - _installPlugin(plugin) (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#143) - methods = plugin.getMethods() (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#219) Event emitted after the call(s): - InstallPlugin(owner,_proxies[owner],plugin,methods) (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#249) - _installPlugin(plugin) (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#143)

/// @inheritdoc IPRBProxyRegistry
function deployAndInstallPlugin(
IPRBProxyPlugin plugin
) external onlyNonProxyOwner(msg.sender) returns (IPRBProxy proxy) {
proxy = _deploy({ owner: msg.sender, target: address(0), data: "" });
_installPlugin(plugin);
}
Comment on lines +147 to +152

Check notice

Code scanning / Slither

Reentrancy vulnerabilities

Reentrancy in PRBProxyRegistryModified.deployAndInstallPlugin(IPRBProxyPlugin) (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#147-152): External calls: - proxy = _deploy({owner:msg.sender,target:address(0),data:}) (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#150) - proxy = new PRBProxy() (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#206) - _installPlugin(plugin) (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#151) - methods = plugin.getMethods() (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#219) State variables written after the call(s): - _installPlugin(plugin) (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#151) - _methods[owner][plugin] = methods (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#246)
Comment on lines +147 to +152

Check notice

Code scanning / Slither

Reentrancy vulnerabilities

Reentrancy in PRBProxyRegistryModified.deployAndInstallPlugin(IPRBProxyPlugin) (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#147-152): External calls: - proxy = _deploy({owner:msg.sender,target:address(0),data:}) (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#150) - proxy = new PRBProxy() (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#206) - _installPlugin(plugin) (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#151) - methods = plugin.getMethods() (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#219) Event emitted after the call(s): - InstallPlugin(owner,_proxies[owner],plugin,methods) (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#249) - _installPlugin(plugin) (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#151)

/// @inheritdoc IPRBProxyRegistry
function installPlugin(IPRBProxyPlugin plugin) external override onlyCallerWithProxy {
_installPlugin(plugin);
}

/// @inheritdoc IPRBProxyRegistry
function setPermission(address envoy, address target, bool permission) external override onlyCallerWithProxy {
address owner = msg.sender;
_permissions[owner][envoy][target] = permission;
emit SetPermission(owner, _proxies[owner], envoy, target, permission);
}

/// @inheritdoc IPRBProxyRegistry
function uninstallPlugin(IPRBProxyPlugin plugin) external override onlyCallerWithProxy {
// Retrieve the methods originally installed by this plugin.
address owner = msg.sender;
bytes4[] memory methods = _methods[owner][plugin];

// The plugin must be a known, previously installed plugin.
uint256 length = methods.length;
if (length == 0) {
revert PRBProxyRegistry_PluginUnknown(plugin);
}

// Uninstall every method in the list.
for (uint256 i = 0; i < length; ) {
delete _plugins[owner][methods[i]];
unchecked {
i += 1;
}
}

// Remove the methods from the reverse mapping.
delete _methods[owner][plugin];

// Log the plugin uninstallation.
emit UninstallPlugin(owner, _proxies[owner], plugin, methods);
}

/*//////////////////////////////////////////////////////////////////////////
INTERNAL NON-CONSTANT FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/

/// @dev See the documentation for the user-facing functions that call this internal function.
function _deploy(address owner, address target, bytes memory data) internal returns (IPRBProxy proxy) {
// Use the address of the owner as the CREATE2 salt.
bytes32 salt = bytes32(abi.encodePacked(owner));

// Set the owner and empty out the target and the data to prevent reentrancy.
constructorParams = ConstructorParams({ owner: owner, target: target, data: data });

// Deploy the proxy with CREATE2.
proxy = new PRBProxy{ salt: salt }();
delete constructorParams;

// Associate the owner and the proxy.
_proxies[owner] = proxy;

// Log the creation of the proxy.
emit DeployProxy({ operator: msg.sender, owner: owner, proxy: proxy });
}
Comment on lines +198 to +214

Check notice

Code scanning / Slither

Reentrancy vulnerabilities

Reentrancy in PRBProxyRegistryModified._deploy(address,address,bytes) (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#198-214): External calls: - proxy = new PRBProxy() (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#206) State variables written after the call(s): - _proxies[owner] = proxy (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#210) - delete constructorParams (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#207)
Comment on lines +198 to +214

Check notice

Code scanning / Slither

Reentrancy vulnerabilities

Reentrancy in PRBProxyRegistryModified._deploy(address,address,bytes) (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#198-214): External calls: - proxy = new PRBProxy() (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#206) Event emitted after the call(s): - DeployProxy({operator:msg.sender,owner:owner,proxy:proxy}) (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#213)

/// @dev See the documentation for the user-facing functions that call this internal function.
function _installPlugin(IPRBProxyPlugin plugin) internal {
// Retrieve the methods to install.
bytes4[] memory methods = plugin.getMethods();

// The plugin must implement at least one method.
uint256 length = methods.length;
if (length == 0) {
revert PRBProxyRegistry_PluginWithZeroMethods(plugin);
}

// Install every method in the list.
address owner = msg.sender;
for (uint256 i = 0; i < length; ) {
// Check for collisions.
bytes4 method = methods[i];
if (address(_plugins[owner][method]) != address(0)) {
revert PRBProxyRegistry_PluginMethodCollision({
currentPlugin: _plugins[owner][method],
newPlugin: plugin,
method: method
});
}
_plugins[owner][method] = plugin;
unchecked {
i += 1;
}
}

// Set the methods in the reverse mapping.
_methods[owner][plugin] = methods;

// Log the plugin installation.
emit InstallPlugin(owner, _proxies[owner], plugin, methods);
}
Comment on lines +217 to +250

Check notice

Code scanning / Slither

Reentrancy vulnerabilities

Reentrancy in PRBProxyRegistryModified._installPlugin(IPRBProxyPlugin) (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#217-250): External calls: - methods = plugin.getMethods() (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#219) State variables written after the call(s): - _methods[owner][plugin] = methods (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#246) - _plugins[owner][method] = plugin (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#239)
Comment on lines +217 to +250

Check notice

Code scanning / Slither

Reentrancy vulnerabilities

Reentrancy in PRBProxyRegistryModified._installPlugin(IPRBProxyPlugin) (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#217-250): External calls: - methods = plugin.getMethods() (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#219) Event emitted after the call(s): - InstallPlugin(owner,_proxies[owner],plugin,methods) (contracts/prebuilts/unaudited/checkout/PRBProxyRegistryModified.sol#249)
}
26 changes: 26 additions & 0 deletions contracts/prebuilts/unaudited/checkout/PluginCheckout.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;

// $$\ $$\ $$\ $$\ $$\
// $$ | $$ | \__| $$ | $$ |
// $$$$$$\ $$$$$$$\ $$\ $$$$$$\ $$$$$$$ |$$\ $$\ $$\ $$$$$$\ $$$$$$$\
// \_$$ _| $$ __$$\ $$ |$$ __$$\ $$ __$$ |$$ | $$ | $$ |$$ __$$\ $$ __$$\
// $$ | $$ | $$ |$$ |$$ | \__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ |
// $$ |$$\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ |
// \$$$$ |$$ | $$ |$$ |$$ | \$$$$$$$ |\$$$$$\$$$$ |\$$$$$$$\ $$$$$$$ |
// \____/ \__| \__|\__|\__| \_______| \_____\____/ \_______|\_______/

import { IPRBProxyPlugin } from "@prb/proxy/src/interfaces/IPRBProxyPlugin.sol";

import "./TargetCheckout.sol";

contract PluginCheckout is IPRBProxyPlugin, TargetCheckout {
function getMethods() external pure override returns (bytes4[] memory) {
bytes4[] memory methods = new bytes4[](4);
methods[0] = this.withdraw.selector;
methods[1] = this.execute.selector;
methods[2] = this.swapAndExecute.selector;
methods[3] = this.approveSwapRouter.selector;
return methods;
}
}
82 changes: 82 additions & 0 deletions contracts/prebuilts/unaudited/checkout/TargetCheckout.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;

import "../../../lib/CurrencyTransferLib.sol";
import "../../../eip/interface/IERC20.sol";

import { IPRBProxy } from "@prb/proxy/src/interfaces/IPRBProxy.sol";
import "./interface/IPluginCheckout.sol";

// $$\ $$\ $$\ $$\ $$\
// $$ | $$ | \__| $$ | $$ |
// $$$$$$\ $$$$$$$\ $$\ $$$$$$\ $$$$$$$ |$$\ $$\ $$\ $$$$$$\ $$$$$$$\
// \_$$ _| $$ __$$\ $$ |$$ __$$\ $$ __$$ |$$ | $$ | $$ |$$ __$$\ $$ __$$\
// $$ | $$ | $$ |$$ |$$ | \__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ |
// $$ |$$\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ |
// \$$$$ |$$ | $$ |$$ |$$ | \$$$$$$$ |\$$$$$\$$$$ |\$$$$$$$\ $$$$$$$ |
// \____/ \__| \__|\__|\__| \_______| \_____\____/ \_______|\_______/

contract TargetCheckout is IPluginCheckout {
mapping(address => bool) public isApprovedRouter;

function withdraw(address _token, uint256 _amount) external {
require(msg.sender == IPRBProxy(address(this)).owner(), "Not authorized");

CurrencyTransferLib.transferCurrency(_token, address(this), msg.sender, _amount);
}

function approveSwapRouter(address _swapRouter, bool _toApprove) external {
require(msg.sender == IPRBProxy(address(this)).owner(), "Not authorized");
require(_swapRouter != address(0), "Zero address");

isApprovedRouter[_swapRouter] = _toApprove;
}

function execute(UserOp memory op) external {
require(_canExecute(op, msg.sender), "Not authorized");

_execute(op);
}

function swapAndExecute(UserOp memory op, UserOp memory swapOp) external {
require(isApprovedRouter[swapOp.target], "Invalid router address");
require(_canExecute(op, msg.sender), "Not authorized");

_execute(swapOp);
_execute(op);
}

// =================================================
// =============== Internal functions ==============
// =================================================

function _execute(UserOp memory op) internal {
bool success;
if (op.currency == CurrencyTransferLib.NATIVE_TOKEN) {
(success, ) = op.target.call{ value: op.valueToSend }(op.data);
} else {
if (op.valueToSend != 0 && op.approvalRequired) {
IERC20(op.currency).approve(op.target, op.valueToSend);
}

(success, ) = op.target.call(op.data);
}

require(success, "Execution failed");
}

Check failure

Code scanning / Slither

Functions that send Ether to arbitrary destinations

TargetCheckout._execute(IPluginCheckout.UserOp) (contracts/prebuilts/unaudited/checkout/TargetCheckout.sol#53-66) sends eth to arbitrary user Dangerous calls: - (success,None) = op.target.call{value: op.valueToSend}(op.data) (contracts/prebuilts/unaudited/checkout/TargetCheckout.sol#56)

Check warning

Code scanning / Slither

Unused return

TargetCheckout._execute(IPluginCheckout.UserOp) (contracts/prebuilts/unaudited/checkout/TargetCheckout.sol#53-66) ignores return value by IERC20(op.currency).approve(op.target,op.valueToSend) (contracts/prebuilts/unaudited/checkout/TargetCheckout.sol#59)

Check warning

Code scanning / Slither

Low-level calls

Low level call in TargetCheckout._execute(IPluginCheckout.UserOp) (contracts/prebuilts/unaudited/checkout/TargetCheckout.sol#53-66): - (success,None) = op.target.call{value: op.valueToSend}(op.data) (contracts/prebuilts/unaudited/checkout/TargetCheckout.sol#56) - (success,None) = op.target.call(op.data) (contracts/prebuilts/unaudited/checkout/TargetCheckout.sol#62)

function _canExecute(UserOp memory op, address caller) internal view returns (bool) {
address owner = IPRBProxy(address(this)).owner();
if (owner != caller) {
bool permission = IPRBProxy(address(this)).registry().getPermissionByOwner({
owner: owner,
envoy: caller,
target: op.target
});

return permission;
}

return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;

interface IPluginCheckout {
/**
* @notice Details of the transaction to execute on target contract.
*
* @param target Address to send the transaction to
*
* @param currency Represents both native token and erc20 token
*
* @param approvalRequired If need to approve erc20 to the target contract
*
* @param valueToSend Transaction value to send - both native and erc20
*
* @param data Transaction calldata
*/
struct UserOp {
address target;
address currency;
bool approvalRequired;
uint256 valueToSend;
bytes data;
}

function execute(UserOp calldata op) external;

function swapAndExecute(UserOp calldata op, UserOp memory swapOp) external;
}
Loading