mirror of
https://github.com/luxfi/sudoamm.git
synced 2026-07-25 16:17:09 +00:00
feat: adds royalty support for IERC2981 lookup addresses
* chore: copy LSSVMRouter.sol * feat: creating router with royalties + integrating tests * feat: adds robust swaps implementation with royalties * feat: improves tests with royalty issuance checks * feat: adds gas optimizations and event emission on royalty issuance * feat: adds event emission on internal issuances * feat: gas optimization on issueTokenRoyalties * feat: rms double substraction * feat: improved comments * feat: avoids double transfers when no royalty Co-authored-by: 0xng <87835144+0xng@users.noreply.github.com> Co-authored-by: 0xGorilla <0xGorilla@defi.sucks>
This commit is contained in:
co-authored by
0xng
0xGorilla
parent
d52312975c
commit
346800b102
+968
-704
File diff suppressed because it is too large
Load Diff
@@ -14,3 +14,9 @@
|
||||
[submodule "lib/solmate"]
|
||||
path = lib/solmate
|
||||
url = https://github.com/rari-capital/solmate
|
||||
[submodule "lib/royalty-registry-solidity.git"]
|
||||
path = lib/royalty-registry-solidity.git
|
||||
url = https://github.com/manifoldxyz/royalty-registry-solidity.git
|
||||
[submodule "lib/libraries-solidity"]
|
||||
path = lib/libraries-solidity
|
||||
url = https://github.com/manifoldxyz/libraries-solidity
|
||||
|
||||
Submodule
+1
Submodule lib/libraries-solidity added at 029ee99f87
Submodule
+1
Submodule lib/royalty-registry-solidity.git added at fee5379264
@@ -15,6 +15,7 @@
|
||||
"prettier-plugin-solidity": "^1.0.0-beta.13",
|
||||
"rimraf": "^3.0.2"
|
||||
},
|
||||
"dependencies": {},
|
||||
"scripts": {
|
||||
"prepublishOnly": "copyfiles -u 1 \"./src/**/*.sol\" --exclude \"./src/test/**/*.sol\" ./",
|
||||
"postpublish": "rimraf ./*.sol",
|
||||
|
||||
+3
-1
@@ -1,4 +1,6 @@
|
||||
@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/
|
||||
@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/
|
||||
ds-test/=lib/ds-test/src/
|
||||
solmate/=lib/solmate/src/
|
||||
solmate/=lib/solmate/src/
|
||||
manifoldxyz/=lib/royalty-registry-solidity.git/contracts
|
||||
@manifoldxyz/=lib/
|
||||
|
||||
+39
-17
@@ -368,6 +368,7 @@ contract LSSVMRouter {
|
||||
)
|
||||
external
|
||||
payable
|
||||
virtual
|
||||
checkDeadline(deadline)
|
||||
returns (uint256 remainingValue)
|
||||
{
|
||||
@@ -425,7 +426,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;
|
||||
@@ -475,14 +482,19 @@ contract LSSVMRouter {
|
||||
@param nftRecipient The address that will receive the NFT output
|
||||
@param deadline The Unix timestamp (in seconds) at/after which the swap will revert
|
||||
@return remainingValue The unspent token amount
|
||||
|
||||
|
||||
*/
|
||||
function robustSwapERC20ForAnyNFTs(
|
||||
RobustPairSwapAny[] calldata swapList,
|
||||
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 +541,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 +588,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 +639,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 +751,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;
|
||||
@@ -906,7 +928,7 @@ contract LSSVMRouter {
|
||||
uint256 inputAmount,
|
||||
address payable ethRecipient,
|
||||
address nftRecipient
|
||||
) internal returns (uint256 remainingValue) {
|
||||
) internal virtual returns (uint256 remainingValue) {
|
||||
remainingValue = inputAmount;
|
||||
|
||||
uint256 pairCost;
|
||||
@@ -959,7 +981,7 @@ contract LSSVMRouter {
|
||||
uint256 inputAmount,
|
||||
address payable ethRecipient,
|
||||
address nftRecipient
|
||||
) internal returns (uint256 remainingValue) {
|
||||
) internal virtual returns (uint256 remainingValue) {
|
||||
remainingValue = inputAmount;
|
||||
|
||||
uint256 pairCost;
|
||||
@@ -1002,7 +1024,7 @@ contract LSSVMRouter {
|
||||
/**
|
||||
@notice Internal function used to swap an ERC20 token for any NFTs
|
||||
@dev Note that we don't need to query the pair's bonding curve first for pricing data because
|
||||
we just calculate and take the required amount from the caller during swap time.
|
||||
we just calculate and take the required amount from the caller during swap time.
|
||||
However, we can't "pull" ETH, which is why for the ETH->NFT swaps, we need to calculate the pricing info
|
||||
to figure out how much the router should send to the pool.
|
||||
@param swapList The list of pairs and swap calldata
|
||||
@@ -1014,7 +1036,7 @@ contract LSSVMRouter {
|
||||
PairSwapAny[] calldata swapList,
|
||||
uint256 inputAmount,
|
||||
address nftRecipient
|
||||
) internal returns (uint256 remainingValue) {
|
||||
) internal virtual returns (uint256 remainingValue) {
|
||||
remainingValue = inputAmount;
|
||||
|
||||
// Do swaps
|
||||
@@ -1040,7 +1062,7 @@ contract LSSVMRouter {
|
||||
/**
|
||||
@notice Internal function used to swap an ERC20 token for specific NFTs
|
||||
@dev Note that we don't need to query the pair's bonding curve first for pricing data because
|
||||
we just calculate and take the required amount from the caller during swap time.
|
||||
we just calculate and take the required amount from the caller during swap time.
|
||||
However, we can't "pull" ETH, which is why for the ETH->NFT swaps, we need to calculate the pricing info
|
||||
to figure out how much the router should send to the pool.
|
||||
@param swapList The list of pairs and swap calldata
|
||||
@@ -1052,7 +1074,7 @@ contract LSSVMRouter {
|
||||
PairSwapSpecific[] calldata swapList,
|
||||
uint256 inputAmount,
|
||||
address nftRecipient
|
||||
) internal returns (uint256 remainingValue) {
|
||||
) internal virtual returns (uint256 remainingValue) {
|
||||
remainingValue = inputAmount;
|
||||
|
||||
// Do swaps
|
||||
@@ -1077,10 +1099,10 @@ contract LSSVMRouter {
|
||||
|
||||
/**
|
||||
@notice Swaps NFTs for tokens, designed to be used for 1 token at a time
|
||||
@dev Calling with multiple tokens is permitted, BUT minOutput will be
|
||||
@dev Calling with multiple tokens is permitted, BUT minOutput will be
|
||||
far from enough of a safety check because different tokens almost certainly have different unit prices.
|
||||
@param swapList The list of pairs and swap calldata
|
||||
@param minOutput The minimum number of tokens to be receieved frm the swaps
|
||||
@param swapList The list of pairs and swap calldata
|
||||
@param minOutput The minimum number of tokens to be receieved from the swaps
|
||||
@param tokenRecipient The address that receives the tokens
|
||||
@return outputAmount The number of tokens to be received
|
||||
*/
|
||||
@@ -1088,7 +1110,7 @@ contract LSSVMRouter {
|
||||
PairSwapSpecific[] calldata swapList,
|
||||
uint256 minOutput,
|
||||
address payable tokenRecipient
|
||||
) internal returns (uint256 outputAmount) {
|
||||
) internal virtual returns (uint256 outputAmount) {
|
||||
// Do swaps
|
||||
uint256 numSwaps = swapList.length;
|
||||
for (uint256 i; i < numSwaps; ) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,9 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
pragma solidity ^0.8.0;
|
||||
import {ERC2981} from "@openzeppelin/contracts/token/common/ERC2981.sol";
|
||||
|
||||
contract Test2981 is ERC2981 {
|
||||
constructor(address receiver, uint96 bps) {
|
||||
_setDefaultRoyalty(receiver, bps);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
|
||||
import {ERC2981} from "@openzeppelin/contracts/token/common/ERC2981.sol";
|
||||
import {RoyaltyRegistry} from "manifoldxyz/RoyaltyRegistry.sol";
|
||||
|
||||
// Gives more realistic scenarios where swaps have to go through multiple pools, for more accurate gas profiling
|
||||
contract TestRoyaltyRegistry is RoyaltyRegistry {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {DSTest} from "ds-test/test.sol";
|
||||
import {ERC721Holder} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
|
||||
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
|
||||
import {ERC2981} from "@openzeppelin/contracts/token/common/ERC2981.sol";
|
||||
import {RoyaltyRegistry} from "manifoldxyz/RoyaltyRegistry.sol";
|
||||
|
||||
import {ICurve} from "../../bonding-curves/ICurve.sol";
|
||||
import {LSSVMPairFactory} from "../../LSSVMPairFactory.sol";
|
||||
import {LSSVMPair} from "../../LSSVMPair.sol";
|
||||
import {LSSVMPairETH} from "../../LSSVMPairETH.sol";
|
||||
import {LSSVMPairERC20} from "../../LSSVMPairERC20.sol";
|
||||
import {LSSVMPairEnumerableETH} from "../../LSSVMPairEnumerableETH.sol";
|
||||
import {LSSVMPairMissingEnumerableETH} from "../../LSSVMPairMissingEnumerableETH.sol";
|
||||
import {LSSVMPairEnumerableERC20} from "../../LSSVMPairEnumerableERC20.sol";
|
||||
import {LSSVMPairMissingEnumerableERC20} from "../../LSSVMPairMissingEnumerableERC20.sol";
|
||||
import {LSSVMRouterWithRoyalties, LSSVMRouter} from "../../LSSVMRouterWithRoyalties.sol";
|
||||
import {IERC721Mintable} from "../interfaces/IERC721Mintable.sol";
|
||||
import {ConfigurableWithRoyalties} from "../mixins/ConfigurableWithRoyalties.sol";
|
||||
import {RouterCaller} from "../mixins/RouterCaller.sol";
|
||||
|
||||
// Gives more realistic scenarios where swaps have to go through multiple pools, for more accurate gas profiling
|
||||
abstract contract RouterMultiPoolWithRoyalties is
|
||||
DSTest,
|
||||
ERC721Holder,
|
||||
ConfigurableWithRoyalties,
|
||||
RouterCaller
|
||||
{
|
||||
IERC721Mintable test721;
|
||||
ERC2981 test2981;
|
||||
RoyaltyRegistry royaltyRegistry;
|
||||
ICurve bondingCurve;
|
||||
LSSVMPairFactory factory;
|
||||
LSSVMRouter router;
|
||||
mapping(uint256 => LSSVMPair) pairs;
|
||||
address payable constant feeRecipient = payable(address(69));
|
||||
uint256 constant protocolFeeMultiplier = 3e15;
|
||||
uint256 numInitialNFTs = 10;
|
||||
|
||||
function setUp() public {
|
||||
bondingCurve = setupCurve();
|
||||
test721 = setup721();
|
||||
test2981 = setup2981();
|
||||
royaltyRegistry = setupRoyaltyRegistry();
|
||||
royaltyRegistry.setRoyaltyLookupAddress(
|
||||
address(test721),
|
||||
address(test2981)
|
||||
);
|
||||
|
||||
LSSVMPairEnumerableETH enumerableETHTemplate = new LSSVMPairEnumerableETH();
|
||||
LSSVMPairMissingEnumerableETH missingEnumerableETHTemplate = new LSSVMPairMissingEnumerableETH();
|
||||
LSSVMPairEnumerableERC20 enumerableERC20Template = new LSSVMPairEnumerableERC20();
|
||||
LSSVMPairMissingEnumerableERC20 missingEnumerableERC20Template = new LSSVMPairMissingEnumerableERC20();
|
||||
factory = new LSSVMPairFactory(
|
||||
enumerableETHTemplate,
|
||||
missingEnumerableETHTemplate,
|
||||
enumerableERC20Template,
|
||||
missingEnumerableERC20Template,
|
||||
feeRecipient,
|
||||
protocolFeeMultiplier
|
||||
);
|
||||
router = new LSSVMRouterWithRoyalties(factory);
|
||||
factory.setBondingCurveAllowed(bondingCurve, true);
|
||||
factory.setRouterAllowed(router, true);
|
||||
|
||||
// set NFT approvals
|
||||
test721.setApprovalForAll(address(factory), true);
|
||||
test721.setApprovalForAll(address(router), true);
|
||||
|
||||
// mint NFT #1-10 to caller
|
||||
for (uint256 i = 1; i <= numInitialNFTs; i++) {
|
||||
test721.mint(address(this), i);
|
||||
}
|
||||
|
||||
// Pair 1 has NFT#1 at 1 ETH price, willing to also buy at the same price
|
||||
// Pair 2 has NFT#2 at 2 ETH price, willing to also buy at the same price
|
||||
// Pair 3 has NFT#3 at 3 ETH price, willing to also buy at the same price
|
||||
// Pair 4 has NFT#4 at 4 ETH price, willing to also buy at the same price
|
||||
// Pair 5 has NFT#5 at 5 ETH price, willing to also buy at the same price
|
||||
// For all, assume no price changes
|
||||
for (uint256 i = 1; i <= 5; i++) {
|
||||
uint256[] memory idList = new uint256[](1);
|
||||
idList[0] = i;
|
||||
pairs[i] = this.setupPair{value: modifyInputAmount(i * 1 ether)}(
|
||||
factory,
|
||||
test721,
|
||||
bondingCurve,
|
||||
payable(address(0)),
|
||||
LSSVMPair.PoolType.TRADE,
|
||||
modifyDelta(0),
|
||||
0,
|
||||
uint128(i * 1 ether),
|
||||
idList,
|
||||
(i * 1 ether),
|
||||
address(router)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function test_swapTokenForAny5NFTs() public {
|
||||
// Swap across all 5 pools
|
||||
LSSVMRouter.PairSwapAny[]
|
||||
memory swapList = new LSSVMRouter.PairSwapAny[](5);
|
||||
uint256 totalInputAmount = 0;
|
||||
uint256 totalRoyaltyAmount = 0;
|
||||
for (uint256 i = 0; i < 5; i++) {
|
||||
uint256 inputAmount;
|
||||
(, , , inputAmount, ) = pairs[i + 1].getBuyNFTQuote(1);
|
||||
|
||||
// calculate royalty and add it to the input amount
|
||||
uint256 royaltyAmount = calcRoyalty(inputAmount);
|
||||
inputAmount += royaltyAmount;
|
||||
totalRoyaltyAmount += royaltyAmount;
|
||||
|
||||
totalInputAmount += inputAmount;
|
||||
swapList[i] = LSSVMRouter.PairSwapAny({
|
||||
pair: pairs[i + 1],
|
||||
numItems: 1
|
||||
});
|
||||
}
|
||||
uint256 startBalance = test721.balanceOf(address(this));
|
||||
this.swapTokenForAnyNFTs{value: modifyInputAmount(totalInputAmount)}(
|
||||
router,
|
||||
swapList,
|
||||
payable(address(this)),
|
||||
address(this),
|
||||
block.timestamp,
|
||||
totalInputAmount
|
||||
);
|
||||
uint256 endBalance = test721.balanceOf(address(this));
|
||||
require((endBalance - startBalance) == 5, "Too few NFTs acquired");
|
||||
|
||||
// check that royalty has been issued
|
||||
assertEq(getBalance(ROYALTY_RECEIVER), totalRoyaltyAmount);
|
||||
}
|
||||
|
||||
function test_swapTokenForSpecific5NFTs() public {
|
||||
// Swap across all 5 pools
|
||||
LSSVMRouter.PairSwapSpecific[]
|
||||
memory swapList = new LSSVMRouter.PairSwapSpecific[](5);
|
||||
uint256 totalInputAmount = 0;
|
||||
uint256 totalRoyaltyAmount = 0;
|
||||
for (uint256 i = 0; i < 5; i++) {
|
||||
uint256 inputAmount;
|
||||
(, , , inputAmount, ) = pairs[i + 1].getBuyNFTQuote(1);
|
||||
|
||||
// calculate royalty and add it to the input amount
|
||||
uint256 royaltyAmount = calcRoyalty(inputAmount);
|
||||
inputAmount += royaltyAmount;
|
||||
totalRoyaltyAmount += royaltyAmount;
|
||||
|
||||
totalInputAmount += inputAmount;
|
||||
uint256[] memory nftIds = new uint256[](1);
|
||||
nftIds[0] = i + 1;
|
||||
swapList[i] = LSSVMRouter.PairSwapSpecific({
|
||||
pair: pairs[i + 1],
|
||||
nftIds: nftIds
|
||||
});
|
||||
}
|
||||
uint256 startBalance = test721.balanceOf(address(this));
|
||||
this.swapTokenForSpecificNFTs{
|
||||
value: modifyInputAmount(totalInputAmount)
|
||||
}(
|
||||
router,
|
||||
swapList,
|
||||
payable(address(this)),
|
||||
address(this),
|
||||
block.timestamp,
|
||||
totalInputAmount
|
||||
);
|
||||
uint256 endBalance = test721.balanceOf(address(this));
|
||||
require((endBalance - startBalance) == 5, "Too few NFTs acquired");
|
||||
|
||||
// check that royalty has been issued
|
||||
assertEq(getBalance(ROYALTY_RECEIVER), totalRoyaltyAmount);
|
||||
}
|
||||
|
||||
function test_swap5NFTsForToken() public {
|
||||
// Swap across all 5 pools
|
||||
LSSVMRouter.PairSwapSpecific[]
|
||||
memory swapList = new LSSVMRouter.PairSwapSpecific[](5);
|
||||
uint256 totalOutputAmount = 0;
|
||||
uint256 totalRoyaltyAmount = 0;
|
||||
for (uint256 i = 0; i < 5; i++) {
|
||||
uint256 outputAmount;
|
||||
(, , , outputAmount, ) = pairs[i + 1].getSellNFTQuote(1);
|
||||
|
||||
// calculate royalty and rm it from the output amount
|
||||
uint256 royaltyAmount = calcRoyalty(outputAmount);
|
||||
outputAmount -= royaltyAmount;
|
||||
totalRoyaltyAmount += royaltyAmount;
|
||||
|
||||
totalOutputAmount += outputAmount;
|
||||
uint256[] memory nftIds = new uint256[](1);
|
||||
// Set it to be an ID we own
|
||||
nftIds[0] = i + 6;
|
||||
swapList[i] = LSSVMRouter.PairSwapSpecific({
|
||||
pair: pairs[i + 1],
|
||||
nftIds: nftIds
|
||||
});
|
||||
}
|
||||
uint256 startBalance = test721.balanceOf(address(this));
|
||||
router.swapNFTsForToken(
|
||||
swapList,
|
||||
totalOutputAmount,
|
||||
payable(address(this)),
|
||||
block.timestamp
|
||||
);
|
||||
uint256 endBalance = test721.balanceOf(address(this));
|
||||
require((startBalance - endBalance) == 5, "Too few NFTs sold");
|
||||
|
||||
// check that royalty has been issued
|
||||
assertEq(getBalance(ROYALTY_RECEIVER), totalRoyaltyAmount);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,508 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {DSTest} from "ds-test/test.sol";
|
||||
import {ERC20} from "solmate/tokens/ERC20.sol";
|
||||
import {ERC721Holder} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
|
||||
import {ERC2981} from "@openzeppelin/contracts/token/common/ERC2981.sol";
|
||||
import {RoyaltyRegistry} from "manifoldxyz/RoyaltyRegistry.sol";
|
||||
|
||||
import {LinearCurve} from "../../bonding-curves/LinearCurve.sol";
|
||||
import {ICurve} from "../../bonding-curves/ICurve.sol";
|
||||
import {LSSVMPairFactory} from "../../LSSVMPairFactory.sol";
|
||||
import {LSSVMPair} from "../../LSSVMPair.sol";
|
||||
import {LSSVMPairETH} from "../../LSSVMPairETH.sol";
|
||||
import {LSSVMPairERC20} from "../../LSSVMPairERC20.sol";
|
||||
import {LSSVMPairEnumerableETH} from "../../LSSVMPairEnumerableETH.sol";
|
||||
import {LSSVMPairMissingEnumerableETH} from "../../LSSVMPairMissingEnumerableETH.sol";
|
||||
import {LSSVMPairEnumerableERC20} from "../../LSSVMPairEnumerableERC20.sol";
|
||||
import {LSSVMPairMissingEnumerableERC20} from "../../LSSVMPairMissingEnumerableERC20.sol";
|
||||
import {LSSVMRouterWithRoyalties, LSSVMRouter} from "../../LSSVMRouterWithRoyalties.sol";
|
||||
import {IERC721Mintable} from "../interfaces/IERC721Mintable.sol";
|
||||
import {Hevm} from "../utils/Hevm.sol";
|
||||
import {ConfigurableWithRoyalties} from "../mixins/ConfigurableWithRoyalties.sol";
|
||||
import {RouterCaller} from "../mixins/RouterCaller.sol";
|
||||
|
||||
abstract contract RouterRobustSwapWithRoyalties is
|
||||
DSTest,
|
||||
ERC721Holder,
|
||||
ConfigurableWithRoyalties,
|
||||
RouterCaller
|
||||
{
|
||||
IERC721Mintable test721;
|
||||
ERC2981 test2981;
|
||||
RoyaltyRegistry royaltyRegistry;
|
||||
ICurve bondingCurve;
|
||||
LSSVMPairFactory factory;
|
||||
LSSVMRouter router;
|
||||
|
||||
// Create 3 pairs
|
||||
LSSVMPair pair1;
|
||||
LSSVMPair pair2;
|
||||
LSSVMPair pair3;
|
||||
|
||||
address payable constant feeRecipient = payable(address(69));
|
||||
|
||||
// Set protocol fee to be 10%
|
||||
uint256 constant protocolFeeMultiplier = 1e17;
|
||||
|
||||
function setUp() public {
|
||||
// Create contracts
|
||||
bondingCurve = setupCurve();
|
||||
test721 = setup721();
|
||||
test2981 = setup2981();
|
||||
royaltyRegistry = setupRoyaltyRegistry();
|
||||
royaltyRegistry.setRoyaltyLookupAddress(
|
||||
address(test721),
|
||||
address(test2981)
|
||||
);
|
||||
|
||||
LSSVMPairEnumerableETH enumerableETHTemplate = new LSSVMPairEnumerableETH();
|
||||
LSSVMPairMissingEnumerableETH missingEnumerableETHTemplate = new LSSVMPairMissingEnumerableETH();
|
||||
LSSVMPairEnumerableERC20 enumerableERC20Template = new LSSVMPairEnumerableERC20();
|
||||
LSSVMPairMissingEnumerableERC20 missingEnumerableERC20Template = new LSSVMPairMissingEnumerableERC20();
|
||||
factory = new LSSVMPairFactory(
|
||||
enumerableETHTemplate,
|
||||
missingEnumerableETHTemplate,
|
||||
enumerableERC20Template,
|
||||
missingEnumerableERC20Template,
|
||||
feeRecipient,
|
||||
protocolFeeMultiplier
|
||||
);
|
||||
router = new LSSVMRouterWithRoyalties(factory);
|
||||
|
||||
// Set approvals
|
||||
test721.setApprovalForAll(address(factory), true);
|
||||
test721.setApprovalForAll(address(router), true);
|
||||
factory.setBondingCurveAllowed(bondingCurve, true);
|
||||
factory.setRouterAllowed(router, true);
|
||||
|
||||
uint256[] memory empty;
|
||||
uint256 nftIndex = 0;
|
||||
|
||||
// Create 3 pairs with 0 delta and 0 trade fee
|
||||
// pair 1 has spot price of 0.1 TOKEN, then pair 2 has 0.2 TOKEN, and pair 3 has 0.3 TOKEN
|
||||
// Send 10 NFTs to each pair
|
||||
// (0-9), (10-19), (20-29)
|
||||
pair1 = this.setupPair{value: modifyInputAmount(10 ether)}(
|
||||
factory,
|
||||
test721,
|
||||
bondingCurve,
|
||||
payable(address(0)),
|
||||
LSSVMPair.PoolType.TRADE,
|
||||
modifyDelta(0),
|
||||
0,
|
||||
0.1 ether,
|
||||
empty,
|
||||
10 ether,
|
||||
address(router)
|
||||
);
|
||||
for (uint256 j = 0; j < 10; j++) {
|
||||
test721.mint(address(this), nftIndex);
|
||||
test721.safeTransferFrom(address(this), address(pair1), nftIndex);
|
||||
nftIndex++;
|
||||
}
|
||||
|
||||
pair2 = this.setupPair{value: modifyInputAmount(10 ether)}(
|
||||
factory,
|
||||
test721,
|
||||
bondingCurve,
|
||||
payable(address(0)),
|
||||
LSSVMPair.PoolType.TRADE,
|
||||
modifyDelta(0),
|
||||
0,
|
||||
0.2 ether,
|
||||
empty,
|
||||
10 ether,
|
||||
address(router)
|
||||
);
|
||||
for (uint256 j = 0; j < 10; j++) {
|
||||
test721.mint(address(this), nftIndex);
|
||||
test721.safeTransferFrom(address(this), address(pair2), nftIndex);
|
||||
nftIndex++;
|
||||
}
|
||||
|
||||
pair3 = this.setupPair{value: modifyInputAmount(10 ether)}(
|
||||
factory,
|
||||
test721,
|
||||
bondingCurve,
|
||||
payable(address(0)),
|
||||
LSSVMPair.PoolType.TRADE,
|
||||
modifyDelta(0),
|
||||
0,
|
||||
0.3 ether,
|
||||
empty,
|
||||
10 ether,
|
||||
address(router)
|
||||
);
|
||||
for (uint256 j = 0; j < 10; j++) {
|
||||
test721.mint(address(this), nftIndex);
|
||||
test721.safeTransferFrom(address(this), address(pair3), nftIndex);
|
||||
nftIndex++;
|
||||
}
|
||||
|
||||
// Mint NFTs 30-39 to this contract
|
||||
for (uint256 i = 0; i < 10; i++) {
|
||||
test721.mint(address(this), nftIndex);
|
||||
nftIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
// Test where pair 1 and pair 2 swap tokens for NFT succeed but pair 3 fails
|
||||
function test_robustSwapTokenForAny2NFTs() public {
|
||||
LSSVMRouter.RobustPairSwapAny[]
|
||||
memory swapList = new LSSVMRouter.RobustPairSwapAny[](3);
|
||||
|
||||
(, , , uint256 pair1InputAmount, ) = pair1.getBuyNFTQuote(2);
|
||||
(, , , uint256 pair2InputAmount, ) = pair2.getBuyNFTQuote(2);
|
||||
|
||||
uint256 totalRoyaltyAmount = 0;
|
||||
|
||||
// calculate royalty and add it to the input amount
|
||||
uint256 royaltyAmount = calcRoyalty(pair1InputAmount);
|
||||
pair1InputAmount += royaltyAmount;
|
||||
totalRoyaltyAmount += royaltyAmount;
|
||||
royaltyAmount = calcRoyalty(pair2InputAmount);
|
||||
pair2InputAmount += royaltyAmount;
|
||||
totalRoyaltyAmount += royaltyAmount;
|
||||
|
||||
swapList[0] = LSSVMRouter.RobustPairSwapAny({
|
||||
swapInfo: LSSVMRouter.PairSwapAny({pair: pair1, numItems: 2}),
|
||||
maxCost: pair2InputAmount
|
||||
});
|
||||
swapList[1] = LSSVMRouter.RobustPairSwapAny({
|
||||
swapInfo: LSSVMRouter.PairSwapAny({pair: pair2, numItems: 2}),
|
||||
maxCost: pair2InputAmount
|
||||
});
|
||||
swapList[2] = LSSVMRouter.RobustPairSwapAny({
|
||||
swapInfo: LSSVMRouter.PairSwapAny({pair: pair3, numItems: 2}),
|
||||
maxCost: pair2InputAmount
|
||||
});
|
||||
|
||||
uint256 beforeNFTBalance = test721.balanceOf(address(this));
|
||||
|
||||
// Expect to have the first two swapPairs succeed, and the last one silently fail
|
||||
// with 10% protocol fee:
|
||||
uint256 remainingValue = this.robustSwapTokenForAnyNFTs{
|
||||
value: modifyInputAmount(pair2InputAmount * 3)
|
||||
}(
|
||||
router,
|
||||
swapList,
|
||||
payable(address(this)),
|
||||
address(this),
|
||||
block.timestamp,
|
||||
pair2InputAmount * 3
|
||||
);
|
||||
|
||||
uint256 afterNFTBalance = test721.balanceOf(address(this));
|
||||
|
||||
// If the first two swap pairs succeed, we gain 4 NFTs
|
||||
assertEq((afterNFTBalance - beforeNFTBalance), 4, "Incorrect NFT swap");
|
||||
|
||||
assertEq(
|
||||
remainingValue,
|
||||
pair2InputAmount * 3 - (pair1InputAmount + pair2InputAmount),
|
||||
"Incorrect refund"
|
||||
);
|
||||
|
||||
// check that royalty has been issued
|
||||
assertEq(getBalance(ROYALTY_RECEIVER), totalRoyaltyAmount);
|
||||
}
|
||||
|
||||
// Test where pair 1 and pair 2 swap tokens for NFT succeed but pair 3 fails
|
||||
function test_robustSwapTokenFor2SpecificNFTs() public {
|
||||
uint256 totalRoyaltyAmount = 0;
|
||||
|
||||
uint256[] memory nftIds1 = new uint256[](2);
|
||||
nftIds1[0] = 0;
|
||||
nftIds1[1] = 1;
|
||||
|
||||
uint256[] memory nftIds2 = new uint256[](2);
|
||||
nftIds2[0] = 10;
|
||||
nftIds2[1] = 11;
|
||||
|
||||
uint256[] memory nftIds3 = new uint256[](2);
|
||||
nftIds3[0] = 20;
|
||||
nftIds3[1] = 21;
|
||||
|
||||
(, , , uint256 pair1InputAmount, ) = pair1.getBuyNFTQuote(2);
|
||||
(, , , uint256 pair2InputAmount, ) = pair2.getBuyNFTQuote(2);
|
||||
|
||||
// calculate royalty and add it to the input amount
|
||||
uint256 royaltyAmount = calcRoyalty(pair1InputAmount);
|
||||
pair1InputAmount += royaltyAmount;
|
||||
totalRoyaltyAmount += royaltyAmount;
|
||||
royaltyAmount = calcRoyalty(pair2InputAmount);
|
||||
pair2InputAmount += royaltyAmount;
|
||||
totalRoyaltyAmount += royaltyAmount;
|
||||
|
||||
LSSVMRouter.RobustPairSwapSpecific[]
|
||||
memory swapList = new LSSVMRouter.RobustPairSwapSpecific[](3);
|
||||
swapList[0] = LSSVMRouter.RobustPairSwapSpecific({
|
||||
swapInfo: LSSVMRouter.PairSwapSpecific({
|
||||
pair: pair1,
|
||||
nftIds: nftIds1
|
||||
}),
|
||||
maxCost: pair2InputAmount
|
||||
});
|
||||
swapList[1] = LSSVMRouter.RobustPairSwapSpecific({
|
||||
swapInfo: LSSVMRouter.PairSwapSpecific({
|
||||
pair: pair2,
|
||||
nftIds: nftIds2
|
||||
}),
|
||||
maxCost: pair2InputAmount
|
||||
});
|
||||
swapList[2] = LSSVMRouter.RobustPairSwapSpecific({
|
||||
swapInfo: LSSVMRouter.PairSwapSpecific({
|
||||
pair: pair3,
|
||||
nftIds: nftIds3
|
||||
}),
|
||||
maxCost: pair2InputAmount
|
||||
});
|
||||
|
||||
uint256 beforeNFTBalance = test721.balanceOf(address(this));
|
||||
|
||||
// Expect to have the first two swapPairs succeed, and the last one silently fail
|
||||
// with 10% protocol fee:
|
||||
uint256 remainingValue = this.robustSwapTokenForSpecificNFTs{
|
||||
value: modifyInputAmount(pair2InputAmount * 3)
|
||||
}(
|
||||
router,
|
||||
swapList,
|
||||
payable(address(this)),
|
||||
address(this),
|
||||
block.timestamp,
|
||||
pair2InputAmount * 3
|
||||
);
|
||||
|
||||
uint256 afterNFTBalance = test721.balanceOf(address(this));
|
||||
|
||||
// If the first two swap pairs succeed we gain 4 NFTs
|
||||
assertEq((afterNFTBalance - beforeNFTBalance), 4, "Incorrect NFT swap");
|
||||
assertEq(
|
||||
remainingValue,
|
||||
pair2InputAmount * 3 - (pair1InputAmount + pair2InputAmount),
|
||||
"Incorrect ETH refund"
|
||||
);
|
||||
|
||||
// check that royalty has been issued
|
||||
assertEq(getBalance(ROYALTY_RECEIVER), totalRoyaltyAmount);
|
||||
}
|
||||
|
||||
// Test where selling to pair 2 and pair 3 succeeds, but selling to pair 1 fails
|
||||
function test_robustSwap2NFTsForToken() public {
|
||||
uint256 totalRoyaltyAmount = 0;
|
||||
|
||||
uint256[] memory nftIds1 = new uint256[](2);
|
||||
nftIds1[0] = 30;
|
||||
nftIds1[1] = 31;
|
||||
|
||||
uint256[] memory nftIds2 = new uint256[](2);
|
||||
nftIds2[0] = 32;
|
||||
nftIds2[1] = 33;
|
||||
|
||||
uint256[] memory nftIds3 = new uint256[](2);
|
||||
nftIds3[0] = 34;
|
||||
nftIds3[1] = 35;
|
||||
|
||||
(, , , uint256 pair2OutputAmount, ) = pair2.getSellNFTQuote(2);
|
||||
(, , , uint256 pair3OutputAmount, ) = pair3.getSellNFTQuote(2);
|
||||
|
||||
// calculate royalty and rm it from the input amount
|
||||
uint256 royaltyAmount = calcRoyalty(pair2OutputAmount);
|
||||
pair2OutputAmount -= royaltyAmount;
|
||||
totalRoyaltyAmount += royaltyAmount;
|
||||
royaltyAmount = calcRoyalty(pair3OutputAmount);
|
||||
pair3OutputAmount -= royaltyAmount;
|
||||
totalRoyaltyAmount += royaltyAmount;
|
||||
|
||||
LSSVMRouter.RobustPairSwapSpecificForToken[]
|
||||
memory swapList = new LSSVMRouter.RobustPairSwapSpecificForToken[](
|
||||
3
|
||||
);
|
||||
swapList[0] = LSSVMRouter.RobustPairSwapSpecificForToken({
|
||||
swapInfo: LSSVMRouter.PairSwapSpecific({
|
||||
pair: pair1,
|
||||
nftIds: nftIds1
|
||||
}),
|
||||
minOutput: pair2OutputAmount
|
||||
});
|
||||
swapList[1] = LSSVMRouter.RobustPairSwapSpecificForToken({
|
||||
swapInfo: LSSVMRouter.PairSwapSpecific({
|
||||
pair: pair2,
|
||||
nftIds: nftIds2
|
||||
}),
|
||||
minOutput: pair2OutputAmount
|
||||
});
|
||||
swapList[2] = LSSVMRouter.RobustPairSwapSpecificForToken({
|
||||
swapInfo: LSSVMRouter.PairSwapSpecific({
|
||||
pair: pair3,
|
||||
nftIds: nftIds3
|
||||
}),
|
||||
minOutput: pair2OutputAmount
|
||||
});
|
||||
|
||||
uint256 beforeNFTBalance = test721.balanceOf(address(this));
|
||||
|
||||
// Expect to have the last two swapPairs succeed, and the first one silently fail
|
||||
// with 10% protocol fee:
|
||||
uint256 remainingValue = router.robustSwapNFTsForToken(
|
||||
swapList,
|
||||
payable(address(this)),
|
||||
block.timestamp
|
||||
);
|
||||
|
||||
uint256 afterNFTBalance = test721.balanceOf(address(this));
|
||||
|
||||
assertEq((beforeNFTBalance - afterNFTBalance), 4, "Incorrect NFT swap");
|
||||
assertEq(
|
||||
remainingValue,
|
||||
pair3OutputAmount + pair2OutputAmount,
|
||||
"Incorrect ETH received"
|
||||
);
|
||||
|
||||
// check that royalty has been issued
|
||||
assertEq(getBalance(ROYALTY_RECEIVER), totalRoyaltyAmount);
|
||||
}
|
||||
|
||||
// Test where selling to pair 2 succeeds,
|
||||
// but selling to pair 1 fails due to slippage
|
||||
// and selling to pair 3 fails due to a bonding curve error
|
||||
function test_robustSwapNFTsForTokenWithBondingCurveError() public {
|
||||
uint256[] memory nftIds1 = new uint256[](2);
|
||||
nftIds1[0] = 30;
|
||||
nftIds1[1] = 31;
|
||||
|
||||
uint256[] memory nftIds2 = new uint256[](2);
|
||||
nftIds2[0] = 32;
|
||||
nftIds2[1] = 33;
|
||||
|
||||
uint256[] memory nftIds3 = new uint256[](0);
|
||||
|
||||
(, , , uint256 pair2OutputAmount, ) = pair2.getSellNFTQuote(2);
|
||||
|
||||
// calculate royalty and rm it from the output amount
|
||||
uint256 royaltyAmount = calcRoyalty(pair2OutputAmount);
|
||||
pair2OutputAmount -= royaltyAmount;
|
||||
|
||||
LSSVMRouter.RobustPairSwapSpecificForToken[]
|
||||
memory swapList = new LSSVMRouter.RobustPairSwapSpecificForToken[](
|
||||
3
|
||||
);
|
||||
swapList[0] = LSSVMRouter.RobustPairSwapSpecificForToken({
|
||||
swapInfo: LSSVMRouter.PairSwapSpecific({
|
||||
pair: pair1,
|
||||
nftIds: nftIds1
|
||||
}),
|
||||
minOutput: pair2OutputAmount
|
||||
});
|
||||
swapList[1] = LSSVMRouter.RobustPairSwapSpecificForToken({
|
||||
swapInfo: LSSVMRouter.PairSwapSpecific({
|
||||
pair: pair2,
|
||||
nftIds: nftIds2
|
||||
}),
|
||||
minOutput: pair2OutputAmount
|
||||
});
|
||||
swapList[2] = LSSVMRouter.RobustPairSwapSpecificForToken({
|
||||
swapInfo: LSSVMRouter.PairSwapSpecific({
|
||||
pair: pair3,
|
||||
nftIds: nftIds3
|
||||
}),
|
||||
minOutput: pair2OutputAmount
|
||||
});
|
||||
|
||||
uint256 beforeNFTBalance = test721.balanceOf(address(this));
|
||||
|
||||
// Expect to have the last two swapPairs succeed, and the first one silently fail
|
||||
// with 10% protocol fee:
|
||||
uint256 remainingValue = router.robustSwapNFTsForToken(
|
||||
swapList,
|
||||
payable(address(this)),
|
||||
block.timestamp
|
||||
);
|
||||
|
||||
uint256 afterNFTBalance = test721.balanceOf(address(this));
|
||||
|
||||
assertEq((beforeNFTBalance - afterNFTBalance), 2, "Incorrect NFT swap");
|
||||
assertEq(remainingValue, pair2OutputAmount, "Incorrect ETH received");
|
||||
|
||||
// check that royalty has been issued
|
||||
assertEq(getBalance(ROYALTY_RECEIVER), royaltyAmount);
|
||||
}
|
||||
|
||||
// Test where we buy and sell in the same tx
|
||||
function test_robustSwapNFTsForTokenAndTokenForNFTs() public {
|
||||
uint256 totalRoyaltyAmount = 0;
|
||||
// Check that we own #0 and #1, and that we don't own #32 and #33
|
||||
assertEq(test721.ownerOf(0), address(pair1));
|
||||
assertEq(test721.ownerOf(1), address(pair1));
|
||||
assertEq(test721.ownerOf(32), address(this));
|
||||
assertEq(test721.ownerOf(33), address(this));
|
||||
|
||||
(, , , uint256 pair1InputAmount, ) = pair1.getBuyNFTQuote(2);
|
||||
(, , , uint256 pair2OutputAmount, ) = pair2.getSellNFTQuote(2);
|
||||
|
||||
// calculate royalty and modify input and output amounts
|
||||
uint256 royaltyAmount = calcRoyalty(pair1InputAmount);
|
||||
pair1InputAmount += royaltyAmount;
|
||||
totalRoyaltyAmount += royaltyAmount;
|
||||
royaltyAmount = calcRoyalty(pair2OutputAmount);
|
||||
pair2OutputAmount -= royaltyAmount;
|
||||
totalRoyaltyAmount += royaltyAmount;
|
||||
|
||||
uint256[] memory nftIds1 = new uint256[](2);
|
||||
nftIds1[0] = 0;
|
||||
nftIds1[1] = 1;
|
||||
LSSVMRouter.RobustPairSwapSpecific[]
|
||||
memory tokenToNFTSwapList = new LSSVMRouter.RobustPairSwapSpecific[](
|
||||
1
|
||||
);
|
||||
tokenToNFTSwapList[0] = LSSVMRouter.RobustPairSwapSpecific({
|
||||
swapInfo: LSSVMRouter.PairSwapSpecific({
|
||||
pair: pair1,
|
||||
nftIds: nftIds1
|
||||
}),
|
||||
maxCost: pair1InputAmount
|
||||
});
|
||||
|
||||
// We queue up a NFT->Token swap that should work
|
||||
uint256[] memory nftIds2 = new uint256[](2);
|
||||
nftIds2[0] = 32;
|
||||
nftIds2[1] = 33;
|
||||
LSSVMRouter.RobustPairSwapSpecificForToken[]
|
||||
memory nftToTokenSwapList = new LSSVMRouter.RobustPairSwapSpecificForToken[](
|
||||
1
|
||||
);
|
||||
nftToTokenSwapList[0] = LSSVMRouter.RobustPairSwapSpecificForToken({
|
||||
swapInfo: LSSVMRouter.PairSwapSpecific({
|
||||
pair: pair2,
|
||||
nftIds: nftIds2
|
||||
}),
|
||||
minOutput: pair2OutputAmount
|
||||
});
|
||||
|
||||
// Do the swap
|
||||
uint256 inputAmount = pair1InputAmount;
|
||||
this.robustSwapTokenForSpecificNFTsAndNFTsForTokens{
|
||||
value: modifyInputAmount(inputAmount)
|
||||
}(
|
||||
router,
|
||||
LSSVMRouter.RobustPairNFTsFoTokenAndTokenforNFTsTrade({
|
||||
nftToTokenTrades: nftToTokenSwapList,
|
||||
tokenToNFTTrades: tokenToNFTSwapList,
|
||||
inputAmount: inputAmount,
|
||||
tokenRecipient: payable(address(this)),
|
||||
nftRecipient: address(this)
|
||||
})
|
||||
);
|
||||
|
||||
// Check that we own #0 and #1, and that we don't own #32 and #33
|
||||
assertEq(test721.ownerOf(0), address(this));
|
||||
assertEq(test721.ownerOf(1), address(this));
|
||||
assertEq(test721.ownerOf(32), address(pair2));
|
||||
assertEq(test721.ownerOf(33), address(pair2));
|
||||
|
||||
// check that royalty has been issued
|
||||
assertEq(getBalance(ROYALTY_RECEIVER), totalRoyaltyAmount);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,546 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {DSTest} from "ds-test/test.sol";
|
||||
import {ERC721Holder} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
|
||||
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
|
||||
import {ERC2981} from "@openzeppelin/contracts/token/common/ERC2981.sol";
|
||||
import {RoyaltyRegistry} from "manifoldxyz/RoyaltyRegistry.sol";
|
||||
|
||||
import {ICurve} from "../../bonding-curves/ICurve.sol";
|
||||
import {LSSVMPairFactory} from "../../LSSVMPairFactory.sol";
|
||||
import {LSSVMPair} from "../../LSSVMPair.sol";
|
||||
import {LSSVMPairETH} from "../../LSSVMPairETH.sol";
|
||||
import {LSSVMPairERC20} from "../../LSSVMPairERC20.sol";
|
||||
import {LSSVMPairEnumerableETH} from "../../LSSVMPairEnumerableETH.sol";
|
||||
import {LSSVMPairMissingEnumerableETH} from "../../LSSVMPairMissingEnumerableETH.sol";
|
||||
import {LSSVMPairEnumerableERC20} from "../../LSSVMPairEnumerableERC20.sol";
|
||||
import {LSSVMPairMissingEnumerableERC20} from "../../LSSVMPairMissingEnumerableERC20.sol";
|
||||
import {LSSVMRouterWithRoyalties, LSSVMRouter} from "../../LSSVMRouterWithRoyalties.sol";
|
||||
import {IERC721Mintable} from "../interfaces/IERC721Mintable.sol";
|
||||
import {ConfigurableWithRoyalties} from "../mixins/ConfigurableWithRoyalties.sol";
|
||||
import {RouterCaller} from "../mixins/RouterCaller.sol";
|
||||
|
||||
abstract contract RouterSinglePoolWithRoyalties is
|
||||
DSTest,
|
||||
ERC721Holder,
|
||||
ConfigurableWithRoyalties,
|
||||
RouterCaller
|
||||
{
|
||||
IERC721Mintable test721;
|
||||
ERC2981 test2981;
|
||||
RoyaltyRegistry royaltyRegistry;
|
||||
ICurve bondingCurve;
|
||||
LSSVMPairFactory factory;
|
||||
LSSVMRouter router;
|
||||
LSSVMPair pair;
|
||||
address payable constant feeRecipient = payable(address(69));
|
||||
uint256 constant protocolFeeMultiplier = 3e15;
|
||||
uint256 constant numInitialNFTs = 10;
|
||||
|
||||
function setUp() public {
|
||||
bondingCurve = setupCurve();
|
||||
test721 = setup721();
|
||||
test2981 = setup2981();
|
||||
royaltyRegistry = setupRoyaltyRegistry();
|
||||
royaltyRegistry.setRoyaltyLookupAddress(
|
||||
address(test721),
|
||||
address(test2981)
|
||||
);
|
||||
|
||||
LSSVMPairEnumerableETH enumerableETHTemplate = new LSSVMPairEnumerableETH();
|
||||
LSSVMPairMissingEnumerableETH missingEnumerableETHTemplate = new LSSVMPairMissingEnumerableETH();
|
||||
LSSVMPairEnumerableERC20 enumerableERC20Template = new LSSVMPairEnumerableERC20();
|
||||
LSSVMPairMissingEnumerableERC20 missingEnumerableERC20Template = new LSSVMPairMissingEnumerableERC20();
|
||||
factory = new LSSVMPairFactory(
|
||||
enumerableETHTemplate,
|
||||
missingEnumerableETHTemplate,
|
||||
enumerableERC20Template,
|
||||
missingEnumerableERC20Template,
|
||||
feeRecipient,
|
||||
protocolFeeMultiplier
|
||||
);
|
||||
router = new LSSVMRouterWithRoyalties(factory);
|
||||
factory.setBondingCurveAllowed(bondingCurve, true);
|
||||
factory.setRouterAllowed(router, true);
|
||||
|
||||
// set NFT approvals
|
||||
test721.setApprovalForAll(address(factory), true);
|
||||
test721.setApprovalForAll(address(router), true);
|
||||
|
||||
// Setup pair parameters
|
||||
uint128 delta = 0 ether;
|
||||
uint128 spotPrice = 1 ether;
|
||||
uint256[] memory idList = new uint256[](numInitialNFTs);
|
||||
for (uint256 i = 1; i <= numInitialNFTs; i++) {
|
||||
test721.mint(address(this), i);
|
||||
idList[i - 1] = i;
|
||||
}
|
||||
|
||||
// Create a pair with a spot price of 1 eth, 10 NFTs, and no price increases
|
||||
pair = this.setupPair{value: modifyInputAmount(10 ether)}(
|
||||
factory,
|
||||
test721,
|
||||
bondingCurve,
|
||||
payable(address(0)),
|
||||
LSSVMPair.PoolType.TRADE,
|
||||
modifyDelta(uint64(delta)),
|
||||
0,
|
||||
spotPrice,
|
||||
idList,
|
||||
10 ether,
|
||||
address(router)
|
||||
);
|
||||
|
||||
// mint extra NFTs to this contract (i.e. to be held by the caller)
|
||||
for (uint256 i = numInitialNFTs + 1; i <= 2 * numInitialNFTs; i++) {
|
||||
test721.mint(address(this), i);
|
||||
}
|
||||
}
|
||||
|
||||
function test_swapTokenForSingleAnyNFT() public {
|
||||
LSSVMRouter.PairSwapAny[]
|
||||
memory swapList = new LSSVMRouter.PairSwapAny[](1);
|
||||
swapList[0] = LSSVMRouter.PairSwapAny({pair: pair, numItems: 1});
|
||||
uint256 inputAmount;
|
||||
(, , , inputAmount, ) = pair.getBuyNFTQuote(1);
|
||||
|
||||
// calculate royalty and add it to the input amount
|
||||
uint256 royaltyAmount = calcRoyalty(inputAmount);
|
||||
inputAmount += royaltyAmount;
|
||||
|
||||
this.swapTokenForAnyNFTs{value: modifyInputAmount(inputAmount)}(
|
||||
router,
|
||||
swapList,
|
||||
payable(address(this)),
|
||||
address(this),
|
||||
block.timestamp,
|
||||
inputAmount
|
||||
);
|
||||
|
||||
// check that royalty has been issued
|
||||
assertEq(getBalance(ROYALTY_RECEIVER), royaltyAmount);
|
||||
}
|
||||
|
||||
function test_swapTokenForSingleSpecificNFT() public {
|
||||
uint256[] memory nftIds = new uint256[](1);
|
||||
nftIds[0] = 1;
|
||||
LSSVMRouter.PairSwapSpecific[]
|
||||
memory swapList = new LSSVMRouter.PairSwapSpecific[](1);
|
||||
swapList[0] = LSSVMRouter.PairSwapSpecific({
|
||||
pair: pair,
|
||||
nftIds: nftIds
|
||||
});
|
||||
uint256 inputAmount;
|
||||
(, , , inputAmount, ) = pair.getBuyNFTQuote(1);
|
||||
|
||||
// calculate royalty and add it to the input amount
|
||||
uint256 royaltyAmount = calcRoyalty(inputAmount);
|
||||
inputAmount += royaltyAmount;
|
||||
|
||||
this.swapTokenForSpecificNFTs{value: modifyInputAmount(inputAmount)}(
|
||||
router,
|
||||
swapList,
|
||||
payable(address(this)),
|
||||
address(this),
|
||||
block.timestamp,
|
||||
inputAmount
|
||||
);
|
||||
|
||||
// check that royalty has been issued
|
||||
assertEq(getBalance(ROYALTY_RECEIVER), royaltyAmount);
|
||||
}
|
||||
|
||||
function test_swapSingleNFTForToken() public {
|
||||
(, , , uint256 outputAmount, ) = pair.getSellNFTQuote(1);
|
||||
|
||||
// calculate royalty and rm it from the output amount
|
||||
uint256 royaltyAmount = calcRoyalty(outputAmount);
|
||||
outputAmount -= outputAmount;
|
||||
|
||||
uint256[] memory nftIds = new uint256[](1);
|
||||
nftIds[0] = numInitialNFTs + 1;
|
||||
LSSVMRouter.PairSwapSpecific[]
|
||||
memory swapList = new LSSVMRouter.PairSwapSpecific[](1);
|
||||
swapList[0] = LSSVMRouter.PairSwapSpecific({
|
||||
pair: pair,
|
||||
nftIds: nftIds
|
||||
});
|
||||
router.swapNFTsForToken(
|
||||
swapList,
|
||||
outputAmount,
|
||||
payable(address(this)),
|
||||
block.timestamp
|
||||
);
|
||||
|
||||
// check that royalty has been issued
|
||||
assertEq(getBalance(ROYALTY_RECEIVER), royaltyAmount);
|
||||
}
|
||||
|
||||
function testGas_swapSingleNFTForToken5Times() public {
|
||||
uint256 totalRoyaltyAmount;
|
||||
for (uint256 i = 1; i <= 5; i++) {
|
||||
(, , , uint256 outputAmount, ) = pair.getSellNFTQuote(1);
|
||||
|
||||
// calculate royalty and rm it from the output amount
|
||||
uint256 royaltyAmount = calcRoyalty(outputAmount);
|
||||
outputAmount -= royaltyAmount;
|
||||
totalRoyaltyAmount += royaltyAmount;
|
||||
|
||||
uint256[] memory nftIds = new uint256[](1);
|
||||
nftIds[0] = numInitialNFTs + i;
|
||||
LSSVMRouter.PairSwapSpecific[]
|
||||
memory swapList = new LSSVMRouter.PairSwapSpecific[](1);
|
||||
swapList[0] = LSSVMRouter.PairSwapSpecific({
|
||||
pair: pair,
|
||||
nftIds: nftIds
|
||||
});
|
||||
router.swapNFTsForToken(
|
||||
swapList,
|
||||
outputAmount,
|
||||
payable(address(this)),
|
||||
block.timestamp
|
||||
);
|
||||
}
|
||||
// check that royalty has been issued
|
||||
assertEq(getBalance(ROYALTY_RECEIVER), totalRoyaltyAmount);
|
||||
}
|
||||
|
||||
function test_swapSingleNFTForAnyNFT() public {
|
||||
uint256 totalRoyaltyAmount;
|
||||
// construct NFT to Token swap list
|
||||
uint256[] memory sellNFTIds = new uint256[](1);
|
||||
sellNFTIds[0] = numInitialNFTs + 1;
|
||||
LSSVMRouter.PairSwapSpecific[]
|
||||
memory nftToTokenSwapList = new LSSVMRouter.PairSwapSpecific[](1);
|
||||
nftToTokenSwapList[0] = LSSVMRouter.PairSwapSpecific({
|
||||
pair: pair,
|
||||
nftIds: sellNFTIds
|
||||
});
|
||||
(, , , uint256 salePrice, ) = nftToTokenSwapList[0]
|
||||
.pair
|
||||
.getSellNFTQuote(sellNFTIds.length);
|
||||
totalRoyaltyAmount += calcRoyalty(salePrice);
|
||||
|
||||
// construct Token to NFT swap list
|
||||
LSSVMRouter.PairSwapAny[]
|
||||
memory tokenToNFTSwapList = new LSSVMRouter.PairSwapAny[](1);
|
||||
tokenToNFTSwapList[0] = LSSVMRouter.PairSwapAny({
|
||||
pair: pair,
|
||||
numItems: 1
|
||||
});
|
||||
|
||||
(, , , uint256 buyPrice, ) = tokenToNFTSwapList[0].pair.getBuyNFTQuote(
|
||||
1
|
||||
);
|
||||
totalRoyaltyAmount += calcRoyalty(buyPrice);
|
||||
|
||||
// NOTE: We send some tokens (more than enough) to cover the protocol fee needed
|
||||
uint256 inputAmount = 0.01 ether;
|
||||
inputAmount += totalRoyaltyAmount;
|
||||
|
||||
this.swapNFTsForAnyNFTsThroughToken{
|
||||
value: modifyInputAmount(inputAmount)
|
||||
}(
|
||||
router,
|
||||
LSSVMRouter.NFTsForAnyNFTsTrade({
|
||||
nftToTokenTrades: nftToTokenSwapList,
|
||||
tokenToNFTTrades: tokenToNFTSwapList
|
||||
}),
|
||||
0,
|
||||
payable(address(this)),
|
||||
address(this),
|
||||
block.timestamp,
|
||||
inputAmount
|
||||
);
|
||||
|
||||
// check that royalty has been issued
|
||||
require(
|
||||
getBalance(ROYALTY_RECEIVER) <=
|
||||
(totalRoyaltyAmount * 1_010) / 1_000,
|
||||
"too much"
|
||||
);
|
||||
require(
|
||||
getBalance(ROYALTY_RECEIVER) >=
|
||||
(totalRoyaltyAmount * 1_000) / 1_500,
|
||||
"too less"
|
||||
);
|
||||
/* NOTE: test is failing with XykCurve
|
||||
* reason: buyQuote is quoted before the nfts are sold
|
||||
* recurring to proximity tests
|
||||
*/
|
||||
// assertEq(getBalance(ROYALTY_RECEIVER), totalRoyaltyAmount);
|
||||
}
|
||||
|
||||
function test_swapSingleNFTForSpecificNFT() public {
|
||||
uint256 totalRoyaltyAmount;
|
||||
// construct NFT to token swap list
|
||||
uint256[] memory sellNFTIds = new uint256[](1);
|
||||
sellNFTIds[0] = numInitialNFTs + 1;
|
||||
LSSVMRouter.PairSwapSpecific[]
|
||||
memory nftToTokenSwapList = new LSSVMRouter.PairSwapSpecific[](1);
|
||||
nftToTokenSwapList[0] = LSSVMRouter.PairSwapSpecific({
|
||||
pair: pair,
|
||||
nftIds: sellNFTIds
|
||||
});
|
||||
|
||||
(, , , uint256 salePrice, ) = nftToTokenSwapList[0]
|
||||
.pair
|
||||
.getSellNFTQuote(sellNFTIds.length);
|
||||
totalRoyaltyAmount += calcRoyalty(salePrice);
|
||||
|
||||
// construct token to NFT swap list
|
||||
uint256[] memory buyNFTIds = new uint256[](1);
|
||||
buyNFTIds[0] = 1;
|
||||
LSSVMRouter.PairSwapSpecific[]
|
||||
memory tokenToNFTSwapList = new LSSVMRouter.PairSwapSpecific[](1);
|
||||
tokenToNFTSwapList[0] = LSSVMRouter.PairSwapSpecific({
|
||||
pair: pair,
|
||||
nftIds: buyNFTIds
|
||||
});
|
||||
|
||||
(, , , uint256 buyPrice, ) = tokenToNFTSwapList[0].pair.getBuyNFTQuote(
|
||||
buyNFTIds.length
|
||||
);
|
||||
totalRoyaltyAmount += calcRoyalty(buyPrice);
|
||||
|
||||
// NOTE: We send some tokens (more than enough) to cover the protocol fee
|
||||
uint256 inputAmount = 0.01 ether;
|
||||
inputAmount += totalRoyaltyAmount;
|
||||
|
||||
this.swapNFTsForSpecificNFTsThroughToken{
|
||||
value: modifyInputAmount(inputAmount)
|
||||
}(
|
||||
router,
|
||||
LSSVMRouter.NFTsForSpecificNFTsTrade({
|
||||
nftToTokenTrades: nftToTokenSwapList,
|
||||
tokenToNFTTrades: tokenToNFTSwapList
|
||||
}),
|
||||
0,
|
||||
payable(address(this)),
|
||||
address(this),
|
||||
block.timestamp,
|
||||
inputAmount
|
||||
);
|
||||
|
||||
// check that royalty has been issued
|
||||
require(
|
||||
getBalance(ROYALTY_RECEIVER) <=
|
||||
(totalRoyaltyAmount * 1_010) / 1_000,
|
||||
"too much"
|
||||
);
|
||||
require(
|
||||
getBalance(ROYALTY_RECEIVER) >=
|
||||
(totalRoyaltyAmount * 1_000) / 1_500,
|
||||
"too less"
|
||||
);
|
||||
/* NOTE: test is failing with XykCurve
|
||||
* reason: buyQuote is quoted before the nfts are sold
|
||||
* recurring to proximity tests
|
||||
*/
|
||||
// assertEq(getBalance(ROYALTY_RECEIVER), totalRoyaltyAmount);
|
||||
}
|
||||
|
||||
function test_swapTokenforAny5NFTs() public {
|
||||
LSSVMRouter.PairSwapAny[]
|
||||
memory swapList = new LSSVMRouter.PairSwapAny[](1);
|
||||
swapList[0] = LSSVMRouter.PairSwapAny({pair: pair, numItems: 5});
|
||||
uint256 startBalance = test721.balanceOf(address(this));
|
||||
uint256 inputAmount;
|
||||
(, , , inputAmount, ) = pair.getBuyNFTQuote(5);
|
||||
|
||||
// calculate royalty and add it to the input amount
|
||||
uint256 royaltyAmount = calcRoyalty(inputAmount);
|
||||
inputAmount += royaltyAmount;
|
||||
|
||||
this.swapTokenForAnyNFTs{value: modifyInputAmount(inputAmount)}(
|
||||
router,
|
||||
swapList,
|
||||
payable(address(this)),
|
||||
address(this),
|
||||
block.timestamp,
|
||||
inputAmount
|
||||
);
|
||||
uint256 endBalance = test721.balanceOf(address(this));
|
||||
require((endBalance - startBalance) == 5, "Too few NFTs acquired");
|
||||
|
||||
// check that royalty has been issued
|
||||
assertEq(getBalance(ROYALTY_RECEIVER), royaltyAmount);
|
||||
}
|
||||
|
||||
function test_swapTokenforSpecific5NFTs() public {
|
||||
LSSVMRouter.PairSwapSpecific[]
|
||||
memory swapList = new LSSVMRouter.PairSwapSpecific[](1);
|
||||
uint256[] memory nftIds = new uint256[](5);
|
||||
nftIds[0] = 1;
|
||||
nftIds[1] = 2;
|
||||
nftIds[2] = 3;
|
||||
nftIds[3] = 4;
|
||||
nftIds[4] = 5;
|
||||
swapList[0] = LSSVMRouter.PairSwapSpecific({
|
||||
pair: pair,
|
||||
nftIds: nftIds
|
||||
});
|
||||
uint256 startBalance = test721.balanceOf(address(this));
|
||||
uint256 inputAmount;
|
||||
(, , , inputAmount, ) = pair.getBuyNFTQuote(5);
|
||||
|
||||
// calculate royalty and add it to the input amount
|
||||
uint256 royaltyAmount = calcRoyalty(inputAmount);
|
||||
inputAmount += royaltyAmount;
|
||||
|
||||
this.swapTokenForSpecificNFTs{value: modifyInputAmount(inputAmount)}(
|
||||
router,
|
||||
swapList,
|
||||
payable(address(this)),
|
||||
address(this),
|
||||
block.timestamp,
|
||||
inputAmount
|
||||
);
|
||||
uint256 endBalance = test721.balanceOf(address(this));
|
||||
require((endBalance - startBalance) == 5, "Too few NFTs acquired");
|
||||
|
||||
// check that royalty has been issued
|
||||
assertEq(getBalance(ROYALTY_RECEIVER), royaltyAmount);
|
||||
}
|
||||
|
||||
function test_swap5NFTsForToken() public {
|
||||
(, , , uint256 outputAmount, ) = pair.getSellNFTQuote(5);
|
||||
|
||||
// calculate royalty and rm it from the output amount
|
||||
uint256 royaltyAmount = calcRoyalty(outputAmount);
|
||||
outputAmount -= royaltyAmount;
|
||||
|
||||
uint256[] memory nftIds = new uint256[](5);
|
||||
for (uint256 i = 0; i < 5; i++) {
|
||||
nftIds[i] = numInitialNFTs + i + 1;
|
||||
}
|
||||
LSSVMRouter.PairSwapSpecific[]
|
||||
memory swapList = new LSSVMRouter.PairSwapSpecific[](1);
|
||||
swapList[0] = LSSVMRouter.PairSwapSpecific({
|
||||
pair: pair,
|
||||
nftIds: nftIds
|
||||
});
|
||||
router.swapNFTsForToken(
|
||||
swapList,
|
||||
outputAmount,
|
||||
payable(address(this)),
|
||||
block.timestamp
|
||||
);
|
||||
|
||||
// check that royalty has been issued
|
||||
assertEq(getBalance(ROYALTY_RECEIVER), royaltyAmount);
|
||||
}
|
||||
|
||||
function testFail_swapTokenForSingleAnyNFTSlippage() public {
|
||||
LSSVMRouter.PairSwapAny[]
|
||||
memory swapList = new LSSVMRouter.PairSwapAny[](1);
|
||||
swapList[0] = LSSVMRouter.PairSwapAny({pair: pair, numItems: 1});
|
||||
uint256 inputAmount;
|
||||
(, , , inputAmount, ) = pair.getBuyNFTQuote(1);
|
||||
inputAmount = addRoyalty(inputAmount);
|
||||
|
||||
inputAmount = inputAmount - 1 wei;
|
||||
this.swapTokenForAnyNFTs{value: modifyInputAmount(inputAmount)}(
|
||||
router,
|
||||
swapList,
|
||||
payable(address(this)),
|
||||
address(this),
|
||||
block.timestamp,
|
||||
inputAmount
|
||||
);
|
||||
}
|
||||
|
||||
function testFail_swapTokenForSingleSpecificNFTSlippage() public {
|
||||
uint256[] memory nftIds = new uint256[](1);
|
||||
nftIds[0] = 1;
|
||||
LSSVMRouter.PairSwapSpecific[]
|
||||
memory swapList = new LSSVMRouter.PairSwapSpecific[](1);
|
||||
swapList[0] = LSSVMRouter.PairSwapSpecific({
|
||||
pair: pair,
|
||||
nftIds: nftIds
|
||||
});
|
||||
uint256 inputAmount;
|
||||
(, , , inputAmount, ) = pair.getBuyNFTQuote(1);
|
||||
inputAmount = addRoyalty(inputAmount);
|
||||
|
||||
inputAmount = inputAmount - 1 wei;
|
||||
this.swapTokenForSpecificNFTs{value: modifyInputAmount(inputAmount)}(
|
||||
router,
|
||||
swapList,
|
||||
payable(address(this)),
|
||||
address(this),
|
||||
block.timestamp,
|
||||
inputAmount
|
||||
);
|
||||
}
|
||||
|
||||
function testFail_swapSingleNFTForNonexistentToken() public {
|
||||
uint256[] memory nftIds = new uint256[](1);
|
||||
nftIds[0] = numInitialNFTs + 1;
|
||||
LSSVMRouter.PairSwapSpecific[]
|
||||
memory swapList = new LSSVMRouter.PairSwapSpecific[](1);
|
||||
swapList[0] = LSSVMRouter.PairSwapSpecific({
|
||||
pair: pair,
|
||||
nftIds: nftIds
|
||||
});
|
||||
uint256 sellAmount;
|
||||
(, , , sellAmount, ) = pair.getSellNFTQuote(1);
|
||||
sellAmount = subRoyalty(sellAmount);
|
||||
|
||||
sellAmount = sellAmount + 1 wei;
|
||||
router.swapNFTsForToken(
|
||||
swapList,
|
||||
sellAmount,
|
||||
payable(address(this)),
|
||||
block.timestamp
|
||||
);
|
||||
}
|
||||
|
||||
function testFail_swapTokenForAnyNFTsPastBalance() public {
|
||||
uint256[] memory nftIds = new uint256[](1);
|
||||
nftIds[0] = numInitialNFTs + 1;
|
||||
LSSVMRouter.PairSwapAny[]
|
||||
memory swapList = new LSSVMRouter.PairSwapAny[](1);
|
||||
swapList[0] = LSSVMRouter.PairSwapAny({
|
||||
pair: pair,
|
||||
numItems: test721.balanceOf(address(pair)) + 1
|
||||
});
|
||||
uint256 inputAmount;
|
||||
(, , , inputAmount, ) = pair.getBuyNFTQuote(
|
||||
test721.balanceOf(address(pair)) + 1
|
||||
);
|
||||
inputAmount = addRoyalty(inputAmount);
|
||||
|
||||
inputAmount = inputAmount + 1 wei;
|
||||
this.swapTokenForAnyNFTs{value: modifyInputAmount(inputAmount)}(
|
||||
router,
|
||||
swapList,
|
||||
payable(address(this)),
|
||||
address(this),
|
||||
block.timestamp,
|
||||
inputAmount
|
||||
);
|
||||
}
|
||||
|
||||
function testFail_swapSingleNFTForTokenWithEmptyList() public {
|
||||
uint256[] memory nftIds = new uint256[](0);
|
||||
LSSVMRouter.PairSwapSpecific[]
|
||||
memory swapList = new LSSVMRouter.PairSwapSpecific[](1);
|
||||
swapList[0] = LSSVMRouter.PairSwapSpecific({
|
||||
pair: pair,
|
||||
nftIds: nftIds
|
||||
});
|
||||
uint256 sellAmount;
|
||||
(, , , sellAmount, ) = pair.getSellNFTQuote(1);
|
||||
sellAmount = subRoyalty(sellAmount);
|
||||
|
||||
sellAmount = sellAmount + 1 wei;
|
||||
router.swapNFTsForToken(
|
||||
swapList,
|
||||
sellAmount,
|
||||
payable(address(this)),
|
||||
block.timestamp
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {Configurable, IERC721, LSSVMPair, ICurve, IERC721Mintable, LSSVMPairFactory} from "./Configurable.sol";
|
||||
|
||||
import {ERC2981} from "@openzeppelin/contracts/token/common/ERC2981.sol";
|
||||
import {Test2981} from "../../mocks/Test2981.sol";
|
||||
import {RoyaltyRegistry} from "manifoldxyz/RoyaltyRegistry.sol";
|
||||
import {TestRoyaltyRegistry} from "../../mocks/TestRoyaltyRegistry.sol";
|
||||
import {DSTest} from "ds-test/test.sol";
|
||||
|
||||
interface IVM {
|
||||
function etch(address where, bytes memory what) external;
|
||||
}
|
||||
|
||||
abstract contract ConfigurableWithRoyalties is Configurable, DSTest {
|
||||
address public constant ROYALTY_RECEIVER = address(420);
|
||||
uint96 public constant BPS = 30;
|
||||
uint96 public constant BASE = 10_000;
|
||||
|
||||
function setup2981() public returns (ERC2981) {
|
||||
return ERC2981(new Test2981(ROYALTY_RECEIVER, BPS));
|
||||
}
|
||||
|
||||
// royalty registry address is set as constant in the contract
|
||||
address constant ROYALTY_REGISTRY =
|
||||
0xaD2184FB5DBcfC05d8f056542fB25b04fa32A95D;
|
||||
|
||||
function setupRoyaltyRegistry()
|
||||
public
|
||||
returns (RoyaltyRegistry royaltyRegistry)
|
||||
{
|
||||
royaltyRegistry = RoyaltyRegistry(new TestRoyaltyRegistry());
|
||||
IVM(HEVM_ADDRESS).etch(ROYALTY_REGISTRY, address(royaltyRegistry).code);
|
||||
royaltyRegistry = RoyaltyRegistry(ROYALTY_REGISTRY);
|
||||
royaltyRegistry.initialize();
|
||||
}
|
||||
|
||||
function addRoyalty(uint256 inputAmount)
|
||||
public
|
||||
pure
|
||||
returns (uint256 outputAmount)
|
||||
{
|
||||
return inputAmount + calcRoyalty(inputAmount);
|
||||
}
|
||||
|
||||
function subRoyalty(uint256 inputAmount)
|
||||
public
|
||||
pure
|
||||
returns (uint256 outputAmount)
|
||||
{
|
||||
return inputAmount - calcRoyalty(inputAmount);
|
||||
}
|
||||
|
||||
function calcRoyalty(uint256 inputAmount)
|
||||
public
|
||||
pure
|
||||
returns (uint256 royaltyAmount)
|
||||
{
|
||||
royaltyAmount = (inputAmount * BPS) / BASE;
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -2,13 +2,13 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterPartialFill} from "../base/RouterPartialFill.sol";
|
||||
import {RouterMultiPoolWithRoyalties} from "../base/RouterMultiPoolWithRoyalties.sol";
|
||||
import {UsingExponentialCurve} from "../mixins/UsingExponentialCurve.sol";
|
||||
import {UsingEnumerable} from "../mixins/UsingEnumerable.sol";
|
||||
import {UsingERC20} from "../mixins/UsingERC20.sol";
|
||||
|
||||
contract RPFExponentialCurveEnumerableERC20Test is
|
||||
RouterPartialFill,
|
||||
contract RMPWRExponentialCurveEnumerableERC20Test is
|
||||
RouterMultiPoolWithRoyalties,
|
||||
UsingExponentialCurve,
|
||||
UsingEnumerable,
|
||||
UsingERC20
|
||||
+3
-3
@@ -2,13 +2,13 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterPartialFill} from "../base/RouterPartialFill.sol";
|
||||
import {RouterMultiPoolWithRoyalties} from "../base/RouterMultiPoolWithRoyalties.sol";
|
||||
import {UsingExponentialCurve} from "../mixins/UsingExponentialCurve.sol";
|
||||
import {UsingEnumerable} from "../mixins/UsingEnumerable.sol";
|
||||
import {UsingETH} from "../mixins/UsingETH.sol";
|
||||
|
||||
contract RPFExponentialCurveEnumerableETHTest is
|
||||
RouterPartialFill,
|
||||
contract RMPWRExponentialCurveEnumerableETHTest is
|
||||
RouterMultiPoolWithRoyalties,
|
||||
UsingExponentialCurve,
|
||||
UsingEnumerable,
|
||||
UsingETH
|
||||
+3
-3
@@ -2,13 +2,13 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterPartialFill} from "../base/RouterPartialFill.sol";
|
||||
import {RouterMultiPoolWithRoyalties} from "../base/RouterMultiPoolWithRoyalties.sol";
|
||||
import {UsingExponentialCurve} from "../mixins/UsingExponentialCurve.sol";
|
||||
import {UsingMissingEnumerable} from "../mixins/UsingMissingEnumerable.sol";
|
||||
import {UsingERC20} from "../mixins/UsingERC20.sol";
|
||||
|
||||
contract RPFExponentialCurveMissingEnumerableERC20Test is
|
||||
RouterPartialFill,
|
||||
contract RMPWRExponentialCurveMissingEnumerableERC20Test is
|
||||
RouterMultiPoolWithRoyalties,
|
||||
UsingExponentialCurve,
|
||||
UsingMissingEnumerable,
|
||||
UsingERC20
|
||||
+3
-3
@@ -2,13 +2,13 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterPartialFill} from "../base/RouterPartialFill.sol";
|
||||
import {RouterMultiPoolWithRoyalties} from "../base/RouterMultiPoolWithRoyalties.sol";
|
||||
import {UsingExponentialCurve} from "../mixins/UsingExponentialCurve.sol";
|
||||
import {UsingMissingEnumerable} from "../mixins/UsingMissingEnumerable.sol";
|
||||
import {UsingETH} from "../mixins/UsingETH.sol";
|
||||
|
||||
contract RPFExponentialCurveMissingEnumerableETHTest is
|
||||
RouterPartialFill,
|
||||
contract RMPWRExponentialCurveMissingEnumerableETHTest is
|
||||
RouterMultiPoolWithRoyalties,
|
||||
UsingExponentialCurve,
|
||||
UsingMissingEnumerable,
|
||||
UsingETH
|
||||
+3
-3
@@ -2,13 +2,13 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterPartialFill} from "../base/RouterPartialFill.sol";
|
||||
import {RouterMultiPoolWithRoyalties} from "../base/RouterMultiPoolWithRoyalties.sol";
|
||||
import {UsingLinearCurve} from "../mixins/UsingLinearCurve.sol";
|
||||
import {UsingEnumerable} from "../mixins/UsingEnumerable.sol";
|
||||
import {UsingERC20} from "../mixins/UsingERC20.sol";
|
||||
|
||||
contract RPFLinearCurveEnumerableERC20Test is
|
||||
RouterPartialFill,
|
||||
contract RMPWRLinearCurveEnumerableERC20Test is
|
||||
RouterMultiPoolWithRoyalties,
|
||||
UsingLinearCurve,
|
||||
UsingEnumerable,
|
||||
UsingERC20
|
||||
+3
-3
@@ -2,13 +2,13 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterPartialFill} from "../base/RouterPartialFill.sol";
|
||||
import {RouterMultiPoolWithRoyalties} from "../base/RouterMultiPoolWithRoyalties.sol";
|
||||
import {UsingLinearCurve} from "../mixins/UsingLinearCurve.sol";
|
||||
import {UsingEnumerable} from "../mixins/UsingEnumerable.sol";
|
||||
import {UsingETH} from "../mixins/UsingETH.sol";
|
||||
|
||||
contract RPFLinearCurveEnumerableETHTest is
|
||||
RouterPartialFill,
|
||||
contract RMPWRLinearCurveEnumerableETHTest is
|
||||
RouterMultiPoolWithRoyalties,
|
||||
UsingLinearCurve,
|
||||
UsingEnumerable,
|
||||
UsingETH
|
||||
+3
-3
@@ -2,13 +2,13 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterPartialFill} from "../base/RouterPartialFill.sol";
|
||||
import {RouterMultiPoolWithRoyalties} from "../base/RouterMultiPoolWithRoyalties.sol";
|
||||
import {UsingLinearCurve} from "../mixins/UsingLinearCurve.sol";
|
||||
import {UsingMissingEnumerable} from "../mixins/UsingMissingEnumerable.sol";
|
||||
import {UsingERC20} from "../mixins/UsingERC20.sol";
|
||||
|
||||
contract RPFLinearCurveMissingEnumerableERC20Test is
|
||||
RouterPartialFill,
|
||||
contract RMPWRLinearCurveMissingEnumerableERC20Test is
|
||||
RouterMultiPoolWithRoyalties,
|
||||
UsingLinearCurve,
|
||||
UsingMissingEnumerable,
|
||||
UsingERC20
|
||||
+3
-3
@@ -2,13 +2,13 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterPartialFill} from "../base/RouterPartialFill.sol";
|
||||
import {RouterMultiPoolWithRoyalties} from "../base/RouterMultiPoolWithRoyalties.sol";
|
||||
import {UsingLinearCurve} from "../mixins/UsingLinearCurve.sol";
|
||||
import {UsingMissingEnumerable} from "../mixins/UsingMissingEnumerable.sol";
|
||||
import {UsingETH} from "../mixins/UsingETH.sol";
|
||||
|
||||
contract RPFLinearCurveMissingEnumerableETHTest is
|
||||
RouterPartialFill,
|
||||
contract RMPWRLinearCurveMissingEnumerableETHTest is
|
||||
RouterMultiPoolWithRoyalties,
|
||||
UsingLinearCurve,
|
||||
UsingMissingEnumerable,
|
||||
UsingETH
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterMultiPoolWithRoyalties} from "../base/RouterMultiPoolWithRoyalties.sol";
|
||||
import {UsingXykCurve} from "../mixins/UsingXykCurve.sol";
|
||||
import {UsingEnumerable} from "../mixins/UsingEnumerable.sol";
|
||||
import {UsingERC20} from "../mixins/UsingERC20.sol";
|
||||
|
||||
contract RMPWRXykCurveEnumerableERC20Test is
|
||||
RouterMultiPoolWithRoyalties,
|
||||
UsingXykCurve,
|
||||
UsingEnumerable,
|
||||
UsingERC20
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterMultiPoolWithRoyalties} from "../base/RouterMultiPoolWithRoyalties.sol";
|
||||
import {UsingXykCurve} from "../mixins/UsingXykCurve.sol";
|
||||
import {UsingEnumerable} from "../mixins/UsingEnumerable.sol";
|
||||
import {UsingETH} from "../mixins/UsingETH.sol";
|
||||
|
||||
contract RMPWRXykCurveEnumerableETHTest is
|
||||
RouterMultiPoolWithRoyalties,
|
||||
UsingXykCurve,
|
||||
UsingEnumerable,
|
||||
UsingETH
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterMultiPoolWithRoyalties} from "../base/RouterMultiPoolWithRoyalties.sol";
|
||||
import {UsingXykCurve} from "../mixins/UsingXykCurve.sol";
|
||||
import {UsingMissingEnumerable} from "../mixins/UsingMissingEnumerable.sol";
|
||||
import {UsingERC20} from "../mixins/UsingERC20.sol";
|
||||
|
||||
contract RMPWRXykCurveMissingEnumerableERC20Test is
|
||||
RouterMultiPoolWithRoyalties,
|
||||
UsingXykCurve,
|
||||
UsingMissingEnumerable,
|
||||
UsingERC20
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterMultiPoolWithRoyalties} from "../base/RouterMultiPoolWithRoyalties.sol";
|
||||
import {UsingXykCurve} from "../mixins/UsingXykCurve.sol";
|
||||
import {UsingMissingEnumerable} from "../mixins/UsingMissingEnumerable.sol";
|
||||
import {UsingETH} from "../mixins/UsingETH.sol";
|
||||
|
||||
contract RMPWRXykCurveMissingEnumerableETHTest is
|
||||
RouterMultiPoolWithRoyalties,
|
||||
UsingXykCurve,
|
||||
UsingMissingEnumerable,
|
||||
UsingETH
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterRobustSwapWithRoyalties} from "../base/RouterRobustSwapWithRoyalties.sol";
|
||||
import {UsingExponentialCurve} from "../mixins/UsingExponentialCurve.sol";
|
||||
import {UsingEnumerable} from "../mixins/UsingEnumerable.sol";
|
||||
import {UsingERC20} from "../mixins/UsingERC20.sol";
|
||||
|
||||
contract RRSWRExponentialCurveEnumerableERC20Test is
|
||||
RouterRobustSwapWithRoyalties,
|
||||
UsingExponentialCurve,
|
||||
UsingEnumerable,
|
||||
UsingERC20
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterRobustSwapWithRoyalties} from "../base/RouterRobustSwapWithRoyalties.sol";
|
||||
import {UsingExponentialCurve} from "../mixins/UsingExponentialCurve.sol";
|
||||
import {UsingEnumerable} from "../mixins/UsingEnumerable.sol";
|
||||
import {UsingETH} from "../mixins/UsingETH.sol";
|
||||
|
||||
contract RRSWRExponentialCurveEnumerableETHTest is
|
||||
RouterRobustSwapWithRoyalties,
|
||||
UsingExponentialCurve,
|
||||
UsingEnumerable,
|
||||
UsingETH
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterRobustSwapWithRoyalties} from "../base/RouterRobustSwapWithRoyalties.sol";
|
||||
import {UsingExponentialCurve} from "../mixins/UsingExponentialCurve.sol";
|
||||
import {UsingMissingEnumerable} from "../mixins/UsingMissingEnumerable.sol";
|
||||
import {UsingERC20} from "../mixins/UsingERC20.sol";
|
||||
|
||||
contract RRSWRExponentialCurveMissingEnumerableERC20Test is
|
||||
RouterRobustSwapWithRoyalties,
|
||||
UsingExponentialCurve,
|
||||
UsingMissingEnumerable,
|
||||
UsingERC20
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterRobustSwapWithRoyalties} from "../base/RouterRobustSwapWithRoyalties.sol";
|
||||
import {UsingExponentialCurve} from "../mixins/UsingExponentialCurve.sol";
|
||||
import {UsingMissingEnumerable} from "../mixins/UsingMissingEnumerable.sol";
|
||||
import {UsingETH} from "../mixins/UsingETH.sol";
|
||||
|
||||
contract RRSWRExponentialCurveMissingEnumerableETHTest is
|
||||
RouterRobustSwapWithRoyalties,
|
||||
UsingExponentialCurve,
|
||||
UsingMissingEnumerable,
|
||||
UsingETH
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterRobustSwapWithRoyalties} from "../base/RouterRobustSwapWithRoyalties.sol";
|
||||
import {UsingLinearCurve} from "../mixins/UsingLinearCurve.sol";
|
||||
import {UsingEnumerable} from "../mixins/UsingEnumerable.sol";
|
||||
import {UsingERC20} from "../mixins/UsingERC20.sol";
|
||||
|
||||
contract RRSWRLinearCurveEnumerableERC20Test is
|
||||
RouterRobustSwapWithRoyalties,
|
||||
UsingLinearCurve,
|
||||
UsingEnumerable,
|
||||
UsingERC20
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterRobustSwapWithRoyalties} from "../base/RouterRobustSwapWithRoyalties.sol";
|
||||
import {UsingLinearCurve} from "../mixins/UsingLinearCurve.sol";
|
||||
import {UsingEnumerable} from "../mixins/UsingEnumerable.sol";
|
||||
import {UsingETH} from "../mixins/UsingETH.sol";
|
||||
|
||||
contract RRSWRLinearCurveEnumerableETHTest is
|
||||
RouterRobustSwapWithRoyalties,
|
||||
UsingLinearCurve,
|
||||
UsingEnumerable,
|
||||
UsingETH
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterRobustSwapWithRoyalties} from "../base/RouterRobustSwapWithRoyalties.sol";
|
||||
import {UsingLinearCurve} from "../mixins/UsingLinearCurve.sol";
|
||||
import {UsingMissingEnumerable} from "../mixins/UsingMissingEnumerable.sol";
|
||||
import {UsingERC20} from "../mixins/UsingERC20.sol";
|
||||
|
||||
contract RRSWRLinearCurveMissingEnumerableERC20Test is
|
||||
RouterRobustSwapWithRoyalties,
|
||||
UsingLinearCurve,
|
||||
UsingMissingEnumerable,
|
||||
UsingERC20
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterRobustSwapWithRoyalties} from "../base/RouterRobustSwapWithRoyalties.sol";
|
||||
import {UsingLinearCurve} from "../mixins/UsingLinearCurve.sol";
|
||||
import {UsingMissingEnumerable} from "../mixins/UsingMissingEnumerable.sol";
|
||||
import {UsingETH} from "../mixins/UsingETH.sol";
|
||||
|
||||
contract RRSWRLinearCurveMissingEnumerableETHTest is
|
||||
RouterRobustSwapWithRoyalties,
|
||||
UsingLinearCurve,
|
||||
UsingMissingEnumerable,
|
||||
UsingETH
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterRobustSwapWithRoyalties} from "../base/RouterRobustSwapWithRoyalties.sol";
|
||||
import {UsingXykCurve} from "../mixins/UsingXykCurve.sol";
|
||||
import {UsingEnumerable} from "../mixins/UsingEnumerable.sol";
|
||||
import {UsingERC20} from "../mixins/UsingERC20.sol";
|
||||
|
||||
contract RRSWRXykCurveEnumerableERC20Test is
|
||||
RouterRobustSwapWithRoyalties,
|
||||
UsingXykCurve,
|
||||
UsingEnumerable,
|
||||
UsingERC20
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterRobustSwapWithRoyalties} from "../base/RouterRobustSwapWithRoyalties.sol";
|
||||
import {UsingXykCurve} from "../mixins/UsingXykCurve.sol";
|
||||
import {UsingEnumerable} from "../mixins/UsingEnumerable.sol";
|
||||
import {UsingETH} from "../mixins/UsingETH.sol";
|
||||
|
||||
contract RRSWRXykCurveEnumerableETHTest is
|
||||
RouterRobustSwapWithRoyalties,
|
||||
UsingXykCurve,
|
||||
UsingEnumerable,
|
||||
UsingETH
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterRobustSwapWithRoyalties} from "../base/RouterRobustSwapWithRoyalties.sol";
|
||||
import {UsingXykCurve} from "../mixins/UsingXykCurve.sol";
|
||||
import {UsingMissingEnumerable} from "../mixins/UsingMissingEnumerable.sol";
|
||||
import {UsingERC20} from "../mixins/UsingERC20.sol";
|
||||
|
||||
contract RRSWRXykCurveMissingEnumerableERC20Test is
|
||||
RouterRobustSwapWithRoyalties,
|
||||
UsingXykCurve,
|
||||
UsingMissingEnumerable,
|
||||
UsingERC20
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterRobustSwapWithRoyalties} from "../base/RouterRobustSwapWithRoyalties.sol";
|
||||
import {UsingXykCurve} from "../mixins/UsingXykCurve.sol";
|
||||
import {UsingMissingEnumerable} from "../mixins/UsingMissingEnumerable.sol";
|
||||
import {UsingETH} from "../mixins/UsingETH.sol";
|
||||
|
||||
contract RRSWRXykCurveMissingEnumerableETHTest is
|
||||
RouterRobustSwapWithRoyalties,
|
||||
UsingXykCurve,
|
||||
UsingMissingEnumerable,
|
||||
UsingETH
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterSinglePoolWithRoyalties} from "../base/RouterSinglePoolWithRoyalties.sol";
|
||||
import {UsingExponentialCurve} from "../mixins/UsingExponentialCurve.sol";
|
||||
import {UsingEnumerable} from "../mixins/UsingEnumerable.sol";
|
||||
import {UsingERC20} from "../mixins/UsingERC20.sol";
|
||||
|
||||
contract RSPWRExponentialCurveEnumerableERC20Test is
|
||||
RouterSinglePoolWithRoyalties,
|
||||
UsingExponentialCurve,
|
||||
UsingEnumerable,
|
||||
UsingERC20
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterSinglePoolWithRoyalties} from "../base/RouterSinglePoolWithRoyalties.sol";
|
||||
import {UsingExponentialCurve} from "../mixins/UsingExponentialCurve.sol";
|
||||
import {UsingEnumerable} from "../mixins/UsingEnumerable.sol";
|
||||
import {UsingETH} from "../mixins/UsingETH.sol";
|
||||
|
||||
contract RSPWRExponentialCurveEnumerableETHTest is
|
||||
RouterSinglePoolWithRoyalties,
|
||||
UsingExponentialCurve,
|
||||
UsingEnumerable,
|
||||
UsingETH
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterSinglePoolWithRoyalties} from "../base/RouterSinglePoolWithRoyalties.sol";
|
||||
import {UsingExponentialCurve} from "../mixins/UsingExponentialCurve.sol";
|
||||
import {UsingMissingEnumerable} from "../mixins/UsingMissingEnumerable.sol";
|
||||
import {UsingERC20} from "../mixins/UsingERC20.sol";
|
||||
|
||||
contract RSPWRExponentialCurveMissingEnumerableERC20Test is
|
||||
RouterSinglePoolWithRoyalties,
|
||||
UsingExponentialCurve,
|
||||
UsingMissingEnumerable,
|
||||
UsingERC20
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterSinglePoolWithRoyalties} from "../base/RouterSinglePoolWithRoyalties.sol";
|
||||
import {UsingExponentialCurve} from "../mixins/UsingExponentialCurve.sol";
|
||||
import {UsingMissingEnumerable} from "../mixins/UsingMissingEnumerable.sol";
|
||||
import {UsingETH} from "../mixins/UsingETH.sol";
|
||||
|
||||
contract RSPWRExponentialCurveMissingEnumerableETHTest is
|
||||
RouterSinglePoolWithRoyalties,
|
||||
UsingExponentialCurve,
|
||||
UsingMissingEnumerable,
|
||||
UsingETH
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterSinglePoolWithRoyalties} from "../base/RouterSinglePoolWithRoyalties.sol";
|
||||
import {UsingLinearCurve} from "../mixins/UsingLinearCurve.sol";
|
||||
import {UsingEnumerable} from "../mixins/UsingEnumerable.sol";
|
||||
import {UsingERC20} from "../mixins/UsingERC20.sol";
|
||||
|
||||
contract RSPWRLinearCurveEnumerableERC20Test is
|
||||
RouterSinglePoolWithRoyalties,
|
||||
UsingLinearCurve,
|
||||
UsingEnumerable,
|
||||
UsingERC20
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterSinglePoolWithRoyalties} from "../base/RouterSinglePoolWithRoyalties.sol";
|
||||
import {UsingLinearCurve} from "../mixins/UsingLinearCurve.sol";
|
||||
import {UsingEnumerable} from "../mixins/UsingEnumerable.sol";
|
||||
import {UsingETH} from "../mixins/UsingETH.sol";
|
||||
|
||||
contract RSPWRLinearCurveEnumerableETHTest is
|
||||
RouterSinglePoolWithRoyalties,
|
||||
UsingLinearCurve,
|
||||
UsingEnumerable,
|
||||
UsingETH
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterSinglePoolWithRoyalties} from "../base/RouterSinglePoolWithRoyalties.sol";
|
||||
import {UsingLinearCurve} from "../mixins/UsingLinearCurve.sol";
|
||||
import {UsingMissingEnumerable} from "../mixins/UsingMissingEnumerable.sol";
|
||||
import {UsingERC20} from "../mixins/UsingERC20.sol";
|
||||
|
||||
contract RSPWRLinearCurveMissingEnumerableERC20Test is
|
||||
RouterSinglePoolWithRoyalties,
|
||||
UsingLinearCurve,
|
||||
UsingMissingEnumerable,
|
||||
UsingERC20
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterSinglePoolWithRoyalties} from "../base/RouterSinglePoolWithRoyalties.sol";
|
||||
import {UsingLinearCurve} from "../mixins/UsingLinearCurve.sol";
|
||||
import {UsingMissingEnumerable} from "../mixins/UsingMissingEnumerable.sol";
|
||||
import {UsingETH} from "../mixins/UsingETH.sol";
|
||||
|
||||
contract RSPWRLinearCurveMissingEnumerableETHTest is
|
||||
RouterSinglePoolWithRoyalties,
|
||||
UsingLinearCurve,
|
||||
UsingMissingEnumerable,
|
||||
UsingETH
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterSinglePoolWithRoyalties} from "../base/RouterSinglePoolWithRoyalties.sol";
|
||||
import {UsingXykCurve} from "../mixins/UsingXykCurve.sol";
|
||||
import {UsingEnumerable} from "../mixins/UsingEnumerable.sol";
|
||||
import {UsingERC20} from "../mixins/UsingERC20.sol";
|
||||
|
||||
contract RSPWRXykCurveEnumerableERC20Test is
|
||||
RouterSinglePoolWithRoyalties,
|
||||
UsingXykCurve,
|
||||
UsingEnumerable,
|
||||
UsingERC20
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterSinglePoolWithRoyalties} from "../base/RouterSinglePoolWithRoyalties.sol";
|
||||
import {UsingXykCurve} from "../mixins/UsingXykCurve.sol";
|
||||
import {UsingEnumerable} from "../mixins/UsingEnumerable.sol";
|
||||
import {UsingETH} from "../mixins/UsingETH.sol";
|
||||
|
||||
contract RSPWRXykCurveEnumerableETHTest is
|
||||
RouterSinglePoolWithRoyalties,
|
||||
UsingXykCurve,
|
||||
UsingEnumerable,
|
||||
UsingETH
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterSinglePoolWithRoyalties} from "../base/RouterSinglePoolWithRoyalties.sol";
|
||||
import {UsingXykCurve} from "../mixins/UsingXykCurve.sol";
|
||||
import {UsingMissingEnumerable} from "../mixins/UsingMissingEnumerable.sol";
|
||||
import {UsingERC20} from "../mixins/UsingERC20.sol";
|
||||
|
||||
contract RSPWRXykCurveMissingEnumerableERC20Test is
|
||||
RouterSinglePoolWithRoyalties,
|
||||
UsingXykCurve,
|
||||
UsingMissingEnumerable,
|
||||
UsingERC20
|
||||
{}
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import {RouterSinglePoolWithRoyalties} from "../base/RouterSinglePoolWithRoyalties.sol";
|
||||
import {UsingXykCurve} from "../mixins/UsingXykCurve.sol";
|
||||
import {UsingMissingEnumerable} from "../mixins/UsingMissingEnumerable.sol";
|
||||
import {UsingETH} from "../mixins/UsingETH.sol";
|
||||
|
||||
contract RSPWRXykCurveMissingEnumerableETHTest is
|
||||
RouterSinglePoolWithRoyalties,
|
||||
UsingXykCurve,
|
||||
UsingMissingEnumerable,
|
||||
UsingETH
|
||||
{}
|
||||
@@ -1,8 +1,10 @@
|
||||
NoArbBondingCurve,NoArb
|
||||
RouterRobustSwap,RRS
|
||||
RouterSinglePool,RSP
|
||||
RouterSinglePoolWithRoyalties,RSPWR
|
||||
PairAndFactory,PAF
|
||||
RouterMultiPool,RMP
|
||||
RouterMultiPoolWithRoyalties,RMPWR
|
||||
RouterSinglePoolWithAssetRecipient,RSPWAR
|
||||
RouterRobustSwapWithAssetRecipient,RRSWAR
|
||||
RouterPartialFill,RPF
|
||||
RouterRobustSwapWithRoyalties,RRSWR
|
||||
|
||||
|
Reference in New Issue
Block a user