Skip to content

Commit b19ecbf

Browse files
committed
feature: add whitelist and add/remove functions for solvers in genericSwap contract
1 parent 5834a58 commit b19ecbf

14 files changed

+193
-98
lines changed

contracts/GenericSwap.sol

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ pragma solidity 0.8.26;
33

44
import { EIP712 } from "./abstracts/EIP712.sol";
55
import { TokenCollector } from "./abstracts/TokenCollector.sol";
6+
import { Ownable } from "./abstracts/Ownable.sol";
67

78
import { IGenericSwap } from "./interfaces/IGenericSwap.sol";
89
import { IStrategy } from "./interfaces/IStrategy.sol";
@@ -14,21 +15,58 @@ import { SignatureValidator } from "./libraries/SignatureValidator.sol";
1415
/// @title GenericSwap Contract
1516
/// @author imToken Labs
1617
/// @notice This contract facilitates token swaps using SmartOrderStrategy strategies.
17-
contract GenericSwap is IGenericSwap, TokenCollector, EIP712 {
18+
contract GenericSwap is IGenericSwap, TokenCollector, EIP712, Ownable {
1819
using Asset for address;
1920

21+
/// @notice Mapping to track addresses authorized as solvers.
22+
/// @dev Maps each address to a boolean indicating whether it is an authorized solver.
23+
mapping(address solver => bool isSolver) public solvers;
24+
2025
/// @notice Mapping to keep track of filled swaps.
2126
/// @dev Stores the status of swaps to ensure they are not filled more than once.
2227
mapping(bytes32 swapHash => bool isFilled) public filledSwap;
2328

29+
modifier onlySolver() {
30+
if (!solvers[msg.sender]) revert InvalidSolver();
31+
_;
32+
}
33+
2434
/// @notice Constructor to initialize the contract with the permit2 and allowance target.
2535
/// @param _uniswapPermit2 The address for Uniswap permit2.
2636
/// @param _allowanceTarget The address for the allowance target.
27-
constructor(address _uniswapPermit2, address _allowanceTarget) TokenCollector(_uniswapPermit2, _allowanceTarget) {}
37+
constructor(
38+
address _uniswapPermit2,
39+
address _allowanceTarget,
40+
address _owner,
41+
address[] memory _trustedSolvers
42+
) TokenCollector(_uniswapPermit2, _allowanceTarget) Ownable(_owner) {
43+
uint256 length = _trustedSolvers.length;
44+
for (uint256 i; i < length; ++i) {
45+
solvers[_trustedSolvers[i]] = true;
46+
}
47+
}
2848

2949
/// @notice Receive function to receive ETH.
3050
receive() external payable {}
3151

52+
function addSolver(address solver) external onlyOwner {
53+
if (solver == address(0)) revert ZeroAddress();
54+
55+
if (!solvers[solver]) {
56+
solvers[solver] = true;
57+
58+
emit AddSolver(solver);
59+
}
60+
}
61+
62+
function removeSolver(address solver) external onlyOwner {
63+
if (solvers[solver]) {
64+
solvers[solver] = false;
65+
66+
emit RemoveSolver(solver);
67+
}
68+
}
69+
3270
/// @inheritdoc IGenericSwap
3371
function executeSwap(
3472
GenericSwapData calldata swapData,
@@ -47,7 +85,7 @@ contract GenericSwap is IGenericSwap, TokenCollector, EIP712 {
4785
bytes calldata takerTokenPermit,
4886
address taker,
4987
bytes calldata takerSig
50-
) external payable returns (uint256 returnAmount) {
88+
) external payable onlySolver returns (uint256 returnAmount) {
5189
bytes32 swapHash = getGSDataHash(swapData);
5290
bytes32 gs712Hash = getEIP712Hash(swapHash);
5391
if (filledSwap[swapHash]) revert AlreadyFilled();
@@ -84,7 +122,7 @@ contract GenericSwap is IGenericSwap, TokenCollector, EIP712 {
84122
_collect(_inputToken, _authorizedUser, _swapData.maker, _swapData.takerTokenAmount, _takerTokenPermit);
85123
}
86124

87-
IStrategy(_swapData.maker).executeStrategy{ value: msg.value }(_outputToken, _swapData.strategyData);
125+
IStrategy(_swapData.maker).executeStrategy{ value: msg.value }(_outputToken, strategyData);
88126

89127
returnAmount = _outputToken.getBalance(address(this));
90128
if (returnAmount > 1) {

contracts/interfaces/IGenericSwap.sol

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@ import { GenericSwapData } from "../libraries/GenericSwapData.sol";
88
/// @notice Interface for a generic swap contract.
99
/// @dev This interface defines functions and events related to executing swaps and handling swap errors.
1010
interface IGenericSwap {
11+
/// @notice Emitted when a new solver is added to the contract.
12+
/// @param solver The address of the solver being added.
13+
event AddSolver(address indexed solver);
14+
15+
/// @notice Emitted when a solver is removed from the contract.
16+
/// @param solver The address of the solver being removed.
17+
event RemoveSolver(address indexed solver);
18+
1119
/// @notice Event emitted when a swap is executed.
1220
/// @param swapHash The hash of the swap data.
1321
/// @param maker The address of the maker initiating the swap.
@@ -30,6 +38,10 @@ interface IGenericSwap {
3038
uint256 salt
3139
);
3240

41+
/// @notice Error to be thrown when an unauthorized address attempts to execute a swap.
42+
/// @dev This error is used to restrict access to certain functions to authorized solvers only
43+
error InvalidSolver();
44+
3345
/// @notice Error to be thrown when a swap is already filled.
3446
/// @dev This error is used when attempting to fill a swap that has already been completed.
3547
error AlreadyFilled();

snapshots/AdminManagement.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
2-
"approveTokens(): testApproveTokens": "133041",
3-
"rescueTokens(): testRescueTokens": "84308"
2+
"approveTokens(): testApproveTokens": "106201",
3+
"rescueTokens(): testRescueTokens": "59723"
44
}

snapshots/AllowanceTarget.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
2-
"pause(): testSpendFromUserToAfterUnpause": "27565",
3-
"spendFromUserTo(): testSpendFromUserTo": "61960",
4-
"spendFromUserTo(): testSpendFromUserToAfterUnpause": "61960",
5-
"spendFromUserTo(): testSpendFromUserToWithDeflationaryToken": "89862",
6-
"spendFromUserTo(): testSpendFromUserToWithNoReturnValueToken": "67278",
7-
"unpause(): testSpendFromUserToAfterUnpause": "27326"
2+
"pause(): testSpendFromUserToAfterUnpause": "6978",
3+
"spendFromUserTo(): testSpendFromUserTo": "36872",
4+
"spendFromUserTo(): testSpendFromUserToAfterUnpause": "34872",
5+
"spendFromUserTo(): testSpendFromUserToWithDeflationaryToken": "65947",
6+
"spendFromUserTo(): testSpendFromUserToWithNoReturnValueToken": "42418",
7+
"unpause(): testSpendFromUserToAfterUnpause": "2175"
88
}

snapshots/Asset.json

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
{
2-
"getBalance(): testGetBalance": "5799",
3-
"getBalance(): testGetBalance(ETH_ADDRESS)": "510",
4-
"getBalance(): testGetBalance(ZERO_ADDRESS)": "517",
5-
"isETH(): testIsETH(ETH_ADDRESS)": "306",
6-
"isETH(): testIsETH(ZERO_ADDRESS)": "313",
7-
"transferTo(): testDoNothingIfTransferToSelf": "22182",
8-
"transferTo(): testDoNothingIfTransferWithZeroAmount": "22170",
9-
"transferTo(): testTransferETH": "56716",
10-
"transferTo(): testTransferToken": "50378"
2+
"getBalance(): testGetBalance": "7087",
3+
"getBalance(): testGetBalance(ETH_ADDRESS)": "1143",
4+
"getBalance(): testGetBalance(ZERO_ADDRESS)": "1165",
5+
"isETH(): testIsETH(ETH_ADDRESS)": "724",
6+
"isETH(): testIsETH(ZERO_ADDRESS)": "746",
7+
"transferTo(): testDoNothingIfTransferToSelf": "877",
8+
"transferTo(): testDoNothingIfTransferWithZeroAmount": "877",
9+
"transferTo(): testTransferETH": "35651",
10+
"transferTo(): testTransferToken": "31566"
1111
}

snapshots/CoordinatedTaker.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"approveTokens(): testApproveTokens": "53171",
3-
"setCoordinator(): testSetCoordinator": "30166",
4-
"submitLimitOrderFill(): testFillWithETH": "189977",
5-
"submitLimitOrderFill(): testFillWithPermission": "252405"
2+
"approveTokens(): testApproveTokens": "28815",
3+
"setCoordinator(): testSetCoordinator": "8995",
4+
"submitLimitOrderFill(): testFillWithETH": "193271",
5+
"submitLimitOrderFill(): testFillWithPermission": "272753"
66
}

snapshots/EIP712.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"EIP712_DOMAIN_SEPARATOR(): testDomainSeparatorOnChain": "337",
3-
"EIP712_DOMAIN_SEPARATOR(): testDomainSeparatorOnDifferentChain": "1074",
4-
"getEIP712Hash(): testGetEIP712Hash": "315"
2+
"EIP712_DOMAIN_SEPARATOR(): testDomainSeparatorOnChain": "443",
3+
"EIP712_DOMAIN_SEPARATOR(): testDomainSeparatorOnDifferentChain": "1404",
4+
"getEIP712Hash(): testGetEIP712Hash": "817"
55
}

snapshots/GenericSwap.json

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
{
2-
"executeSwap(): testGenericSwapWithUniswap": "248141",
3-
"executeSwap(): testLeaveOneWeiWithMultipleUsers(the first deposit)": "248141",
4-
"executeSwap(): testLeaveOneWeiWithMultipleUsers(the second deposit)": "204495",
5-
"executeSwap(): testSwapWithETHInput": "97813",
6-
"executeSwap(): testSwapWithETHOutput": "127973",
7-
"executeSwap(): testSwapWithLessOutputButWithinTolerance": "157429",
8-
"executeSwapWithSig(): testGenericSwapRelayed": "279472"
2+
"addSolver(): testAddSolver": "26392",
3+
"executeSwap(): testGenericSwapWithUniswap": "240706",
4+
"executeSwap(): testLeaveOneWeiWithMultipleUsers(the first deposit)": "234706",
5+
"executeSwap(): testLeaveOneWeiWithMultipleUsers(the second deposit)": "143860",
6+
"executeSwap(): testSwapWithETHInput": "61310",
7+
"executeSwap(): testSwapWithETHOutput": "89483",
8+
"executeSwap(): testSwapWithLessOutputButWithinTolerance": "117249",
9+
"executeSwapWithSig(): testGenericSwapRelayed": "270770",
10+
"removeSolver(): testRemoveSolver": "9261"
911
}

snapshots/LimitOrderSwap.json

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
{
2-
"cancelOrder(): testCancelOrder": "52957",
3-
"fillLimitOrder(): testFillLimitOrderWithETH": "155159",
4-
"fillLimitOrder(): testFillWithBetterTakingAmount": "212150",
5-
"fillLimitOrder(): testFillWithBetterTakingAmountButGetAdjusted": "212318",
6-
"fillLimitOrder(): testFillWithETHRefund": "162238",
7-
"fillLimitOrder(): testFillWithLargerVolumeAndSettleAsManyAsPossible": "212306",
8-
"fillLimitOrder(): testFillWithoutMakerSigForVerifiedOrder": "212150",
9-
"fillLimitOrder(): testFillWithoutMakerSigForVerifiedOrder(without makerSig)": "119214",
10-
"fillLimitOrder(): testFullyFillLimitOrder": "212150",
11-
"fillLimitOrder(): testFullyFillLimitOrderUsingAMM": "231466",
12-
"fillLimitOrder(): testPartiallyFillLimitOrder": "212150",
13-
"fillLimitOrderFullOrKill(): testFillWithFOK": "212327",
14-
"fillLimitOrderGroup(): testGroupFillRingTrade": "287118",
15-
"fillLimitOrderGroup(): testGroupFillWithPartialWETHUnwrap": "273557",
16-
"fillLimitOrderGroup(): testGroupFillWithTakerPrefundETH": "195696",
17-
"fillLimitOrderGroup(): testGroupFillWithWETHUnwrap": "195696",
18-
"fillLimitOrderGroup(): testPartialFillLargeOrderWithSmallOrders": "261176",
19-
"testGroupFillWithProfit: fillLimitOrderGroup()": "221442"
2+
"cancelOrder(): testCancelOrder": "35188",
3+
"fillLimitOrder(): testFillLimitOrderWithETH": "147904",
4+
"fillLimitOrder(): testFillWithBetterTakingAmount": "203163",
5+
"fillLimitOrder(): testFillWithBetterTakingAmountButGetAdjusted": "203649",
6+
"fillLimitOrder(): testFillWithETHRefund": "155664",
7+
"fillLimitOrder(): testFillWithLargerVolumeAndSettleAsManyAsPossible": "203649",
8+
"fillLimitOrder(): testFillWithoutMakerSigForVerifiedOrder": "220163",
9+
"fillLimitOrder(): testFillWithoutMakerSigForVerifiedOrder(without makerSig)": "66600",
10+
"fillLimitOrder(): testFullyFillLimitOrder": "203163",
11+
"fillLimitOrder(): testFullyFillLimitOrderUsingAMM": "230361",
12+
"fillLimitOrder(): testPartiallyFillLimitOrder": "203163",
13+
"fillLimitOrderFullOrKill(): testFillWithFOK": "203208",
14+
"fillLimitOrderGroup(): testGroupFillRingTrade": "312414",
15+
"fillLimitOrderGroup(): testGroupFillWithPartialWETHUnwrap": "286911",
16+
"fillLimitOrderGroup(): testGroupFillWithTakerPrefundETH": "208427",
17+
"fillLimitOrderGroup(): testGroupFillWithWETHUnwrap": "208427",
18+
"fillLimitOrderGroup(): testPartialFillLargeOrderWithSmallOrders": "275390",
19+
"testGroupFillWithProfit: fillLimitOrderGroup()": "235042"
2020
}

snapshots/Ownable.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"acceptOwnership(): testAcceptOwnership": "28029",
3-
"nominateNewOwner(): testNominateNewOwner": "46965",
4-
"renounceOwnership(): testRenounceOwnership": "25105"
2+
"acceptOwnership(): testAcceptOwnership": "5634",
3+
"nominateNewOwner(): testNominateNewOwner": "25920",
4+
"renounceOwnership(): testRenounceOwnership": "9241"
55
}

0 commit comments

Comments
 (0)