Skip to content
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

Chore/increase test coverage and add natspec #314

Merged
Show file tree
Hide file tree
Changes from all 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
13 changes: 12 additions & 1 deletion contracts/AllowanceTarget.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,33 @@ import { Pausable } from "@openzeppelin/contracts/utils/Pausable.sol";
import { Ownable } from "./abstracts/Ownable.sol";
import { IAllowanceTarget } from "./interfaces/IAllowanceTarget.sol";

/// @title AllowanceTarget Contract
/// @author imToken Labs
/// @notice This contract manages allowances and authorizes spenders to transfer tokens on behalf of users.
contract AllowanceTarget is IAllowanceTarget, Pausable, Ownable {
using SafeERC20 for IERC20;

mapping(address => bool) public authorized;
/// @notice Mapping of authorized addresses permitted to call spendFromUserTo.
mapping(address trustedCaller => bool isAuthorized) public authorized;

/// @notice Constructor to initialize the contract with the owner and trusted callers.
/// @param _owner The address of the contract owner.
/// @param trustedCaller An array of addresses that are initially authorized to call spendFromUserTo.
constructor(address _owner, address[] memory trustedCaller) Ownable(_owner) {
uint256 callerCount = trustedCaller.length;
for (uint256 i = 0; i < callerCount; ++i) {
authorized[trustedCaller[i]] = true;
}
}

/// @notice Pauses the contract, preventing the execution of spendFromUserTo.
/// @dev Only the owner can call this function.
function pause() external onlyOwner {
_pause();
}

/// @notice Unpauses the contract, allowing the execution of spendFromUserTo.
/// @dev Only the owner can call this function.
function unpause() external onlyOwner {
_unpause();
}
Expand Down
22 changes: 18 additions & 4 deletions contracts/CoordinatedTaker.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,24 @@ import { SignatureValidator } from "./libraries/SignatureValidator.sol";

/// @title CoordinatedTaker Contract
/// @author imToken Labs
/// @notice This contract allows for the coordinator of limit order fills through a designated coordinator.
alex0207s marked this conversation as resolved.
Show resolved Hide resolved
contract CoordinatedTaker is ICoordinatedTaker, AdminManagement, TokenCollector, EIP712 {
using Asset for address;

IWETH public immutable weth;
ILimitOrderSwap public immutable limitOrderSwap;
address public coordinator;

mapping(bytes32 => bool) public allowFillUsed;
/// @notice Mapping to keep track of used allow fill hashes.
mapping(bytes32 allowFillHash => bool isUsed) public allowFillUsed;

/// @notice Constructor to initialize the contract with the owner, Uniswap permit2, allowance target, WETH, coordinator and LimitOrderSwap contract.
/// @param _owner The address of the contract owner.
/// @param _uniswapPermit2 The address for Uniswap permit2.
/// @param _allowanceTarget The address for the allowance target.
/// @param _weth The WETH contract instance.
/// @param _coordinator The initial coordinator address.
/// @param _limitOrderSwap The LimitOrderSwap contract address.
constructor(
address _owner,
address _uniswapPermit2,
Expand All @@ -36,15 +45,20 @@ contract CoordinatedTaker is ICoordinatedTaker, AdminManagement, TokenCollector,
limitOrderSwap = _limitOrderSwap;
}

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

/// @notice Sets a new coordinator address.
/// @dev Only the owner can call this function.
/// @param _newCoordinator The address of the new coordinator.
function setCoordinator(address _newCoordinator) external onlyOwner {
if (_newCoordinator == address(0)) revert ZeroAddress();
coordinator = _newCoordinator;

emit SetCoordinator(_newCoordinator);
}

/// @inheritdoc ICoordinatedTaker
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why have natspec in both this contract and ICoordinatedTaker?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For maintain consistency and ensure comprehensive documentation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll remove it and just leave @inheritdoc comment in the contract.

function submitLimitOrderFill(
LimitOrder calldata order,
bytes calldata makerSignature,
Expand All @@ -59,15 +73,15 @@ contract CoordinatedTaker is ICoordinatedTaker, AdminManagement, TokenCollector,
if (crdParams.expiry < block.timestamp) revert ExpiredPermission();

bytes32 orderHash = getLimitOrderHash(order);

bytes32 allowFillHash = getEIP712Hash(
getAllowFillHash(
AllowFill({ orderHash: orderHash, taker: msg.sender, fillAmount: makerTokenAmount, salt: crdParams.salt, expiry: crdParams.expiry })
)
);
if (!SignatureValidator.validateSignature(coordinator, allowFillHash, crdParams.sig)) revert InvalidSignature();

if (!SignatureValidator.validateSignature(coordinator, allowFillHash, crdParams.sig)) revert InvalidSignature();
if (allowFillUsed[allowFillHash]) revert ReusedPermission();

allowFillUsed[allowFillHash] = true;

emit CoordinatorFill({ user: msg.sender, orderHash: orderHash, allowFillHash: allowFillHash });
Expand All @@ -80,7 +94,7 @@ contract CoordinatedTaker is ICoordinatedTaker, AdminManagement, TokenCollector,
}

// send order to limit order contract
// use fullOrKill since coordinator should manage fill amount distribution
// use fillLimitOrderFullOrKill since coordinator should manage fill amount distribution
limitOrderSwap.fillLimitOrderFullOrKill{ value: msg.value }(
order,
makerSignature,
Expand Down
29 changes: 22 additions & 7 deletions contracts/GenericSwap.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,32 @@ import { GenericSwapData, getGSDataHash } from "./libraries/GenericSwapData.sol"
import { Asset } from "./libraries/Asset.sol";
import { SignatureValidator } from "./libraries/SignatureValidator.sol";

/// @title GenericSwap Contract
/// @author imToken Labs
/// @notice This contract facilitates token swaps using SmartOrderStrategy strategies.
contract GenericSwap is IGenericSwap, TokenCollector, EIP712 {
using Asset for address;

mapping(bytes32 => bool) private filledSwap;
/// @notice Mapping to keep track of filled swaps.
/// @dev Stores the status of swaps to ensure they are not filled more than once.
mapping(bytes32 swapHash => bool isFilled) public filledSwap;

/// @notice Constructor to initialize the contract with the permit2 and allowance target.
/// @param _uniswapPermit2 The address for Uniswap permit2.
/// @param _allowanceTarget The address for the allowance target.
constructor(address _uniswapPermit2, address _allowanceTarget) TokenCollector(_uniswapPermit2, _allowanceTarget) {}

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

/// @param swapData Swap data
/// @return returnAmount Output amount of the swap
/// @inheritdoc IGenericSwap
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto. Why have natspec here too?

function executeSwap(GenericSwapData calldata swapData, bytes calldata takerTokenPermit) external payable returns (uint256 returnAmount) {
returnAmount = _executeSwap(swapData, msg.sender, takerTokenPermit);

_emitGSExecuted(getGSDataHash(swapData), swapData, msg.sender, returnAmount);
}

/// @param swapData Swap data
/// @param taker Claimed taker address
/// @param takerSig Taker signature
/// @return returnAmount Output amount of the swap
/// @inheritdoc IGenericSwap
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

function executeSwapWithSig(
GenericSwapData calldata swapData,
bytes calldata takerTokenPermit,
Expand All @@ -47,6 +52,11 @@ contract GenericSwap is IGenericSwap, TokenCollector, EIP712 {
_emitGSExecuted(swapHash, swapData, taker, returnAmount);
}

/// @notice Executes a generic swap.
/// @param _swapData The swap data containing details of the swap.
/// @param _authorizedUser The address authorized to execute the swap.
/// @param _takerTokenPermit The permit for the taker token.
/// @return returnAmount The output amount of the swap.
function _executeSwap(
GenericSwapData calldata _swapData,
address _authorizedUser,
Expand Down Expand Up @@ -78,6 +88,11 @@ contract GenericSwap is IGenericSwap, TokenCollector, EIP712 {
_outputToken.transferTo(_swapData.recipient, returnAmount);
}

/// @notice Emits the Swap event after executing a generic swap.
/// @param _gsOfferHash The hash of the generic swap offer.
/// @param _swapData The swap data containing details of the swap.
/// @param _taker The address of the taker.
/// @param returnAmount The output amount of the swap.
function _emitGSExecuted(bytes32 _gsOfferHash, GenericSwapData calldata _swapData, address _taker, uint256 returnAmount) internal {
emit Swap(
_gsOfferHash,
Expand Down
Loading
Loading