Skip to content
Open
Show file tree
Hide file tree
Changes from 6 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
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;
}
1 change: 1 addition & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ remappings = [
'erc721a/=lib/ERC721A/',
'@thirdweb-dev/dynamic-contracts/=lib/dynamic-contracts/',
'lib/sstore2=lib/dynamic-contracts/lib/sstore2/',
'@prb/proxy/=lib/prb-proxy/',
]
fs_permissions = [{ access = "read-write", path = "./src/test/smart-wallet/utils"}]
src = 'contracts'
Expand Down
1 change: 1 addition & 0 deletions lib/prb-proxy
Submodule prb-proxy added at 1c43be
Loading