From f22d745e5599e1b7d3dc902d0bfe6aa592aa5d04 Mon Sep 17 00:00:00 2001 From: vasa Date: Tue, 16 Aug 2022 19:49:18 +0530 Subject: [PATCH] refactor: add eip-2981 extension (wip) License: BUSL-1.1 Signed-off-by: Vaibhav Saini --- src/LSSVMRouter.sol | 84 +++++++++++++++++++++++++++------- src/LSSVMRouterWithRoyalty.sol | 8 ++++ src/extensions/EIP2981.sol | 49 ++++++++++++++++++++ 3 files changed, 124 insertions(+), 17 deletions(-) create mode 100644 src/LSSVMRouterWithRoyalty.sol create mode 100644 src/extensions/EIP2981.sol diff --git a/src/LSSVMRouter.sol b/src/LSSVMRouter.sol index bc2ddb6..554fe2c 100644 --- a/src/LSSVMRouter.sol +++ b/src/LSSVMRouter.sol @@ -48,7 +48,7 @@ contract LSSVMRouter { } struct RobustPairNFTsFoTokenAndTokenforNFTsTrade { - RobustPairSwapSpecific[] tokenToNFTTrades; + RobustPairSwapSpecific[] tokenToNFTTrades; RobustPairSwapSpecificForToken[] nftToTokenTrades; uint256 inputAmount; address payable tokenRecipient; @@ -86,6 +86,7 @@ contract LSSVMRouter { ) external payable + virtual checkDeadline(deadline) returns (uint256 remainingValue) { @@ -109,6 +110,7 @@ contract LSSVMRouter { ) external payable + virtual checkDeadline(deadline) returns (uint256 remainingValue) { @@ -137,7 +139,13 @@ contract LSSVMRouter { address payable ethRecipient, address nftRecipient, uint256 deadline - ) external payable checkDeadline(deadline) returns (uint256 outputAmount) { + ) + external + payable + virtual + checkDeadline(deadline) + returns (uint256 outputAmount) + { // Swap NFTs for ETH // minOutput of swap set to 0 since we're doing an aggregate slippage check outputAmount = _swapNFTsForToken( @@ -177,7 +185,13 @@ contract LSSVMRouter { address payable ethRecipient, address nftRecipient, uint256 deadline - ) external payable checkDeadline(deadline) returns (uint256 outputAmount) { + ) + external + payable + virtual + checkDeadline(deadline) + returns (uint256 outputAmount) + { // Swap NFTs for ETH // minOutput of swap set to 0 since we're doing an aggregate slippage check outputAmount = _swapNFTsForToken( @@ -225,7 +239,12 @@ contract LSSVMRouter { uint256 inputAmount, address nftRecipient, uint256 deadline - ) external checkDeadline(deadline) returns (uint256 remainingValue) { + ) + external + virtual + checkDeadline(deadline) + returns (uint256 remainingValue) + { return _swapERC20ForAnyNFTs(swapList, inputAmount, nftRecipient); } @@ -242,7 +261,12 @@ contract LSSVMRouter { uint256 inputAmount, address nftRecipient, uint256 deadline - ) external checkDeadline(deadline) returns (uint256 remainingValue) { + ) + external + virtual + checkDeadline(deadline) + returns (uint256 remainingValue) + { return _swapERC20ForSpecificNFTs(swapList, inputAmount, nftRecipient); } @@ -259,7 +283,7 @@ contract LSSVMRouter { uint256 minOutput, address tokenRecipient, uint256 deadline - ) external checkDeadline(deadline) returns (uint256 outputAmount) { + ) external virtual checkDeadline(deadline) returns (uint256 outputAmount) { return _swapNFTsForToken(swapList, minOutput, payable(tokenRecipient)); } @@ -279,7 +303,7 @@ contract LSSVMRouter { uint256 minOutput, address nftRecipient, uint256 deadline - ) external checkDeadline(deadline) returns (uint256 outputAmount) { + ) external virtual checkDeadline(deadline) returns (uint256 outputAmount) { // Swap NFTs for ERC20 // minOutput of swap set to 0 since we're doing an aggregate slippage check // output tokens are sent to msg.sender @@ -320,7 +344,7 @@ contract LSSVMRouter { uint256 minOutput, address nftRecipient, uint256 deadline - ) external checkDeadline(deadline) returns (uint256 outputAmount) { + ) external virtual checkDeadline(deadline) returns (uint256 outputAmount) { // Swap NFTs for ERC20 // minOutput of swap set to 0 since we're doing an aggregate slippage check // output tokens are sent to msg.sender @@ -368,6 +392,7 @@ contract LSSVMRouter { ) external payable + virtual checkDeadline(deadline) returns (uint256 remainingValue) { @@ -425,7 +450,13 @@ contract LSSVMRouter { address payable ethRecipient, address nftRecipient, uint256 deadline - ) public payable checkDeadline(deadline) returns (uint256 remainingValue) { + ) + public + payable + virtual + checkDeadline(deadline) + returns (uint256 remainingValue) + { remainingValue = msg.value; uint256 pairCost; CurveErrorCodes.Error error; @@ -482,7 +513,12 @@ contract LSSVMRouter { uint256 inputAmount, address nftRecipient, uint256 deadline - ) external checkDeadline(deadline) returns (uint256 remainingValue) { + ) + external + virtual + checkDeadline(deadline) + returns (uint256 remainingValue) + { remainingValue = inputAmount; uint256 pairCost; CurveErrorCodes.Error error; @@ -529,7 +565,7 @@ contract LSSVMRouter { uint256 inputAmount, address nftRecipient, uint256 deadline - ) public checkDeadline(deadline) returns (uint256 remainingValue) { + ) public virtual checkDeadline(deadline) returns (uint256 remainingValue) { remainingValue = inputAmount; uint256 pairCost; CurveErrorCodes.Error error; @@ -576,7 +612,7 @@ contract LSSVMRouter { RobustPairSwapSpecificForToken[] calldata swapList, address payable tokenRecipient, uint256 deadline - ) public checkDeadline(deadline) returns (uint256 outputAmount) { + ) public virtual checkDeadline(deadline) returns (uint256 outputAmount) { // Try doing each swap uint256 numSwaps = swapList.length; for (uint256 i; i < numSwaps; ) { @@ -627,7 +663,12 @@ contract LSSVMRouter { */ function robustSwapETHForSpecificNFTsAndNFTsToToken( RobustPairNFTsFoTokenAndTokenforNFTsTrade calldata params - ) external payable returns (uint256 remainingValue, uint256 outputAmount) { + ) + external + payable + virtual + returns (uint256 remainingValue, uint256 outputAmount) + { { remainingValue = msg.value; uint256 pairCost; @@ -734,7 +775,12 @@ contract LSSVMRouter { */ function robustSwapERC20ForSpecificNFTsAndNFTsToToken( RobustPairNFTsFoTokenAndTokenforNFTsTrade calldata params - ) external payable returns (uint256 remainingValue, uint256 outputAmount) { + ) + external + payable + virtual + returns (uint256 remainingValue, uint256 outputAmount) + { { remainingValue = params.inputAmount; uint256 pairCost; @@ -744,17 +790,21 @@ contract LSSVMRouter { uint256 numSwaps = params.tokenToNFTTrades.length; for (uint256 i; i < numSwaps; ) { // Calculate actual cost per swap - (error, , , pairCost, ) = params.tokenToNFTTrades[i] + (error, , , pairCost, ) = params + .tokenToNFTTrades[i] .swapInfo .pair - .getBuyNFTQuote(params.tokenToNFTTrades[i].swapInfo.nftIds.length); + .getBuyNFTQuote( + params.tokenToNFTTrades[i].swapInfo.nftIds.length + ); // If within our maxCost and no error, proceed if ( pairCost <= params.tokenToNFTTrades[i].maxCost && error == CurveErrorCodes.Error.OK ) { - remainingValue -= params.tokenToNFTTrades[i] + remainingValue -= params + .tokenToNFTTrades[i] .swapInfo .pair .swapTokenForSpecificNFTs( diff --git a/src/LSSVMRouterWithRoyalty.sol b/src/LSSVMRouterWithRoyalty.sol new file mode 100644 index 0000000..709c2e9 --- /dev/null +++ b/src/LSSVMRouterWithRoyalty.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity ^0.8.0; + +import {LSSVMRouter} from "./LSSVMRouter.sol"; + +contract LSSVMRouterWithRoyalty is LSSVMRouter, EIP2981Extension { + // TODO: Add EIP2981 complaint versions of all sudoswap swap functions. +} diff --git a/src/extensions/EIP2981.sol b/src/extensions/EIP2981.sol new file mode 100644 index 0000000..450e885 --- /dev/null +++ b/src/extensions/EIP2981.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity ^0.8.0; + +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + +/// +/// @dev Interface for the NFT Royalty Standard +/// +interface IERC2981 is IERC165 { + /// ERC165 bytes to add to interface array - set in parent contract + /// implementing this standard + /// + /// bytes4(keccak256("royaltyInfo(uint256,uint256)")) == 0x2a55205a + /// bytes4 private constant _INTERFACE_ID_ERC2981 = 0x2a55205a; + /// _registerInterface(_INTERFACE_ID_ERC2981); + + /// @notice Called with the sale price to determine how much royalty + // is owed and to whom. + /// @param _tokenId - the NFT asset queried for royalty information + /// @param _salePrice - the sale price of the NFT asset specified by _tokenId + /// @return receiver - address of who should be sent the royalty payment + /// @return royaltyAmount - the royalty payment amount for _salePrice + function royaltyInfo(uint256 _tokenId, uint256 _salePrice) + external + view + returns (address receiver, uint256 royaltyAmount); +} + +contract EIP2981Extension { + bytes4 private constant _INTERFACE_ID_ERC2981 = 0x2a55205a; + + function _checkRoyalties(address _contract) internal view returns (bool) { + bool success = IERC165(_contract).supportsInterface( + _INTERFACE_ID_ERC2981 + ); + return success; + } + + function _getRoyaltyInfo( + IERC2981 _token, + uint256 _tokenId, + uint256 _salePrice + ) internal view returns (address _royaltyReceiver, uint256 _royaltyAmount) { + (_royaltyReceiver, _royaltyAmount) = IERC2981(_token).royaltyInfo( + _tokenId, + _salePrice + ); + } +}