diff --git a/.eslintrc.json b/.eslintrc.json index 5818630d8..b743b8b8a 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -14,6 +14,7 @@ "node/no-missing-import": "off", "no-unpublished-import": "off", "no-case-declarations": "off", - "@typescript-eslint/no-non-null-assertion": "off" + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/no-non-null-asserted-optional-chain": "off" } } diff --git a/.gitignore b/.gitignore index 7d17c0151..962d72d94 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,10 @@ coverage.json /coverage dist +artifacts-zk/ +cache-zk/ +zk-libraries.json + keystore/ # Setting for non zero-installs (https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored) diff --git a/.nvmrc b/.nvmrc index 3c032078a..6d80269a4 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -18 +18.16.0 diff --git a/Makefile b/Makefile index f3c770610..0a05762d8 100644 --- a/Makefile +++ b/Makefile @@ -19,19 +19,18 @@ init: submodules .PHONY: test test: - npx hardhat test ./test/${TEST_TARGET} --network ${NETWORK} # --verbose - + npx hardhat test ./test/${TEST_TARGET} --network ${NETWORK} --no-compile .PHONY: local-test local-test: make MOCHA_JOBS=0 DB_PATH=deployed-contracts.json DEPLOY_START=21 NETWORK=localhost test .PHONY: slow-test slow-test: - MOCHA_JOBS=0 DB_PATH=deployed-contracts.json npx hardhat test ./test/${TEST_TARGET} --network ${NETWORK} # --verbose + MOCHA_JOBS=0 DB_PATH=deployed-contracts.json npx hardhat test ./test/${TEST_TARGET} --network ${NETWORK} --no-compile .PHONY: fast-test fast-test: - MOCHA_JOBS=4 DB_PATH=:memory: npx hardhat test ./test/${TEST_TARGET} --network ${NETWORK} # --verbose + MOCHA_JOBS=4 DB_PATH=:memory: npx hardhat test ./test/${TEST_TARGET} --network ${NETWORK} --no-compile .PHONY: size size: @@ -39,7 +38,8 @@ size: .PHONY: build build: clean - yarn build + yarn build --network ${NETWORK} + yarn typechain .PHONY: doc doc: @@ -52,7 +52,7 @@ lint: .PHONY: coverage coverage: - yarn coverage + yarn coverage --no-compile .PHONY: format format: @@ -264,9 +264,9 @@ test-ape-staking: test-auto-compound-ape: make TEST_TARGET=auto_compound_ape.spec.ts test -.PHONY: test-p2p-pair-staking -test-p2p-pair-staking: - make TEST_TARGET=p2p_pair_staking.spec.ts test +.PHONY: test-para-ape-staking +test-para-aper-staking: + make TEST_TARGET=para_ape_staking.spec.ts test .PHONY: test-sape-operation test-sape-operation: @@ -286,7 +286,7 @@ test-stakefish-nft: .PHONY: run run: - npx hardhat run $(SCRIPT_PATH) --network $(NETWORK) + npx hardhat run $(SCRIPT_PATH) --network $(NETWORK) --no-compile .PHONY: run-task run-task: @@ -384,9 +384,9 @@ deploy-blur-exchange: deploy-flashClaimRegistry: make TASK_NAME=deploy:flash-claim-registry run-task -.PHONY: deploy-p2p-pair-staking -deploy-p2p-pair-staking: - make TASK_NAME=deploy:P2PPairStaking run-task +.PHONY: deploy-para-ape-staking +deploy-para-ape-staking: + make TASK_NAME=deploy:ParaApeStaking run-task .PHONY: deploy-timelock deploy-timelock: @@ -396,6 +396,10 @@ deploy-timelock: deploy-renounceOwnership: make TASK_NAME=deploy:renounce-ownership run-task +.PHONY: deploy-all-libraries +deploy-all-libraries: + make TASK_NAME=deploy:all-libraries run-task + .PHONY: ad-hoc ad-hoc: make SCRIPT_PATH=./scripts/dev/1.ad-hoc.ts run @@ -444,6 +448,14 @@ set-timelock-strategy: acl: make SCRIPT_PATH=./scripts/dev/13.acl.ts run +.PHONY: zksync-bytecode-hashes +zksync-bytecode-hashes: + make SCRIPT_PATH=./scripts/dev/14.zksync-bytecode-hashes.ts run + +.PHONY: redeploy-market +redeploy-market: + make SCRIPT_PATH=./scripts/dev/15.redeploy-market.ts run + .PHONY: transfer-tokens transfer-tokens: make SCRIPT_PATH=./scripts/dev/2.transfer-tokens.ts run @@ -636,9 +648,9 @@ upgrade-auto-compound-ape: upgrade-timelock: make TASK_NAME=upgrade:timelock run-task -.PHONY: upgrade-p2p-pair-staking -upgrade-p2p-pair-staking: - make TASK_NAME=upgrade:p2p-pair-staking run-task +.PHONY: upgrade-para-ape-staking +upgrade-para-ape-staking: + make TASK_NAME=upgrade:para-ape-staking run-task .PHONY: upgrade-ntoken upgrade-ntoken: @@ -671,15 +683,16 @@ hardhat: .PHONY: anvil anvil: anvil \ - $(if $(FORK),--fork-url https://eth-$(FORK).alchemyapi.io/v2/$(ALCHEMY_KEY) --no-rate-limit,) \ - $(if $(FORK),--chain-id 522,--chain-id 31337) \ - --tracing \ + $(if $(FORK),--fork-url https://eth-$(FORK).alchemyapi.io/v2/$(ALCHEMY_KEY) --chain-id 522 --no-rate-limit,--chain-id 31337) \ + $(if $(FORK_BLOCK_NUMBER),--fork-block-number $(FORK_BLOCK_NUMBER),) \ + $(if $(DEPLOYER_MNEMONIC),--mnemonic "${DEPLOYER_MNEMONIC}",--mnemonic "test test test test test test test test test test test junk") \ --host 0.0.0.0 \ --state-interval 60 \ --dump-state state.json \ $(if $(wildcard state.json),--load-state state.json,) \ --disable-block-gas-limit \ --code-size-limit 100000 \ + --timeout 9000000 .PHONY: image image: @@ -701,7 +714,7 @@ shutdown: docker-compose \ down \ --remove-orphans > /dev/null 2>&1 || true - docker volume prune -f + docker volume prune -f || true sudo rm -fr redis-data || true sudo rm -fr logs || true sudo rm -fr state.json || true diff --git a/contracts/apestaking/AutoCompoundApe.sol b/contracts/apestaking/AutoCompoundApe.sol index 54401938c..8080040a9 100644 --- a/contracts/apestaking/AutoCompoundApe.sol +++ b/contracts/apestaking/AutoCompoundApe.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "../dependencies/openzeppelin/upgradeability/Initializable.sol"; import "../dependencies/openzeppelin/upgradeability/OwnableUpgradeable.sol"; diff --git a/contracts/apestaking/AutoYieldApe.sol b/contracts/apestaking/AutoYieldApe.sol index 61c2667a4..ce008d825 100644 --- a/contracts/apestaking/AutoYieldApe.sol +++ b/contracts/apestaking/AutoYieldApe.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "../dependencies/openzeppelin/upgradeability/Initializable.sol"; import "../dependencies/openzeppelin/upgradeability/ERC20Upgradeable.sol"; @@ -8,7 +8,7 @@ import "../dependencies/openzeppelin/contracts/IERC20.sol"; import "../dependencies/openzeppelin/contracts/SafeERC20.sol"; import "../dependencies/openzeppelin/contracts/SafeCast.sol"; import "../dependencies/openzeppelin/contracts/Address.sol"; -import "../dependencies/univ3/interfaces/ISwapRouter.sol"; +import "../dependencies/uniswapv3-periphery/interfaces/ISwapRouter.sol"; import "../dependencies/yoga-labs/ApeCoinStaking.sol"; import "../interfaces/IAutoYieldApe.sol"; import "../interfaces/IYieldInfo.sol"; diff --git a/contracts/apestaking/P2PPairStaking.sol b/contracts/apestaking/P2PPairStaking.sol deleted file mode 100644 index 8c0ffb0d8..000000000 --- a/contracts/apestaking/P2PPairStaking.sol +++ /dev/null @@ -1,772 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.10; - -import "../dependencies/openzeppelin/upgradeability/Initializable.sol"; -import "../dependencies/openzeppelin/upgradeability/OwnableUpgradeable.sol"; -import "../dependencies/openzeppelin/upgradeability/ReentrancyGuardUpgradeable.sol"; -import "../dependencies/yoga-labs/ApeCoinStaking.sol"; -import "../interfaces/IP2PPairStaking.sol"; -import "../dependencies/openzeppelin/contracts/SafeCast.sol"; -import "../interfaces/IAutoCompoundApe.sol"; -import "../interfaces/ICApe.sol"; -import {IERC721} from "../dependencies/openzeppelin/contracts/IERC721.sol"; -import {IERC20, SafeERC20} from "../dependencies/openzeppelin/contracts/SafeERC20.sol"; -import {PercentageMath} from "../protocol/libraries/math/PercentageMath.sol"; -import {SignatureChecker} from "../dependencies/looksrare/contracts/libraries/SignatureChecker.sol"; -import "../protocol/libraries/helpers/Errors.sol"; -import "../interfaces/IACLManager.sol"; - -contract P2PPairStaking is - Initializable, - OwnableUpgradeable, - ReentrancyGuardUpgradeable, - IP2PPairStaking -{ - using SafeERC20 for IERC20; - using PercentageMath for uint256; - using SafeCast for uint256; - - //keccak256("ListingOrder(uint8 stakingType,address offerer,address token,uint256 tokenId,uint256 share,uint256 startTime,uint256 endTime)"); - bytes32 internal constant LISTING_ORDER_HASH = - 0x227f9dd14259caacdbcf45411b33cf1c018f31bd3da27e613a66edf8ae45814f; - - //keccak256("MatchedOrder(uint8 stakingType,address apeToken,uint32 apeTokenId,uint32 apeShare,uint32 bakcTokenId,uint32 bakcShare,address apeCoinOfferer,uint32 apeCoinShare,uint256 apePrincipleAmount)"); - bytes32 internal constant MATCHED_ORDER_HASH = - 0x7db3dae7d89c86e6881a66a131841305c008b207e41ff86a804b4bb056652808; - - //keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); - bytes32 internal constant EIP712_DOMAIN = - 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; - - uint256 internal constant WAD = 1e18; - - address internal immutable bayc; - address internal immutable mayc; - address internal immutable bakc; - address internal immutable nBayc; - address internal immutable nMayc; - address internal immutable nBakc; - address internal immutable apeCoin; - address internal immutable cApe; - ApeCoinStaking internal immutable apeCoinStaking; - uint256 public immutable compoundFee; - uint256 private immutable baycMatchedCap; - uint256 private immutable maycMatchedCap; - uint256 private immutable bakcMatchedCap; - - bytes32 internal DOMAIN_SEPARATOR; - mapping(bytes32 => ListingOrderStatus) public listingOrderStatus; - mapping(bytes32 => MatchedOrder) public matchedOrders; - mapping(address => mapping(uint32 => uint256)) private apeMatchedCount; - mapping(address => uint256) private cApeShareBalance; - address public __matchingOperator; - uint256 public __compoundFee; - uint256 private __baycMatchedCap; - uint256 private __maycMatchedCap; - uint256 private __bakcMatchedCap; - address public compoundBot; - bool private paused; - IACLManager private immutable aclManager; - - constructor( - address _bayc, - address _mayc, - address _bakc, - address _nBayc, - address _nMayc, - address _nBakc, - address _apeCoin, - address _cApe, - address _apeCoinStaking, - address _aclManager, - uint256 _compoundFee - ) { - bayc = _bayc; - mayc = _mayc; - bakc = _bakc; - nBayc = _nBayc; - nMayc = _nMayc; - nBakc = _nBakc; - apeCoin = _apeCoin; - cApe = _cApe; - apeCoinStaking = ApeCoinStaking(_apeCoinStaking); - aclManager = IACLManager(_aclManager); - compoundFee = _compoundFee; - - ( - , - ApeCoinStaking.PoolUI memory baycPool, - ApeCoinStaking.PoolUI memory maycPool, - ApeCoinStaking.PoolUI memory bakcPool - ) = apeCoinStaking.getPoolsUI(); - - baycMatchedCap = baycPool.currentTimeRange.capPerPosition; - maycMatchedCap = maycPool.currentTimeRange.capPerPosition; - bakcMatchedCap = bakcPool.currentTimeRange.capPerPosition; - } - - function initialize() public initializer { - __Ownable_init(); - __ReentrancyGuard_init(); - - DOMAIN_SEPARATOR = keccak256( - abi.encode( - EIP712_DOMAIN, - //keccak256("ParaSpace"), - 0x88d989289235fb06c18e3c2f7ea914f41f773e86fb0073d632539f566f4df353, - //keccak256(bytes("1")), - 0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6, - block.chainid, - address(this) - ) - ); - - //approve ApeCoin for apeCoinStaking - IERC20(apeCoin).safeApprove(address(apeCoinStaking), type(uint256).max); - //approve ApeCoin for cApe - IERC20(apeCoin).safeApprove(cApe, type(uint256).max); - } - - function cancelListing(ListingOrder calldata listingOrder) - external - nonReentrant - { - require(msg.sender == listingOrder.offerer, "not order offerer"); - bytes32 orderHash = getListingOrderHash(listingOrder); - require( - listingOrderStatus[orderHash] != ListingOrderStatus.Cancelled, - "order already cancelled" - ); - listingOrderStatus[orderHash] = ListingOrderStatus.Cancelled; - - emit OrderCancelled(orderHash, listingOrder.offerer); - } - - function matchPairStakingList( - ListingOrder calldata apeOrder, - ListingOrder calldata apeCoinOrder - ) external nonReentrant whenNotPaused returns (bytes32 orderHash) { - //1 validate all order - _validateApeOrder(apeOrder); - bytes32 apeCoinListingOrderHash = _validateApeCoinOrder(apeCoinOrder); - - //2 check if orders can match - require( - apeOrder.stakingType == StakingType.MAYCStaking || - apeOrder.stakingType == StakingType.BAYCStaking, - "invalid stake type" - ); - require( - apeOrder.stakingType == apeCoinOrder.stakingType, - "orders type match failed" - ); - require( - apeOrder.share + apeCoinOrder.share == - PercentageMath.PERCENTAGE_FACTOR, - "orders share match failed" - ); - - //3 transfer token - _handleApeTransfer(apeOrder); - uint256 apeAmount = _handleCApeTransferAndConvert(apeCoinOrder); - - //4 create match order - MatchedOrder memory matchedOrder = MatchedOrder({ - stakingType: apeOrder.stakingType, - apeToken: apeOrder.token, - apeTokenId: apeOrder.tokenId, - apeShare: apeOrder.share, - bakcTokenId: 0, - bakcShare: 0, - apeCoinOfferer: apeCoinOrder.offerer, - apeCoinShare: apeCoinOrder.share, - apePrincipleAmount: apeAmount, - apeCoinListingOrderHash: apeCoinListingOrderHash - }); - orderHash = getMatchedOrderHash(matchedOrder); - matchedOrders[orderHash] = matchedOrder; - apeMatchedCount[apeOrder.token][apeOrder.tokenId] += 1; - - //5 stake for ApeCoinStaking - ApeCoinStaking.SingleNft[] - memory singleNft = new ApeCoinStaking.SingleNft[](1); - singleNft[0].tokenId = apeOrder.tokenId; - singleNft[0].amount = apeAmount.toUint224(); - if (apeOrder.stakingType == StakingType.BAYCStaking) { - apeCoinStaking.depositBAYC(singleNft); - } else { - apeCoinStaking.depositMAYC(singleNft); - } - - //6 update ape coin listing order status - listingOrderStatus[apeCoinListingOrderHash] = ListingOrderStatus - .Matched; - - //7 emit event - emit PairStakingMatched(orderHash); - - return orderHash; - } - - function matchBAKCPairStakingList( - ListingOrder calldata apeOrder, - ListingOrder calldata bakcOrder, - ListingOrder calldata apeCoinOrder - ) external nonReentrant whenNotPaused returns (bytes32 orderHash) { - //1 validate all order - _validateApeOrder(apeOrder); - _validateBakcOrder(bakcOrder); - bytes32 apeCoinListingOrderHash = _validateApeCoinOrder(apeCoinOrder); - - //2 check if orders can match - require( - apeOrder.stakingType == StakingType.BAKCPairStaking, - "invalid stake type" - ); - require( - apeOrder.stakingType == bakcOrder.stakingType && - apeOrder.stakingType == apeCoinOrder.stakingType, - "orders type match failed" - ); - require( - apeOrder.share + bakcOrder.share + apeCoinOrder.share == - PercentageMath.PERCENTAGE_FACTOR, - "share match failed" - ); - - //3 transfer token - _handleApeTransfer(apeOrder); - IERC721(bakc).safeTransferFrom(nBakc, address(this), bakcOrder.tokenId); - uint256 apeAmount = _handleCApeTransferAndConvert(apeCoinOrder); - - //4 create match order - MatchedOrder memory matchedOrder = MatchedOrder({ - stakingType: apeOrder.stakingType, - apeToken: apeOrder.token, - apeTokenId: apeOrder.tokenId, - apeShare: apeOrder.share, - bakcTokenId: bakcOrder.tokenId, - bakcShare: bakcOrder.share, - apeCoinOfferer: apeCoinOrder.offerer, - apeCoinShare: apeCoinOrder.share, - apePrincipleAmount: apeAmount, - apeCoinListingOrderHash: apeCoinListingOrderHash - }); - orderHash = getMatchedOrderHash(matchedOrder); - matchedOrders[orderHash] = matchedOrder; - apeMatchedCount[apeOrder.token][apeOrder.tokenId] += 1; - - //5 stake for ApeCoinStaking - ApeCoinStaking.PairNftDepositWithAmount[] - memory _stakingPairs = new ApeCoinStaking.PairNftDepositWithAmount[]( - 1 - ); - _stakingPairs[0].mainTokenId = apeOrder.tokenId; - _stakingPairs[0].bakcTokenId = bakcOrder.tokenId; - _stakingPairs[0].amount = apeAmount.toUint184(); - ApeCoinStaking.PairNftDepositWithAmount[] - memory _otherPairs = new ApeCoinStaking.PairNftDepositWithAmount[]( - 0 - ); - if (apeOrder.token == bayc) { - apeCoinStaking.depositBAKC(_stakingPairs, _otherPairs); - } else { - apeCoinStaking.depositBAKC(_otherPairs, _stakingPairs); - } - - //6 update ape coin listing order status - listingOrderStatus[apeCoinListingOrderHash] = ListingOrderStatus - .Matched; - - //7 emit event - emit PairStakingMatched(orderHash); - - return orderHash; - } - - function breakUpMatchedOrder(bytes32 orderHash) - external - nonReentrant - whenNotPaused - { - MatchedOrder memory order = matchedOrders[orderHash]; - - //1 check if have permission to break up - address apeNToken = _getApeNTokenAddress(order.apeToken); - address apeNTokenOwner = IERC721(apeNToken).ownerOf(order.apeTokenId); - address nBakcOwner = IERC721(nBakc).ownerOf(order.bakcTokenId); - require( - msg.sender == apeNTokenOwner || - msg.sender == order.apeCoinOfferer || - (msg.sender == nBakcOwner && - order.stakingType == StakingType.BAKCPairStaking), - "no permission to break up" - ); - - //2 claim pending reward and compound - bytes32[] memory orderHashes = new bytes32[](1); - orderHashes[0] = orderHash; - _claimForMatchedOrdersAndCompound(orderHashes); - - //3 delete matched order - delete matchedOrders[orderHash]; - - //4 exit from ApeCoinStaking - if (order.stakingType < StakingType.BAKCPairStaking) { - ApeCoinStaking.SingleNft[] - memory _nfts = new ApeCoinStaking.SingleNft[](1); - _nfts[0].tokenId = order.apeTokenId; - _nfts[0].amount = order.apePrincipleAmount.toUint224(); - if (order.stakingType == StakingType.BAYCStaking) { - apeCoinStaking.withdrawSelfBAYC(_nfts); - } else { - apeCoinStaking.withdrawSelfMAYC(_nfts); - } - } else { - ApeCoinStaking.PairNftWithdrawWithAmount[] - memory _nfts = new ApeCoinStaking.PairNftWithdrawWithAmount[]( - 1 - ); - _nfts[0].mainTokenId = order.apeTokenId; - _nfts[0].bakcTokenId = order.bakcTokenId; - _nfts[0].amount = order.apePrincipleAmount.toUint184(); - _nfts[0].isUncommit = true; - ApeCoinStaking.PairNftWithdrawWithAmount[] - memory _otherPairs = new ApeCoinStaking.PairNftWithdrawWithAmount[]( - 0 - ); - if (order.apeToken == bayc) { - apeCoinStaking.withdrawBAKC(_nfts, _otherPairs); - } else { - apeCoinStaking.withdrawBAKC(_otherPairs, _nfts); - } - } - //5 transfer token - uint256 matchedCount = apeMatchedCount[order.apeToken][ - order.apeTokenId - ]; - if (matchedCount == 1) { - IERC721(order.apeToken).safeTransferFrom( - address(this), - apeNToken, - order.apeTokenId - ); - } - apeMatchedCount[order.apeToken][order.apeTokenId] = matchedCount - 1; - - IAutoCompoundApe(cApe).deposit( - order.apeCoinOfferer, - order.apePrincipleAmount - ); - if (order.stakingType == StakingType.BAKCPairStaking) { - IERC721(bakc).safeTransferFrom( - address(this), - nBakc, - order.bakcTokenId - ); - } - - //6 reset ape coin listing order status - if ( - listingOrderStatus[order.apeCoinListingOrderHash] != - ListingOrderStatus.Cancelled - ) { - listingOrderStatus[ - order.apeCoinListingOrderHash - ] = ListingOrderStatus.Pending; - } - - //7 emit event - emit PairStakingBreakUp(orderHash); - } - - function claimForMatchedOrderAndCompound(bytes32[] calldata orderHashes) - external - nonReentrant - whenNotPaused - { - require(msg.sender == compoundBot, "no permission to compound"); - _claimForMatchedOrdersAndCompound(orderHashes); - } - - function _claimForMatchedOrdersAndCompound(bytes32[] memory orderHashes) - internal - { - //ignore getShareByPooledApe return 0 case. - uint256 cApeExchangeRate = ICApe(cApe).getPooledApeByShares(WAD); - uint256 _compoundFee = compoundFee; - uint256 totalReward; - uint256 totalFee; - uint256 orderCounts = orderHashes.length; - for (uint256 index = 0; index < orderCounts; index++) { - bytes32 orderHash = orderHashes[index]; - (uint256 reward, uint256 fee) = _claimForMatchedOrderAndCompound( - orderHash, - cApeExchangeRate, - _compoundFee - ); - totalReward += reward; - totalFee += fee; - } - if (totalReward > 0) { - IAutoCompoundApe(cApe).deposit(address(this), totalReward); - IERC20(apeCoin).safeTransfer(compoundBot, totalFee); - } - } - - function claimCApeReward(address receiver) - external - nonReentrant - whenNotPaused - { - uint256 cApeAmount = pendingCApeReward(msg.sender); - if (cApeAmount > 0) { - IERC20(cApe).safeTransfer(receiver, cApeAmount); - delete cApeShareBalance[msg.sender]; - emit CApeClaimed(msg.sender, receiver, cApeAmount); - } - } - - function pendingCApeReward(address user) public view returns (uint256) { - uint256 amount = 0; - uint256 shareBalance = cApeShareBalance[user]; - if (shareBalance > 0) { - amount = ICApe(cApe).getPooledApeByShares(shareBalance); - } - return amount; - } - - function getApeCoinStakingCap(StakingType stakingType) - public - view - returns (uint256) - { - if (stakingType == StakingType.BAYCStaking) { - return baycMatchedCap; - } else if (stakingType == StakingType.MAYCStaking) { - return maycMatchedCap; - } else { - return bakcMatchedCap; - } - } - - function getListingOrderHash(ListingOrder calldata order) - public - pure - returns (bytes32) - { - return - keccak256( - abi.encode( - LISTING_ORDER_HASH, - order.stakingType, - order.offerer, - order.token, - order.tokenId, - order.share, - order.startTime, - order.endTime - ) - ); - } - - function getMatchedOrderHash(MatchedOrder memory order) - public - pure - returns (bytes32) - { - return - keccak256( - abi.encode( - MATCHED_ORDER_HASH, - order.stakingType, - order.apeToken, - order.apeTokenId, - order.apeShare, - order.bakcTokenId, - order.bakcShare, - order.apeCoinOfferer, - order.apeCoinShare, - order.apePrincipleAmount - ) - ); - } - - function _getApeNTokenAddress(address apeToken) - internal - view - returns (address) - { - if (apeToken == bayc) { - return nBayc; - } else if (apeToken == mayc) { - return nMayc; - } else { - revert("unsupported ape token"); - } - } - - function _claimForMatchedOrderAndCompound( - bytes32 orderHash, - uint256 cApeExchangeRate, - uint256 _compoundFee - ) internal returns (uint256, uint256) { - MatchedOrder memory order = matchedOrders[orderHash]; - uint256 balanceBefore = IERC20(apeCoin).balanceOf(address(this)); - if ( - order.stakingType == StakingType.BAYCStaking || - order.stakingType == StakingType.MAYCStaking - ) { - uint256[] memory _nfts = new uint256[](1); - _nfts[0] = order.apeTokenId; - if (order.stakingType == StakingType.BAYCStaking) { - apeCoinStaking.claimSelfBAYC(_nfts); - } else { - apeCoinStaking.claimSelfMAYC(_nfts); - } - } else { - ApeCoinStaking.PairNft[] - memory _nfts = new ApeCoinStaking.PairNft[](1); - _nfts[0].mainTokenId = order.apeTokenId; - _nfts[0].bakcTokenId = order.bakcTokenId; - ApeCoinStaking.PairNft[] - memory _otherPairs = new ApeCoinStaking.PairNft[](0); - if (order.apeToken == bayc) { - apeCoinStaking.claimSelfBAKC(_nfts, _otherPairs); - } else { - apeCoinStaking.claimSelfBAKC(_otherPairs, _nfts); - } - } - uint256 balanceAfter = IERC20(apeCoin).balanceOf(address(this)); - uint256 rewardAmount = balanceAfter - balanceBefore; - if (rewardAmount == 0) { - return (0, 0); - } - - uint256 feeAmount = rewardAmount.percentMul(_compoundFee); - rewardAmount -= feeAmount; - uint256 rewardShare = (rewardAmount * WAD) / cApeExchangeRate; - - _depositCApeShareForUser( - IERC721(_getApeNTokenAddress(order.apeToken)).ownerOf( - order.apeTokenId - ), - rewardShare.percentMul(order.apeShare) - ); - _depositCApeShareForUser( - order.apeCoinOfferer, - rewardShare.percentMul(order.apeCoinShare) - ); - if (order.stakingType == StakingType.BAKCPairStaking) { - _depositCApeShareForUser( - IERC721(nBakc).ownerOf(order.bakcTokenId), - rewardShare.percentMul(order.bakcShare) - ); - } - - emit OrderClaimedAndCompounded(orderHash, rewardAmount + feeAmount); - - return (rewardAmount, feeAmount); - } - - function _depositCApeShareForUser(address user, uint256 amount) internal { - if (amount > 0) { - cApeShareBalance[user] += amount; - } - } - - function _handleApeTransfer(ListingOrder calldata order) internal { - address currentOwner = IERC721(order.token).ownerOf(order.tokenId); - if (currentOwner != address(this)) { - address nTokenAddress = _getApeNTokenAddress(order.token); - IERC721(order.token).safeTransferFrom( - nTokenAddress, - address(this), - order.tokenId - ); - } - } - - function _handleCApeTransferAndConvert(ListingOrder calldata apeCoinOrder) - internal - returns (uint256) - { - uint256 apeAmount = getApeCoinStakingCap(apeCoinOrder.stakingType); - IERC20(cApe).safeTransferFrom( - apeCoinOrder.offerer, - address(this), - apeAmount - ); - IAutoCompoundApe(cApe).withdraw(apeAmount); - return apeAmount; - } - - function _validateOrderBasicInfo(ListingOrder calldata listingOrder) - internal - view - returns (bytes32 orderHash) - { - require( - listingOrder.startTime <= block.timestamp, - "ape order not start" - ); - require(listingOrder.endTime >= block.timestamp, "ape offer expired"); - - orderHash = getListingOrderHash(listingOrder); - require( - listingOrderStatus[orderHash] != ListingOrderStatus.Cancelled, - "order already cancelled" - ); - - if (msg.sender != listingOrder.offerer) { - require( - validateOrderSignature( - listingOrder.offerer, - orderHash, - listingOrder.v, - listingOrder.r, - listingOrder.s - ), - "invalid signature" - ); - } - } - - function _validateApeOrder(ListingOrder calldata apeOrder) internal view { - _validateOrderBasicInfo(apeOrder); - - address nToken = _getApeNTokenAddress(apeOrder.token); - require( - IERC721(nToken).ownerOf(apeOrder.tokenId) == apeOrder.offerer, - "ape order invalid NToken owner" - ); - } - - function _validateBakcOrder(ListingOrder calldata bakcOrder) internal view { - _validateOrderBasicInfo(bakcOrder); - - require(bakcOrder.token == bakc, "bakc order invalid token"); - require( - IERC721(nBakc).ownerOf(bakcOrder.tokenId) == bakcOrder.offerer, - "bakc order invalid NToken owner" - ); - } - - function _validateApeCoinOrder(ListingOrder calldata apeCoinOrder) - internal - view - returns (bytes32 orderHash) - { - orderHash = _validateOrderBasicInfo(apeCoinOrder); - require(apeCoinOrder.token == cApe, "ape coin order invalid token"); - require( - listingOrderStatus[orderHash] != ListingOrderStatus.Matched, - "ape coin order already matched" - ); - } - - function validateOrderSignature( - address signer, - bytes32 orderHash, - uint8 v, - bytes32 r, - bytes32 s - ) public view returns (bool) { - return - SignatureChecker.verify( - orderHash, - signer, - v, - r, - s, - DOMAIN_SEPARATOR - ); - } - - function onERC721Received( - address, - address, - uint256, - bytes memory - ) external pure returns (bytes4) { - return this.onERC721Received.selector; - } - - function setCompoundBot(address _compoundBot) external onlyPoolAdmin { - address oldValue = compoundBot; - if (oldValue != _compoundBot) { - compoundBot = _compoundBot; - emit CompoundBotUpdated(oldValue, _compoundBot); - } - } - - function claimCompoundFee(address receiver) external onlyPoolAdmin { - this.claimCApeReward(receiver); - } - - /** - * @notice Pauses the contract. Only pool admin or emergency admin can call this function - **/ - function pause() external onlyEmergencyOrPoolAdmin whenNotPaused { - paused = true; - emit Paused(_msgSender()); - } - - /** - * @notice Unpause the contract. Only pool admin can call this function - **/ - function unpause() external onlyPoolAdmin whenPaused { - paused = false; - emit Unpaused(_msgSender()); - } - - function rescueERC20( - address token, - address to, - uint256 amount - ) external onlyPoolAdmin { - IERC20(token).safeTransfer(to, amount); - emit RescueERC20(token, to, amount); - } - - modifier whenNotPaused() { - require(!paused, "paused"); - _; - } - - modifier whenPaused() { - require(paused, "not paused"); - _; - } - - /** - * @dev Only pool admin can call functions marked by this modifier. - **/ - modifier onlyPoolAdmin() { - _onlyPoolAdmin(); - _; - } - - /** - * @dev Only emergency or pool admin can call functions marked by this modifier. - **/ - modifier onlyEmergencyOrPoolAdmin() { - _onlyPoolOrEmergencyAdmin(); - _; - } - - function _onlyPoolAdmin() internal view { - require( - aclManager.isPoolAdmin(msg.sender), - Errors.CALLER_NOT_POOL_ADMIN - ); - } - - function _onlyPoolOrEmergencyAdmin() internal view { - require( - aclManager.isPoolAdmin(msg.sender) || - aclManager.isEmergencyAdmin(msg.sender), - Errors.CALLER_NOT_POOL_OR_EMERGENCY_ADMIN - ); - } -} diff --git a/contracts/apestaking/ParaApeStaking.sol b/contracts/apestaking/ParaApeStaking.sol new file mode 100644 index 000000000..d712e0d05 --- /dev/null +++ b/contracts/apestaking/ParaApeStaking.sol @@ -0,0 +1,985 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity ^0.8.0; + +import "../interfaces/IParaApeStaking.sol"; +import "../dependencies/openzeppelin/upgradeability/Initializable.sol"; +import "../dependencies/openzeppelin/upgradeability/ReentrancyGuardUpgradeable.sol"; +import "../dependencies/openzeppelin/upgradeability/PausableUpgradeable.sol"; +import {IERC20, SafeERC20} from "../dependencies/openzeppelin/contracts/SafeERC20.sol"; +import "../dependencies/openzeppelin/contracts/SafeCast.sol"; +import "../dependencies/openzeppelin/contracts/Multicall.sol"; +import "../dependencies/yoga-labs/ApeCoinStaking.sol"; +import "../interfaces/IACLManager.sol"; +import "../interfaces/ICApe.sol"; +import {PercentageMath} from "../protocol/libraries/math/PercentageMath.sol"; +import "./logic/ApeStakingP2PLogic.sol"; +import "./logic/ApeStakingPairPoolLogic.sol"; +import "./logic/ApeStakingSinglePoolLogic.sol"; +import "./logic/ApeCoinPoolLogic.sol"; +import "./logic/ApeStakingCommonLogic.sol"; +import "../protocol/libraries/helpers/Errors.sol"; + +contract ParaApeStaking is + Initializable, + ReentrancyGuardUpgradeable, + PausableUpgradeable, + Multicall, + IParaApeStaking +{ + using SafeERC20 for IERC20; + using SafeCast for uint256; + + //keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); + bytes32 internal constant EIP712_DOMAIN = + 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; + + address internal immutable pool; + address internal immutable bayc; + address internal immutable mayc; + address internal immutable bakc; + address internal immutable nBayc; + address internal immutable nMayc; + address internal immutable nBakc; + address internal immutable apeCoin; + address internal immutable cApe; + ApeCoinStaking internal immutable apeCoinStaking; + uint256 private immutable baycMatchedCap; + uint256 private immutable maycMatchedCap; + uint256 private immutable bakcMatchedCap; + IACLManager private immutable aclManager; + uint16 public immutable sApeReserveId; + address private immutable psApe; + + //record all pool states + mapping(uint256 => PoolState) public poolStates; + + //record user sApe balance + mapping(address => SApeBalance) private sApeBalance; + + //P2P storage + bytes32 internal DOMAIN_SEPARATOR; + mapping(bytes32 => ListingOrderStatus) public listingOrderStatus; + mapping(bytes32 => MatchedOrder) public matchedOrders; + + //record Ape in P2P and ApeCoin pool + mapping(address => mapping(uint32 => uint256)) private apeMatchedCount; + mapping(address => uint256) private cApeShareBalance; + + address public apeStakingBot; + uint64 public compoundFee; + uint32 apePairStakingRewardRatio; + + constructor( + address _pool, + address _bayc, + address _mayc, + address _bakc, + address _nBayc, + address _nMayc, + address _nBakc, + address _apeCoin, + address _cApe, + address _apeCoinStaking, + address _aclManager + ) { + pool = _pool; + bayc = _bayc; + mayc = _mayc; + bakc = _bakc; + nBayc = _nBayc; + nMayc = _nMayc; + nBakc = _nBakc; + apeCoin = _apeCoin; + cApe = _cApe; + apeCoinStaking = ApeCoinStaking(_apeCoinStaking); + aclManager = IACLManager(_aclManager); + + ( + , + ApeCoinStaking.PoolUI memory baycPool, + ApeCoinStaking.PoolUI memory maycPool, + ApeCoinStaking.PoolUI memory bakcPool + ) = apeCoinStaking.getPoolsUI(); + + baycMatchedCap = baycPool.currentTimeRange.capPerPosition; + maycMatchedCap = maycPool.currentTimeRange.capPerPosition; + bakcMatchedCap = bakcPool.currentTimeRange.capPerPosition; + + DataTypes.ReserveData memory sApeData = IPool(_pool).getReserveData( + DataTypes.SApeAddress + ); + psApe = sApeData.xTokenAddress; + sApeReserveId = sApeData.id; + } + + function initialize() public initializer { + __ReentrancyGuard_init(); + __Pausable_init(); + + DOMAIN_SEPARATOR = keccak256( + abi.encode( + EIP712_DOMAIN, + //keccak256("ParaSpace"), + 0x88d989289235fb06c18e3c2f7ea914f41f773e86fb0073d632539f566f4df353, + //keccak256(bytes("1")), + 0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6, + block.chainid, + address(this) + ) + ); + + //approve ApeCoin for apeCoinStaking + IERC20(apeCoin).safeApprove(address(apeCoinStaking), type(uint256).max); + //approve ApeCoin for cApe + IERC20(apeCoin).safeApprove(cApe, type(uint256).max); + //approve cApe for pool + IERC20(cApe).safeApprove(pool, type(uint256).max); + } + + /** + * @dev Only pool admin can call functions marked by this modifier. + **/ + modifier onlyPoolAdmin() { + _onlyPoolAdmin(); + _; + } + + /** + * @dev Only emergency or pool admin can call functions marked by this modifier. + **/ + modifier onlyEmergencyOrPoolAdmin() { + _onlyPoolOrEmergencyAdmin(); + _; + } + + modifier onlyApeStakingBot() { + require(apeStakingBot == msg.sender, Errors.NOT_APE_STAKING_BOT); + _; + } + + function _onlyPoolAdmin() internal view { + require( + aclManager.isPoolAdmin(msg.sender), + Errors.CALLER_NOT_POOL_ADMIN + ); + } + + function _onlyPoolOrEmergencyAdmin() internal view { + require( + aclManager.isPoolAdmin(msg.sender) || + aclManager.isEmergencyAdmin(msg.sender), + Errors.CALLER_NOT_POOL_OR_EMERGENCY_ADMIN + ); + } + + function setApeStakingBot(address _apeStakingBot) external onlyPoolAdmin { + address oldValue = apeStakingBot; + if (oldValue != _apeStakingBot) { + apeStakingBot = _apeStakingBot; + emit ApeStakingBotUpdated(oldValue, _apeStakingBot); + } + } + + function setCompoundFee(uint64 _compoundFee) external onlyPoolAdmin { + //0.1e4 means 10% + require(_compoundFee <= 0.1e4, Errors.INVALID_PARAMETER); + uint64 oldValue = compoundFee; + if (oldValue != _compoundFee) { + compoundFee = _compoundFee; + emit CompoundFeeUpdated(oldValue, _compoundFee); + } + } + + function claimCompoundFee(address receiver) external onlyApeStakingBot { + this.claimCApeReward(receiver); + } + + /** + * @notice Pauses the contract. Only pool admin or emergency admin can call this function + **/ + function pause() external onlyEmergencyOrPoolAdmin { + _pause(); + } + + /** + * @notice Unpause the contract. Only pool admin can call this function + **/ + function unpause() external onlyPoolAdmin { + _unpause(); + } + + /** + * @notice Rescue erc20 from this contract address. Only pool admin can call this function + * @param token The token address to be rescued, _yieldToken cannot be rescued. + * @param to The account address to receive token + * @param amount The amount to be rescued + **/ + function rescueERC20( + address token, + address to, + uint256 amount + ) external onlyPoolAdmin { + IERC20(token).safeTransfer(to, amount); + emit RescueERC20(token, to, amount); + } + + /* + *common Logic + */ + /// @inheritdoc IParaApeStaking + function poolTokenStatus(uint256 poolId, uint256 tokenId) + external + view + returns (IParaApeStaking.TokenStatus memory) + { + return poolStates[poolId].tokenStatus[tokenId]; + } + + /// @inheritdoc IParaApeStaking + function getPendingReward(uint256 poolId, uint32[] calldata tokenIds) + external + view + returns (uint256) + { + return + ApeCoinPoolLogic.getPendingReward( + poolStates[poolId], + cApe, + tokenIds + ); + } + + /// @inheritdoc IParaApeStaking + function claimPendingReward(uint256 poolId, uint32[] calldata tokenIds) + external + whenNotPaused + nonReentrant + { + ApeStakingVaultCacheVars memory vars = _createCacheVars(); + address owner = ApeCoinPoolLogic.claimPendingReward( + poolStates[poolId], + vars, + poolId, + tokenIds + ); + require(msg.sender == owner, Errors.CALLER_NOT_ALLOWED); + } + + /* + *sApe Logic + */ + /// @inheritdoc IParaApeStaking + function stakedSApeBalance(address user) external view returns (uint256) { + return sApeBalance[user].stakedBalance; + } + + /// @inheritdoc IParaApeStaking + function freeSApeBalance(address user) external view returns (uint256) { + uint256 freeShareBalance = sApeBalance[user].freeShareBalance; + if (freeShareBalance == 0) { + return 0; + } + return ICApe(cApe).getPooledApeByShares(freeShareBalance); + } + + /// @inheritdoc IParaApeStaking + function totalSApeBalance(address user) external view returns (uint256) { + IParaApeStaking.SApeBalance memory cache = sApeBalance[user]; + uint256 freeShareBalance = cache.freeShareBalance; + if (freeShareBalance == 0) { + return cache.stakedBalance; + } + return + ICApe(cApe).getPooledApeByShares(freeShareBalance) + + cache.stakedBalance; + } + + /// @inheritdoc IParaApeStaking + function transferFreeSApeBalance( + address from, + address to, + uint256 amount + ) external { + require(msg.sender == psApe, Errors.CALLER_NOT_ALLOWED); + uint256 shareAmount = ICApe(cApe).getShareByPooledApe(amount); + sApeBalance[from].freeShareBalance -= shareAmount.toUint128(); + sApeBalance[to].freeShareBalance += shareAmount.toUint128(); + } + + /// @inheritdoc IParaApeStaking + function depositFreeSApe(address cashAsset, uint128 amount) + external + whenNotPaused + nonReentrant + { + ApeCoinPoolLogic.depositFreeSApe( + sApeBalance, + apeCoin, + cApe, + msg.sender, + cashAsset, + amount + ); + } + + /// @inheritdoc IParaApeStaking + function withdrawFreeSApe(address receiveAsset, uint128 amount) + external + whenNotPaused + nonReentrant + { + ApeCoinPoolLogic.withdrawFreeSApe( + sApeBalance, + pool, + apeCoin, + cApe, + sApeReserveId, + msg.sender, + receiveAsset, + amount + ); + } + + /* + *Ape Coin Staking Pool Logic + */ + /// @inheritdoc IApeCoinPool + function depositApeCoinPool(ApeCoinDepositInfo calldata depositInfo) + external + whenNotPaused + nonReentrant + { + require( + msg.sender == pool || msg.sender == depositInfo.onBehalf, + Errors.CALLER_NOT_ALLOWED + ); + ApeStakingVaultCacheVars memory vars = _createCacheVars(); + uint256 poolId = depositInfo.isBAYC + ? ApeStakingCommonLogic.BAYC_APECOIN_POOL_ID + : ApeStakingCommonLogic.MAYC_APECOIN_POOL_ID; + ApeCoinPoolLogic.depositApeCoinPool( + poolStates[poolId], + apeMatchedCount, + sApeBalance, + vars, + depositInfo + ); + } + + /// @inheritdoc IApeCoinPool + function compoundApeCoinPool(bool isBAYC, uint32[] calldata tokenIds) + external + onlyApeStakingBot + { + ApeStakingVaultCacheVars memory vars = _createCacheVars(); + vars.compoundFee = compoundFee; + uint256 poolId = isBAYC + ? ApeStakingCommonLogic.BAYC_APECOIN_POOL_ID + : ApeStakingCommonLogic.MAYC_APECOIN_POOL_ID; + ApeCoinPoolLogic.compoundApeCoinPool( + poolStates[poolId], + cApeShareBalance, + vars, + isBAYC, + tokenIds + ); + } + + /// @inheritdoc IApeCoinPool + function withdrawApeCoinPool(ApeCoinWithdrawInfo calldata withdrawInfo) + external + whenNotPaused + nonReentrant + { + ApeStakingVaultCacheVars memory vars = _createCacheVars(); + vars.compoundFee = compoundFee; + vars.sApeReserveId = sApeReserveId; + uint256 poolId = withdrawInfo.isBAYC + ? ApeStakingCommonLogic.BAYC_APECOIN_POOL_ID + : ApeStakingCommonLogic.MAYC_APECOIN_POOL_ID; + ApeCoinPoolLogic.withdrawApeCoinPool( + poolStates[poolId], + apeMatchedCount, + sApeBalance, + cApeShareBalance, + vars, + withdrawInfo, + poolId + ); + } + + /// @inheritdoc IApeCoinPool + function depositApeCoinPairPool(ApeCoinPairDepositInfo calldata depositInfo) + external + whenNotPaused + nonReentrant + { + require( + msg.sender == pool || msg.sender == depositInfo.onBehalf, + Errors.CALLER_NOT_ALLOWED + ); + ApeStakingVaultCacheVars memory vars = _createCacheVars(); + uint256 poolId = depositInfo.isBAYC + ? ApeStakingCommonLogic.BAYC_BAKC_APECOIN_POOL_ID + : ApeStakingCommonLogic.MAYC_BAKC_APECOIN_POOL_ID; + ApeCoinPoolLogic.depositApeCoinPairPool( + poolStates[poolId], + apeMatchedCount, + sApeBalance, + vars, + depositInfo + ); + } + + /// @inheritdoc IApeCoinPool + function compoundApeCoinPairPool( + bool isBAYC, + uint32[] calldata apeTokenIds, + uint32[] calldata bakcTokenIds + ) external onlyApeStakingBot { + ApeStakingVaultCacheVars memory vars = _createCacheVars(); + vars.compoundFee = compoundFee; + uint256 poolId = isBAYC + ? ApeStakingCommonLogic.BAYC_BAKC_APECOIN_POOL_ID + : ApeStakingCommonLogic.MAYC_BAKC_APECOIN_POOL_ID; + ApeCoinPoolLogic.compoundApeCoinPairPool( + poolStates[poolId], + cApeShareBalance, + vars, + isBAYC, + apeTokenIds, + bakcTokenIds + ); + } + + /// @inheritdoc IApeCoinPool + function withdrawApeCoinPairPool( + ApeCoinPairWithdrawInfo calldata withdrawInfo + ) external whenNotPaused nonReentrant { + ApeStakingVaultCacheVars memory vars = _createCacheVars(); + vars.compoundFee = compoundFee; + vars.sApeReserveId = sApeReserveId; + uint256 poolId = withdrawInfo.isBAYC + ? ApeStakingCommonLogic.BAYC_BAKC_APECOIN_POOL_ID + : ApeStakingCommonLogic.MAYC_BAKC_APECOIN_POOL_ID; + ApeCoinPoolLogic.withdrawApeCoinPairPool( + poolStates[poolId], + apeMatchedCount, + sApeBalance, + cApeShareBalance, + vars, + withdrawInfo, + poolId + ); + } + + /// @inheritdoc IApeCoinPool + function nBakcOwnerChangeCallback(uint32[] calldata tokenIds) + external + whenNotPaused + nonReentrant + { + require(msg.sender == nBakc, Errors.CALLER_NOT_ALLOWED); + ApeStakingVaultCacheVars memory vars = _createCacheVars(); + uint256 poolId = ApeStakingCommonLogic.BAKC_SINGLE_POOL_ID; + ApeStakingSinglePoolLogic.tryClaimNFT( + poolStates[poolId], + vars, + poolId, + bakc, + tokenIds + ); + } + + /// @inheritdoc IApeCoinPool + function nApeOwnerChangeCallback(bool isBAYC, uint32[] calldata tokenIds) + external + whenNotPaused + nonReentrant + { + require( + msg.sender == nBayc || msg.sender == nMayc, + Errors.CALLER_NOT_ALLOWED + ); + ApeStakingVaultCacheVars memory vars = _createCacheVars(); + vars.compoundFee = compoundFee; + + uint32[] memory apeCoinPoolTokenIds = new uint32[](tokenIds.length); + uint256 apeCoinPoolCount = 0; + //handle nft pool in the scope to avoid stack too deep + { + uint32[] memory pairPoolTokenIds = new uint32[](tokenIds.length); + uint32[] memory singlePoolTokenIds = new uint32[](tokenIds.length); + uint256 pairPoolCount = 0; + uint256 singlePoolCount = 0; + + for (uint256 index = 0; index < tokenIds.length; index++) { + uint32 tokenId = tokenIds[index]; + + //check if ape in pair pool + uint256 poolId = isBAYC + ? ApeStakingCommonLogic.BAYC_BAKC_PAIR_POOL_ID + : ApeStakingCommonLogic.MAYC_BAKC_PAIR_POOL_ID; + TokenStatus memory tokenStatus = poolStates[poolId].tokenStatus[ + tokenId + ]; + if (tokenStatus.isInPool) { + pairPoolTokenIds[pairPoolCount] = tokenId; + pairPoolCount++; + continue; + } + + //check if ape in single pool + poolId = isBAYC + ? ApeStakingCommonLogic.BAYC_SINGLE_POOL_ID + : ApeStakingCommonLogic.MAYC_SINGLE_POOL_ID; + if (poolStates[poolId].tokenStatus[tokenId].isInPool) { + singlePoolTokenIds[singlePoolCount] = tokenId; + singlePoolCount++; + continue; + } + + //must be in ape coin pool + apeCoinPoolTokenIds[apeCoinPoolCount] = tokenId; + apeCoinPoolCount++; + } + + if (pairPoolCount > 0) { + assembly { + mstore(pairPoolTokenIds, pairPoolCount) + } + uint256 poolId = isBAYC + ? ApeStakingCommonLogic.BAYC_BAKC_PAIR_POOL_ID + : ApeStakingCommonLogic.MAYC_BAKC_PAIR_POOL_ID; + ApeCoinPoolLogic.claimPendingReward( + poolStates[poolId], + vars, + poolId, + pairPoolTokenIds + ); + } + + if (singlePoolCount > 0) { + assembly { + mstore(singlePoolTokenIds, singlePoolCount) + } + uint256 poolId = isBAYC + ? ApeStakingCommonLogic.BAYC_SINGLE_POOL_ID + : ApeStakingCommonLogic.MAYC_SINGLE_POOL_ID; + ApeCoinPoolLogic.claimPendingReward( + poolStates[poolId], + vars, + poolId, + singlePoolTokenIds + ); + } + } + + if (apeCoinPoolCount > 0) { + assembly { + mstore(apeCoinPoolTokenIds, apeCoinPoolCount) + } + + ApeCoinPoolLogic.tryUnstakeApeCoinPoolPosition( + poolStates, + apeMatchedCount, + sApeBalance, + cApeShareBalance, + vars, + isBAYC, + apeCoinPoolTokenIds + ); + } + } + + /* + * P2P Pair Staking Logic + */ + + /// @inheritdoc IApeStakingP2P + function cancelListing(ListingOrder calldata listingOrder) + external + override + nonReentrant + { + bytes32 orderHash = ApeStakingP2PLogic.cancelListing( + listingOrder, + listingOrderStatus + ); + + emit OrderCancelled(orderHash, listingOrder.offerer); + } + + /// @inheritdoc IApeStakingP2P + function matchPairStakingList( + ListingOrder calldata apeOrder, + ListingOrder calldata apeCoinOrder + ) external override nonReentrant whenNotPaused returns (bytes32 orderHash) { + ApeStakingVaultCacheVars memory vars = _createCacheVars(); + vars.DOMAIN_SEPARATOR = DOMAIN_SEPARATOR; + orderHash = ApeStakingP2PLogic.matchPairStakingList( + apeOrder, + apeCoinOrder, + listingOrderStatus, + matchedOrders, + apeMatchedCount, + sApeBalance, + vars + ); + + emit PairStakingMatched(orderHash); + + return orderHash; + } + + /// @inheritdoc IApeStakingP2P + function matchBAKCPairStakingList( + ListingOrder calldata apeOrder, + ListingOrder calldata bakcOrder, + ListingOrder calldata apeCoinOrder + ) external override nonReentrant whenNotPaused returns (bytes32 orderHash) { + ApeStakingVaultCacheVars memory vars = _createCacheVars(); + vars.DOMAIN_SEPARATOR = DOMAIN_SEPARATOR; + orderHash = ApeStakingP2PLogic.matchBAKCPairStakingList( + apeOrder, + bakcOrder, + apeCoinOrder, + listingOrderStatus, + matchedOrders, + apeMatchedCount, + sApeBalance, + vars + ); + + emit PairStakingMatched(orderHash); + + return orderHash; + } + + /// @inheritdoc IApeStakingP2P + function breakUpMatchedOrder(bytes32 orderHash) + external + override + nonReentrant + whenNotPaused + { + ApeStakingVaultCacheVars memory vars = _createCacheVars(); + vars.compoundFee = compoundFee; + vars.sApeReserveId = sApeReserveId; + ApeStakingP2PLogic.breakUpMatchedOrder( + listingOrderStatus, + matchedOrders, + cApeShareBalance, + apeMatchedCount, + sApeBalance, + vars, + orderHash + ); + + //7 emit event + emit PairStakingBreakUp(orderHash); + } + + /// @inheritdoc IApeStakingP2P + function claimForMatchedOrderAndCompound(bytes32[] calldata orderHashes) + external + override + nonReentrant + whenNotPaused + { + ApeStakingVaultCacheVars memory vars = _createCacheVars(); + vars.compoundFee = compoundFee; + ApeStakingP2PLogic.claimForMatchedOrdersAndCompound( + matchedOrders, + cApeShareBalance, + vars, + orderHashes + ); + } + + /// @inheritdoc IApeStakingP2P + function claimCApeReward(address receiver) + external + override + nonReentrant + whenNotPaused + { + uint256 cApeAmount = pendingCApeReward(msg.sender); + if (cApeAmount > 0) { + IERC20(cApe).safeTransfer(receiver, cApeAmount); + delete cApeShareBalance[msg.sender]; + emit CApeClaimed(msg.sender, receiver, cApeAmount); + } + } + + /// @inheritdoc IApeStakingP2P + function pendingCApeReward(address user) + public + view + override + returns (uint256) + { + uint256 amount = 0; + uint256 shareBalance = cApeShareBalance[user]; + if (shareBalance > 0) { + amount = ICApe(cApe).getPooledApeByShares(shareBalance); + } + return amount; + } + + /// @inheritdoc IApeStakingP2P + function getApeCoinStakingCap(StakingType stakingType) + public + view + override + returns (uint256) + { + ApeStakingVaultCacheVars memory vars = _createCacheVars(); + return ApeStakingP2PLogic.getApeCoinStakingCap(stakingType, vars); + } + + /* + * Ape Staking Vault Logic + */ + + function setSinglePoolApeRewardRatio(uint32 apeRewardRatio) + external + onlyPoolAdmin + { + require( + apeRewardRatio < PercentageMath.PERCENTAGE_FACTOR, + Errors.INVALID_PARAMETER + ); + uint32 oldValue = apePairStakingRewardRatio; + if (oldValue != apeRewardRatio) { + apePairStakingRewardRatio = apeRewardRatio; + emit ApePairStakingRewardRatioUpdated(oldValue, apeRewardRatio); + } + } + + /// @inheritdoc IApeStakingVault + function depositPairNFT( + bool isBAYC, + uint32[] calldata apeTokenIds, + uint32[] calldata bakcTokenIds + ) external override whenNotPaused nonReentrant { + ApeStakingVaultCacheVars memory vars = _createCacheVars(); + uint256 poolId = isBAYC + ? ApeStakingCommonLogic.BAYC_BAKC_PAIR_POOL_ID + : ApeStakingCommonLogic.MAYC_BAKC_PAIR_POOL_ID; + ApeStakingPairPoolLogic.depositPairNFT( + poolStates[poolId], + vars, + isBAYC, + apeTokenIds, + bakcTokenIds + ); + } + + /// @inheritdoc IApeStakingVault + function stakingPairNFT( + bool isBAYC, + uint32[] calldata apeTokenIds, + uint32[] calldata bakcTokenIds + ) external override whenNotPaused nonReentrant { + ApeStakingVaultCacheVars memory vars = _createCacheVars(); + uint256 poolId = isBAYC + ? ApeStakingCommonLogic.BAYC_BAKC_PAIR_POOL_ID + : ApeStakingCommonLogic.MAYC_BAKC_PAIR_POOL_ID; + ApeStakingPairPoolLogic.stakingPairNFT( + poolStates[poolId], + vars, + isBAYC, + apeTokenIds, + bakcTokenIds + ); + } + + /// @inheritdoc IApeStakingVault + function compoundPairNFT( + bool isBAYC, + uint32[] calldata apeTokenIds, + uint32[] calldata bakcTokenIds + ) external override onlyApeStakingBot { + ApeStakingVaultCacheVars memory vars = _createCacheVars(); + vars.compoundFee = compoundFee; + uint256 poolId = isBAYC + ? ApeStakingCommonLogic.BAYC_BAKC_PAIR_POOL_ID + : ApeStakingCommonLogic.MAYC_BAKC_PAIR_POOL_ID; + ApeStakingPairPoolLogic.compoundPairNFT( + poolStates[poolId], + cApeShareBalance, + vars, + isBAYC, + apeTokenIds, + bakcTokenIds + ); + } + + /// @inheritdoc IApeStakingVault + function withdrawPairNFT( + bool isBAYC, + uint32[] calldata apeTokenIds, + uint32[] calldata bakcTokenIds + ) external override whenNotPaused nonReentrant { + ApeStakingVaultCacheVars memory vars = _createCacheVars(); + vars.compoundFee = compoundFee; + uint256 poolId = isBAYC + ? ApeStakingCommonLogic.BAYC_BAKC_PAIR_POOL_ID + : ApeStakingCommonLogic.MAYC_BAKC_PAIR_POOL_ID; + ApeStakingPairPoolLogic.withdrawPairNFT( + poolStates[poolId], + cApeShareBalance, + vars, + isBAYC, + apeTokenIds, + bakcTokenIds + ); + } + + /// @inheritdoc IApeStakingVault + function depositNFT(address nft, uint32[] calldata tokenIds) + external + override + whenNotPaused + nonReentrant + { + require( + nft == bayc || nft == mayc || nft == bakc, + Errors.NFT_NOT_ALLOWED + ); + ApeStakingVaultCacheVars memory vars = _createCacheVars(); + uint256 poolId = (nft == bayc) + ? ApeStakingCommonLogic.BAYC_SINGLE_POOL_ID + : (nft == mayc) + ? ApeStakingCommonLogic.MAYC_SINGLE_POOL_ID + : ApeStakingCommonLogic.BAKC_SINGLE_POOL_ID; + ApeStakingSinglePoolLogic.depositNFT( + poolStates[poolId], + vars, + nft, + tokenIds + ); + } + + /// @inheritdoc IApeStakingVault + function stakingApe(bool isBAYC, uint32[] calldata tokenIds) + external + override + whenNotPaused + nonReentrant + { + ApeStakingVaultCacheVars memory vars = _createCacheVars(); + uint256 poolId = isBAYC + ? ApeStakingCommonLogic.BAYC_SINGLE_POOL_ID + : ApeStakingCommonLogic.MAYC_SINGLE_POOL_ID; + ApeStakingSinglePoolLogic.stakingApe( + poolStates[poolId], + vars, + isBAYC, + tokenIds + ); + } + + /// @inheritdoc IApeStakingVault + function stakingBAKC(BAKCPairActionInfo calldata actionInfo) + external + override + whenNotPaused + nonReentrant + { + ApeStakingVaultCacheVars memory vars = _createCacheVars(); + ApeStakingSinglePoolLogic.stakingBAKC(poolStates, vars, actionInfo); + } + + /// @inheritdoc IApeStakingVault + function compoundApe(bool isBAYC, uint32[] calldata tokenIds) + external + override + onlyApeStakingBot + { + ApeStakingVaultCacheVars memory vars = _createCacheVars(); + vars.compoundFee = compoundFee; + uint256 poolId = isBAYC + ? ApeStakingCommonLogic.BAYC_SINGLE_POOL_ID + : ApeStakingCommonLogic.MAYC_SINGLE_POOL_ID; + ApeStakingSinglePoolLogic.compoundApe( + poolStates[poolId], + cApeShareBalance, + vars, + isBAYC, + tokenIds + ); + } + + /// @inheritdoc IApeStakingVault + function compoundBAKC(BAKCPairActionInfo calldata actionInfo) + external + override + onlyApeStakingBot + { + ApeStakingVaultCacheVars memory vars = _createCacheVars(); + vars.compoundFee = compoundFee; + vars.apeRewardRatio = apePairStakingRewardRatio; + ApeStakingSinglePoolLogic.compoundBAKC( + poolStates, + cApeShareBalance, + vars, + actionInfo + ); + } + + /// @inheritdoc IApeStakingVault + function withdrawNFT(address nft, uint32[] calldata tokenIds) + external + override + whenNotPaused + nonReentrant + { + require( + nft == bayc || nft == mayc || nft == bakc, + Errors.NFT_NOT_ALLOWED + ); + ApeStakingVaultCacheVars memory vars = _createCacheVars(); + vars.compoundFee = compoundFee; + vars.apeRewardRatio = apePairStakingRewardRatio; + ApeStakingSinglePoolLogic.withdrawNFT( + poolStates, + cApeShareBalance, + vars, + nft, + tokenIds + ); + } + + function _createCacheVars() + internal + view + returns (ApeStakingVaultCacheVars memory) + { + ApeStakingVaultCacheVars memory vars; + vars.pool = pool; + vars.bayc = bayc; + vars.mayc = mayc; + vars.bakc = bakc; + vars.nBayc = nBayc; + vars.nMayc = nMayc; + vars.nBakc = nBakc; + vars.apeCoin = apeCoin; + vars.cApe = cApe; + vars.apeCoinStaking = apeCoinStaking; + vars.baycMatchedCap = baycMatchedCap; + vars.maycMatchedCap = maycMatchedCap; + vars.bakcMatchedCap = bakcMatchedCap; + return vars; + } + + function onERC721Received( + address, + address, + uint256, + bytes memory + ) external pure returns (bytes4) { + return this.onERC721Received.selector; + } +} diff --git a/contracts/apestaking/base/CApe.sol b/contracts/apestaking/base/CApe.sol index e94139b07..a3c9911d0 100644 --- a/contracts/apestaking/base/CApe.sol +++ b/contracts/apestaking/base/CApe.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "../../dependencies/openzeppelin/upgradeability/ContextUpgradeable.sol"; import "../../dependencies/openzeppelin/upgradeability/PausableUpgradeable.sol"; diff --git a/contracts/apestaking/logic/ApeCoinPoolLogic.sol b/contracts/apestaking/logic/ApeCoinPoolLogic.sol new file mode 100644 index 000000000..51a086535 --- /dev/null +++ b/contracts/apestaking/logic/ApeCoinPoolLogic.sol @@ -0,0 +1,929 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.0; + +import {IPool} from "../../interfaces/IPool.sol"; +import "../../interfaces/IParaApeStaking.sol"; +import "../../interfaces/IApeCoinPool.sol"; +import "../../interfaces/ITimeLock.sol"; +import {IERC20, SafeERC20} from "../../dependencies/openzeppelin/contracts/SafeERC20.sol"; +import "../../dependencies/yoga-labs/ApeCoinStaking.sol"; +import {PercentageMath} from "../../protocol/libraries/math/PercentageMath.sol"; +import "../../interfaces/IAutoCompoundApe.sol"; +import "../../interfaces/ICApe.sol"; +import "../../dependencies/openzeppelin/contracts/SafeCast.sol"; +import {WadRayMath} from "../../protocol/libraries/math/WadRayMath.sol"; +import "./ApeStakingCommonLogic.sol"; +import "../../protocol/libraries/helpers/Errors.sol"; +import {UserConfiguration} from "../../protocol/libraries/configuration/UserConfiguration.sol"; +import {DataTypes} from "../../protocol/libraries/types/DataTypes.sol"; + +/** + * @title ApeCoinPoolLogic library + * + * @notice Implements the base logic for para ape staking apecoin pool + */ +library ApeCoinPoolLogic { + using UserConfiguration for DataTypes.UserConfigurationMap; + using PercentageMath for uint256; + using SafeCast for uint256; + using SafeERC20 for IERC20; + using WadRayMath for uint256; + + event ApeCoinPoolDeposited(bool isBAYC, uint256 tokenId); + event ApeCoinPoolCompounded(bool isBAYC, uint256 tokenId); + event ApeCoinPoolWithdrew(bool isBAYC, uint256 tokenId); + event ApeCoinPairPoolDeposited( + bool isBAYC, + uint256 apeTokenId, + uint256 bakcTokenId + ); + event ApeCoinPairPoolCompounded( + bool isBAYC, + uint256 apeTokenId, + uint256 bakcTokenId + ); + event ApeCoinPairPoolWithdrew( + bool isBAYC, + uint256 apeTokenId, + uint256 bakcTokenId + ); + + function getPendingReward( + IParaApeStaking.PoolState storage poolState, + address cApe, + uint32[] memory tokenIds + ) external view returns (uint256) { + uint256 rewardShares; + uint256 arrayLength = tokenIds.length; + uint256 accumulatedRewardsPerNft = poolState.accumulatedRewardsPerNft; + for (uint256 index = 0; index < arrayLength; index++) { + uint32 tokenId = tokenIds[index]; + + IParaApeStaking.TokenStatus memory tokenStatus = poolState + .tokenStatus[tokenId]; + require(tokenStatus.isInPool, Errors.NFT_NOT_IN_POOL); + + rewardShares += (accumulatedRewardsPerNft - + tokenStatus.rewardsDebt); + } + return ICApe(cApe).getPooledApeByShares(rewardShares); + } + + function claimPendingReward( + IParaApeStaking.PoolState storage poolState, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + uint256 poolId, + uint32[] calldata tokenIds + ) external returns (address) { + ApeStakingCommonLogic.validateTokenIdArray(tokenIds); + (, address nToken) = ApeStakingCommonLogic.getNftFromPoolId( + vars, + poolId + ); + return + ApeStakingCommonLogic.claimPendingReward( + poolState, + vars, + poolId, + nToken, + true, + tokenIds + ); + } + + function depositFreeSApe( + mapping(address => IParaApeStaking.SApeBalance) storage sApeBalance, + address apeCoin, + address cApe, + address user, + address cashAsset, + uint128 amount + ) external { + require( + cashAsset == cApe || cashAsset == apeCoin, + Errors.INVALID_TOKEN + ); + + IERC20(cashAsset).safeTransferFrom(user, address(this), amount); + + if (cashAsset == apeCoin) { + IAutoCompoundApe(cApe).deposit(address(this), amount); + } + + //update sApe balance + IParaApeStaking.SApeBalance memory sApeBalanceCache = sApeBalance[user]; + uint256 shareAmount = ICApe(cApe).getShareByPooledApe(amount); + sApeBalanceCache.freeShareBalance += shareAmount.toUint128(); + sApeBalance[user] = sApeBalanceCache; + } + + function withdrawFreeSApe( + mapping(address => IParaApeStaking.SApeBalance) storage sApeBalance, + address pool, + address apeCoin, + address cApe, + uint16 sApeReserveId, + address user, + address receiveAsset, + uint128 amount + ) external { + require( + receiveAsset == cApe || receiveAsset == apeCoin, + Errors.INVALID_TOKEN + ); + + IParaApeStaking.SApeBalance memory sApeBalanceCache = sApeBalance[user]; + uint256 shareAmount = ICApe(cApe).getShareByPooledApe(amount); + require( + sApeBalanceCache.freeShareBalance >= shareAmount, + Errors.SAPE_FREE_BALANCE_NOT_ENOUGH + ); + sApeBalanceCache.freeShareBalance -= shareAmount.toUint128(); + sApeBalance[user] = sApeBalanceCache; + + _validateDropSApeBalance(pool, sApeReserveId, user); + if (receiveAsset == apeCoin) { + IAutoCompoundApe(cApe).withdraw(amount); + } + _sendUserFunds(pool, receiveAsset, amount, user); + } + + function depositApeCoinPool( + IParaApeStaking.PoolState storage poolState, + mapping(address => mapping(uint32 => uint256)) storage apeMatchedCount, + mapping(address => IParaApeStaking.SApeBalance) storage sApeBalance, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + IParaApeStaking.ApeCoinDepositInfo calldata depositInfo + ) external { + uint256 arrayLength = depositInfo.tokenIds.length; + require(arrayLength > 0, Errors.INVALID_PARAMETER); + + if (depositInfo.isBAYC) { + vars.apeToken = vars.bayc; + vars.nApe = vars.nBayc; + vars.positionCap = vars.baycMatchedCap; + } else { + vars.apeToken = vars.mayc; + vars.nApe = vars.nMayc; + vars.positionCap = vars.maycMatchedCap; + } + uint128 accumulatedRewardsPerNft = poolState.accumulatedRewardsPerNft; + ApeCoinStaking.SingleNft[] + memory _nfts = new ApeCoinStaking.SingleNft[](arrayLength); + for (uint256 index = 0; index < arrayLength; index++) { + uint32 tokenId = depositInfo.tokenIds[index]; + + require( + depositInfo.onBehalf == IERC721(vars.nApe).ownerOf(tokenId), + Errors.NOT_THE_OWNER + ); + + ApeStakingCommonLogic.handleApeTransferIn( + apeMatchedCount, + vars.apeToken, + vars.nApe, + tokenId + ); + + //update status + poolState + .tokenStatus[tokenId] + .rewardsDebt = accumulatedRewardsPerNft; + poolState.tokenStatus[tokenId].isInPool = true; + + // construct staking data + _nfts[index] = ApeCoinStaking.SingleNft({ + tokenId: tokenId, + amount: vars.positionCap.toUint224() + }); + + //emit event + emit ApeCoinPoolDeposited(depositInfo.isBAYC, tokenId); + } + + //transfer ape coin + uint256 totalApeCoinNeeded = vars.positionCap * arrayLength; + _prepareApeCoin( + sApeBalance, + vars, + totalApeCoinNeeded.toUint128(), + depositInfo.cashToken, + depositInfo.cashAmount, + depositInfo.onBehalf + ); + + //stake in ApeCoinStaking + if (depositInfo.isBAYC) { + vars.apeCoinStaking.depositBAYC(_nfts); + } else { + vars.apeCoinStaking.depositMAYC(_nfts); + } + + poolState.totalPosition += arrayLength.toUint24(); + } + + function compoundApeCoinPool( + IParaApeStaking.PoolState storage poolState, + mapping(address => uint256) storage cApeShareBalance, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + bool isBAYC, + uint32[] calldata tokenIds + ) external { + uint256 arrayLength = tokenIds.length; + require(arrayLength > 0, Errors.INVALID_PARAMETER); + + uint256[] memory _nfts = new uint256[](arrayLength); + for (uint256 index = 0; index < arrayLength; index++) { + uint32 tokenId = tokenIds[index]; + + require( + poolState.tokenStatus[tokenId].isInPool, + Errors.NFT_NOT_IN_POOL + ); + + // construct staking data + _nfts[index] = tokenId; + + emit ApeCoinPoolCompounded(isBAYC, tokenId); + } + + vars.balanceBefore = IERC20(vars.apeCoin).balanceOf(address(this)); + //claim from ApeCoinStaking + if (isBAYC) { + vars.apeCoinStaking.claimSelfBAYC(_nfts); + } else { + vars.apeCoinStaking.claimSelfMAYC(_nfts); + } + vars.balanceAfter = IERC20(vars.apeCoin).balanceOf(address(this)); + vars.totalClaimedApe = vars.balanceAfter - vars.balanceBefore; + _distributePoolReward( + poolState, + cApeShareBalance, + vars, + vars.totalClaimedApe, + poolState.totalPosition + ); + } + + function withdrawApeCoinPool( + IParaApeStaking.PoolState storage poolState, + mapping(address => mapping(uint32 => uint256)) storage apeMatchedCount, + mapping(address => IParaApeStaking.SApeBalance) storage sApeBalance, + mapping(address => uint256) storage cApeShareBalance, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + IParaApeStaking.ApeCoinWithdrawInfo memory withdrawInfo, + uint256 poolId + ) public { + uint256 arrayLength = withdrawInfo.tokenIds.length; + require(arrayLength > 0, Errors.INVALID_PARAMETER); + + if (withdrawInfo.isBAYC) { + vars.apeToken = vars.bayc; + vars.nApe = vars.nBayc; + vars.positionCap = vars.baycMatchedCap; + } else { + vars.apeToken = vars.mayc; + vars.nApe = vars.nMayc; + vars.positionCap = vars.maycMatchedCap; + } + + address nApeOwner = ApeStakingCommonLogic.claimPendingReward( + poolState, + vars, + poolId, + vars.nApe, + false, + withdrawInfo.tokenIds + ); + + address msgSender = msg.sender; + require( + msgSender == nApeOwner || msgSender == vars.nApe, + Errors.NOT_THE_OWNER + ); + ApeCoinStaking.SingleNft[] + memory _nfts = new ApeCoinStaking.SingleNft[](arrayLength); + for (uint256 index = 0; index < arrayLength; index++) { + uint32 tokenId = withdrawInfo.tokenIds[index]; + + // we don't need check pair is in pool here again + + delete poolState.tokenStatus[tokenId]; + + // construct staking data + _nfts[index] = ApeCoinStaking.SingleNft({ + tokenId: tokenId, + amount: vars.positionCap.toUint224() + }); + } + + //withdraw from ApeCoinStaking + vars.balanceBefore = IERC20(vars.apeCoin).balanceOf(address(this)); + if (withdrawInfo.isBAYC) { + vars.apeCoinStaking.withdrawSelfBAYC(_nfts); + } else { + vars.apeCoinStaking.withdrawSelfMAYC(_nfts); + } + vars.balanceAfter = IERC20(vars.apeCoin).balanceOf(address(this)); + vars.totalClaimedApe = vars.balanceAfter - vars.balanceBefore; + + uint128 totalApeCoinAmount = (vars.positionCap * arrayLength) + .toUint128(); + _handleApeCoin( + sApeBalance, + vars, + totalApeCoinAmount, + withdrawInfo.cashToken, + withdrawInfo.cashAmount, + nApeOwner + ); + + //distribute reward + uint24 totalPosition = poolState.totalPosition; + totalPosition -= arrayLength.toUint24(); + if (vars.totalClaimedApe > totalApeCoinAmount) { + _distributePoolReward( + poolState, + cApeShareBalance, + vars, + vars.totalClaimedApe - totalApeCoinAmount, + totalPosition + ); + } + poolState.totalPosition = totalPosition; + + //transfer ape and BAKC back to nToken + for (uint256 index = 0; index < arrayLength; index++) { + uint32 tokenId = withdrawInfo.tokenIds[index]; + + ApeStakingCommonLogic.handleApeTransferOut( + apeMatchedCount, + vars.apeToken, + vars.nApe, + tokenId + ); + + //emit event + emit ApeCoinPoolWithdrew(withdrawInfo.isBAYC, tokenId); + } + } + + function depositApeCoinPairPool( + IParaApeStaking.PoolState storage poolState, + mapping(address => mapping(uint32 => uint256)) storage apeMatchedCount, + mapping(address => IParaApeStaking.SApeBalance) storage sApeBalance, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + IParaApeStaking.ApeCoinPairDepositInfo calldata depositInfo + ) external { + uint256 arrayLength = depositInfo.apeTokenIds.length; + require( + arrayLength == depositInfo.bakcTokenIds.length && arrayLength > 0, + Errors.INVALID_PARAMETER + ); + + if (depositInfo.isBAYC) { + vars.apeToken = vars.bayc; + vars.nApe = vars.nBayc; + } else { + vars.apeToken = vars.mayc; + vars.nApe = vars.nMayc; + } + vars.accumulatedRewardsPerNft = poolState.accumulatedRewardsPerNft; + ApeCoinStaking.PairNftDepositWithAmount[] + memory _nftPairs = new ApeCoinStaking.PairNftDepositWithAmount[]( + arrayLength + ); + for (uint256 index = 0; index < arrayLength; index++) { + uint32 apeTokenId = depositInfo.apeTokenIds[index]; + uint32 bakcTokenId = depositInfo.bakcTokenIds[index]; + + //check ntoken owner + { + address nApeOwner = IERC721(vars.nApe).ownerOf(apeTokenId); + address nBakcOwner = IERC721(vars.nBakc).ownerOf(bakcTokenId); + require( + depositInfo.onBehalf == nApeOwner && + depositInfo.onBehalf == nBakcOwner, + Errors.NOT_THE_OWNER + ); + } + + ApeStakingCommonLogic.handleApeTransferIn( + apeMatchedCount, + vars.apeToken, + vars.nApe, + apeTokenId + ); + IERC721(vars.bakc).safeTransferFrom( + vars.nBakc, + address(this), + bakcTokenId + ); + + //update status + poolState.tokenStatus[apeTokenId].rewardsDebt = vars + .accumulatedRewardsPerNft; + poolState.tokenStatus[apeTokenId].isInPool = true; + poolState.tokenStatus[apeTokenId].bakcTokenId = bakcTokenId; + + // construct staking data + _nftPairs[index] = ApeCoinStaking.PairNftDepositWithAmount({ + mainTokenId: apeTokenId, + bakcTokenId: bakcTokenId, + amount: vars.bakcMatchedCap.toUint184() + }); + + //emit event + emit ApeCoinPairPoolDeposited( + depositInfo.isBAYC, + apeTokenId, + bakcTokenId + ); + } + + //transfer ape coin + uint256 totalApeCoinNeeded = vars.bakcMatchedCap * arrayLength; + _prepareApeCoin( + sApeBalance, + vars, + totalApeCoinNeeded.toUint128(), + depositInfo.cashToken, + depositInfo.cashAmount, + depositInfo.onBehalf + ); + + //stake in ApeCoinStaking + ApeCoinStaking.PairNftDepositWithAmount[] + memory _otherPairs = new ApeCoinStaking.PairNftDepositWithAmount[]( + 0 + ); + if (depositInfo.isBAYC) { + vars.apeCoinStaking.depositBAKC(_nftPairs, _otherPairs); + } else { + vars.apeCoinStaking.depositBAKC(_otherPairs, _nftPairs); + } + + poolState.totalPosition += arrayLength.toUint24(); + } + + function compoundApeCoinPairPool( + IParaApeStaking.PoolState storage poolState, + mapping(address => uint256) storage cApeShareBalance, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + bool isBAYC, + uint32[] calldata apeTokenIds, + uint32[] calldata bakcTokenIds + ) external { + uint256 arrayLength = apeTokenIds.length; + require( + arrayLength == bakcTokenIds.length && arrayLength > 0, + Errors.INVALID_PARAMETER + ); + + ApeCoinStaking.PairNft[] + memory _nftPairs = new ApeCoinStaking.PairNft[](arrayLength); + for (uint256 index = 0; index < arrayLength; index++) { + uint32 apeTokenId = apeTokenIds[index]; + uint32 bakcTokenId = bakcTokenIds[index]; + + require( + poolState.tokenStatus[apeTokenId].isInPool, + Errors.NFT_NOT_IN_POOL + ); + + // construct staking data + _nftPairs[index] = ApeCoinStaking.PairNft({ + mainTokenId: apeTokenId, + bakcTokenId: bakcTokenId + }); + } + + vars.balanceBefore = IERC20(vars.apeCoin).balanceOf(address(this)); + //claim from ApeCoinStaking + { + ApeCoinStaking.PairNft[] + memory _otherPairs = new ApeCoinStaking.PairNft[](0); + if (isBAYC) { + vars.apeCoinStaking.claimSelfBAKC(_nftPairs, _otherPairs); + } else { + vars.apeCoinStaking.claimSelfBAKC(_otherPairs, _nftPairs); + } + } + vars.balanceAfter = IERC20(vars.apeCoin).balanceOf(address(this)); + vars.totalClaimedApe = vars.balanceAfter - vars.balanceBefore; + _distributePoolReward( + poolState, + cApeShareBalance, + vars, + vars.totalClaimedApe, + poolState.totalPosition + ); + } + + function withdrawApeCoinPairPool( + IParaApeStaking.PoolState storage poolState, + mapping(address => mapping(uint32 => uint256)) storage apeMatchedCount, + mapping(address => IParaApeStaking.SApeBalance) storage sApeBalance, + mapping(address => uint256) storage cApeShareBalance, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + IParaApeStaking.ApeCoinPairWithdrawInfo memory withdrawInfo, + uint256 poolId + ) public { + uint256 arrayLength = withdrawInfo.apeTokenIds.length; + require( + arrayLength == withdrawInfo.bakcTokenIds.length && arrayLength > 0, + Errors.INVALID_PARAMETER + ); + + if (withdrawInfo.isBAYC) { + vars.apeToken = vars.bayc; + vars.nApe = vars.nBayc; + } else { + vars.apeToken = vars.mayc; + vars.nApe = vars.nMayc; + } + + address nApeOwner = ApeStakingCommonLogic.claimPendingReward( + poolState, + vars, + poolId, + vars.nApe, + false, + withdrawInfo.apeTokenIds + ); + + ApeCoinStaking.PairNftWithdrawWithAmount[] + memory _nftPairs = new ApeCoinStaking.PairNftWithdrawWithAmount[]( + arrayLength + ); + bool isBAKCOwnerWithdraw = false; + for (uint256 index = 0; index < arrayLength; index++) { + uint32 apeTokenId = withdrawInfo.apeTokenIds[index]; + uint32 bakcTokenId = withdrawInfo.bakcTokenIds[index]; + + //check ntoken owner + { + if (nApeOwner != msg.sender && vars.nApe != msg.sender) { + address nBakcOwner = IERC721(vars.nBakc).ownerOf( + bakcTokenId + ); + require(msg.sender == nBakcOwner, Errors.NOT_THE_OWNER); + isBAKCOwnerWithdraw = true; + } + } + + // we don't need check pair is in pool here again + + delete poolState.tokenStatus[apeTokenId]; + + // construct staking data + _nftPairs[index] = ApeCoinStaking.PairNftWithdrawWithAmount({ + mainTokenId: apeTokenId, + bakcTokenId: bakcTokenId, + amount: vars.bakcMatchedCap.toUint184(), + isUncommit: true + }); + } + + //withdraw from ApeCoinStaking + { + vars.balanceBefore = IERC20(vars.apeCoin).balanceOf(address(this)); + ApeCoinStaking.PairNftWithdrawWithAmount[] + memory _otherPairs = new ApeCoinStaking.PairNftWithdrawWithAmount[]( + 0 + ); + if (withdrawInfo.isBAYC) { + vars.apeCoinStaking.withdrawBAKC(_nftPairs, _otherPairs); + } else { + vars.apeCoinStaking.withdrawBAKC(_otherPairs, _nftPairs); + } + vars.balanceAfter = IERC20(vars.apeCoin).balanceOf(address(this)); + vars.totalClaimedApe = vars.balanceAfter - vars.balanceBefore; + } + + uint128 totalApeCoinAmount = (vars.bakcMatchedCap * arrayLength) + .toUint128(); + _handleApeCoin( + sApeBalance, + vars, + totalApeCoinAmount, + withdrawInfo.cashToken, + isBAKCOwnerWithdraw ? 0 : withdrawInfo.cashAmount, + nApeOwner + ); + + //distribute reward + uint24 totalPosition = poolState.totalPosition; + totalPosition -= arrayLength.toUint24(); + if (vars.totalClaimedApe > totalApeCoinAmount) { + _distributePoolReward( + poolState, + cApeShareBalance, + vars, + vars.totalClaimedApe - totalApeCoinAmount, + totalPosition + ); + } + poolState.totalPosition = totalPosition; + + //transfer ape and BAKC back to nToken + for (uint256 index = 0; index < arrayLength; index++) { + uint32 apeTokenId = withdrawInfo.apeTokenIds[index]; + uint32 bakcTokenId = withdrawInfo.bakcTokenIds[index]; + + ApeStakingCommonLogic.handleApeTransferOut( + apeMatchedCount, + vars.apeToken, + vars.nApe, + apeTokenId + ); + IERC721(vars.bakc).safeTransferFrom( + address(this), + vars.nBakc, + bakcTokenId + ); + + //emit event + emit ApeCoinPairPoolWithdrew( + withdrawInfo.isBAYC, + apeTokenId, + bakcTokenId + ); + } + } + + function tryUnstakeApeCoinPoolPosition( + mapping(uint256 => IParaApeStaking.PoolState) storage poolStates, + mapping(address => mapping(uint32 => uint256)) storage apeMatchedCount, + mapping(address => IParaApeStaking.SApeBalance) storage sApeBalance, + mapping(address => uint256) storage cApeShareBalance, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + bool isBAYC, + uint32[] calldata tokenIds + ) external { + require(tokenIds.length > 0, Errors.INVALID_PARAMETER); + + // check single + { + uint256 singlePoolId = isBAYC + ? ApeStakingCommonLogic.BAYC_APECOIN_POOL_ID + : ApeStakingCommonLogic.MAYC_APECOIN_POOL_ID; + + uint32[] memory singlePoolTokenIds = new uint32[](tokenIds.length); + uint256 singleCount = 0; + for (uint256 index = 0; index < tokenIds.length; index++) { + uint32 tokenId = tokenIds[index]; + + IParaApeStaking.TokenStatus + memory singlePoolTokenStatus = poolStates[singlePoolId] + .tokenStatus[tokenId]; + if (singlePoolTokenStatus.isInPool) { + singlePoolTokenIds[singleCount] = tokenId; + singleCount++; + } + } + + if (singleCount > 0) { + assembly { + mstore(singlePoolTokenIds, singleCount) + } + + withdrawApeCoinPool( + poolStates[singlePoolId], + apeMatchedCount, + sApeBalance, + cApeShareBalance, + vars, + IApeCoinPool.ApeCoinWithdrawInfo({ + cashToken: vars.cApe, + cashAmount: 0, + isBAYC: isBAYC, + tokenIds: singlePoolTokenIds + }), + singlePoolId + ); + } + } + + // check pair + { + uint256 pairPoolId = isBAYC + ? ApeStakingCommonLogic.BAYC_BAKC_APECOIN_POOL_ID + : ApeStakingCommonLogic.MAYC_BAKC_APECOIN_POOL_ID; + + uint32[] memory parePoolTokenIds = new uint32[](tokenIds.length); + uint32[] memory bakcTokenIds = new uint32[](tokenIds.length); + uint256 pairCount = 0; + for (uint256 index = 0; index < tokenIds.length; index++) { + uint32 tokenId = tokenIds[index]; + + IParaApeStaking.TokenStatus + memory pairPoolTokenStatus = poolStates[pairPoolId] + .tokenStatus[tokenId]; + if (pairPoolTokenStatus.isInPool) { + parePoolTokenIds[pairCount] = tokenId; + bakcTokenIds[pairCount] = pairPoolTokenStatus.bakcTokenId; + pairCount++; + } + } + + if (pairCount > 0) { + assembly { + mstore(parePoolTokenIds, pairCount) + mstore(bakcTokenIds, pairCount) + } + + withdrawApeCoinPairPool( + poolStates[pairPoolId], + apeMatchedCount, + sApeBalance, + cApeShareBalance, + vars, + IApeCoinPool.ApeCoinPairWithdrawInfo({ + cashToken: vars.cApe, + cashAmount: 0, + isBAYC: isBAYC, + apeTokenIds: parePoolTokenIds, + bakcTokenIds: bakcTokenIds + }), + pairPoolId + ); + } + } + } + + function _prepareApeCoin( + mapping(address => IParaApeStaking.SApeBalance) storage sApeBalance, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + uint128 totalApeCoinNeeded, + address cashToken, + uint256 cashAmount, + address user + ) internal { + require( + cashToken == vars.cApe || cashToken == vars.apeCoin, + Errors.INVALID_TOKEN + ); + require(cashAmount <= totalApeCoinNeeded, Errors.INVALID_CASH_AMOUNT); + + if (cashAmount != 0) { + IERC20(cashToken).safeTransferFrom( + msg.sender, + address(this), + cashAmount + ); + } + + uint256 cApeWithdrawAmount = (cashToken == vars.apeCoin) + ? 0 + : cashAmount; + IParaApeStaking.SApeBalance memory sApeBalanceCache = sApeBalance[user]; + if (cashAmount < totalApeCoinNeeded) { + uint256 freeSApeBalanceNeeded = totalApeCoinNeeded - cashAmount; + uint256 freeShareBalanceNeeded = ICApe(vars.cApe) + .getShareByPooledApe(freeSApeBalanceNeeded); + require( + sApeBalanceCache.freeShareBalance >= freeShareBalanceNeeded, + Errors.SAPE_FREE_BALANCE_NOT_ENOUGH + ); + sApeBalanceCache.freeShareBalance -= freeShareBalanceNeeded + .toUint128(); + cApeWithdrawAmount += freeSApeBalanceNeeded; + } + + if (cApeWithdrawAmount > 0) { + IAutoCompoundApe(vars.cApe).withdraw(cApeWithdrawAmount); + } + + sApeBalanceCache.stakedBalance += totalApeCoinNeeded; + sApeBalance[user] = sApeBalanceCache; + } + + function _handleApeCoin( + mapping(address => IParaApeStaking.SApeBalance) storage sApeBalance, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + uint128 totalApeCoinWithdrew, + address cashToken, + uint256 cashAmount, + address user + ) internal { + require( + cashToken == vars.cApe || cashToken == vars.apeCoin, + Errors.INVALID_TOKEN + ); + require(cashAmount <= totalApeCoinWithdrew, Errors.INVALID_CASH_AMOUNT); + + uint256 cApeDepositAmount = (cashToken == vars.apeCoin) + ? 0 + : cashAmount; + IParaApeStaking.SApeBalance memory sApeBalanceCache = sApeBalance[user]; + if (cashAmount < totalApeCoinWithdrew) { + if (vars.cApeExchangeRate == 0) { + vars.cApeExchangeRate = ICApe(vars.cApe).getPooledApeByShares( + WadRayMath.RAY + ); + } + uint256 freeSApeBalanceAdded = totalApeCoinWithdrew - cashAmount; + uint256 freeShareBalanceAdded = freeSApeBalanceAdded.rayDiv( + vars.cApeExchangeRate + ); + sApeBalanceCache.freeShareBalance += freeShareBalanceAdded + .toUint128(); + cApeDepositAmount += freeSApeBalanceAdded; + } + sApeBalanceCache.stakedBalance -= totalApeCoinWithdrew; + sApeBalance[user] = sApeBalanceCache; + + if (cApeDepositAmount > 0) { + IAutoCompoundApe(vars.cApe).deposit( + address(this), + cApeDepositAmount + ); + } + + if (cashAmount > 0) { + _validateDropSApeBalance(vars.pool, vars.sApeReserveId, user); + _sendUserFunds(vars.pool, cashToken, cashAmount, user); + } + } + + function _distributePoolReward( + IParaApeStaking.PoolState storage poolState, + mapping(address => uint256) storage cApeShareBalance, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + uint256 rewardAmount, + uint24 totalPosition + ) internal { + if (vars.cApeExchangeRate == 0) { + vars.cApeExchangeRate = ICApe(vars.cApe).getPooledApeByShares( + WadRayMath.RAY + ); + } + IAutoCompoundApe(vars.cApe).deposit(address(this), rewardAmount); + + uint256 cApeShare = rewardAmount.rayDiv(vars.cApeExchangeRate); + uint256 compoundFee = cApeShare; + if (totalPosition != 0) { + compoundFee = cApeShare.percentMul(vars.compoundFee); + cApeShare -= compoundFee; + poolState.accumulatedRewardsPerNft += + cApeShare.toUint104() / + totalPosition; + } + + if (compoundFee > 0) { + cApeShareBalance[address(this)] += compoundFee; + } + } + + function _validateDropSApeBalance( + address pool, + uint16 sApeReserveId, + address user + ) internal view { + DataTypes.UserConfigurationMap memory userConfig = IPool(pool) + .getUserConfiguration(user); + bool usageAsCollateralEnabled = userConfig.isUsingAsCollateral( + sApeReserveId + ); + if (usageAsCollateralEnabled && userConfig.isBorrowingAny()) { + (, , , , , uint256 healthFactor, ) = IPool(pool).getUserAccountData( + user + ); + //need to check user health factor + require( + healthFactor >= + ApeStakingCommonLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD, + Errors.HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD + ); + } + } + + function _sendUserFunds( + address pool, + address asset, + uint256 amount, + address user + ) internal { + address receiver = user; + DataTypes.TimeLockParams memory timeLockParams = IPool(pool) + .calculateTimeLockParams(asset, amount); + if (timeLockParams.releaseTime != 0) { + ITimeLock timeLock = IPool(pool).TIME_LOCK(); + uint256[] memory amounts = new uint256[](1); + amounts[0] = amount; + + timeLock.createAgreement( + DataTypes.AssetType.ERC20, + DataTypes.TimeLockActionType.WITHDRAW, + address(0), + asset, + amounts, + user, + timeLockParams.releaseTime + ); + receiver = address(timeLock); + } + IERC20(asset).safeTransfer(receiver, amount); + } +} diff --git a/contracts/apestaking/logic/ApeStakingCommonLogic.sol b/contracts/apestaking/logic/ApeStakingCommonLogic.sol new file mode 100644 index 000000000..7962dc29f --- /dev/null +++ b/contracts/apestaking/logic/ApeStakingCommonLogic.sol @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.0; + +import "../../interfaces/IParaApeStaking.sol"; +import {PercentageMath} from "../../protocol/libraries/math/PercentageMath.sol"; +import "../../interfaces/IAutoCompoundApe.sol"; +import "../../interfaces/ICApe.sol"; +import "../../dependencies/openzeppelin/contracts/SafeCast.sol"; +import {WadRayMath} from "../../protocol/libraries/math/WadRayMath.sol"; +import {IPool} from "../../interfaces/IPool.sol"; +import "../../protocol/libraries/helpers/Errors.sol"; +import {IERC20, SafeERC20} from "../../dependencies/openzeppelin/contracts/SafeERC20.sol"; + +/** + * @title ApeStakingVaultLogic library + * + * @notice Implements the base logic for ape staking vault + */ +library ApeStakingCommonLogic { + using PercentageMath for uint256; + using SafeCast for uint256; + using WadRayMath for uint256; + using SafeERC20 for IERC20; + + event PoolRewardClaimed( + uint256 poolId, + uint256 tokenId, + uint256 rewardAmount + ); + + /** + * @dev Minimum health factor to consider a user position healthy + * A value of 1e18 results in 1 + */ + uint256 public constant HEALTH_FACTOR_LIQUIDATION_THRESHOLD = 1e18; + + uint256 public constant BAYC_BAKC_PAIR_POOL_ID = 1; + uint256 public constant MAYC_BAKC_PAIR_POOL_ID = 2; + uint256 public constant BAYC_SINGLE_POOL_ID = 3; + uint256 public constant MAYC_SINGLE_POOL_ID = 4; + uint256 public constant BAKC_SINGLE_POOL_ID = 5; + uint256 public constant BAYC_APECOIN_POOL_ID = 6; + uint256 public constant MAYC_APECOIN_POOL_ID = 7; + uint256 public constant BAYC_BAKC_APECOIN_POOL_ID = 8; + uint256 public constant MAYC_BAKC_APECOIN_POOL_ID = 9; + + uint256 public constant BAYC_POOL_ID = 1; + uint256 public constant MAYC_POOL_ID = 2; + uint256 public constant BAKC_POOL_ID = 3; + + function validateTokenIdArray(uint32[] calldata tokenIds) internal pure { + uint256 arrayLength = tokenIds.length; + require(arrayLength > 0, Errors.INVALID_PARAMETER); + if (arrayLength >= 2) { + for (uint256 index = 1; index < arrayLength; index++) { + require( + tokenIds[index] > tokenIds[index - 1], + Errors.INVALID_PARAMETER + ); + } + } + } + + function depositCApeShareForUser( + mapping(address => uint256) storage cApeShareBalance, + address user, + uint256 amount + ) internal { + if (amount > 0) { + cApeShareBalance[user] += amount; + } + } + + function calculateRepayAndCompound( + IParaApeStaking.PoolState storage poolState, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + uint256 positionCap + ) internal returns (uint256, uint256) { + if (vars.cApeExchangeRate == 0) { + vars.cApeExchangeRate = ICApe(vars.cApe).getPooledApeByShares( + WadRayMath.RAY + ); + } + uint256 cApeDebtShare = poolState.cApeDebtShare; + uint256 debtInterest = calculateCurrentPositionDebtInterest( + cApeDebtShare, + poolState.stakingPosition, + positionCap, + vars.cApeExchangeRate, + vars.latestBorrowIndex + ); + uint256 repayAmount = (debtInterest >= vars.totalClaimedApe) + ? vars.totalClaimedApe + : debtInterest; + cApeDebtShare -= repayAmount.rayDiv(vars.latestBorrowIndex).rayDiv( + vars.cApeExchangeRate + ); + poolState.cApeDebtShare = cApeDebtShare.toUint104(); + uint256 compoundFee = 0; + if (vars.totalClaimedApe > debtInterest) { + uint256 shareRewardAmount = (vars.totalClaimedApe - debtInterest) + .rayDiv(vars.cApeExchangeRate); + compoundFee = shareRewardAmount.percentMul(vars.compoundFee); + shareRewardAmount -= compoundFee; + //update reward index + uint104 currentTotalPosition = poolState.totalPosition; + if (currentTotalPosition != 0) { + poolState.accumulatedRewardsPerNft += + shareRewardAmount.toUint104() / + currentTotalPosition; + } else { + compoundFee += shareRewardAmount; + } + } + + return (repayAmount, compoundFee); + } + + function borrowCApeFromPool( + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + uint256 totalBorrow + ) internal returns (uint256) { + uint256 latestBorrowIndex = IPool(vars.pool).borrowPoolCApe( + totalBorrow + ); + IAutoCompoundApe(vars.cApe).withdraw(totalBorrow); + uint256 cApeExchangeRate = ICApe(vars.cApe).getPooledApeByShares( + WadRayMath.RAY + ); + return totalBorrow.rayDiv(latestBorrowIndex).rayDiv(cApeExchangeRate); + } + + function calculateCurrentPositionDebtInterest( + uint256 cApeDebtShare, + uint256 currentStakingPosition, + uint256 perPositionCap, + uint256 cApeExchangeRate, + uint256 latestBorrowIndex + ) internal pure returns (uint256) { + uint256 currentDebt = cApeDebtShare.rayMul(cApeExchangeRate).rayMul( + latestBorrowIndex + ); + return (currentDebt - perPositionCap * currentStakingPosition); + } + + function handleApeTransferIn( + mapping(address => mapping(uint32 => uint256)) storage apeMatchedCount, + address ape, + address nApe, + uint32 tokenId + ) internal { + uint256 currentMatchCount = apeMatchedCount[ape][tokenId]; + if (currentMatchCount == 0) { + IERC721(ape).safeTransferFrom(nApe, address(this), tokenId); + } + apeMatchedCount[ape][tokenId] = currentMatchCount + 1; + } + + function handleApeTransferOut( + mapping(address => mapping(uint32 => uint256)) storage apeMatchedCount, + address ape, + address nApe, + uint32 tokenId + ) internal { + uint256 matchedCount = apeMatchedCount[ape][tokenId]; + matchedCount -= 1; + if (matchedCount == 0) { + IERC721(ape).safeTransferFrom(address(this), nApe, tokenId); + } + apeMatchedCount[ape][tokenId] = matchedCount; + } + + function claimPendingReward( + IParaApeStaking.PoolState storage poolState, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + uint256 poolId, + address nToken, + bool needUpdateStatus, + uint32[] memory tokenIds + ) internal returns (address) { + if (vars.cApeExchangeRate == 0) { + vars.cApeExchangeRate = ICApe(vars.cApe).getPooledApeByShares( + WadRayMath.RAY + ); + } + + address claimFor; + uint256 totalRewardShares; + vars.accumulatedRewardsPerNft = poolState.accumulatedRewardsPerNft; + for (uint256 index = 0; index < tokenIds.length; index++) { + uint32 tokenId = tokenIds[index]; + + //just need to check ape ntoken owner + { + address nApeOwner = IERC721(nToken).ownerOf(tokenId); + if (claimFor == address(0)) { + claimFor = nApeOwner; + } else { + require(nApeOwner == claimFor, Errors.NOT_THE_SAME_OWNER); + } + } + + IParaApeStaking.TokenStatus memory tokenStatus = poolState + .tokenStatus[tokenId]; + + //check is in pool + require(tokenStatus.isInPool, Errors.NFT_NOT_IN_POOL); + + //update reward, to save gas we don't claim pending reward in ApeCoinStaking. + uint256 rewardShare = vars.accumulatedRewardsPerNft - + tokenStatus.rewardsDebt; + totalRewardShares += rewardShare; + + if (needUpdateStatus) { + poolState.tokenStatus[tokenId].rewardsDebt = vars + .accumulatedRewardsPerNft; + } + + //emit event + emit PoolRewardClaimed( + poolId, + tokenId, + rewardShare.rayMul(vars.cApeExchangeRate) + ); + } + + if (totalRewardShares > 0) { + uint256 pendingReward = totalRewardShares.rayMul( + vars.cApeExchangeRate + ); + IERC20(vars.cApe).safeTransfer(claimFor, pendingReward); + } + + return claimFor; + } + + function getNftFromPoolId( + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + uint256 poolId + ) internal pure returns (address, address) { + if (poolId == ApeStakingCommonLogic.BAKC_SINGLE_POOL_ID) { + return (vars.bakc, vars.nBakc); + } else if ( + poolId == ApeStakingCommonLogic.BAYC_BAKC_PAIR_POOL_ID || + poolId == ApeStakingCommonLogic.BAYC_SINGLE_POOL_ID || + poolId == ApeStakingCommonLogic.BAYC_APECOIN_POOL_ID || + poolId == ApeStakingCommonLogic.BAYC_BAKC_APECOIN_POOL_ID + ) { + return (vars.bayc, vars.nBayc); + } else { + return (vars.mayc, vars.nMayc); + } + } +} diff --git a/contracts/apestaking/logic/ApeStakingP2PLogic.sol b/contracts/apestaking/logic/ApeStakingP2PLogic.sol new file mode 100644 index 000000000..161d9a716 --- /dev/null +++ b/contracts/apestaking/logic/ApeStakingP2PLogic.sol @@ -0,0 +1,733 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.0; + +import "../../interfaces/IApeStakingP2P.sol"; +import "../../interfaces/IApeStakingP2P.sol"; +import {IERC20, SafeERC20} from "../../dependencies/openzeppelin/contracts/SafeERC20.sol"; +import "../../dependencies/yoga-labs/ApeCoinStaking.sol"; +import {PercentageMath} from "../../protocol/libraries/math/PercentageMath.sol"; +import "../../interfaces/IAutoCompoundApe.sol"; +import "../../interfaces/ICApe.sol"; +import {SignatureChecker} from "../../dependencies/looksrare/contracts/libraries/SignatureChecker.sol"; +import "../../dependencies/openzeppelin/contracts/SafeCast.sol"; +import "./ApeStakingCommonLogic.sol"; +import {WadRayMath} from "../../protocol/libraries/math/WadRayMath.sol"; +import "../../protocol/libraries/helpers/Errors.sol"; +import {UserConfiguration} from "../../protocol/libraries/configuration/UserConfiguration.sol"; +import {DataTypes} from "../../protocol/libraries/types/DataTypes.sol"; + +/** + * @title ApeStakingVaultLogic library + * + * @notice Implements the base logic for ape staking vault + */ +library ApeStakingP2PLogic { + using UserConfiguration for DataTypes.UserConfigurationMap; + using PercentageMath for uint256; + using SafeCast for uint256; + using SafeERC20 for IERC20; + using WadRayMath for uint256; + + event OrderClaimedAndCompounded(bytes32 orderHash, uint256 totalReward); + + uint256 internal constant WAD = 1e18; + + //keccak256("ListingOrder(uint8 stakingType,address offerer,address token,uint256 tokenId,uint256 share,uint256 startTime,uint256 endTime)"); + bytes32 internal constant LISTING_ORDER_HASH = + 0x227f9dd14259caacdbcf45411b33cf1c018f31bd3da27e613a66edf8ae45814f; + + //keccak256("MatchedOrder(uint8 stakingType,address apeToken,uint32 apeTokenId,uint32 apeShare,uint32 bakcTokenId,uint32 bakcShare,address apeCoinOfferer,uint32 apeCoinShare)"); + bytes32 internal constant MATCHED_ORDER_HASH = + 0x48f3bc7b1131aafcb847892fa3593862086dbde63aca2af4deccea8f6e8a380e; + + function cancelListing( + IApeStakingP2P.ListingOrder calldata listingOrder, + mapping(bytes32 => IApeStakingP2P.ListingOrderStatus) + storage listingOrderStatus + ) external returns (bytes32) { + require(msg.sender == listingOrder.offerer, Errors.NOT_ORDER_OFFERER); + + bytes32 orderHash = getListingOrderHash(listingOrder); + require( + listingOrderStatus[orderHash] != + IApeStakingP2P.ListingOrderStatus.Cancelled, + Errors.ORDER_ALREADY_CANCELLED + ); + listingOrderStatus[orderHash] = IApeStakingP2P + .ListingOrderStatus + .Cancelled; + return orderHash; + } + + function matchPairStakingList( + IApeStakingP2P.ListingOrder calldata apeOrder, + IApeStakingP2P.ListingOrder calldata apeCoinOrder, + mapping(bytes32 => IApeStakingP2P.ListingOrderStatus) + storage listingOrderStatus, + mapping(bytes32 => IApeStakingP2P.MatchedOrder) storage matchedOrders, + mapping(address => mapping(uint32 => uint256)) storage apeMatchedCount, + mapping(address => IParaApeStaking.SApeBalance) storage sApeBalance, + IParaApeStaking.ApeStakingVaultCacheVars memory vars + ) external returns (bytes32 orderHash) { + //1 validate all order + _validateApeOrder(listingOrderStatus, apeOrder, vars); + bytes32 apeCoinListingOrderHash = _validateApeCoinOrder( + listingOrderStatus, + apeCoinOrder, + vars + ); + + //2 check if orders can match + require( + (apeOrder.token == vars.mayc && + apeOrder.stakingType == + IApeStakingP2P.StakingType.MAYCStaking) || + (apeOrder.token == vars.bayc && + apeOrder.stakingType == + IApeStakingP2P.StakingType.BAYCStaking), + Errors.INVALID_STAKING_TYPE + ); + require( + apeOrder.stakingType == apeCoinOrder.stakingType, + Errors.ORDER_TYPE_MATCH_FAILED + ); + require( + apeOrder.share + apeCoinOrder.share == + PercentageMath.PERCENTAGE_FACTOR, + Errors.ORDER_SHARE_MATCH_FAILED + ); + + //3 transfer token + address nTokenAddress = _getApeNTokenAddress(vars, apeOrder.token); + ApeStakingCommonLogic.handleApeTransferIn( + apeMatchedCount, + apeOrder.token, + nTokenAddress, + apeOrder.tokenId + ); + uint256 apeCoinCap = getApeCoinStakingCap( + apeCoinOrder.stakingType, + vars + ); + _prepareApeCoin( + sApeBalance, + vars.cApe, + apeCoinOrder.offerer, + apeCoinCap + ); + + //4 create match order + IApeStakingP2P.MatchedOrder memory matchedOrder = IApeStakingP2P + .MatchedOrder({ + stakingType: apeOrder.stakingType, + apeToken: apeOrder.token, + apeTokenId: apeOrder.tokenId, + apeShare: apeOrder.share, + bakcTokenId: 0, + bakcShare: 0, + apeCoinOfferer: apeCoinOrder.offerer, + apeCoinShare: apeCoinOrder.share, + apeCoinListingOrderHash: apeCoinListingOrderHash + }); + orderHash = getMatchedOrderHash(matchedOrder); + matchedOrders[orderHash] = matchedOrder; + + //5 stake for ApeCoinStaking + ApeCoinStaking.SingleNft[] + memory singleNft = new ApeCoinStaking.SingleNft[](1); + singleNft[0].tokenId = apeOrder.tokenId; + singleNft[0].amount = apeCoinCap.toUint224(); + if (apeOrder.stakingType == IApeStakingP2P.StakingType.BAYCStaking) { + vars.apeCoinStaking.depositBAYC(singleNft); + } else { + vars.apeCoinStaking.depositMAYC(singleNft); + } + + //6 update ape coin listing order status + listingOrderStatus[apeCoinListingOrderHash] = IApeStakingP2P + .ListingOrderStatus + .Matched; + + return orderHash; + } + + function matchBAKCPairStakingList( + IApeStakingP2P.ListingOrder calldata apeOrder, + IApeStakingP2P.ListingOrder calldata bakcOrder, + IApeStakingP2P.ListingOrder calldata apeCoinOrder, + mapping(bytes32 => IApeStakingP2P.ListingOrderStatus) + storage listingOrderStatus, + mapping(bytes32 => IApeStakingP2P.MatchedOrder) storage matchedOrders, + mapping(address => mapping(uint32 => uint256)) storage apeMatchedCount, + mapping(address => IParaApeStaking.SApeBalance) storage sApeBalance, + IParaApeStaking.ApeStakingVaultCacheVars memory vars + ) external returns (bytes32 orderHash) { + //1 validate all order + _validateApeOrder(listingOrderStatus, apeOrder, vars); + _validateBakcOrder(listingOrderStatus, bakcOrder, vars); + bytes32 apeCoinListingOrderHash = _validateApeCoinOrder( + listingOrderStatus, + apeCoinOrder, + vars + ); + + //2 check if orders can match + require( + apeOrder.stakingType == IApeStakingP2P.StakingType.BAKCPairStaking, + Errors.INVALID_STAKING_TYPE + ); + require( + apeOrder.stakingType == bakcOrder.stakingType && + apeOrder.stakingType == apeCoinOrder.stakingType, + Errors.ORDER_TYPE_MATCH_FAILED + ); + require( + apeOrder.share + bakcOrder.share + apeCoinOrder.share == + PercentageMath.PERCENTAGE_FACTOR, + Errors.ORDER_SHARE_MATCH_FAILED + ); + + //3 transfer token + address nTokenAddress = _getApeNTokenAddress(vars, apeOrder.token); + ApeStakingCommonLogic.handleApeTransferIn( + apeMatchedCount, + apeOrder.token, + nTokenAddress, + apeOrder.tokenId + ); + IERC721(vars.bakc).safeTransferFrom( + vars.nBakc, + address(this), + bakcOrder.tokenId + ); + uint256 apeCoinCap = getApeCoinStakingCap( + apeCoinOrder.stakingType, + vars + ); + _prepareApeCoin( + sApeBalance, + vars.cApe, + apeCoinOrder.offerer, + apeCoinCap + ); + + //4 create match order + IApeStakingP2P.MatchedOrder memory matchedOrder = IApeStakingP2P + .MatchedOrder({ + stakingType: apeOrder.stakingType, + apeToken: apeOrder.token, + apeTokenId: apeOrder.tokenId, + apeShare: apeOrder.share, + bakcTokenId: bakcOrder.tokenId, + bakcShare: bakcOrder.share, + apeCoinOfferer: apeCoinOrder.offerer, + apeCoinShare: apeCoinOrder.share, + apeCoinListingOrderHash: apeCoinListingOrderHash + }); + orderHash = getMatchedOrderHash(matchedOrder); + matchedOrders[orderHash] = matchedOrder; + + //5 stake for ApeCoinStaking + ApeCoinStaking.PairNftDepositWithAmount[] + memory _stakingPairs = new ApeCoinStaking.PairNftDepositWithAmount[]( + 1 + ); + _stakingPairs[0].mainTokenId = apeOrder.tokenId; + _stakingPairs[0].bakcTokenId = bakcOrder.tokenId; + _stakingPairs[0].amount = apeCoinCap.toUint184(); + ApeCoinStaking.PairNftDepositWithAmount[] + memory _otherPairs = new ApeCoinStaking.PairNftDepositWithAmount[]( + 0 + ); + if (apeOrder.token == vars.bayc) { + vars.apeCoinStaking.depositBAKC(_stakingPairs, _otherPairs); + } else { + vars.apeCoinStaking.depositBAKC(_otherPairs, _stakingPairs); + } + + //6 update ape coin listing order status + listingOrderStatus[apeCoinListingOrderHash] = IApeStakingP2P + .ListingOrderStatus + .Matched; + + return orderHash; + } + + function breakUpMatchedOrder( + mapping(bytes32 => IApeStakingP2P.ListingOrderStatus) + storage listingOrderStatus, + mapping(bytes32 => IApeStakingP2P.MatchedOrder) storage matchedOrders, + mapping(address => uint256) storage cApeShareBalance, + mapping(address => mapping(uint32 => uint256)) storage apeMatchedCount, + mapping(address => IParaApeStaking.SApeBalance) storage sApeBalance, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + bytes32 orderHash + ) external { + IApeStakingP2P.MatchedOrder memory order = matchedOrders[orderHash]; + + //1 check if have permission to break up + address apeNToken = _getApeNTokenAddress(vars, order.apeToken); + require( + msg.sender == order.apeCoinOfferer || + msg.sender == IERC721(apeNToken).ownerOf(order.apeTokenId) || + (order.stakingType == + IApeStakingP2P.StakingType.BAKCPairStaking && + msg.sender == + IERC721(vars.nBakc).ownerOf(order.bakcTokenId)) || + _ifCanLiquidateApeCoinOffererSApe( + vars.pool, + vars.sApeReserveId, + order.apeCoinOfferer + ), + Errors.NO_BREAK_UP_PERMISSION + ); + + //2 exit from ApeCoinStaking + uint256 apeCoinCap = getApeCoinStakingCap(order.stakingType, vars); + uint256 balanceBefore = IERC20(vars.apeCoin).balanceOf(address(this)); + if ( + order.stakingType == IApeStakingP2P.StakingType.BAYCStaking || + order.stakingType == IApeStakingP2P.StakingType.MAYCStaking + ) { + ApeCoinStaking.SingleNft[] + memory _nfts = new ApeCoinStaking.SingleNft[](1); + _nfts[0].tokenId = order.apeTokenId; + _nfts[0].amount = apeCoinCap.toUint224(); + if (order.stakingType == IApeStakingP2P.StakingType.BAYCStaking) { + vars.apeCoinStaking.withdrawSelfBAYC(_nfts); + } else { + vars.apeCoinStaking.withdrawSelfMAYC(_nfts); + } + } else { + ApeCoinStaking.PairNftWithdrawWithAmount[] + memory _nfts = new ApeCoinStaking.PairNftWithdrawWithAmount[]( + 1 + ); + _nfts[0].mainTokenId = order.apeTokenId; + _nfts[0].bakcTokenId = order.bakcTokenId; + _nfts[0].amount = apeCoinCap.toUint184(); + _nfts[0].isUncommit = true; + ApeCoinStaking.PairNftWithdrawWithAmount[] + memory _otherPairs = new ApeCoinStaking.PairNftWithdrawWithAmount[]( + 0 + ); + if (order.apeToken == vars.bayc) { + vars.apeCoinStaking.withdrawBAKC(_nfts, _otherPairs); + } else { + vars.apeCoinStaking.withdrawBAKC(_otherPairs, _nfts); + } + } + uint256 balanceAfter = IERC20(vars.apeCoin).balanceOf(address(this)); + uint256 withdrawAmount = balanceAfter - balanceBefore; + + vars.cApeExchangeRate = ICApe(vars.cApe).getPooledApeByShares( + WadRayMath.RAY + ); + if (withdrawAmount > apeCoinCap) { + uint256 _compoundFeeShare = _distributeReward( + cApeShareBalance, + vars, + order, + vars.cApeExchangeRate, + withdrawAmount - apeCoinCap + ); + ApeStakingCommonLogic.depositCApeShareForUser( + cApeShareBalance, + address(this), + _compoundFeeShare + ); + } + + //3 transfer token + ApeStakingCommonLogic.handleApeTransferOut( + apeMatchedCount, + order.apeToken, + apeNToken, + order.apeTokenId + ); + _updateUserSApeBalance( + sApeBalance, + order.apeCoinOfferer, + apeCoinCap, + vars.cApeExchangeRate + ); + IAutoCompoundApe(vars.cApe).deposit(address(this), withdrawAmount); + + if (order.stakingType == IApeStakingP2P.StakingType.BAKCPairStaking) { + IERC721(vars.bakc).safeTransferFrom( + address(this), + vars.nBakc, + order.bakcTokenId + ); + } + + //4 delete matched order + delete matchedOrders[orderHash]; + + //5 reset ape coin listing order status + if ( + listingOrderStatus[order.apeCoinListingOrderHash] != + IApeStakingP2P.ListingOrderStatus.Cancelled + ) { + listingOrderStatus[order.apeCoinListingOrderHash] = IApeStakingP2P + .ListingOrderStatus + .Pending; + } + } + + function claimForMatchedOrdersAndCompound( + mapping(bytes32 => IApeStakingP2P.MatchedOrder) storage matchedOrders, + mapping(address => uint256) storage cApeShareBalance, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + bytes32[] memory orderHashes + ) public { + //ignore getShareByPooledApe return 0 case. + uint256 cApeExchangeRate = ICApe(vars.cApe).getPooledApeByShares( + WadRayMath.RAY + ); + uint256 totalReward; + uint256 totalFeeShare; + uint256 orderCounts = orderHashes.length; + for (uint256 index = 0; index < orderCounts; index++) { + bytes32 orderHash = orderHashes[index]; + ( + uint256 reward, + uint256 feeShare + ) = _claimForMatchedOrderAndCompound( + matchedOrders, + cApeShareBalance, + vars, + orderHash, + cApeExchangeRate + ); + totalReward += reward; + totalFeeShare += feeShare; + } + if (totalReward > 0) { + IAutoCompoundApe(vars.cApe).deposit(address(this), totalReward); + ApeStakingCommonLogic.depositCApeShareForUser( + cApeShareBalance, + address(this), + totalFeeShare + ); + } + } + + function getApeCoinStakingCap( + IApeStakingP2P.StakingType stakingType, + IParaApeStaking.ApeStakingVaultCacheVars memory vars + ) internal pure returns (uint256) { + if (stakingType == IApeStakingP2P.StakingType.BAYCStaking) { + return vars.baycMatchedCap; + } else if (stakingType == IApeStakingP2P.StakingType.MAYCStaking) { + return vars.maycMatchedCap; + } else { + return vars.bakcMatchedCap; + } + } + + function _claimForMatchedOrderAndCompound( + mapping(bytes32 => IApeStakingP2P.MatchedOrder) storage matchedOrders, + mapping(address => uint256) storage cApeShareBalance, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + bytes32 orderHash, + uint256 cApeExchangeRate + ) internal returns (uint256, uint256) { + IApeStakingP2P.MatchedOrder memory order = matchedOrders[orderHash]; + uint256 balanceBefore = IERC20(vars.apeCoin).balanceOf(address(this)); + if ( + order.stakingType == IApeStakingP2P.StakingType.BAYCStaking || + order.stakingType == IApeStakingP2P.StakingType.MAYCStaking + ) { + uint256[] memory _nfts = new uint256[](1); + _nfts[0] = order.apeTokenId; + if (order.stakingType == IApeStakingP2P.StakingType.BAYCStaking) { + vars.apeCoinStaking.claimSelfBAYC(_nfts); + } else { + vars.apeCoinStaking.claimSelfMAYC(_nfts); + } + } else { + ApeCoinStaking.PairNft[] + memory _nfts = new ApeCoinStaking.PairNft[](1); + _nfts[0].mainTokenId = order.apeTokenId; + _nfts[0].bakcTokenId = order.bakcTokenId; + ApeCoinStaking.PairNft[] + memory _otherPairs = new ApeCoinStaking.PairNft[](0); + if (order.apeToken == vars.bayc) { + vars.apeCoinStaking.claimSelfBAKC(_nfts, _otherPairs); + } else { + vars.apeCoinStaking.claimSelfBAKC(_otherPairs, _nfts); + } + } + uint256 balanceAfter = IERC20(vars.apeCoin).balanceOf(address(this)); + uint256 rewardAmount = balanceAfter - balanceBefore; + if (rewardAmount == 0) { + return (0, 0); + } + + uint256 _compoundFeeShare = _distributeReward( + cApeShareBalance, + vars, + order, + cApeExchangeRate, + rewardAmount + ); + + emit OrderClaimedAndCompounded(orderHash, rewardAmount); + + return (rewardAmount, _compoundFeeShare); + } + + function _distributeReward( + mapping(address => uint256) storage cApeShareBalance, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + IApeStakingP2P.MatchedOrder memory order, + uint256 cApeExchangeRate, + uint256 rewardAmount + ) internal returns (uint256) { + uint256 rewardShare = rewardAmount.rayDiv(cApeExchangeRate); + //compound fee + uint256 _compoundFeeShare = rewardShare.percentMul(vars.compoundFee); + rewardShare -= _compoundFeeShare; + + ApeStakingCommonLogic.depositCApeShareForUser( + cApeShareBalance, + IERC721(_getApeNTokenAddress(vars, order.apeToken)).ownerOf( + order.apeTokenId + ), + rewardShare.percentMul(order.apeShare) + ); + ApeStakingCommonLogic.depositCApeShareForUser( + cApeShareBalance, + order.apeCoinOfferer, + rewardShare.percentMul(order.apeCoinShare) + ); + if (order.stakingType == IApeStakingP2P.StakingType.BAKCPairStaking) { + ApeStakingCommonLogic.depositCApeShareForUser( + cApeShareBalance, + IERC721(vars.nBakc).ownerOf(order.bakcTokenId), + rewardShare.percentMul(order.bakcShare) + ); + } + + return _compoundFeeShare; + } + + function _validateOrderBasicInfo( + bytes32 DOMAIN_SEPARATOR, + mapping(bytes32 => IApeStakingP2P.ListingOrderStatus) + storage listingOrderStatus, + IApeStakingP2P.ListingOrder calldata listingOrder + ) internal view returns (bytes32 orderHash) { + require( + listingOrder.startTime <= block.timestamp, + Errors.ORDER_NOT_STARTED + ); + require(listingOrder.endTime >= block.timestamp, Errors.ORDER_EXPIRED); + + orderHash = getListingOrderHash(listingOrder); + require( + listingOrderStatus[orderHash] == + IApeStakingP2P.ListingOrderStatus.Pending, + Errors.INVALID_ORDER_STATUS + ); + + if (msg.sender != listingOrder.offerer) { + require( + validateOrderSignature( + DOMAIN_SEPARATOR, + listingOrder.offerer, + orderHash, + listingOrder.v, + listingOrder.r, + listingOrder.s + ), + Errors.INVALID_SIGNATURE + ); + } + } + + function _validateApeOrder( + mapping(bytes32 => IApeStakingP2P.ListingOrderStatus) + storage listingOrderStatus, + IApeStakingP2P.ListingOrder calldata apeOrder, + IParaApeStaking.ApeStakingVaultCacheVars memory vars + ) internal view { + _validateOrderBasicInfo( + vars.DOMAIN_SEPARATOR, + listingOrderStatus, + apeOrder + ); + + address nToken = _getApeNTokenAddress(vars, apeOrder.token); + require( + IERC721(nToken).ownerOf(apeOrder.tokenId) == apeOrder.offerer, + Errors.NOT_THE_OWNER + ); + } + + function _validateApeCoinOrder( + mapping(bytes32 => IApeStakingP2P.ListingOrderStatus) + storage listingOrderStatus, + IApeStakingP2P.ListingOrder calldata apeCoinOrder, + IParaApeStaking.ApeStakingVaultCacheVars memory vars + ) internal view returns (bytes32 orderHash) { + orderHash = _validateOrderBasicInfo( + vars.DOMAIN_SEPARATOR, + listingOrderStatus, + apeCoinOrder + ); + require( + apeCoinOrder.token == DataTypes.SApeAddress, + Errors.INVALID_TOKEN + ); + } + + function _validateBakcOrder( + mapping(bytes32 => IApeStakingP2P.ListingOrderStatus) + storage listingOrderStatus, + IApeStakingP2P.ListingOrder calldata bakcOrder, + IParaApeStaking.ApeStakingVaultCacheVars memory vars + ) internal view { + _validateOrderBasicInfo( + vars.DOMAIN_SEPARATOR, + listingOrderStatus, + bakcOrder + ); + + require(bakcOrder.token == vars.bakc, Errors.INVALID_TOKEN); + require( + IERC721(vars.nBakc).ownerOf(bakcOrder.tokenId) == bakcOrder.offerer, + Errors.NOT_THE_OWNER + ); + } + + function _prepareApeCoin( + mapping(address => IParaApeStaking.SApeBalance) storage sApeBalance, + address cApe, + address user, + uint256 amount + ) internal { + uint256 freeShareBalanceNeeded = ICApe(cApe).getShareByPooledApe( + amount + ); + IParaApeStaking.SApeBalance memory sApeBalanceCache = sApeBalance[user]; + require( + sApeBalanceCache.freeShareBalance >= freeShareBalanceNeeded, + Errors.SAPE_FREE_BALANCE_NOT_ENOUGH + ); + sApeBalanceCache.freeShareBalance -= freeShareBalanceNeeded.toUint128(); + sApeBalanceCache.stakedBalance += amount.toUint128(); + sApeBalance[user] = sApeBalanceCache; + + IAutoCompoundApe(cApe).withdraw(amount); + } + + function _updateUserSApeBalance( + mapping(address => IParaApeStaking.SApeBalance) storage sApeBalance, + address user, + uint256 apeCoinAmount, + uint256 cApeExchangeRate + ) internal { + uint256 freeSApeBalanceAdded = apeCoinAmount.rayDiv(cApeExchangeRate); + IParaApeStaking.SApeBalance memory sApeBalanceCache = sApeBalance[user]; + sApeBalanceCache.freeShareBalance += freeSApeBalanceAdded.toUint128(); + sApeBalanceCache.stakedBalance -= apeCoinAmount.toUint128(); + sApeBalance[user] = sApeBalanceCache; + } + + function _getApeNTokenAddress( + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + address apeToken + ) internal pure returns (address) { + if (apeToken == vars.bayc) { + return vars.nBayc; + } else if (apeToken == vars.mayc) { + return vars.nMayc; + } else { + revert(Errors.INVALID_TOKEN); + } + } + + function _ifCanLiquidateApeCoinOffererSApe( + address pool, + uint16 sApeReserveId, + address user + ) internal view returns (bool) { + DataTypes.UserConfigurationMap memory userConfig = IPool(pool) + .getUserConfiguration(user); + bool usageAsCollateralEnabled = userConfig.isUsingAsCollateral( + sApeReserveId + ); + + if (usageAsCollateralEnabled && userConfig.isBorrowingAny()) { + (, , , , , uint256 healthFactor, ) = IPool(pool).getUserAccountData( + user + ); + return + healthFactor < + ApeStakingCommonLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD; + } + return false; + } + + function getMatchedOrderHash(IApeStakingP2P.MatchedOrder memory order) + public + pure + returns (bytes32) + { + return + keccak256( + abi.encode( + MATCHED_ORDER_HASH, + order.stakingType, + order.apeToken, + order.apeTokenId, + order.apeShare, + order.bakcTokenId, + order.bakcShare, + order.apeCoinOfferer, + order.apeCoinShare + ) + ); + } + + function getListingOrderHash(IApeStakingP2P.ListingOrder calldata order) + public + pure + returns (bytes32) + { + return + keccak256( + abi.encode( + LISTING_ORDER_HASH, + order.stakingType, + order.offerer, + order.token, + order.tokenId, + order.share, + order.startTime, + order.endTime + ) + ); + } + + function validateOrderSignature( + bytes32 DOMAIN_SEPARATOR, + address signer, + bytes32 orderHash, + uint8 v, + bytes32 r, + bytes32 s + ) public view returns (bool) { + return + SignatureChecker.verify( + orderHash, + signer, + v, + r, + s, + DOMAIN_SEPARATOR + ); + } +} diff --git a/contracts/apestaking/logic/ApeStakingPairPoolLogic.sol b/contracts/apestaking/logic/ApeStakingPairPoolLogic.sol new file mode 100644 index 000000000..672597c4a --- /dev/null +++ b/contracts/apestaking/logic/ApeStakingPairPoolLogic.sol @@ -0,0 +1,442 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.0; + +import {IPool} from "../../interfaces/IPool.sol"; +import "../../interfaces/IParaApeStaking.sol"; +import {IERC20, SafeERC20} from "../../dependencies/openzeppelin/contracts/SafeERC20.sol"; +import "../../dependencies/yoga-labs/ApeCoinStaking.sol"; +import {PercentageMath} from "../../protocol/libraries/math/PercentageMath.sol"; +import "../../interfaces/IAutoCompoundApe.sol"; +import "../../interfaces/ICApe.sol"; +import "../../dependencies/openzeppelin/contracts/SafeCast.sol"; +import {WadRayMath} from "../../protocol/libraries/math/WadRayMath.sol"; +import "./ApeStakingCommonLogic.sol"; +import "../../protocol/libraries/helpers/Errors.sol"; + +/** + * @title ApeStakingPairPoolLogic library + * + * @notice Implements the base logic for ape staking vault + */ +library ApeStakingPairPoolLogic { + using PercentageMath for uint256; + using SafeCast for uint256; + using SafeERC20 for IERC20; + using WadRayMath for uint256; + + event PairNFTDeposited( + bool isBAYC, + uint256 apeTokenId, + uint256 bakcTokenId + ); + event PairNFTStaked(bool isBAYC, uint256 apeTokenId, uint256 bakcTokenId); + event PairNFTWithdrew(bool isBAYC, uint256 apeTokenId, uint256 bakcTokenId); + event PairNFTCompounded( + bool isBAYC, + uint256 apeTokenId, + uint256 bakcTokenId + ); + + function depositPairNFT( + IParaApeStaking.PoolState storage poolState, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + bool isBAYC, + uint32[] calldata apeTokenIds, + uint32[] calldata bakcTokenIds + ) external { + uint256 arrayLength = apeTokenIds.length; + require( + arrayLength == bakcTokenIds.length && arrayLength > 0, + Errors.INVALID_PARAMETER + ); + + if (isBAYC) { + vars.apeStakingPoolId = ApeStakingCommonLogic.BAYC_POOL_ID; + vars.apeToken = vars.bayc; + vars.nApe = vars.nBayc; + } else { + vars.apeStakingPoolId = ApeStakingCommonLogic.MAYC_POOL_ID; + vars.apeToken = vars.mayc; + vars.nApe = vars.nMayc; + } + address msgSender = msg.sender; + uint128 accumulatedRewardsPerNft = poolState.accumulatedRewardsPerNft; + for (uint256 index = 0; index < arrayLength; index++) { + uint32 apeTokenId = apeTokenIds[index]; + uint32 bakcTokenId = bakcTokenIds[index]; + + //check ntoken owner + { + address nApeOwner = IERC721(vars.nApe).ownerOf(apeTokenId); + address nBakcOwner = IERC721(vars.nBakc).ownerOf(bakcTokenId); + require( + msgSender == nApeOwner && msgSender == nBakcOwner, + Errors.NOT_THE_OWNER + ); + } + + // check both ape and bakc are not staking + { + (uint256 stakedAmount, ) = vars.apeCoinStaking.nftPosition( + vars.apeStakingPoolId, + apeTokenId + ); + require(stakedAmount == 0, Errors.APE_POSITION_EXISTED); + (stakedAmount, ) = vars.apeCoinStaking.nftPosition( + ApeStakingCommonLogic.BAKC_POOL_ID, + bakcTokenId + ); + require(stakedAmount == 0, Errors.BAKC_POSITION_EXISTED); + (, bool isPaired) = vars.apeCoinStaking.mainToBakc( + vars.apeStakingPoolId, + apeTokenId + ); + require(!isPaired, Errors.PAIR_POSITION_EXISTED); + } + + //update token status + poolState.tokenStatus[apeTokenId] = IParaApeStaking.TokenStatus({ + rewardsDebt: accumulatedRewardsPerNft, + isInPool: true, + bakcTokenId: bakcTokenId, + isPaired: true + }); + + //transfer ape and BAKC + IERC721(vars.apeToken).safeTransferFrom( + vars.nApe, + address(this), + apeTokenId + ); + IERC721(vars.bakc).safeTransferFrom( + vars.nBakc, + address(this), + bakcTokenId + ); + + //emit event + emit PairNFTDeposited(isBAYC, apeTokenId, bakcTokenId); + } + + poolState.totalPosition += arrayLength.toUint24(); + } + + function stakingPairNFT( + IParaApeStaking.PoolState storage poolState, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + bool isBAYC, + uint32[] calldata apeTokenIds, + uint32[] calldata bakcTokenIds + ) external { + uint256 arrayLength = apeTokenIds.length; + require( + arrayLength == bakcTokenIds.length && arrayLength > 0, + Errors.INVALID_PARAMETER + ); + + ApeCoinStaking.SingleNft[] + memory _nfts = new ApeCoinStaking.SingleNft[](arrayLength); + ApeCoinStaking.PairNftDepositWithAmount[] + memory _nftPairs = new ApeCoinStaking.PairNftDepositWithAmount[]( + arrayLength + ); + vars.positionCap = isBAYC ? vars.baycMatchedCap : vars.maycMatchedCap; + for (uint256 index = 0; index < arrayLength; index++) { + uint32 apeTokenId = apeTokenIds[index]; + uint32 bakcTokenId = bakcTokenIds[index]; + + // check pair status + { + IParaApeStaking.TokenStatus memory localTokenStatus = poolState + .tokenStatus[apeTokenId]; + require( + localTokenStatus.bakcTokenId == bakcTokenId && + localTokenStatus.isPaired, + Errors.NOT_PAIRED_APE_AND_BAKC + ); + } + + // construct staking data + _nfts[index] = ApeCoinStaking.SingleNft({ + tokenId: apeTokenId, + amount: vars.positionCap.toUint224() + }); + _nftPairs[index] = ApeCoinStaking.PairNftDepositWithAmount({ + mainTokenId: apeTokenId, + bakcTokenId: bakcTokenId, + amount: vars.bakcMatchedCap.toUint184() + }); + + //emit event + emit PairNFTStaked(isBAYC, apeTokenId, bakcTokenId); + } + + // prepare Ape coin + uint256 totalBorrow = (vars.positionCap + vars.bakcMatchedCap) * + arrayLength; + uint256 cApeDebtShare = ApeStakingCommonLogic.borrowCApeFromPool( + vars, + totalBorrow + ); + poolState.cApeDebtShare += cApeDebtShare.toUint104(); + + //stake in ApeCoinStaking + ApeCoinStaking.PairNftDepositWithAmount[] + memory _otherPairs = new ApeCoinStaking.PairNftDepositWithAmount[]( + 0 + ); + if (isBAYC) { + vars.apeCoinStaking.depositBAYC(_nfts); + vars.apeCoinStaking.depositBAKC(_nftPairs, _otherPairs); + } else { + vars.apeCoinStaking.depositMAYC(_nfts); + vars.apeCoinStaking.depositBAKC(_otherPairs, _nftPairs); + } + + poolState.stakingPosition += arrayLength.toUint24(); + } + + function withdrawPairNFT( + IParaApeStaking.PoolState storage poolState, + mapping(address => uint256) storage cApeShareBalance, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + bool isBAYC, + uint32[] calldata apeTokenIds, + uint32[] calldata bakcTokenIds + ) external { + uint256 arrayLength = apeTokenIds.length; + require( + arrayLength == bakcTokenIds.length && arrayLength > 0, + Errors.INVALID_PARAMETER + ); + + if (isBAYC) { + vars.apeStakingPoolId = ApeStakingCommonLogic.BAYC_POOL_ID; + vars.apeToken = vars.bayc; + vars.nApe = vars.nBayc; + vars.positionCap = vars.baycMatchedCap; + } else { + vars.apeStakingPoolId = ApeStakingCommonLogic.MAYC_POOL_ID; + vars.apeToken = vars.mayc; + vars.nApe = vars.nMayc; + vars.positionCap = vars.maycMatchedCap; + } + + vars.nApeOwner = ApeStakingCommonLogic.claimPendingReward( + poolState, + vars, + isBAYC + ? ApeStakingCommonLogic.BAYC_BAKC_PAIR_POOL_ID + : ApeStakingCommonLogic.MAYC_BAKC_PAIR_POOL_ID, + vars.nApe, + false, + apeTokenIds + ); + + ApeCoinStaking.SingleNft[] + memory _nfts = new ApeCoinStaking.SingleNft[](arrayLength); + ApeCoinStaking.PairNftWithdrawWithAmount[] + memory _nftPairs = new ApeCoinStaking.PairNftWithdrawWithAmount[]( + arrayLength + ); + uint24 stakingPair = 0; + for (uint256 index = 0; index < arrayLength; index++) { + uint32 apeTokenId = apeTokenIds[index]; + uint32 bakcTokenId = bakcTokenIds[index]; + + //check ntoken owner + { + if (vars.nApeOwner != msg.sender) { + address nBakcOwner = IERC721(vars.nBakc).ownerOf( + bakcTokenId + ); + require(msg.sender == nBakcOwner, Errors.NOT_THE_OWNER); + } + } + + // check pair status + require( + poolState.tokenStatus[apeTokenId].bakcTokenId == bakcTokenId, + Errors.NOT_PAIRED_APE_AND_BAKC + ); + + // update pair status + delete poolState.tokenStatus[apeTokenId]; + + // we only need to check pair staking position + (, vars.isPaired) = vars.apeCoinStaking.mainToBakc( + vars.apeStakingPoolId, + apeTokenId + ); + if (vars.isPaired) { + _nfts[stakingPair] = ApeCoinStaking.SingleNft({ + tokenId: apeTokenId, + amount: vars.positionCap.toUint224() + }); + + _nftPairs[stakingPair] = ApeCoinStaking + .PairNftWithdrawWithAmount({ + mainTokenId: apeTokenId, + bakcTokenId: bakcTokenId, + amount: vars.bakcMatchedCap.toUint184(), + isUncommit: true + }); + stakingPair++; + } + } + + //update state + poolState.totalPosition -= arrayLength.toUint24(); + + //withdraw from ApeCoinStaking and compound + if (stakingPair > 0) { + poolState.stakingPosition -= stakingPair; + + assembly { + mstore(_nfts, stakingPair) + } + assembly { + mstore(_nftPairs, stakingPair) + } + + vars.balanceBefore = IERC20(vars.apeCoin).balanceOf(address(this)); + ApeCoinStaking.PairNftWithdrawWithAmount[] + memory _otherPairs = new ApeCoinStaking.PairNftWithdrawWithAmount[]( + 0 + ); + if (isBAYC) { + vars.apeCoinStaking.withdrawSelfBAYC(_nfts); + vars.apeCoinStaking.withdrawBAKC(_nftPairs, _otherPairs); + } else { + vars.apeCoinStaking.withdrawSelfMAYC(_nfts); + vars.apeCoinStaking.withdrawBAKC(_otherPairs, _nftPairs); + } + vars.balanceAfter = IERC20(vars.apeCoin).balanceOf(address(this)); + vars.totalClaimedApe = vars.balanceAfter - vars.balanceBefore; + IAutoCompoundApe(vars.cApe).deposit( + address(this), + vars.totalClaimedApe + ); + + vars.latestBorrowIndex = IPool(vars.pool) + .getReserveNormalizedVariableDebt(vars.cApe); + (vars.totalRepay, vars.totalCompoundFee) = ApeStakingCommonLogic + .calculateRepayAndCompound( + poolState, + vars, + vars.positionCap + vars.bakcMatchedCap + ); + + if (vars.totalRepay > 0) { + IPool(vars.pool).repay( + vars.cApe, + vars.totalRepay, + address(this) + ); + } + if (vars.totalCompoundFee > 0) { + cApeShareBalance[address(this)] += vars.totalCompoundFee; + } + } + + //transfer ape and BAKC back to nToken + for (uint256 index = 0; index < arrayLength; index++) { + uint32 apeTokenId = apeTokenIds[index]; + uint32 bakcTokenId = bakcTokenIds[index]; + + IERC721(vars.apeToken).safeTransferFrom( + address(this), + vars.nApe, + apeTokenId + ); + IERC721(vars.bakc).safeTransferFrom( + address(this), + vars.nBakc, + bakcTokenId + ); + + //emit event + emit PairNFTWithdrew(isBAYC, apeTokenId, bakcTokenId); + } + } + + function compoundPairNFT( + IParaApeStaking.PoolState storage poolState, + mapping(address => uint256) storage cApeShareBalance, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + bool isBAYC, + uint32[] calldata apeTokenIds, + uint32[] calldata bakcTokenIds + ) external { + uint256 arrayLength = apeTokenIds.length; + require( + arrayLength == bakcTokenIds.length && arrayLength > 0, + Errors.INVALID_PARAMETER + ); + + uint256[] memory _nfts = new uint256[](arrayLength); + ApeCoinStaking.PairNft[] + memory _nftPairs = new ApeCoinStaking.PairNft[](arrayLength); + for (uint256 index = 0; index < arrayLength; index++) { + uint32 apeTokenId = apeTokenIds[index]; + uint32 bakcTokenId = bakcTokenIds[index]; + + // check pair status + IParaApeStaking.TokenStatus memory localTokenStatus = poolState + .tokenStatus[apeTokenId]; + require( + localTokenStatus.bakcTokenId == bakcTokenId && + localTokenStatus.isPaired, + Errors.NOT_PAIRED_APE_AND_BAKC + ); + + // construct staking data + _nfts[index] = apeTokenId; + _nftPairs[index] = ApeCoinStaking.PairNft({ + mainTokenId: apeTokenId, + bakcTokenId: bakcTokenId + }); + + //emit event + emit PairNFTCompounded(isBAYC, apeTokenId, bakcTokenId); + } + + vars.balanceBefore = IERC20(vars.apeCoin).balanceOf(address(this)); + //claim from ApeCoinStaking + { + ApeCoinStaking.PairNft[] + memory _otherPairs = new ApeCoinStaking.PairNft[](0); + if (isBAYC) { + vars.apeCoinStaking.claimSelfBAYC(_nfts); + vars.apeCoinStaking.claimSelfBAKC(_nftPairs, _otherPairs); + } else { + vars.apeCoinStaking.claimSelfMAYC(_nfts); + vars.apeCoinStaking.claimSelfBAKC(_otherPairs, _nftPairs); + } + } + vars.balanceAfter = IERC20(vars.apeCoin).balanceOf(address(this)); + vars.totalClaimedApe = vars.balanceAfter - vars.balanceBefore; + IAutoCompoundApe(vars.cApe).deposit( + address(this), + vars.totalClaimedApe + ); + + //repay and compound + vars.positionCap = isBAYC ? vars.baycMatchedCap : vars.maycMatchedCap; + vars.latestBorrowIndex = IPool(vars.pool) + .getReserveNormalizedVariableDebt(vars.cApe); + (vars.totalRepay, vars.totalCompoundFee) = ApeStakingCommonLogic + .calculateRepayAndCompound( + poolState, + vars, + vars.positionCap + vars.bakcMatchedCap + ); + + if (vars.totalRepay > 0) { + IPool(vars.pool).repay(vars.cApe, vars.totalRepay, address(this)); + } + if (vars.totalCompoundFee > 0) { + cApeShareBalance[address(this)] += vars.totalCompoundFee; + } + } +} diff --git a/contracts/apestaking/logic/ApeStakingSinglePoolLogic.sol b/contracts/apestaking/logic/ApeStakingSinglePoolLogic.sol new file mode 100644 index 000000000..b5f8e6f3c --- /dev/null +++ b/contracts/apestaking/logic/ApeStakingSinglePoolLogic.sol @@ -0,0 +1,807 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.0; + +import {IPool} from "../../interfaces/IPool.sol"; +import "../../interfaces/IParaApeStaking.sol"; +import {IERC20, SafeERC20} from "../../dependencies/openzeppelin/contracts/SafeERC20.sol"; +import "../../dependencies/yoga-labs/ApeCoinStaking.sol"; +import {PercentageMath} from "../../protocol/libraries/math/PercentageMath.sol"; +import "../../interfaces/IAutoCompoundApe.sol"; +import "../../interfaces/ICApe.sol"; +import "../../dependencies/openzeppelin/contracts/SafeCast.sol"; +import {WadRayMath} from "../../protocol/libraries/math/WadRayMath.sol"; +import "./ApeStakingCommonLogic.sol"; +import "../../protocol/libraries/helpers/Errors.sol"; + +/** + * @title ApeStakingSinglePoolLogic library + * + * @notice Implements the base logic for ape staking vault + */ +library ApeStakingSinglePoolLogic { + using PercentageMath for uint256; + using SafeCast for uint256; + using SafeERC20 for IERC20; + using WadRayMath for uint256; + + event NFTDeposited(address nft, uint256 tokenId); + event ApeStaked(bool isBAYC, uint256 tokenId); + event BakcStaked(bool isBAYC, uint256 apeTokenId, uint256 bakcTokenId); + event ApeCompounded(bool isBAYC, uint256 tokenId); + event BakcCompounded(bool isBAYC, uint256 apeTokenId, uint256 bakcTokenId); + event NFTWithdrawn(address nft, uint256 tokenId); + + function depositNFT( + IParaApeStaking.PoolState storage poolState, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + address nft, + uint32[] calldata tokenIds + ) external { + uint256 arrayLength = tokenIds.length; + require(arrayLength > 0, Errors.INVALID_PARAMETER); + + address nToken; + uint256 apeStakingPoolId; + if (nft == vars.bayc) { + nToken = vars.nBayc; + apeStakingPoolId = ApeStakingCommonLogic.BAYC_POOL_ID; + } else if (nft == vars.mayc) { + nToken = vars.nMayc; + apeStakingPoolId = ApeStakingCommonLogic.MAYC_POOL_ID; + } else { + nToken = vars.nBakc; + apeStakingPoolId = ApeStakingCommonLogic.BAKC_POOL_ID; + } + address msgSender = msg.sender; + uint128 accumulatedRewardsPerNft = poolState.accumulatedRewardsPerNft; + for (uint256 index = 0; index < arrayLength; index++) { + uint32 tokenId = tokenIds[index]; + + require( + msgSender == IERC721(nToken).ownerOf(tokenId), + Errors.NOT_THE_OWNER + ); + + (uint256 stakedAmount, ) = vars.apeCoinStaking.nftPosition( + apeStakingPoolId, + tokenId + ); + require(stakedAmount == 0, Errors.APE_POSITION_EXISTED); + if (nft != vars.bakc) { + (, bool isPaired) = vars.apeCoinStaking.mainToBakc( + apeStakingPoolId, + tokenId + ); + require(!isPaired, Errors.PAIR_POSITION_EXISTED); + } + + IERC721(nft).safeTransferFrom(nToken, address(this), tokenId); + + //update token status + poolState.tokenStatus[tokenId] = IParaApeStaking.TokenStatus({ + rewardsDebt: accumulatedRewardsPerNft, + isInPool: true, + bakcTokenId: 0, + isPaired: false + }); + + //emit event + emit NFTDeposited(nft, tokenId); + } + + //update state + poolState.totalPosition += arrayLength.toUint24(); + } + + function stakingApe( + IParaApeStaking.PoolState storage poolState, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + bool isBAYC, + uint32[] calldata tokenIds + ) external { + uint256 arrayLength = tokenIds.length; + require(arrayLength > 0, Errors.INVALID_PARAMETER); + + ApeCoinStaking.SingleNft[] + memory _nfts = new ApeCoinStaking.SingleNft[](arrayLength); + uint256 positionCap = isBAYC + ? vars.baycMatchedCap + : vars.maycMatchedCap; + for (uint256 index = 0; index < arrayLength; index++) { + uint32 tokenId = tokenIds[index]; + + require( + poolState.tokenStatus[tokenId].isInPool, + Errors.NFT_NOT_IN_POOL + ); + + // construct staking data + _nfts[index] = ApeCoinStaking.SingleNft({ + tokenId: tokenId, + amount: positionCap.toUint224() + }); + + //emit event + emit ApeStaked(isBAYC, tokenId); + } + + // prepare Ape coin + uint256 totalBorrow = positionCap * arrayLength; + uint256 cApeDebtShare = ApeStakingCommonLogic.borrowCApeFromPool( + vars, + totalBorrow + ); + poolState.cApeDebtShare += cApeDebtShare.toUint104(); + + //stake in ApeCoinStaking + if (isBAYC) { + vars.apeCoinStaking.depositBAYC(_nfts); + } else { + vars.apeCoinStaking.depositMAYC(_nfts); + } + + poolState.stakingPosition += arrayLength.toUint24(); + } + + function stakingBAKC( + mapping(uint256 => IParaApeStaking.PoolState) storage poolStates, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + IParaApeStaking.BAKCPairActionInfo calldata actionInfo + ) external { + _validateBAKCPairActionInfo(actionInfo); + uint256 baycArrayLength = actionInfo.baycTokenIds.length; + uint256 maycArrayLength = actionInfo.maycTokenIds.length; + + ApeCoinStaking.PairNftDepositWithAmount[] + memory _baycPairs = new ApeCoinStaking.PairNftDepositWithAmount[]( + baycArrayLength + ); + ApeCoinStaking.PairNftDepositWithAmount[] + memory _maycPairs = new ApeCoinStaking.PairNftDepositWithAmount[]( + maycArrayLength + ); + IParaApeStaking.PoolState storage bakcPoolState = poolStates[ + ApeStakingCommonLogic.BAKC_SINGLE_POOL_ID + ]; + for (uint256 index = 0; index < baycArrayLength; index++) { + uint32 apeTokenId = actionInfo.baycTokenIds[index]; + uint32 bakcTokenId = actionInfo.bakcPairBaycTokenIds[index]; + + IParaApeStaking.PoolState storage baycPoolState = poolStates[ + ApeStakingCommonLogic.BAYC_SINGLE_POOL_ID + ]; + + require( + baycPoolState.tokenStatus[apeTokenId].isInPool, + Errors.NFT_NOT_IN_POOL + ); + require( + bakcPoolState.tokenStatus[bakcTokenId].isInPool, + Errors.NFT_NOT_IN_POOL + ); + + // construct staking data + _baycPairs[index] = ApeCoinStaking.PairNftDepositWithAmount({ + mainTokenId: apeTokenId, + bakcTokenId: bakcTokenId, + amount: vars.bakcMatchedCap.toUint184() + }); + + //emit event + emit BakcStaked(true, apeTokenId, bakcTokenId); + } + + for (uint256 index = 0; index < maycArrayLength; index++) { + uint32 apeTokenId = actionInfo.maycTokenIds[index]; + uint32 bakcTokenId = actionInfo.bakcPairMaycTokenIds[index]; + + IParaApeStaking.PoolState storage maycPoolState = poolStates[ + ApeStakingCommonLogic.MAYC_SINGLE_POOL_ID + ]; + + require( + maycPoolState.tokenStatus[apeTokenId].isInPool, + Errors.NFT_NOT_IN_POOL + ); + require( + bakcPoolState.tokenStatus[bakcTokenId].isInPool, + Errors.NFT_NOT_IN_POOL + ); + + // construct staking data + _maycPairs[index] = ApeCoinStaking.PairNftDepositWithAmount({ + mainTokenId: apeTokenId, + bakcTokenId: bakcTokenId, + amount: vars.bakcMatchedCap.toUint184() + }); + + //emit event + emit BakcStaked(false, apeTokenId, bakcTokenId); + } + + // prepare Ape coin + uint256 totalBorrow = vars.bakcMatchedCap * + (baycArrayLength + maycArrayLength); + uint256 cApeDebtShare = ApeStakingCommonLogic.borrowCApeFromPool( + vars, + totalBorrow + ); + + //stake in ApeCoinStaking + vars.apeCoinStaking.depositBAKC(_baycPairs, _maycPairs); + + //update bakc pool state + bakcPoolState.stakingPosition += (baycArrayLength + maycArrayLength) + .toUint24(); + bakcPoolState.cApeDebtShare += cApeDebtShare.toUint104(); + } + + function compoundApe( + IParaApeStaking.PoolState storage poolState, + mapping(address => uint256) storage cApeShareBalance, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + bool isBAYC, + uint32[] calldata tokenIds + ) external { + uint256 arrayLength = tokenIds.length; + require(arrayLength > 0, Errors.INVALID_PARAMETER); + + uint256[] memory _nfts = new uint256[](arrayLength); + for (uint256 index = 0; index < arrayLength; index++) { + uint32 tokenId = tokenIds[index]; + + require( + poolState.tokenStatus[tokenId].isInPool, + Errors.NFT_NOT_IN_POOL + ); + + // construct staking data + _nfts[index] = tokenId; + + //emit event + emit ApeCompounded(isBAYC, tokenId); + } + + vars.balanceBefore = IERC20(vars.apeCoin).balanceOf(address(this)); + //claim from ApeCoinStaking + if (isBAYC) { + vars.apeCoinStaking.claimSelfBAYC(_nfts); + vars.positionCap = vars.baycMatchedCap; + } else { + vars.apeCoinStaking.claimSelfMAYC(_nfts); + vars.positionCap = vars.maycMatchedCap; + } + vars.balanceAfter = IERC20(vars.apeCoin).balanceOf(address(this)); + vars.totalClaimedApe = vars.balanceAfter - vars.balanceBefore; + IAutoCompoundApe(vars.cApe).deposit( + address(this), + vars.totalClaimedApe + ); + + //repay and compound + vars.latestBorrowIndex = IPool(vars.pool) + .getReserveNormalizedVariableDebt(vars.cApe); + (vars.totalRepay, vars.totalCompoundFee) = ApeStakingCommonLogic + .calculateRepayAndCompound(poolState, vars, vars.positionCap); + + if (vars.totalRepay > 0) { + IPool(vars.pool).repay(vars.cApe, vars.totalRepay, address(this)); + } + if (vars.totalCompoundFee > 0) { + cApeShareBalance[address(this)] += vars.totalCompoundFee; + } + } + + function compoundBAKC( + mapping(uint256 => IParaApeStaking.PoolState) storage poolStates, + mapping(address => uint256) storage cApeShareBalance, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + IParaApeStaking.BAKCPairActionInfo calldata actionInfo + ) external { + _validateBAKCPairActionInfo(actionInfo); + uint256 baycArrayLength = actionInfo.baycTokenIds.length; + uint256 maycArrayLength = actionInfo.maycTokenIds.length; + + ApeCoinStaking.PairNft[] + memory _baycPairs = new ApeCoinStaking.PairNft[](baycArrayLength); + ApeCoinStaking.PairNft[] + memory _maycPairs = new ApeCoinStaking.PairNft[](maycArrayLength); + IParaApeStaking.PoolState storage bakcPoolState = poolStates[ + ApeStakingCommonLogic.BAKC_SINGLE_POOL_ID + ]; + + for (uint256 index = 0; index < baycArrayLength; index++) { + uint32 apeTokenId = actionInfo.baycTokenIds[index]; + uint32 bakcTokenId = actionInfo.bakcPairBaycTokenIds[index]; + + // we just need to check bakc is in the pool + require( + bakcPoolState.tokenStatus[bakcTokenId].isInPool, + Errors.NFT_NOT_IN_POOL + ); + + // construct staking data + _baycPairs[index] = ApeCoinStaking.PairNft({ + mainTokenId: apeTokenId, + bakcTokenId: bakcTokenId + }); + + //emit event + emit BakcCompounded(true, apeTokenId, bakcTokenId); + } + + for (uint256 index = 0; index < maycArrayLength; index++) { + uint32 apeTokenId = actionInfo.maycTokenIds[index]; + uint32 bakcTokenId = actionInfo.bakcPairMaycTokenIds[index]; + + // we just need to check bakc is in the pool + require( + bakcPoolState.tokenStatus[bakcTokenId].isInPool, + Errors.NFT_NOT_IN_POOL + ); + + // construct staking data + _maycPairs[index] = ApeCoinStaking.PairNft({ + mainTokenId: apeTokenId, + bakcTokenId: bakcTokenId + }); + + //emit event + emit BakcCompounded(false, apeTokenId, bakcTokenId); + } + + vars.balanceBefore = IERC20(vars.apeCoin).balanceOf(address(this)); + vars.apeCoinStaking.claimSelfBAKC(_baycPairs, _maycPairs); + vars.balanceAfter = IERC20(vars.apeCoin).balanceOf(address(this)); + vars.totalClaimedApe = vars.balanceAfter - vars.balanceBefore; + IAutoCompoundApe(vars.cApe).deposit( + address(this), + vars.totalClaimedApe + ); + + //repay and compound + vars.latestBorrowIndex = IPool(vars.pool) + .getReserveNormalizedVariableDebt(vars.cApe); + ( + vars.totalRepay, + vars.totalCompoundFee + ) = _calculateRepayAndCompoundBAKC(poolStates, vars); + + if (vars.totalRepay > 0) { + IPool(vars.pool).repay(vars.cApe, vars.totalRepay, address(this)); + } + if (vars.totalCompoundFee > 0) { + cApeShareBalance[address(this)] += vars.totalCompoundFee; + } + } + + function withdrawNFT( + mapping(uint256 => IParaApeStaking.PoolState) storage poolStates, + mapping(address => uint256) storage cApeShareBalance, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + address nft, + uint32[] calldata tokenIds + ) external { + uint256 arrayLength = tokenIds.length; + require(arrayLength > 0, Errors.INVALID_PARAMETER); + + uint256 poolId; + address nToken; + if (nft == vars.bayc) { + poolId = ApeStakingCommonLogic.BAYC_SINGLE_POOL_ID; + nToken = vars.nBayc; + } else if (nft == vars.mayc) { + poolId = ApeStakingCommonLogic.MAYC_SINGLE_POOL_ID; + nToken = vars.nMayc; + } else { + poolId = ApeStakingCommonLogic.BAKC_SINGLE_POOL_ID; + nToken = vars.nBakc; + } + + //claim pending reward + IParaApeStaking.PoolState storage poolState = poolStates[poolId]; + address nApeOwner = ApeStakingCommonLogic.claimPendingReward( + poolState, + vars, + poolId, + nToken, + false, + tokenIds + ); + if (nft == vars.bayc) { + _unstakeApe(poolStates, cApeShareBalance, vars, true, tokenIds); + } else if (nft == vars.mayc) { + _unstakeApe(poolStates, cApeShareBalance, vars, false, tokenIds); + } else { + _unstakeBAKC(poolStates, cApeShareBalance, vars, tokenIds); + } + + //transfer nft back to nToken + require(msg.sender == nApeOwner, Errors.NOT_THE_OWNER); + for (uint256 index = 0; index < arrayLength; index++) { + uint32 tokenId = tokenIds[index]; + + delete poolState.tokenStatus[tokenId]; + + IERC721(nft).safeTransferFrom(address(this), nToken, tokenId); + + //emit event + emit NFTWithdrawn(nft, tokenId); + } + } + + function tryClaimNFT( + IParaApeStaking.PoolState storage poolState, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + uint256 poolId, + address nft, + uint32[] calldata tokenIds + ) external { + ApeStakingCommonLogic.validateTokenIdArray(tokenIds); + + uint256 arrayLength = tokenIds.length; + uint32[] memory singlePoolTokenIds = new uint32[](arrayLength); + uint256 singlePoolCount = 0; + + for (uint256 index = 0; index < arrayLength; index++) { + uint32 tokenId = tokenIds[index]; + if (poolState.tokenStatus[tokenId].isInPool) { + singlePoolTokenIds[singlePoolCount] = tokenId; + singlePoolCount++; + } + } + + if (singlePoolCount > 0) { + assembly { + mstore(singlePoolTokenIds, singlePoolCount) + } + + address nToken = (nft == vars.bayc) + ? vars.nBayc + : (nft == vars.mayc) + ? vars.nMayc + : vars.nBakc; + + ApeStakingCommonLogic.claimPendingReward( + poolState, + vars, + poolId, + nToken, + true, + singlePoolTokenIds + ); + } + } + + function _unstakeApe( + mapping(uint256 => IParaApeStaking.PoolState) storage poolStates, + mapping(address => uint256) storage cApeShareBalance, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + bool isBAYC, + uint32[] calldata tokenIds + ) internal { + IParaApeStaking.PoolState storage apePoolState; + if (isBAYC) { + vars.apeStakingPoolId = ApeStakingCommonLogic.BAYC_POOL_ID; + vars.positionCap = vars.baycMatchedCap; + apePoolState = poolStates[ + ApeStakingCommonLogic.BAYC_SINGLE_POOL_ID + ]; + } else { + vars.apeStakingPoolId = ApeStakingCommonLogic.MAYC_POOL_ID; + vars.positionCap = vars.maycMatchedCap; + apePoolState = poolStates[ + ApeStakingCommonLogic.MAYC_SINGLE_POOL_ID + ]; + } + apePoolState.totalPosition -= tokenIds.length.toUint24(); + + ApeCoinStaking.SingleNft[] + memory _nfts = new ApeCoinStaking.SingleNft[](tokenIds.length); + ApeCoinStaking.PairNftWithdrawWithAmount[] + memory _nftPairs = new ApeCoinStaking.PairNftWithdrawWithAmount[]( + tokenIds.length + ); + uint24 singleStakingCount; + uint24 pairStakingCount; + for (uint256 index = 0; index < tokenIds.length; index++) { + uint32 tokenId = tokenIds[index]; + + //check ape position + { + (uint256 stakedAmount, ) = vars.apeCoinStaking.nftPosition( + vars.apeStakingPoolId, + tokenId + ); + if (stakedAmount > 0) { + _nfts[singleStakingCount] = ApeCoinStaking.SingleNft({ + tokenId: tokenId, + amount: vars.positionCap.toUint224() + }); + singleStakingCount++; + } + } + + //check bakc position + { + (uint256 bakcTokenId, bool isPaired) = vars + .apeCoinStaking + .mainToBakc(vars.apeStakingPoolId, tokenId); + if (isPaired) { + _nftPairs[pairStakingCount] = ApeCoinStaking + .PairNftWithdrawWithAmount({ + mainTokenId: tokenId, + bakcTokenId: bakcTokenId.toUint32(), + amount: vars.bakcMatchedCap.toUint184(), + isUncommit: true + }); + pairStakingCount++; + } + } + } + + if (singleStakingCount > 0 || pairStakingCount > 0) { + vars.latestBorrowIndex = IPool(vars.pool) + .getReserveNormalizedVariableDebt(vars.cApe); + } + uint256 totalClaimed = 0; + if (singleStakingCount > 0) { + assembly { + mstore(_nfts, singleStakingCount) + } + apePoolState.stakingPosition -= singleStakingCount; + + vars.balanceBefore = IERC20(vars.apeCoin).balanceOf(address(this)); + if (isBAYC) { + vars.apeCoinStaking.withdrawBAYC(_nfts, address(this)); + } else { + vars.apeCoinStaking.withdrawMAYC(_nfts, address(this)); + } + vars.balanceAfter = IERC20(vars.apeCoin).balanceOf(address(this)); + vars.totalClaimedApe = vars.balanceAfter - vars.balanceBefore; + totalClaimed += vars.totalClaimedApe; + + (vars.totalRepay, vars.totalCompoundFee) = ApeStakingCommonLogic + .calculateRepayAndCompound( + apePoolState, + vars, + vars.positionCap + ); + } + + if (pairStakingCount > 0) { + assembly { + mstore(_nftPairs, pairStakingCount) + } + poolStates[ApeStakingCommonLogic.BAKC_SINGLE_POOL_ID] + .stakingPosition -= pairStakingCount; + + vars.balanceBefore = IERC20(vars.apeCoin).balanceOf(address(this)); + ApeCoinStaking.PairNftWithdrawWithAmount[] + memory _otherPairs = new ApeCoinStaking.PairNftWithdrawWithAmount[]( + 0 + ); + if (isBAYC) { + vars.apeCoinStaking.withdrawBAKC(_nftPairs, _otherPairs); + } else { + vars.apeCoinStaking.withdrawBAKC(_otherPairs, _nftPairs); + } + vars.balanceAfter = IERC20(vars.apeCoin).balanceOf(address(this)); + vars.totalClaimedApe = vars.balanceAfter - vars.balanceBefore; + totalClaimed += vars.totalClaimedApe; + + ( + uint256 bakcTotalRepay, + uint256 bakcCompoundFee + ) = _calculateRepayAndCompoundBAKC(poolStates, vars); + vars.totalRepay += bakcTotalRepay; + vars.totalCompoundFee += bakcCompoundFee; + } + + if (totalClaimed > 0) { + IAutoCompoundApe(vars.cApe).deposit(address(this), totalClaimed); + } + if (vars.totalRepay > 0) { + IPool(vars.pool).repay(vars.cApe, vars.totalRepay, address(this)); + } + if (vars.totalCompoundFee > 0) { + cApeShareBalance[address(this)] += vars.totalCompoundFee; + } + } + + function _unstakeBAKC( + mapping(uint256 => IParaApeStaking.PoolState) storage poolStates, + mapping(address => uint256) storage cApeShareBalance, + IParaApeStaking.ApeStakingVaultCacheVars memory vars, + uint32[] calldata tokenIds + ) internal { + uint256 arrayLength = tokenIds.length; + IParaApeStaking.PoolState storage bakcPoolState = poolStates[ + ApeStakingCommonLogic.BAKC_SINGLE_POOL_ID + ]; + bakcPoolState.totalPosition -= arrayLength.toUint24(); + ApeCoinStaking.PairNftWithdrawWithAmount[] + memory baycPair = new ApeCoinStaking.PairNftWithdrawWithAmount[]( + arrayLength + ); + ApeCoinStaking.PairNftWithdrawWithAmount[] + memory maycPair = new ApeCoinStaking.PairNftWithdrawWithAmount[]( + arrayLength + ); + uint24 baycPairCount; + uint24 maycPairCount; + for (uint256 index = 0; index < arrayLength; index++) { + uint32 tokenId = tokenIds[index]; + + (uint256 mainTokenId, bool isPaired) = vars + .apeCoinStaking + .bakcToMain(tokenId, ApeStakingCommonLogic.BAYC_POOL_ID); + if (isPaired) { + baycPair[baycPairCount] = ApeCoinStaking + .PairNftWithdrawWithAmount({ + mainTokenId: mainTokenId.toUint32(), + bakcTokenId: tokenId, + amount: vars.bakcMatchedCap.toUint184(), + isUncommit: true + }); + baycPairCount++; + continue; + } + + (mainTokenId, isPaired) = vars.apeCoinStaking.bakcToMain( + tokenId, + ApeStakingCommonLogic.MAYC_POOL_ID + ); + if (isPaired) { + maycPair[maycPairCount] = ApeCoinStaking + .PairNftWithdrawWithAmount({ + mainTokenId: mainTokenId.toUint32(), + bakcTokenId: tokenId, + amount: vars.bakcMatchedCap.toUint184(), + isUncommit: true + }); + maycPairCount++; + continue; + } + } + + if (baycPairCount > 0 || maycPairCount > 0) { + assembly { + mstore(baycPair, baycPairCount) + } + assembly { + mstore(maycPair, maycPairCount) + } + + vars.latestBorrowIndex = IPool(vars.pool) + .getReserveNormalizedVariableDebt(vars.cApe); + + bakcPoolState.stakingPosition -= (baycPairCount + maycPairCount); + + vars.balanceBefore = IERC20(vars.apeCoin).balanceOf(address(this)); + vars.apeCoinStaking.withdrawBAKC(baycPair, maycPair); + vars.balanceAfter = IERC20(vars.apeCoin).balanceOf(address(this)); + vars.totalClaimedApe = vars.balanceAfter - vars.balanceBefore; + IAutoCompoundApe(vars.cApe).deposit( + address(this), + vars.totalClaimedApe + ); + + ( + vars.totalRepay, + vars.totalCompoundFee + ) = _calculateRepayAndCompoundBAKC(poolStates, vars); + + if (vars.totalRepay > 0) { + IPool(vars.pool).repay( + vars.cApe, + vars.totalRepay, + address(this) + ); + } + if (vars.totalCompoundFee > 0) { + cApeShareBalance[address(this)] += vars.totalCompoundFee; + } + } + } + + function _calculateRepayAndCompoundBAKC( + mapping(uint256 => IParaApeStaking.PoolState) storage poolStates, + IParaApeStaking.ApeStakingVaultCacheVars memory vars + ) internal returns (uint256, uint256) { + if (vars.cApeExchangeRate == 0) { + vars.cApeExchangeRate = ICApe(vars.cApe).getPooledApeByShares( + WadRayMath.RAY + ); + } + + IParaApeStaking.PoolState storage bakcPoolState = poolStates[ + ApeStakingCommonLogic.BAKC_SINGLE_POOL_ID + ]; + uint256 cApeDebtShare = bakcPoolState.cApeDebtShare; + uint256 debtInterest = ApeStakingCommonLogic + .calculateCurrentPositionDebtInterest( + cApeDebtShare, + bakcPoolState.stakingPosition, + vars.bakcMatchedCap, + vars.cApeExchangeRate, + vars.latestBorrowIndex + ); + uint256 repayAmount = (debtInterest >= vars.totalClaimedApe) + ? vars.totalClaimedApe + : debtInterest; + cApeDebtShare -= repayAmount.rayDiv(vars.latestBorrowIndex).rayDiv( + vars.cApeExchangeRate + ); + bakcPoolState.cApeDebtShare = cApeDebtShare.toUint104(); + uint256 compoundFee = 0; + if (vars.totalClaimedApe > debtInterest) { + //update reward index + uint256 shareRewardAmount = (vars.totalClaimedApe - debtInterest) + .rayDiv(vars.cApeExchangeRate); + compoundFee = shareRewardAmount.percentMul(vars.compoundFee); + shareRewardAmount -= compoundFee; + + uint256 apeShareAmount = shareRewardAmount.percentMul( + vars.apeRewardRatio + ); + + IParaApeStaking.PoolState storage baycPoolState = poolStates[ + ApeStakingCommonLogic.BAYC_SINGLE_POOL_ID + ]; + IParaApeStaking.PoolState storage maycPoolState = poolStates[ + ApeStakingCommonLogic.MAYC_SINGLE_POOL_ID + ]; + uint24 baycPositon = baycPoolState.totalPosition; + uint24 maycPositon = maycPoolState.totalPosition; + uint24 apeTotalPosition = baycPositon + maycPositon; + if (apeTotalPosition != 0) { + uint256 baycShareAmount = (apeShareAmount * baycPositon) / + apeTotalPosition; + uint256 maycShareAmount = apeShareAmount - baycShareAmount; + if (baycPositon != 0) { + baycPoolState.accumulatedRewardsPerNft += + baycShareAmount.toUint104() / + baycPositon; + } + if (maycPositon != 0) { + maycPoolState.accumulatedRewardsPerNft += + maycShareAmount.toUint104() / + maycPositon; + } + } else { + compoundFee += apeShareAmount; + } + uint104 bakcTotalPosition = bakcPoolState.totalPosition; + shareRewardAmount -= apeShareAmount; + if (bakcTotalPosition != 0) { + bakcPoolState.accumulatedRewardsPerNft += + shareRewardAmount.toUint104() / + bakcTotalPosition; + } else { + compoundFee += shareRewardAmount; + } + } + + return (repayAmount, compoundFee); + } + + function _validateBAKCPairActionInfo( + IParaApeStaking.BAKCPairActionInfo calldata actionInfo + ) internal pure { + uint256 baycArrayLength = actionInfo.baycTokenIds.length; + uint256 maycArrayLength = actionInfo.maycTokenIds.length; + require( + baycArrayLength == actionInfo.bakcPairBaycTokenIds.length, + Errors.INVALID_PARAMETER + ); + require( + maycArrayLength == actionInfo.bakcPairMaycTokenIds.length, + Errors.INVALID_PARAMETER + ); + require( + baycArrayLength > 0 || maycArrayLength > 0, + Errors.INVALID_PARAMETER + ); + } +} diff --git a/contracts/dependencies/benddao/contracts/interfaces/ILendPool.sol b/contracts/dependencies/benddao/contracts/interfaces/ILendPool.sol index c532ba21c..8cf158ff0 100644 --- a/contracts/dependencies/benddao/contracts/interfaces/ILendPool.sol +++ b/contracts/dependencies/benddao/contracts/interfaces/ILendPool.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {BDaoDataTypes} from "../libraries/types/BDaoDataTypes.sol"; diff --git a/contracts/dependencies/benddao/contracts/interfaces/ILendPoolLoan.sol b/contracts/dependencies/benddao/contracts/interfaces/ILendPoolLoan.sol index 0e46a61f9..58bf44161 100644 --- a/contracts/dependencies/benddao/contracts/interfaces/ILendPoolLoan.sol +++ b/contracts/dependencies/benddao/contracts/interfaces/ILendPoolLoan.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {BDaoDataTypes} from "../libraries/types/BDaoDataTypes.sol"; diff --git a/contracts/dependencies/benddao/contracts/libraries/types/BDaoDataTypes.sol b/contracts/dependencies/benddao/contracts/libraries/types/BDaoDataTypes.sol index d278655b4..f6dc63e16 100644 --- a/contracts/dependencies/benddao/contracts/libraries/types/BDaoDataTypes.sol +++ b/contracts/dependencies/benddao/contracts/libraries/types/BDaoDataTypes.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; library BDaoDataTypes { struct ReserveData { diff --git a/contracts/dependencies/benddao/contracts/libraries/types/ConfigTypes.sol b/contracts/dependencies/benddao/contracts/libraries/types/ConfigTypes.sol index 6e10428b9..d42f57e56 100644 --- a/contracts/dependencies/benddao/contracts/libraries/types/ConfigTypes.sol +++ b/contracts/dependencies/benddao/contracts/libraries/types/ConfigTypes.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; library ConfigTypes { struct InitReserveInput { diff --git a/contracts/dependencies/blur-exchange/BlurExchange.sol b/contracts/dependencies/blur-exchange/BlurExchange.sol index 351d2c4c7..c8a4e3178 100644 --- a/contracts/dependencies/blur-exchange/BlurExchange.sol +++ b/contracts/dependencies/blur-exchange/BlurExchange.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "../openzeppelin/upgradeability/Initializable.sol"; import "../openzeppelin/upgradeability/UUPSUpgradeable.sol"; diff --git a/contracts/dependencies/blur-exchange/EIP712.sol b/contracts/dependencies/blur-exchange/EIP712.sol index 4f91ca250..b1a8fc6e0 100644 --- a/contracts/dependencies/blur-exchange/EIP712.sol +++ b/contracts/dependencies/blur-exchange/EIP712.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {Order, Fee} from "./OrderStructs.sol"; diff --git a/contracts/dependencies/blur-exchange/ExecutionDelegate.sol b/contracts/dependencies/blur-exchange/ExecutionDelegate.sol index d1c794595..a8d925801 100644 --- a/contracts/dependencies/blur-exchange/ExecutionDelegate.sol +++ b/contracts/dependencies/blur-exchange/ExecutionDelegate.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "../openzeppelin/contracts/IERC20.sol"; import "../openzeppelin/contracts/IERC721.sol"; diff --git a/contracts/dependencies/blur-exchange/IBlurExchange.sol b/contracts/dependencies/blur-exchange/IBlurExchange.sol index 23a58aa83..58fd3c83b 100644 --- a/contracts/dependencies/blur-exchange/IBlurExchange.sol +++ b/contracts/dependencies/blur-exchange/IBlurExchange.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {Input, Order} from "./OrderStructs.sol"; import "./IExecutionDelegate.sol"; diff --git a/contracts/dependencies/blur-exchange/IExecutionDelegate.sol b/contracts/dependencies/blur-exchange/IExecutionDelegate.sol index fc6865ac7..318bc5b4c 100644 --- a/contracts/dependencies/blur-exchange/IExecutionDelegate.sol +++ b/contracts/dependencies/blur-exchange/IExecutionDelegate.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; interface IExecutionDelegate { function approveContract(address _contract) external; diff --git a/contracts/dependencies/blur-exchange/IMatchingPolicy.sol b/contracts/dependencies/blur-exchange/IMatchingPolicy.sol index f0159d99f..ee251d125 100644 --- a/contracts/dependencies/blur-exchange/IMatchingPolicy.sol +++ b/contracts/dependencies/blur-exchange/IMatchingPolicy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {Order, AssetType} from "./OrderStructs.sol"; diff --git a/contracts/dependencies/blur-exchange/IPolicyManager.sol b/contracts/dependencies/blur-exchange/IPolicyManager.sol index edd7d75fc..d5c34adf0 100644 --- a/contracts/dependencies/blur-exchange/IPolicyManager.sol +++ b/contracts/dependencies/blur-exchange/IPolicyManager.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; interface IPolicyManager { function addPolicy(address policy) external; diff --git a/contracts/dependencies/blur-exchange/MerkleVerifier.sol b/contracts/dependencies/blur-exchange/MerkleVerifier.sol index 0fcefb21c..781f91c1b 100644 --- a/contracts/dependencies/blur-exchange/MerkleVerifier.sol +++ b/contracts/dependencies/blur-exchange/MerkleVerifier.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title MerkleVerifier diff --git a/contracts/dependencies/blur-exchange/OrderStructs.sol b/contracts/dependencies/blur-exchange/OrderStructs.sol index 1a814a16e..8699841f9 100644 --- a/contracts/dependencies/blur-exchange/OrderStructs.sol +++ b/contracts/dependencies/blur-exchange/OrderStructs.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; enum Side { Buy, Sell } enum SignatureVersion { Single, Bulk } diff --git a/contracts/dependencies/blur-exchange/PolicyManager.sol b/contracts/dependencies/blur-exchange/PolicyManager.sol index 999042c53..1db62fa5f 100644 --- a/contracts/dependencies/blur-exchange/PolicyManager.sol +++ b/contracts/dependencies/blur-exchange/PolicyManager.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {Ownable} from "../openzeppelin/contracts/Ownable.sol"; import {EnumerableSet} from "../openzeppelin/contracts/EnumerableSet.sol"; diff --git a/contracts/dependencies/blur-exchange/StandardPolicyERC721.sol b/contracts/dependencies/blur-exchange/StandardPolicyERC721.sol index c1d6dd034..ec6063c30 100644 --- a/contracts/dependencies/blur-exchange/StandardPolicyERC721.sol +++ b/contracts/dependencies/blur-exchange/StandardPolicyERC721.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {Order, AssetType} from "./OrderStructs.sol"; import {IMatchingPolicy} from "./IMatchingPolicy.sol"; diff --git a/contracts/dependencies/chainlink/AggregatorInterface.sol b/contracts/dependencies/chainlink/AggregatorInterface.sol index 101f06e4e..3a6518dfb 100644 --- a/contracts/dependencies/chainlink/AggregatorInterface.sol +++ b/contracts/dependencies/chainlink/AggregatorInterface.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT // Chainlink Contracts v0.8 -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; interface AggregatorInterface { function latestAnswer() external view returns (int256); diff --git a/contracts/dependencies/chainlink/AggregatorV2V3Interface.sol b/contracts/dependencies/chainlink/AggregatorV2V3Interface.sol index 264adb1b2..2b115f5f0 100644 --- a/contracts/dependencies/chainlink/AggregatorV2V3Interface.sol +++ b/contracts/dependencies/chainlink/AggregatorV2V3Interface.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import "./AggregatorInterface.sol"; import "./AggregatorV3Interface.sol"; diff --git a/contracts/dependencies/chainlink/AggregatorV3Interface.sol b/contracts/dependencies/chainlink/AggregatorV3Interface.sol index 15dbfc28b..3007a2a0c 100644 --- a/contracts/dependencies/chainlink/AggregatorV3Interface.sol +++ b/contracts/dependencies/chainlink/AggregatorV3Interface.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; interface AggregatorV3Interface { function decimals() external view returns (uint8); diff --git a/contracts/dependencies/chainlink/ICLSynchronicityPriceAdapter.sol b/contracts/dependencies/chainlink/ICLSynchronicityPriceAdapter.sol index 4276a874f..aced8a023 100644 --- a/contracts/dependencies/chainlink/ICLSynchronicityPriceAdapter.sol +++ b/contracts/dependencies/chainlink/ICLSynchronicityPriceAdapter.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; interface ICLSynchronicityPriceAdapter { /** diff --git a/contracts/dependencies/delegation/DelegationRegistry.sol b/contracts/dependencies/delegation/DelegationRegistry.sol index f5d0c1028..b0c0bf73c 100644 --- a/contracts/dependencies/delegation/DelegationRegistry.sol +++ b/contracts/dependencies/delegation/DelegationRegistry.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import {IDelegationRegistry} from "./IDelegationRegistry.sol"; import {EnumerableSet} from "../openzeppelin/contracts/EnumerableSet.sol"; diff --git a/contracts/dependencies/delegation/IDelegationRegistry.sol b/contracts/dependencies/delegation/IDelegationRegistry.sol index ff5151f41..bf826b2c9 100644 --- a/contracts/dependencies/delegation/IDelegationRegistry.sol +++ b/contracts/dependencies/delegation/IDelegationRegistry.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; /** * @title An immutable registry contract to be deployed as a standalone primitive diff --git a/contracts/dependencies/erc721-collections/IMoonBird.sol b/contracts/dependencies/erc721-collections/IMoonBird.sol index 28ff8396a..b902c5e8c 100644 --- a/contracts/dependencies/erc721-collections/IMoonBird.sol +++ b/contracts/dependencies/erc721-collections/IMoonBird.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** @title MoonBirds contract interface diff --git a/contracts/dependencies/gnosis/contracts/GPv2SafeERC20.sol b/contracts/dependencies/gnosis/contracts/GPv2SafeERC20.sol index a022f13ab..2cc39842e 100644 --- a/contracts/dependencies/gnosis/contracts/GPv2SafeERC20.sol +++ b/contracts/dependencies/gnosis/contracts/GPv2SafeERC20.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: LGPL-3.0-or-later -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC20} from "../../openzeppelin/contracts/IERC20.sol"; diff --git a/contracts/dependencies/looksrare/contracts/interfaces/IWETH.sol b/contracts/dependencies/looksrare/contracts/interfaces/IWETH.sol index d0c981ecd..ad04b1544 100644 --- a/contracts/dependencies/looksrare/contracts/interfaces/IWETH.sol +++ b/contracts/dependencies/looksrare/contracts/interfaces/IWETH.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GNU -pragma solidity >=0.5.0; +pragma solidity ^0.8.0; interface IWETH { function deposit() external payable; diff --git a/contracts/dependencies/math/PRBMath.sol b/contracts/dependencies/math/PRBMath.sol index 26d9820e0..8433e7d59 100644 --- a/contracts/dependencies/math/PRBMath.sol +++ b/contracts/dependencies/math/PRBMath.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Unlicense -pragma solidity >=0.8.4; +pragma solidity ^0.8.0; /// @notice Emitted when the result overflows uint256. error PRBMath__MulDivFixedPointOverflow(uint256 prod1); diff --git a/contracts/dependencies/math/PRBMathSD59x18.sol b/contracts/dependencies/math/PRBMathSD59x18.sol index 3d8c351cb..87d24b6d2 100644 --- a/contracts/dependencies/math/PRBMathSD59x18.sol +++ b/contracts/dependencies/math/PRBMathSD59x18.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Unlicense -pragma solidity >=0.8.4; +pragma solidity ^0.8.0; import "./PRBMath.sol"; diff --git a/contracts/dependencies/math/PRBMathUD60x18.sol b/contracts/dependencies/math/PRBMathUD60x18.sol index c4a5b8456..70f4758a4 100644 --- a/contracts/dependencies/math/PRBMathUD60x18.sol +++ b/contracts/dependencies/math/PRBMathUD60x18.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Unlicense -pragma solidity >=0.8.4; +pragma solidity ^0.8.0; import "./PRBMath.sol"; diff --git a/contracts/dependencies/math/SqrtLib.sol b/contracts/dependencies/math/SqrtLib.sol index 57fb31fc3..0910ee91e 100644 --- a/contracts/dependencies/math/SqrtLib.sol +++ b/contracts/dependencies/math/SqrtLib.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; library SqrtLib { function sqrt(uint256 x) internal pure returns (uint256 z) { diff --git a/contracts/dependencies/openzeppelin/contracts/AccessControl.sol b/contracts/dependencies/openzeppelin/contracts/AccessControl.sol index e0f658b27..27e7e4414 100644 --- a/contracts/dependencies/openzeppelin/contracts/AccessControl.sol +++ b/contracts/dependencies/openzeppelin/contracts/AccessControl.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "./IAccessControl.sol"; import "./Context.sol"; diff --git a/contracts/dependencies/openzeppelin/contracts/Address.sol b/contracts/dependencies/openzeppelin/contracts/Address.sol index 746a292c8..9cbbced9f 100644 --- a/contracts/dependencies/openzeppelin/contracts/Address.sol +++ b/contracts/dependencies/openzeppelin/contracts/Address.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol) -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type diff --git a/contracts/dependencies/openzeppelin/contracts/Base64.sol b/contracts/dependencies/openzeppelin/contracts/Base64.sol index ac1d87cb2..4e08cd563 100644 --- a/contracts/dependencies/openzeppelin/contracts/Base64.sol +++ b/contracts/dependencies/openzeppelin/contracts/Base64.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Base64.sol) -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; /** * @dev Provides a set of functions to operate with Base64 strings. diff --git a/contracts/dependencies/openzeppelin/contracts/Context.sol b/contracts/dependencies/openzeppelin/contracts/Context.sol index 0f18ffbb3..056cd500a 100644 --- a/contracts/dependencies/openzeppelin/contracts/Context.sol +++ b/contracts/dependencies/openzeppelin/contracts/Context.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /* * @dev Provides information about the current execution context, including the diff --git a/contracts/dependencies/openzeppelin/contracts/ERC165.sol b/contracts/dependencies/openzeppelin/contracts/ERC165.sol index ce4710af4..77e0be713 100644 --- a/contracts/dependencies/openzeppelin/contracts/ERC165.sol +++ b/contracts/dependencies/openzeppelin/contracts/ERC165.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "./IERC165.sol"; diff --git a/contracts/dependencies/openzeppelin/contracts/ERC20.sol b/contracts/dependencies/openzeppelin/contracts/ERC20.sol index ff7b3a5fb..0a4d2d2ca 100644 --- a/contracts/dependencies/openzeppelin/contracts/ERC20.sol +++ b/contracts/dependencies/openzeppelin/contracts/ERC20.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "./Context.sol"; import "./IERC20.sol"; diff --git a/contracts/dependencies/openzeppelin/contracts/ERC721.sol b/contracts/dependencies/openzeppelin/contracts/ERC721.sol index bbd2d0cdb..0ddebc97f 100644 --- a/contracts/dependencies/openzeppelin/contracts/ERC721.sol +++ b/contracts/dependencies/openzeppelin/contracts/ERC721.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/ERC721.sol) -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "./IERC721.sol"; import "./IERC721Receiver.sol"; diff --git a/contracts/dependencies/openzeppelin/contracts/ERC721Enumerable.sol b/contracts/dependencies/openzeppelin/contracts/ERC721Enumerable.sol index 0ec947832..e1a15f361 100644 --- a/contracts/dependencies/openzeppelin/contracts/ERC721Enumerable.sol +++ b/contracts/dependencies/openzeppelin/contracts/ERC721Enumerable.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/ERC721Enumerable.sol) -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import "./ERC721.sol"; import "./IERC721Enumerable.sol"; diff --git a/contracts/dependencies/openzeppelin/contracts/EnumerableSet.sol b/contracts/dependencies/openzeppelin/contracts/EnumerableSet.sol index ae0016b5f..7004733a1 100644 --- a/contracts/dependencies/openzeppelin/contracts/EnumerableSet.sol +++ b/contracts/dependencies/openzeppelin/contracts/EnumerableSet.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @dev Library for managing diff --git a/contracts/dependencies/openzeppelin/contracts/IAccessControl.sol b/contracts/dependencies/openzeppelin/contracts/IAccessControl.sol index 83a6eb87b..7a6c59c80 100644 --- a/contracts/dependencies/openzeppelin/contracts/IAccessControl.sol +++ b/contracts/dependencies/openzeppelin/contracts/IAccessControl.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. diff --git a/contracts/dependencies/openzeppelin/contracts/IERC1155.sol b/contracts/dependencies/openzeppelin/contracts/IERC1155.sol index 55e2fa80b..b8b8fce61 100644 --- a/contracts/dependencies/openzeppelin/contracts/IERC1155.sol +++ b/contracts/dependencies/openzeppelin/contracts/IERC1155.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC1155/IERC1155.sol) -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import "./IERC165.sol"; diff --git a/contracts/dependencies/openzeppelin/contracts/IERC1155Receiver.sol b/contracts/dependencies/openzeppelin/contracts/IERC1155Receiver.sol index 803e0e878..8a38c31e8 100644 --- a/contracts/dependencies/openzeppelin/contracts/IERC1155Receiver.sol +++ b/contracts/dependencies/openzeppelin/contracts/IERC1155Receiver.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol) -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import "./IERC165.sol"; diff --git a/contracts/dependencies/openzeppelin/contracts/IERC1271.sol b/contracts/dependencies/openzeppelin/contracts/IERC1271.sol index ce6bae182..f6a40b2a0 100644 --- a/contracts/dependencies/openzeppelin/contracts/IERC1271.sol +++ b/contracts/dependencies/openzeppelin/contracts/IERC1271.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol) -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @dev Interface of the ERC1271 standard signature validation method for diff --git a/contracts/dependencies/openzeppelin/contracts/IERC165.sol b/contracts/dependencies/openzeppelin/contracts/IERC165.sol index 2bddd4275..01c9c0864 100644 --- a/contracts/dependencies/openzeppelin/contracts/IERC165.sol +++ b/contracts/dependencies/openzeppelin/contracts/IERC165.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the diff --git a/contracts/dependencies/openzeppelin/contracts/IERC20.sol b/contracts/dependencies/openzeppelin/contracts/IERC20.sol index 5b024845a..234d8373a 100644 --- a/contracts/dependencies/openzeppelin/contracts/IERC20.sol +++ b/contracts/dependencies/openzeppelin/contracts/IERC20.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. diff --git a/contracts/dependencies/openzeppelin/contracts/IERC20Detailed.sol b/contracts/dependencies/openzeppelin/contracts/IERC20Detailed.sol index 371d0d260..7112110c1 100644 --- a/contracts/dependencies/openzeppelin/contracts/IERC20Detailed.sol +++ b/contracts/dependencies/openzeppelin/contracts/IERC20Detailed.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC20} from "./IERC20.sol"; diff --git a/contracts/dependencies/openzeppelin/contracts/IERC20WithPermit.sol b/contracts/dependencies/openzeppelin/contracts/IERC20WithPermit.sol index bc9a9ae0d..c6803afc1 100644 --- a/contracts/dependencies/openzeppelin/contracts/IERC20WithPermit.sol +++ b/contracts/dependencies/openzeppelin/contracts/IERC20WithPermit.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import {IERC20} from "./IERC20.sol"; diff --git a/contracts/dependencies/openzeppelin/contracts/IERC2981.sol b/contracts/dependencies/openzeppelin/contracts/IERC2981.sol index 150c6a1a8..14d095e5b 100644 --- a/contracts/dependencies/openzeppelin/contracts/IERC2981.sol +++ b/contracts/dependencies/openzeppelin/contracts/IERC2981.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (interfaces/IERC2981.sol) -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "./IERC165.sol"; diff --git a/contracts/dependencies/openzeppelin/contracts/IERC721.sol b/contracts/dependencies/openzeppelin/contracts/IERC721.sol index cd4467d83..6bb1ceb5b 100644 --- a/contracts/dependencies/openzeppelin/contracts/IERC721.sol +++ b/contracts/dependencies/openzeppelin/contracts/IERC721.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol) -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import "./IERC165.sol"; diff --git a/contracts/dependencies/openzeppelin/contracts/IERC721Enumerable.sol b/contracts/dependencies/openzeppelin/contracts/IERC721Enumerable.sol index 646ed5ce0..5d2969817 100644 --- a/contracts/dependencies/openzeppelin/contracts/IERC721Enumerable.sol +++ b/contracts/dependencies/openzeppelin/contracts/IERC721Enumerable.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol) -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import "./IERC721.sol"; diff --git a/contracts/dependencies/openzeppelin/contracts/IERC721Metadata.sol b/contracts/dependencies/openzeppelin/contracts/IERC721Metadata.sol index 05a7b1b3c..839db0d6b 100644 --- a/contracts/dependencies/openzeppelin/contracts/IERC721Metadata.sol +++ b/contracts/dependencies/openzeppelin/contracts/IERC721Metadata.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import "./IERC721.sol"; diff --git a/contracts/dependencies/openzeppelin/contracts/IERC721Receiver.sol b/contracts/dependencies/openzeppelin/contracts/IERC721Receiver.sol index 62c0f75be..298e3565f 100644 --- a/contracts/dependencies/openzeppelin/contracts/IERC721Receiver.sol +++ b/contracts/dependencies/openzeppelin/contracts/IERC721Receiver.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol) -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface diff --git a/contracts/dependencies/openzeppelin/contracts/IMintableERC20.sol b/contracts/dependencies/openzeppelin/contracts/IMintableERC20.sol index 06abd6617..a0c3a75cc 100644 --- a/contracts/dependencies/openzeppelin/contracts/IMintableERC20.sol +++ b/contracts/dependencies/openzeppelin/contracts/IMintableERC20.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "./IERC20Detailed.sol"; diff --git a/contracts/dependencies/openzeppelin/contracts/ITransferHook.sol b/contracts/dependencies/openzeppelin/contracts/ITransferHook.sol index f460d65d1..477403e30 100644 --- a/contracts/dependencies/openzeppelin/contracts/ITransferHook.sol +++ b/contracts/dependencies/openzeppelin/contracts/ITransferHook.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; interface ITransferHook { function onTransfer( diff --git a/contracts/dependencies/openzeppelin/contracts/MerkleProof.sol b/contracts/dependencies/openzeppelin/contracts/MerkleProof.sol index 8f059b021..f490cc29d 100644 --- a/contracts/dependencies/openzeppelin/contracts/MerkleProof.sol +++ b/contracts/dependencies/openzeppelin/contracts/MerkleProof.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol) -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @dev These functions deal with verification of Merkle Tree proofs. diff --git a/contracts/dependencies/openzeppelin/contracts/Multicall.sol b/contracts/dependencies/openzeppelin/contracts/Multicall.sol new file mode 100644 index 000000000..bdb820139 --- /dev/null +++ b/contracts/dependencies/openzeppelin/contracts/Multicall.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (utils/Multicall.sol) + +pragma solidity ^0.8.0; + +import "./Address.sol"; + +/** + * @dev Provides a function to batch together multiple calls in a single external call. + * + * _Available since v4.1._ + */ +abstract contract Multicall { + /** + * @dev Receives and executes a batch of function calls on this contract. + */ + function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) { + results = new bytes[](data.length); + for (uint256 i = 0; i < data.length; i++) { + results[i] = Address.functionDelegateCall(address(this), data[i]); + } + return results; + } +} diff --git a/contracts/dependencies/openzeppelin/contracts/Ownable.sol b/contracts/dependencies/openzeppelin/contracts/Ownable.sol index 569d8f06a..907f00a52 100644 --- a/contracts/dependencies/openzeppelin/contracts/Ownable.sol +++ b/contracts/dependencies/openzeppelin/contracts/Ownable.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "./Context.sol"; diff --git a/contracts/dependencies/openzeppelin/contracts/Pausable.sol b/contracts/dependencies/openzeppelin/contracts/Pausable.sol index deee15615..f8b37a443 100644 --- a/contracts/dependencies/openzeppelin/contracts/Pausable.sol +++ b/contracts/dependencies/openzeppelin/contracts/Pausable.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import "./Context.sol"; diff --git a/contracts/dependencies/openzeppelin/contracts/ReentrancyGuard.sol b/contracts/dependencies/openzeppelin/contracts/ReentrancyGuard.sol index 2d9cca2dc..f9281ec64 100644 --- a/contracts/dependencies/openzeppelin/contracts/ReentrancyGuard.sol +++ b/contracts/dependencies/openzeppelin/contracts/ReentrancyGuard.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol) -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. diff --git a/contracts/dependencies/openzeppelin/contracts/SafeCast.sol b/contracts/dependencies/openzeppelin/contracts/SafeCast.sol index ea2c33a01..ccbf69dab 100644 --- a/contracts/dependencies/openzeppelin/contracts/SafeCast.sol +++ b/contracts/dependencies/openzeppelin/contracts/SafeCast.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol) -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow @@ -71,6 +71,23 @@ library SafeCast { return uint128(value); } + /** + * @dev Returns the downcasted uint104 from uint256, reverting on + * overflow (when the input is greater than largest uint104). + * + * Counterpart to Solidity's `uint104` operator. + * + * Requirements: + * + * - input must fit into 104 bits + * + * _Available since v4.7._ + */ + function toUint104(uint256 value) internal pure returns (uint104) { + require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits"); + return uint104(value); + } + /** * @dev Returns the downcasted uint96 from uint256, reverting on * overflow (when the input is greater than largest uint96). @@ -142,6 +159,23 @@ library SafeCast { return uint32(value); } + /** + * @dev Returns the downcasted uint24 from uint256, reverting on + * overflow (when the input is greater than largest uint24). + * + * Counterpart to Solidity's `uint24` operator. + * + * Requirements: + * + * - input must fit into 24 bits + * + * _Available since v4.7._ + */ + function toUint24(uint256 value) internal pure returns (uint24) { + require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits"); + return uint24(value); + } + /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). diff --git a/contracts/dependencies/openzeppelin/contracts/SafeERC20.sol b/contracts/dependencies/openzeppelin/contracts/SafeERC20.sol index 88fcde857..26681dfbe 100644 --- a/contracts/dependencies/openzeppelin/contracts/SafeERC20.sol +++ b/contracts/dependencies/openzeppelin/contracts/SafeERC20.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol) -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "./IERC20.sol"; import "./draft-IERC20Permit.sol"; diff --git a/contracts/dependencies/openzeppelin/contracts/SafeMath.sol b/contracts/dependencies/openzeppelin/contracts/SafeMath.sol index 7ebbe140b..bf1be352e 100644 --- a/contracts/dependencies/openzeppelin/contracts/SafeMath.sol +++ b/contracts/dependencies/openzeppelin/contracts/SafeMath.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /// @title Optimized overflow and underflow safe math operations /// @notice Contains methods for doing math operations that revert on overflow or underflow for minimal gas cost diff --git a/contracts/dependencies/openzeppelin/contracts/SignedSafeMath.sol b/contracts/dependencies/openzeppelin/contracts/SignedSafeMath.sol index 3d334155e..fc5923d1e 100644 --- a/contracts/dependencies/openzeppelin/contracts/SignedSafeMath.sol +++ b/contracts/dependencies/openzeppelin/contracts/SignedSafeMath.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title SignedSafeMath diff --git a/contracts/dependencies/openzeppelin/contracts/StorageSlot.sol b/contracts/dependencies/openzeppelin/contracts/StorageSlot.sol index 3c9e0d6d4..6ab8f5dc6 100644 --- a/contracts/dependencies/openzeppelin/contracts/StorageSlot.sol +++ b/contracts/dependencies/openzeppelin/contracts/StorageSlot.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol) -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; /** * @dev Library for reading and writing primitive types to specific storage slots. diff --git a/contracts/dependencies/openzeppelin/contracts/Strings.sol b/contracts/dependencies/openzeppelin/contracts/Strings.sol index 17f484653..86bdeb2cf 100644 --- a/contracts/dependencies/openzeppelin/contracts/Strings.sol +++ b/contracts/dependencies/openzeppelin/contracts/Strings.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @dev String operations. diff --git a/contracts/dependencies/openzeppelin/contracts/draft-IERC20Permit.sol b/contracts/dependencies/openzeppelin/contracts/draft-IERC20Permit.sol index d9e19654c..17a186f5b 100644 --- a/contracts/dependencies/openzeppelin/contracts/draft-IERC20Permit.sol +++ b/contracts/dependencies/openzeppelin/contracts/draft-IERC20Permit.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in diff --git a/contracts/dependencies/openzeppelin/upgradeability/AddressUpgradeable.sol b/contracts/dependencies/openzeppelin/upgradeability/AddressUpgradeable.sol index d2f04ee72..51fca23c5 100644 --- a/contracts/dependencies/openzeppelin/upgradeability/AddressUpgradeable.sol +++ b/contracts/dependencies/openzeppelin/upgradeability/AddressUpgradeable.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol) -pragma solidity ^0.8.1; +pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type diff --git a/contracts/dependencies/openzeppelin/upgradeability/AdminUpgradeabilityProxy.sol b/contracts/dependencies/openzeppelin/upgradeability/AdminUpgradeabilityProxy.sol index 3ece218e3..6b6df43f6 100644 --- a/contracts/dependencies/openzeppelin/upgradeability/AdminUpgradeabilityProxy.sol +++ b/contracts/dependencies/openzeppelin/upgradeability/AdminUpgradeabilityProxy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "./BaseAdminUpgradeabilityProxy.sol"; diff --git a/contracts/dependencies/openzeppelin/upgradeability/BaseAdminUpgradeabilityProxy.sol b/contracts/dependencies/openzeppelin/upgradeability/BaseAdminUpgradeabilityProxy.sol index 66d3a5005..c1ce574f6 100644 --- a/contracts/dependencies/openzeppelin/upgradeability/BaseAdminUpgradeabilityProxy.sol +++ b/contracts/dependencies/openzeppelin/upgradeability/BaseAdminUpgradeabilityProxy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "./UpgradeabilityProxy.sol"; diff --git a/contracts/dependencies/openzeppelin/upgradeability/BaseUpgradeabilityProxy.sol b/contracts/dependencies/openzeppelin/upgradeability/BaseUpgradeabilityProxy.sol index fa637bdc8..1015e80cf 100644 --- a/contracts/dependencies/openzeppelin/upgradeability/BaseUpgradeabilityProxy.sol +++ b/contracts/dependencies/openzeppelin/upgradeability/BaseUpgradeabilityProxy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "./Proxy.sol"; import "../contracts/Address.sol"; diff --git a/contracts/dependencies/openzeppelin/upgradeability/Clones.sol b/contracts/dependencies/openzeppelin/upgradeability/Clones.sol index 3a1dc4b53..1463e34c4 100644 --- a/contracts/dependencies/openzeppelin/upgradeability/Clones.sol +++ b/contracts/dependencies/openzeppelin/upgradeability/Clones.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (proxy/Clones.sol) -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for diff --git a/contracts/dependencies/openzeppelin/upgradeability/ERC1967Upgrade.sol b/contracts/dependencies/openzeppelin/upgradeability/ERC1967Upgrade.sol index b5da1332c..183db1d04 100644 --- a/contracts/dependencies/openzeppelin/upgradeability/ERC1967Upgrade.sol +++ b/contracts/dependencies/openzeppelin/upgradeability/ERC1967Upgrade.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol) -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import "./IBeacon.sol"; import "./draft-IERC1822.sol"; diff --git a/contracts/dependencies/openzeppelin/upgradeability/IBeacon.sol b/contracts/dependencies/openzeppelin/upgradeability/IBeacon.sol index a0b6fb219..fba3ee2ab 100644 --- a/contracts/dependencies/openzeppelin/upgradeability/IBeacon.sol +++ b/contracts/dependencies/openzeppelin/upgradeability/IBeacon.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. diff --git a/contracts/dependencies/openzeppelin/upgradeability/Initializable.sol b/contracts/dependencies/openzeppelin/upgradeability/Initializable.sol index 9895abd50..37fd28a1e 100644 --- a/contracts/dependencies/openzeppelin/upgradeability/Initializable.sol +++ b/contracts/dependencies/openzeppelin/upgradeability/Initializable.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol) -pragma solidity ^0.8.2; +pragma solidity ^0.8.0; import "../contracts/Address.sol"; diff --git a/contracts/dependencies/openzeppelin/upgradeability/InitializableAdminUpgradeabilityProxy.sol b/contracts/dependencies/openzeppelin/upgradeability/InitializableAdminUpgradeabilityProxy.sol index 7ecc0685a..2bab4cbbe 100644 --- a/contracts/dependencies/openzeppelin/upgradeability/InitializableAdminUpgradeabilityProxy.sol +++ b/contracts/dependencies/openzeppelin/upgradeability/InitializableAdminUpgradeabilityProxy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "./BaseAdminUpgradeabilityProxy.sol"; import "./InitializableUpgradeabilityProxy.sol"; diff --git a/contracts/dependencies/openzeppelin/upgradeability/InitializableUpgradeabilityProxy.sol b/contracts/dependencies/openzeppelin/upgradeability/InitializableUpgradeabilityProxy.sol index 8040ee14c..91bd1a282 100644 --- a/contracts/dependencies/openzeppelin/upgradeability/InitializableUpgradeabilityProxy.sol +++ b/contracts/dependencies/openzeppelin/upgradeability/InitializableUpgradeabilityProxy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "./BaseUpgradeabilityProxy.sol"; diff --git a/contracts/dependencies/openzeppelin/upgradeability/Proxy.sol b/contracts/dependencies/openzeppelin/upgradeability/Proxy.sol index 8a33b13f7..bc483474a 100644 --- a/contracts/dependencies/openzeppelin/upgradeability/Proxy.sol +++ b/contracts/dependencies/openzeppelin/upgradeability/Proxy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title Proxy diff --git a/contracts/dependencies/openzeppelin/upgradeability/UUPSUpgradeable.sol b/contracts/dependencies/openzeppelin/upgradeability/UUPSUpgradeable.sol index 59962f58a..1bf739015 100644 --- a/contracts/dependencies/openzeppelin/upgradeability/UUPSUpgradeable.sol +++ b/contracts/dependencies/openzeppelin/upgradeability/UUPSUpgradeable.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/UUPSUpgradeable.sol) -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import "./draft-IERC1822.sol"; import "./ERC1967Upgrade.sol"; diff --git a/contracts/dependencies/openzeppelin/upgradeability/UpgradeabilityProxy.sol b/contracts/dependencies/openzeppelin/upgradeability/UpgradeabilityProxy.sol index 8a2c37fc2..326750132 100644 --- a/contracts/dependencies/openzeppelin/upgradeability/UpgradeabilityProxy.sol +++ b/contracts/dependencies/openzeppelin/upgradeability/UpgradeabilityProxy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "./BaseUpgradeabilityProxy.sol"; diff --git a/contracts/dependencies/openzeppelin/upgradeability/draft-IERC1822.sol b/contracts/dependencies/openzeppelin/upgradeability/draft-IERC1822.sol index 83c58c415..3b73d744c 100644 --- a/contracts/dependencies/openzeppelin/upgradeability/draft-IERC1822.sol +++ b/contracts/dependencies/openzeppelin/upgradeability/draft-IERC1822.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified diff --git a/contracts/dependencies/pyth/IPyth.sol b/contracts/dependencies/pyth/IPyth.sol new file mode 100644 index 000000000..5914b52bd --- /dev/null +++ b/contracts/dependencies/pyth/IPyth.sol @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.0; + +import "./PythStructs.sol"; +import "./IPythEvents.sol"; + +/// @title Consume prices from the Pyth Network (https://pyth.network/). +/// @dev Please refer to the guidance at https://docs.pyth.network/consumers/best-practices for how to consume prices safely. +/// @author Pyth Data Association +interface IPyth is IPythEvents { + /// @notice Returns the period (in seconds) that a price feed is considered valid since its publish time + function getValidTimePeriod() external view returns (uint validTimePeriod); + + /// @notice Returns the price and confidence interval. + /// @dev Reverts if the price has not been updated within the last `getValidTimePeriod()` seconds. + /// @param id The Pyth Price Feed ID of which to fetch the price and confidence interval. + /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely. + function getPrice( + bytes32 id + ) external view returns (PythStructs.Price memory price); + + /// @notice Returns the exponentially-weighted moving average price and confidence interval. + /// @dev Reverts if the EMA price is not available. + /// @param id The Pyth Price Feed ID of which to fetch the EMA price and confidence interval. + /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely. + function getEmaPrice( + bytes32 id + ) external view returns (PythStructs.Price memory price); + + /// @notice Returns the price of a price feed without any sanity checks. + /// @dev This function returns the most recent price update in this contract without any recency checks. + /// This function is unsafe as the returned price update may be arbitrarily far in the past. + /// + /// Users of this function should check the `publishTime` in the price to ensure that the returned price is + /// sufficiently recent for their application. If you are considering using this function, it may be + /// safer / easier to use either `getPrice` or `getPriceNoOlderThan`. + /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely. + function getPriceUnsafe( + bytes32 id + ) external view returns (PythStructs.Price memory price); + + /// @notice Returns the price that is no older than `age` seconds of the current time. + /// @dev This function is a sanity-checked version of `getPriceUnsafe` which is useful in + /// applications that require a sufficiently-recent price. Reverts if the price wasn't updated sufficiently + /// recently. + /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely. + function getPriceNoOlderThan( + bytes32 id, + uint age + ) external view returns (PythStructs.Price memory price); + + /// @notice Returns the exponentially-weighted moving average price of a price feed without any sanity checks. + /// @dev This function returns the same price as `getEmaPrice` in the case where the price is available. + /// However, if the price is not recent this function returns the latest available price. + /// + /// The returned price can be from arbitrarily far in the past; this function makes no guarantees that + /// the returned price is recent or useful for any particular application. + /// + /// Users of this function should check the `publishTime` in the price to ensure that the returned price is + /// sufficiently recent for their application. If you are considering using this function, it may be + /// safer / easier to use either `getEmaPrice` or `getEmaPriceNoOlderThan`. + /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely. + function getEmaPriceUnsafe( + bytes32 id + ) external view returns (PythStructs.Price memory price); + + /// @notice Returns the exponentially-weighted moving average price that is no older than `age` seconds + /// of the current time. + /// @dev This function is a sanity-checked version of `getEmaPriceUnsafe` which is useful in + /// applications that require a sufficiently-recent price. Reverts if the price wasn't updated sufficiently + /// recently. + /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely. + function getEmaPriceNoOlderThan( + bytes32 id, + uint age + ) external view returns (PythStructs.Price memory price); + + /// @notice Update price feeds with given update messages. + /// This method requires the caller to pay a fee in wei; the required fee can be computed by calling + /// `getUpdateFee` with the length of the `updateData` array. + /// Prices will be updated if they are more recent than the current stored prices. + /// The call will succeed even if the update is not the most recent. + /// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid. + /// @param updateData Array of price update data. + function updatePriceFeeds(bytes[] calldata updateData) external payable; + + /// @notice Wrapper around updatePriceFeeds that rejects fast if a price update is not necessary. A price update is + /// necessary if the current on-chain publishTime is older than the given publishTime. It relies solely on the + /// given `publishTimes` for the price feeds and does not read the actual price update publish time within `updateData`. + /// + /// This method requires the caller to pay a fee in wei; the required fee can be computed by calling + /// `getUpdateFee` with the length of the `updateData` array. + /// + /// `priceIds` and `publishTimes` are two arrays with the same size that correspond to senders known publishTime + /// of each priceId when calling this method. If all of price feeds within `priceIds` have updated and have + /// a newer or equal publish time than the given publish time, it will reject the transaction to save gas. + /// Otherwise, it calls updatePriceFeeds method to update the prices. + /// + /// @dev Reverts if update is not needed or the transferred fee is not sufficient or the updateData is invalid. + /// @param updateData Array of price update data. + /// @param priceIds Array of price ids. + /// @param publishTimes Array of publishTimes. `publishTimes[i]` corresponds to known `publishTime` of `priceIds[i]` + function updatePriceFeedsIfNecessary( + bytes[] calldata updateData, + bytes32[] calldata priceIds, + uint64[] calldata publishTimes + ) external payable; + + /// @notice Returns the required fee to update an array of price updates. + /// @param updateData Array of price update data. + /// @return feeAmount The required fee in Wei. + function getUpdateFee( + bytes[] calldata updateData + ) external view returns (uint feeAmount); + + /// @notice Parse `updateData` and return price feeds of the given `priceIds` if they are all published + /// within `minPublishTime` and `maxPublishTime`. + /// + /// You can use this method if you want to use a Pyth price at a fixed time and not the most recent price; + /// otherwise, please consider using `updatePriceFeeds`. This method does not store the price updates on-chain. + /// + /// This method requires the caller to pay a fee in wei; the required fee can be computed by calling + /// `getUpdateFee` with the length of the `updateData` array. + /// + /// + /// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid or there is + /// no update for any of the given `priceIds` within the given time range. + /// @param updateData Array of price update data. + /// @param priceIds Array of price ids. + /// @param minPublishTime minimum acceptable publishTime for the given `priceIds`. + /// @param maxPublishTime maximum acceptable publishTime for the given `priceIds`. + /// @return priceFeeds Array of the price feeds corresponding to the given `priceIds` (with the same order). + function parsePriceFeedUpdates( + bytes[] calldata updateData, + bytes32[] calldata priceIds, + uint64 minPublishTime, + uint64 maxPublishTime + ) external payable returns (PythStructs.PriceFeed[] memory priceFeeds); +} diff --git a/contracts/dependencies/pyth/IPythEvents.sol b/contracts/dependencies/pyth/IPythEvents.sol new file mode 100644 index 000000000..ac4c05cec --- /dev/null +++ b/contracts/dependencies/pyth/IPythEvents.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.0; + +/// @title IPythEvents contains the events that Pyth contract emits. +/// @dev This interface can be used for listening to the updates for off-chain and testing purposes. +interface IPythEvents { + /// @dev Emitted when the price feed with `id` has received a fresh update. + /// @param id The Pyth Price Feed ID. + /// @param publishTime Publish time of the given price update. + /// @param price Price of the given price update. + /// @param conf Confidence interval of the given price update. + event PriceFeedUpdate( + bytes32 indexed id, + uint64 publishTime, + int64 price, + uint64 conf + ); + + /// @dev Emitted when a batch price update is processed successfully. + /// @param chainId ID of the source chain that the batch price update comes from. + /// @param sequenceNumber Sequence number of the batch price update. + event BatchPriceFeedUpdate(uint16 chainId, uint64 sequenceNumber); +} diff --git a/contracts/dependencies/pyth/PythStructs.sol b/contracts/dependencies/pyth/PythStructs.sol new file mode 100644 index 000000000..a0fa5290c --- /dev/null +++ b/contracts/dependencies/pyth/PythStructs.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.0; + +contract PythStructs { + // A price with a degree of uncertainty, represented as a price +- a confidence interval. + // + // The confidence interval roughly corresponds to the standard error of a normal distribution. + // Both the price and confidence are stored in a fixed-point numeric representation, + // `x * (10^expo)`, where `expo` is the exponent. + // + // Please refer to the documentation at https://docs.pyth.network/consumers/best-practices for how + // to how this price safely. + struct Price { + // Price + int64 price; + // Confidence interval around the price + uint64 conf; + // Price exponent + int32 expo; + // Unix timestamp describing when the price was published + uint publishTime; + } + + // PriceFeed represents a current aggregate price from pyth publisher feeds. + struct PriceFeed { + // The price ID. + bytes32 id; + // Latest available price + Price price; + // Latest available exponentially-weighted moving average price + Price emaPrice; + } +} diff --git a/contracts/dependencies/safe/MultiSendCallOnly.sol b/contracts/dependencies/safe/MultiSendCallOnly.sol index 0f7c5f951..2a84c3fcb 100644 --- a/contracts/dependencies/safe/MultiSendCallOnly.sol +++ b/contracts/dependencies/safe/MultiSendCallOnly.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: LGPL-3.0-only -pragma solidity >=0.7.0 <0.9.0; +pragma solidity ^0.8.0; /// @title Multi Send Call Only - Allows to batch multiple transactions into one, but only calls /// @author Stefan George - diff --git a/contracts/dependencies/seaport/contracts/Seaport.sol b/contracts/dependencies/seaport/contracts/Seaport.sol index fcf695a0a..a23eac723 100644 --- a/contracts/dependencies/seaport/contracts/Seaport.sol +++ b/contracts/dependencies/seaport/contracts/Seaport.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import { Consideration } from "./lib/Consideration.sol"; diff --git a/contracts/dependencies/seaport/contracts/conduit/Conduit.sol b/contracts/dependencies/seaport/contracts/conduit/Conduit.sol index 1f67d062b..df9b58648 100644 --- a/contracts/dependencies/seaport/contracts/conduit/Conduit.sol +++ b/contracts/dependencies/seaport/contracts/conduit/Conduit.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; import { ConduitInterface } from "../interfaces/ConduitInterface.sol"; diff --git a/contracts/dependencies/seaport/contracts/conduit/ConduitController.sol b/contracts/dependencies/seaport/contracts/conduit/ConduitController.sol index 317413730..baa2a7958 100644 --- a/contracts/dependencies/seaport/contracts/conduit/ConduitController.sol +++ b/contracts/dependencies/seaport/contracts/conduit/ConduitController.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; import { ConduitControllerInterface diff --git a/contracts/dependencies/seaport/contracts/conduit/lib/ConduitConstants.sol b/contracts/dependencies/seaport/contracts/conduit/lib/ConduitConstants.sol index 516607318..504a8b260 100644 --- a/contracts/dependencies/seaport/contracts/conduit/lib/ConduitConstants.sol +++ b/contracts/dependencies/seaport/contracts/conduit/lib/ConduitConstants.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; // error ChannelClosed(address channel) uint256 constant ChannelClosed_error_signature = ( diff --git a/contracts/dependencies/seaport/contracts/conduit/lib/ConduitEnums.sol b/contracts/dependencies/seaport/contracts/conduit/lib/ConduitEnums.sol index 2154bf7bd..b8f6a6acf 100644 --- a/contracts/dependencies/seaport/contracts/conduit/lib/ConduitEnums.sol +++ b/contracts/dependencies/seaport/contracts/conduit/lib/ConduitEnums.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; enum ConduitItemType { NATIVE, // unused diff --git a/contracts/dependencies/seaport/contracts/conduit/lib/ConduitStructs.sol b/contracts/dependencies/seaport/contracts/conduit/lib/ConduitStructs.sol index 03c54f4ec..20e078632 100644 --- a/contracts/dependencies/seaport/contracts/conduit/lib/ConduitStructs.sol +++ b/contracts/dependencies/seaport/contracts/conduit/lib/ConduitStructs.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; import { ConduitItemType } from "./ConduitEnums.sol"; diff --git a/contracts/dependencies/seaport/contracts/helpers/TransferHelper.sol b/contracts/dependencies/seaport/contracts/helpers/TransferHelper.sol index b577436f1..65ac7dce3 100644 --- a/contracts/dependencies/seaport/contracts/helpers/TransferHelper.sol +++ b/contracts/dependencies/seaport/contracts/helpers/TransferHelper.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; import { IERC721Receiver } from "../interfaces/IERC721Receiver.sol"; diff --git a/contracts/dependencies/seaport/contracts/helpers/TransferHelperStructs.sol b/contracts/dependencies/seaport/contracts/helpers/TransferHelperStructs.sol index 26c6f1457..bb9dd1ef0 100644 --- a/contracts/dependencies/seaport/contracts/helpers/TransferHelperStructs.sol +++ b/contracts/dependencies/seaport/contracts/helpers/TransferHelperStructs.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; import { ConduitItemType } from "../conduit/lib/ConduitEnums.sol"; diff --git a/contracts/dependencies/seaport/contracts/interfaces/AbridgedTokenInterfaces.sol b/contracts/dependencies/seaport/contracts/interfaces/AbridgedTokenInterfaces.sol index d961faf29..85a03bba6 100644 --- a/contracts/dependencies/seaport/contracts/interfaces/AbridgedTokenInterfaces.sol +++ b/contracts/dependencies/seaport/contracts/interfaces/AbridgedTokenInterfaces.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; interface ERC20Interface { function transferFrom( diff --git a/contracts/dependencies/seaport/contracts/interfaces/AmountDerivationErrors.sol b/contracts/dependencies/seaport/contracts/interfaces/AmountDerivationErrors.sol index 58deccc40..f52152cba 100644 --- a/contracts/dependencies/seaport/contracts/interfaces/AmountDerivationErrors.sol +++ b/contracts/dependencies/seaport/contracts/interfaces/AmountDerivationErrors.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; /** * @title AmountDerivationErrors diff --git a/contracts/dependencies/seaport/contracts/interfaces/ConduitControllerInterface.sol b/contracts/dependencies/seaport/contracts/interfaces/ConduitControllerInterface.sol index bf3ec0c8a..c430995ac 100644 --- a/contracts/dependencies/seaport/contracts/interfaces/ConduitControllerInterface.sol +++ b/contracts/dependencies/seaport/contracts/interfaces/ConduitControllerInterface.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; /** * @title ConduitControllerInterface diff --git a/contracts/dependencies/seaport/contracts/interfaces/ConduitInterface.sol b/contracts/dependencies/seaport/contracts/interfaces/ConduitInterface.sol index 84870981c..b3ca9958c 100644 --- a/contracts/dependencies/seaport/contracts/interfaces/ConduitInterface.sol +++ b/contracts/dependencies/seaport/contracts/interfaces/ConduitInterface.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; import { ConduitTransfer, diff --git a/contracts/dependencies/seaport/contracts/interfaces/ConsiderationEventsAndErrors.sol b/contracts/dependencies/seaport/contracts/interfaces/ConsiderationEventsAndErrors.sol index 6d84b04d1..952f0e174 100644 --- a/contracts/dependencies/seaport/contracts/interfaces/ConsiderationEventsAndErrors.sol +++ b/contracts/dependencies/seaport/contracts/interfaces/ConsiderationEventsAndErrors.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; import { SpentItem, ReceivedItem } from "../lib/ConsiderationStructs.sol"; diff --git a/contracts/dependencies/seaport/contracts/interfaces/ConsiderationInterface.sol b/contracts/dependencies/seaport/contracts/interfaces/ConsiderationInterface.sol index c17b7ba34..21f819432 100644 --- a/contracts/dependencies/seaport/contracts/interfaces/ConsiderationInterface.sol +++ b/contracts/dependencies/seaport/contracts/interfaces/ConsiderationInterface.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; import { BasicOrderParameters, diff --git a/contracts/dependencies/seaport/contracts/interfaces/CriteriaResolutionErrors.sol b/contracts/dependencies/seaport/contracts/interfaces/CriteriaResolutionErrors.sol index 9d7af48ae..768257ee8 100644 --- a/contracts/dependencies/seaport/contracts/interfaces/CriteriaResolutionErrors.sol +++ b/contracts/dependencies/seaport/contracts/interfaces/CriteriaResolutionErrors.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; /** * @title CriteriaResolutionErrors diff --git a/contracts/dependencies/seaport/contracts/interfaces/EIP1271Interface.sol b/contracts/dependencies/seaport/contracts/interfaces/EIP1271Interface.sol index 50b671196..ca932e27f 100644 --- a/contracts/dependencies/seaport/contracts/interfaces/EIP1271Interface.sol +++ b/contracts/dependencies/seaport/contracts/interfaces/EIP1271Interface.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; interface EIP1271Interface { function isValidSignature(bytes32 digest, bytes calldata signature) diff --git a/contracts/dependencies/seaport/contracts/interfaces/FulfillmentApplicationErrors.sol b/contracts/dependencies/seaport/contracts/interfaces/FulfillmentApplicationErrors.sol index e72d4a40d..2b9a9cb1b 100644 --- a/contracts/dependencies/seaport/contracts/interfaces/FulfillmentApplicationErrors.sol +++ b/contracts/dependencies/seaport/contracts/interfaces/FulfillmentApplicationErrors.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; import { Side } from "../lib/ConsiderationEnums.sol"; diff --git a/contracts/dependencies/seaport/contracts/interfaces/IERC721Receiver.sol b/contracts/dependencies/seaport/contracts/interfaces/IERC721Receiver.sol index 1f045c355..ff8e31ac8 100644 --- a/contracts/dependencies/seaport/contracts/interfaces/IERC721Receiver.sol +++ b/contracts/dependencies/seaport/contracts/interfaces/IERC721Receiver.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; interface IERC721Receiver { function onERC721Received( diff --git a/contracts/dependencies/seaport/contracts/interfaces/ImmutableCreate2FactoryInterface.sol b/contracts/dependencies/seaport/contracts/interfaces/ImmutableCreate2FactoryInterface.sol index e9756fb95..a8dde59ee 100644 --- a/contracts/dependencies/seaport/contracts/interfaces/ImmutableCreate2FactoryInterface.sol +++ b/contracts/dependencies/seaport/contracts/interfaces/ImmutableCreate2FactoryInterface.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; /** * @title ImmutableCreate2FactoryInterface diff --git a/contracts/dependencies/seaport/contracts/interfaces/ReentrancyErrors.sol b/contracts/dependencies/seaport/contracts/interfaces/ReentrancyErrors.sol index 94f523873..1357eefab 100644 --- a/contracts/dependencies/seaport/contracts/interfaces/ReentrancyErrors.sol +++ b/contracts/dependencies/seaport/contracts/interfaces/ReentrancyErrors.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; /** * @title ReentrancyErrors diff --git a/contracts/dependencies/seaport/contracts/interfaces/SeaportInterface.sol b/contracts/dependencies/seaport/contracts/interfaces/SeaportInterface.sol index fa30df811..745c11146 100644 --- a/contracts/dependencies/seaport/contracts/interfaces/SeaportInterface.sol +++ b/contracts/dependencies/seaport/contracts/interfaces/SeaportInterface.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; import { BasicOrderParameters, diff --git a/contracts/dependencies/seaport/contracts/interfaces/SignatureVerificationErrors.sol b/contracts/dependencies/seaport/contracts/interfaces/SignatureVerificationErrors.sol index b20ea0033..e65fe62f1 100644 --- a/contracts/dependencies/seaport/contracts/interfaces/SignatureVerificationErrors.sol +++ b/contracts/dependencies/seaport/contracts/interfaces/SignatureVerificationErrors.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; /** * @title SignatureVerificationErrors diff --git a/contracts/dependencies/seaport/contracts/interfaces/TokenTransferrerErrors.sol b/contracts/dependencies/seaport/contracts/interfaces/TokenTransferrerErrors.sol index 6734c9fba..154f3deea 100644 --- a/contracts/dependencies/seaport/contracts/interfaces/TokenTransferrerErrors.sol +++ b/contracts/dependencies/seaport/contracts/interfaces/TokenTransferrerErrors.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; /** * @title TokenTransferrerErrors diff --git a/contracts/dependencies/seaport/contracts/interfaces/TransferHelperErrors.sol b/contracts/dependencies/seaport/contracts/interfaces/TransferHelperErrors.sol index 290b5d73f..3e33513e5 100644 --- a/contracts/dependencies/seaport/contracts/interfaces/TransferHelperErrors.sol +++ b/contracts/dependencies/seaport/contracts/interfaces/TransferHelperErrors.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; /** * @title TransferHelperErrors diff --git a/contracts/dependencies/seaport/contracts/interfaces/TransferHelperInterface.sol b/contracts/dependencies/seaport/contracts/interfaces/TransferHelperInterface.sol index e6fcc705a..513e340e5 100644 --- a/contracts/dependencies/seaport/contracts/interfaces/TransferHelperInterface.sol +++ b/contracts/dependencies/seaport/contracts/interfaces/TransferHelperInterface.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; import { TransferHelperItem, diff --git a/contracts/dependencies/seaport/contracts/interfaces/ZoneInteractionErrors.sol b/contracts/dependencies/seaport/contracts/interfaces/ZoneInteractionErrors.sol index fc0ef9773..abdc26a68 100644 --- a/contracts/dependencies/seaport/contracts/interfaces/ZoneInteractionErrors.sol +++ b/contracts/dependencies/seaport/contracts/interfaces/ZoneInteractionErrors.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; /** * @title ZoneInteractionErrors diff --git a/contracts/dependencies/seaport/contracts/interfaces/ZoneInterface.sol b/contracts/dependencies/seaport/contracts/interfaces/ZoneInterface.sol index 22e18d0a6..2d6a69562 100644 --- a/contracts/dependencies/seaport/contracts/interfaces/ZoneInterface.sol +++ b/contracts/dependencies/seaport/contracts/interfaces/ZoneInterface.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; import { AdvancedOrder, diff --git a/contracts/dependencies/seaport/contracts/lib/AmountDeriver.sol b/contracts/dependencies/seaport/contracts/lib/AmountDeriver.sol index 246bcbc58..a8663e071 100644 --- a/contracts/dependencies/seaport/contracts/lib/AmountDeriver.sol +++ b/contracts/dependencies/seaport/contracts/lib/AmountDeriver.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import { AmountDerivationErrors diff --git a/contracts/dependencies/seaport/contracts/lib/Assertions.sol b/contracts/dependencies/seaport/contracts/lib/Assertions.sol index e5250cdb1..8dc4c4d71 100644 --- a/contracts/dependencies/seaport/contracts/lib/Assertions.sol +++ b/contracts/dependencies/seaport/contracts/lib/Assertions.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import { OrderParameters } from "./ConsiderationStructs.sol"; diff --git a/contracts/dependencies/seaport/contracts/lib/BasicOrderFulfiller.sol b/contracts/dependencies/seaport/contracts/lib/BasicOrderFulfiller.sol index da5c538cc..126cdadcc 100644 --- a/contracts/dependencies/seaport/contracts/lib/BasicOrderFulfiller.sol +++ b/contracts/dependencies/seaport/contracts/lib/BasicOrderFulfiller.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import { ConduitInterface } from "../interfaces/ConduitInterface.sol"; diff --git a/contracts/dependencies/seaport/contracts/lib/Consideration.sol b/contracts/dependencies/seaport/contracts/lib/Consideration.sol index ac181e615..84c488a83 100644 --- a/contracts/dependencies/seaport/contracts/lib/Consideration.sol +++ b/contracts/dependencies/seaport/contracts/lib/Consideration.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import { ConsiderationInterface diff --git a/contracts/dependencies/seaport/contracts/lib/ConsiderationBase.sol b/contracts/dependencies/seaport/contracts/lib/ConsiderationBase.sol index de2ade5d9..5a29a17eb 100644 --- a/contracts/dependencies/seaport/contracts/lib/ConsiderationBase.sol +++ b/contracts/dependencies/seaport/contracts/lib/ConsiderationBase.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import { ConduitControllerInterface diff --git a/contracts/dependencies/seaport/contracts/lib/ConsiderationConstants.sol b/contracts/dependencies/seaport/contracts/lib/ConsiderationConstants.sol index 4aa08de85..c6fc5280c 100644 --- a/contracts/dependencies/seaport/contracts/lib/ConsiderationConstants.sol +++ b/contracts/dependencies/seaport/contracts/lib/ConsiderationConstants.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; /* * -------------------------- Disambiguation & Other Notes --------------------- diff --git a/contracts/dependencies/seaport/contracts/lib/ConsiderationEnums.sol b/contracts/dependencies/seaport/contracts/lib/ConsiderationEnums.sol index 6bcfd701c..7bae8bf5c 100644 --- a/contracts/dependencies/seaport/contracts/lib/ConsiderationEnums.sol +++ b/contracts/dependencies/seaport/contracts/lib/ConsiderationEnums.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; // prettier-ignore enum OrderType { diff --git a/contracts/dependencies/seaport/contracts/lib/ConsiderationStructs.sol b/contracts/dependencies/seaport/contracts/lib/ConsiderationStructs.sol index 903cf7f34..c6da93f9b 100644 --- a/contracts/dependencies/seaport/contracts/lib/ConsiderationStructs.sol +++ b/contracts/dependencies/seaport/contracts/lib/ConsiderationStructs.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; import { OrderType, diff --git a/contracts/dependencies/seaport/contracts/lib/CounterManager.sol b/contracts/dependencies/seaport/contracts/lib/CounterManager.sol index 225c6c916..b6b3c334b 100644 --- a/contracts/dependencies/seaport/contracts/lib/CounterManager.sol +++ b/contracts/dependencies/seaport/contracts/lib/CounterManager.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import { ConsiderationEventsAndErrors diff --git a/contracts/dependencies/seaport/contracts/lib/CriteriaResolution.sol b/contracts/dependencies/seaport/contracts/lib/CriteriaResolution.sol index f361e6390..0572a9879 100644 --- a/contracts/dependencies/seaport/contracts/lib/CriteriaResolution.sol +++ b/contracts/dependencies/seaport/contracts/lib/CriteriaResolution.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import { ItemType, Side } from "./ConsiderationEnums.sol"; diff --git a/contracts/dependencies/seaport/contracts/lib/Executor.sol b/contracts/dependencies/seaport/contracts/lib/Executor.sol index 51e7c2775..e24492338 100644 --- a/contracts/dependencies/seaport/contracts/lib/Executor.sol +++ b/contracts/dependencies/seaport/contracts/lib/Executor.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import { ConduitInterface } from "../interfaces/ConduitInterface.sol"; diff --git a/contracts/dependencies/seaport/contracts/lib/FulfillmentApplier.sol b/contracts/dependencies/seaport/contracts/lib/FulfillmentApplier.sol index 984807746..433506128 100644 --- a/contracts/dependencies/seaport/contracts/lib/FulfillmentApplier.sol +++ b/contracts/dependencies/seaport/contracts/lib/FulfillmentApplier.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import { ItemType, Side } from "./ConsiderationEnums.sol"; diff --git a/contracts/dependencies/seaport/contracts/lib/GettersAndDerivers.sol b/contracts/dependencies/seaport/contracts/lib/GettersAndDerivers.sol index d2be4eb54..7d46328d0 100644 --- a/contracts/dependencies/seaport/contracts/lib/GettersAndDerivers.sol +++ b/contracts/dependencies/seaport/contracts/lib/GettersAndDerivers.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import { OrderParameters } from "./ConsiderationStructs.sol"; diff --git a/contracts/dependencies/seaport/contracts/lib/LowLevelHelpers.sol b/contracts/dependencies/seaport/contracts/lib/LowLevelHelpers.sol index 892ae9986..e7d75279d 100644 --- a/contracts/dependencies/seaport/contracts/lib/LowLevelHelpers.sol +++ b/contracts/dependencies/seaport/contracts/lib/LowLevelHelpers.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import "./ConsiderationConstants.sol"; diff --git a/contracts/dependencies/seaport/contracts/lib/OrderCombiner.sol b/contracts/dependencies/seaport/contracts/lib/OrderCombiner.sol index 3f082f4f9..955cefec8 100644 --- a/contracts/dependencies/seaport/contracts/lib/OrderCombiner.sol +++ b/contracts/dependencies/seaport/contracts/lib/OrderCombiner.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import { Side, ItemType } from "./ConsiderationEnums.sol"; diff --git a/contracts/dependencies/seaport/contracts/lib/OrderFulfiller.sol b/contracts/dependencies/seaport/contracts/lib/OrderFulfiller.sol index 2bb4af368..632c0763f 100644 --- a/contracts/dependencies/seaport/contracts/lib/OrderFulfiller.sol +++ b/contracts/dependencies/seaport/contracts/lib/OrderFulfiller.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import { ItemType } from "./ConsiderationEnums.sol"; diff --git a/contracts/dependencies/seaport/contracts/lib/OrderValidator.sol b/contracts/dependencies/seaport/contracts/lib/OrderValidator.sol index b80df114c..6ac333799 100644 --- a/contracts/dependencies/seaport/contracts/lib/OrderValidator.sol +++ b/contracts/dependencies/seaport/contracts/lib/OrderValidator.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import { OrderType } from "./ConsiderationEnums.sol"; diff --git a/contracts/dependencies/seaport/contracts/lib/ReentrancyGuard.sol b/contracts/dependencies/seaport/contracts/lib/ReentrancyGuard.sol index f80805e45..0dafb782e 100644 --- a/contracts/dependencies/seaport/contracts/lib/ReentrancyGuard.sol +++ b/contracts/dependencies/seaport/contracts/lib/ReentrancyGuard.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import { ReentrancyErrors } from "../interfaces/ReentrancyErrors.sol"; diff --git a/contracts/dependencies/seaport/contracts/lib/SignatureVerification.sol b/contracts/dependencies/seaport/contracts/lib/SignatureVerification.sol index 2b3ed6b3b..813661476 100644 --- a/contracts/dependencies/seaport/contracts/lib/SignatureVerification.sol +++ b/contracts/dependencies/seaport/contracts/lib/SignatureVerification.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import { EIP1271Interface } from "../interfaces/EIP1271Interface.sol"; diff --git a/contracts/dependencies/seaport/contracts/lib/TokenTransferrer.sol b/contracts/dependencies/seaport/contracts/lib/TokenTransferrer.sol index 4a6438faa..94b0dd89b 100644 --- a/contracts/dependencies/seaport/contracts/lib/TokenTransferrer.sol +++ b/contracts/dependencies/seaport/contracts/lib/TokenTransferrer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; import "./TokenTransferrerConstants.sol"; diff --git a/contracts/dependencies/seaport/contracts/lib/TokenTransferrerConstants.sol b/contracts/dependencies/seaport/contracts/lib/TokenTransferrerConstants.sol index 54293bcb4..b23976baa 100644 --- a/contracts/dependencies/seaport/contracts/lib/TokenTransferrerConstants.sol +++ b/contracts/dependencies/seaport/contracts/lib/TokenTransferrerConstants.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; /* * -------------------------- Disambiguation & Other Notes --------------------- diff --git a/contracts/dependencies/seaport/contracts/lib/Verifiers.sol b/contracts/dependencies/seaport/contracts/lib/Verifiers.sol index 3ba351478..c282325f7 100644 --- a/contracts/dependencies/seaport/contracts/lib/Verifiers.sol +++ b/contracts/dependencies/seaport/contracts/lib/Verifiers.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import { OrderStatus } from "./ConsiderationStructs.sol"; diff --git a/contracts/dependencies/seaport/contracts/lib/ZoneInteraction.sol b/contracts/dependencies/seaport/contracts/lib/ZoneInteraction.sol index 8d8b44258..38477e5f1 100644 --- a/contracts/dependencies/seaport/contracts/lib/ZoneInteraction.sol +++ b/contracts/dependencies/seaport/contracts/lib/ZoneInteraction.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import { ZoneInterface } from "../interfaces/ZoneInterface.sol"; diff --git a/contracts/dependencies/seaport/contracts/zones/PausableZone.sol b/contracts/dependencies/seaport/contracts/zones/PausableZone.sol index d94497d3d..acc55d1dc 100644 --- a/contracts/dependencies/seaport/contracts/zones/PausableZone.sol +++ b/contracts/dependencies/seaport/contracts/zones/PausableZone.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; import { ZoneInterface } from "../interfaces/ZoneInterface.sol"; import { ZoneInteractionErrors } from "../interfaces/ZoneInteractionErrors.sol"; @@ -100,13 +100,13 @@ contract PausableZone is * zone will not be fulfillable unless the zone is redeployed to the * same address. */ - function pause(address payee) external override isController { - // Emit an event signifying that the zone is paused. - emit Paused(); - - // Destroy the zone, sending any ether to the transaction submitter. - selfdestruct(payable(payee)); - } + // function pause(address payee) external override isController { + // // Emit an event signifying that the zone is paused. + // emit Paused(); + // + // // Destroy the zone, sending any ether to the transaction submitter. + // selfdestruct(payable(payee)); + // } /** * @notice Assign the given address with the ability to operate the zone. diff --git a/contracts/dependencies/seaport/contracts/zones/PausableZoneController.sol b/contracts/dependencies/seaport/contracts/zones/PausableZoneController.sol index 9761dfc2d..249f17801 100644 --- a/contracts/dependencies/seaport/contracts/zones/PausableZoneController.sol +++ b/contracts/dependencies/seaport/contracts/zones/PausableZoneController.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; import { PausableZone } from "./PausableZone.sol"; @@ -122,18 +122,18 @@ contract PausableZoneController is * * @return success A boolean indicating the zone has been paused. */ - function pause(address zone) - external - override - isPauser - returns (bool success) - { - // Call pause on the given zone. - PausableZone(zone).pause(msg.sender); - - // Return a boolean indicating the pause was successful. - success = true; - } + // function pause(address zone) + // external + // override + // isPauser + // returns (bool success) + // { + // // Call pause on the given zone. + // PausableZone(zone).pause(msg.sender); + // + // // Return a boolean indicating the pause was successful. + // success = true; + // } /** * @notice Cancel Seaport orders on a given zone. diff --git a/contracts/dependencies/seaport/contracts/zones/interfaces/PausableZoneControllerInterface.sol b/contracts/dependencies/seaport/contracts/zones/interfaces/PausableZoneControllerInterface.sol index f4d155abf..36558254c 100644 --- a/contracts/dependencies/seaport/contracts/zones/interfaces/PausableZoneControllerInterface.sol +++ b/contracts/dependencies/seaport/contracts/zones/interfaces/PausableZoneControllerInterface.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; import { PausableZone } from "../PausableZone.sol"; @@ -40,7 +40,7 @@ interface PausableZoneControllerInterface { * * @return success A boolean indicating the zone has been paused. */ - function pause(address zone) external returns (bool success); + // function pause(address zone) external returns (bool success); /** * @notice Cancel Seaport offers on a given zone. diff --git a/contracts/dependencies/seaport/contracts/zones/interfaces/PausableZoneEventsAndErrors.sol b/contracts/dependencies/seaport/contracts/zones/interfaces/PausableZoneEventsAndErrors.sol index ffe14f7a7..86b1a55ca 100644 --- a/contracts/dependencies/seaport/contracts/zones/interfaces/PausableZoneEventsAndErrors.sol +++ b/contracts/dependencies/seaport/contracts/zones/interfaces/PausableZoneEventsAndErrors.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; /** * @notice PausableZoneEventsAndErrors contains errors and events diff --git a/contracts/dependencies/seaport/contracts/zones/interfaces/PausableZoneInterface.sol b/contracts/dependencies/seaport/contracts/zones/interfaces/PausableZoneInterface.sol index 19c414c81..662f264f4 100644 --- a/contracts/dependencies/seaport/contracts/zones/interfaces/PausableZoneInterface.sol +++ b/contracts/dependencies/seaport/contracts/zones/interfaces/PausableZoneInterface.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.0; import { SeaportInterface } from "../../interfaces/SeaportInterface.sol"; @@ -89,7 +89,7 @@ interface PausableZoneInterface { * zone will not be fulfillable unless the zone is redeployed to the * same address. */ - function pause(address payee) external; + // function pause(address payee) external; /** * @notice Assign the given address with the ability to operate the zone. diff --git a/contracts/dependencies/stakefish/StakefishNFTManager.sol b/contracts/dependencies/stakefish/StakefishNFTManager.sol index 42bfae6b4..2babd49e6 100644 --- a/contracts/dependencies/stakefish/StakefishNFTManager.sol +++ b/contracts/dependencies/stakefish/StakefishNFTManager.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import "../openzeppelin/contracts/ERC721Enumerable.sol"; import "../openzeppelin/contracts/ReentrancyGuard.sol"; diff --git a/contracts/dependencies/stakefish/StakefishValidatorBase.sol b/contracts/dependencies/stakefish/StakefishValidatorBase.sol index 389bcc9c2..1c2c909a4 100644 --- a/contracts/dependencies/stakefish/StakefishValidatorBase.sol +++ b/contracts/dependencies/stakefish/StakefishValidatorBase.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import "../openzeppelin/contracts/StorageSlot.sol"; import "./interfaces/IStakefishValidatorFactory.sol"; diff --git a/contracts/dependencies/stakefish/StakefishValidatorFactory.sol b/contracts/dependencies/stakefish/StakefishValidatorFactory.sol index df2584f30..b850310f2 100644 --- a/contracts/dependencies/stakefish/StakefishValidatorFactory.sol +++ b/contracts/dependencies/stakefish/StakefishValidatorFactory.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import "../openzeppelin/upgradeability/Clones.sol"; import "../openzeppelin/contracts/Ownable.sol"; diff --git a/contracts/dependencies/stakefish/StakefishValidatorOperator.sol b/contracts/dependencies/stakefish/StakefishValidatorOperator.sol index 4ba75feec..36cc02fe8 100644 --- a/contracts/dependencies/stakefish/StakefishValidatorOperator.sol +++ b/contracts/dependencies/stakefish/StakefishValidatorOperator.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import "../openzeppelin/contracts/Address.sol"; import "../openzeppelin/contracts/Ownable.sol"; diff --git a/contracts/dependencies/stakefish/StakefishValidatorWallet.sol b/contracts/dependencies/stakefish/StakefishValidatorWallet.sol index 4e116325b..675e29fa0 100644 --- a/contracts/dependencies/stakefish/StakefishValidatorWallet.sol +++ b/contracts/dependencies/stakefish/StakefishValidatorWallet.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import "../openzeppelin/upgradeability/Proxy.sol"; diff --git a/contracts/dependencies/stakefish/implementations/StakefishValidatorV1.sol b/contracts/dependencies/stakefish/implementations/StakefishValidatorV1.sol index 9680fa38e..27b70b4d2 100644 --- a/contracts/dependencies/stakefish/implementations/StakefishValidatorV1.sol +++ b/contracts/dependencies/stakefish/implementations/StakefishValidatorV1.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import "../../openzeppelin/contracts/ReentrancyGuard.sol"; import "../../openzeppelin/upgradeability/Initializable.sol"; diff --git a/contracts/dependencies/stakefish/interfaces/IDepositContract.sol b/contracts/dependencies/stakefish/interfaces/IDepositContract.sol index 9942b9884..dbb88d30c 100644 --- a/contracts/dependencies/stakefish/interfaces/IDepositContract.sol +++ b/contracts/dependencies/stakefish/interfaces/IDepositContract.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity >0.5.0 <0.9.0; +pragma solidity ^0.8.0; interface IDepositContract { function deposit( diff --git a/contracts/dependencies/stakefish/interfaces/IStakefishNFTManager.sol b/contracts/dependencies/stakefish/interfaces/IStakefishNFTManager.sol index abe07320c..6dc9e7c28 100644 --- a/contracts/dependencies/stakefish/interfaces/IStakefishNFTManager.sol +++ b/contracts/dependencies/stakefish/interfaces/IStakefishNFTManager.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import '../../openzeppelin/contracts/IERC721Metadata.sol'; import '../../openzeppelin/contracts/IERC721Enumerable.sol'; diff --git a/contracts/dependencies/stakefish/interfaces/IStakefishTransactionFeePoolV2.sol b/contracts/dependencies/stakefish/interfaces/IStakefishTransactionFeePoolV2.sol index 615b666be..bb9d0b492 100644 --- a/contracts/dependencies/stakefish/interfaces/IStakefishTransactionFeePoolV2.sol +++ b/contracts/dependencies/stakefish/interfaces/IStakefishTransactionFeePoolV2.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; interface IStakefishTransactionFeePoolV2 { function collectReward(address payable beneficiary, uint256 amountRequested) external; diff --git a/contracts/dependencies/stakefish/interfaces/IStakefishValidator.sol b/contracts/dependencies/stakefish/interfaces/IStakefishValidator.sol index 57592a4b4..bb5337df3 100644 --- a/contracts/dependencies/stakefish/interfaces/IStakefishValidator.sol +++ b/contracts/dependencies/stakefish/interfaces/IStakefishValidator.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; /// @title The interface for StakefishValidator /// @notice Defines implementation of the wallet (deposit, withdraw, collect fees) diff --git a/contracts/dependencies/stakefish/interfaces/IStakefishValidatorFactory.sol b/contracts/dependencies/stakefish/interfaces/IStakefishValidatorFactory.sol index 0d33fe720..82dbe601e 100644 --- a/contracts/dependencies/stakefish/interfaces/IStakefishValidatorFactory.sol +++ b/contracts/dependencies/stakefish/interfaces/IStakefishValidatorFactory.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; /// @dev We can pas salt in to create deterministic address in solidity // https://docs.soliditylang.org/en/develop/control-structures.html#salted-contract-creations-create2 diff --git a/contracts/dependencies/stakefish/interfaces/IStakefishValidatorOperator.sol b/contracts/dependencies/stakefish/interfaces/IStakefishValidatorOperator.sol index e13c40779..ff350d304 100644 --- a/contracts/dependencies/stakefish/interfaces/IStakefishValidatorOperator.sol +++ b/contracts/dependencies/stakefish/interfaces/IStakefishValidatorOperator.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; interface IStakefishValidatorOperator { /// @notice immutable nft manager address diff --git a/contracts/dependencies/stakefish/interfaces/IStakefishValidatorWallet.sol b/contracts/dependencies/stakefish/interfaces/IStakefishValidatorWallet.sol index 502c1f8e8..58708f952 100644 --- a/contracts/dependencies/stakefish/interfaces/IStakefishValidatorWallet.sol +++ b/contracts/dependencies/stakefish/interfaces/IStakefishValidatorWallet.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; /// @title The interface for StakefishValidatorWallet /// @notice Factory created contract representing the validator withdrawal address diff --git a/contracts/dependencies/stakefish/library/ERC1976Thin.sol b/contracts/dependencies/stakefish/library/ERC1976Thin.sol index 13943261b..0f2bb77ae 100644 --- a/contracts/dependencies/stakefish/library/ERC1976Thin.sol +++ b/contracts/dependencies/stakefish/library/ERC1976Thin.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import '../../openzeppelin/contracts/Address.sol'; import '../../openzeppelin/contracts/StorageSlot.sol'; diff --git a/contracts/dependencies/uniswap/libraries/LICENSE_MIT b/contracts/dependencies/uniswap/libraries/LICENSE_MIT deleted file mode 100644 index bf4f90a28..000000000 --- a/contracts/dependencies/uniswap/libraries/LICENSE_MIT +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2021 Remco Bloemen - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/contracts/dependencies/uniswap/libraries/SafeCast.sol b/contracts/dependencies/uniswap/libraries/SafeCast.sol deleted file mode 100644 index a8ea22987..000000000 --- a/contracts/dependencies/uniswap/libraries/SafeCast.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; - -/// @title Safe casting methods -/// @notice Contains methods for safely casting between types -library SafeCast { - /// @notice Cast a uint256 to a uint160, revert on overflow - /// @param y The uint256 to be downcasted - /// @return z The downcasted integer, now type uint160 - function toUint160(uint256 y) internal pure returns (uint160 z) { - require((z = uint160(y)) == y); - } - - /// @notice Cast a int256 to a int128, revert on overflow or underflow - /// @param y The int256 to be downcasted - /// @return z The downcasted integer, now type int128 - function toInt128(int256 y) internal pure returns (int128 z) { - require((z = int128(y)) == y); - } - - /// @notice Cast a uint256 to a int256, revert on overflow - /// @param y The uint256 to be casted - /// @return z The casted integer, now type int256 - function toInt256(uint256 y) internal pure returns (int256 z) { - require(y < 2**255); - z = int256(y); - } -} diff --git a/contracts/dependencies/uniswap/libraries/TickMath.sol b/contracts/dependencies/uniswap/libraries/TickMath.sol deleted file mode 100644 index 64d076926..000000000 --- a/contracts/dependencies/uniswap/libraries/TickMath.sol +++ /dev/null @@ -1,257 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.8.0; - -/// @title Math library for computing sqrt prices from ticks and vice versa -/// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports -/// prices between 2**-128 and 2**128 -library TickMath { - error T(); - error R(); - - /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128 - int24 internal constant MIN_TICK = -887272; - /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128 - int24 internal constant MAX_TICK = -MIN_TICK; - - /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK) - uint160 internal constant MIN_SQRT_RATIO = 4295128739; - /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK) - uint160 internal constant MAX_SQRT_RATIO = - 1461446703485210103287273052203988822378723970342; - - /// @notice Calculates sqrt(1.0001^tick) * 2^96 - /// @dev Throws if |tick| > max tick - /// @param tick The input tick for the above formula - /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0) - /// at the given tick - function getSqrtRatioAtTick(int24 tick) - internal - pure - returns (uint160 sqrtPriceX96) - { - unchecked { - uint256 absTick = tick < 0 - ? uint256(-int256(tick)) - : uint256(int256(tick)); - if (absTick > uint256(int256(MAX_TICK))) revert T(); - - uint256 ratio = absTick & 0x1 != 0 - ? 0xfffcb933bd6fad37aa2d162d1a594001 - : 0x100000000000000000000000000000000; - if (absTick & 0x2 != 0) - ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128; - if (absTick & 0x4 != 0) - ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128; - if (absTick & 0x8 != 0) - ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128; - if (absTick & 0x10 != 0) - ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128; - if (absTick & 0x20 != 0) - ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128; - if (absTick & 0x40 != 0) - ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128; - if (absTick & 0x80 != 0) - ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128; - if (absTick & 0x100 != 0) - ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128; - if (absTick & 0x200 != 0) - ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128; - if (absTick & 0x400 != 0) - ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128; - if (absTick & 0x800 != 0) - ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128; - if (absTick & 0x1000 != 0) - ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128; - if (absTick & 0x2000 != 0) - ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128; - if (absTick & 0x4000 != 0) - ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128; - if (absTick & 0x8000 != 0) - ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128; - if (absTick & 0x10000 != 0) - ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128; - if (absTick & 0x20000 != 0) - ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128; - if (absTick & 0x40000 != 0) - ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128; - if (absTick & 0x80000 != 0) - ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128; - - if (tick > 0) ratio = type(uint256).max / ratio; - - // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96. - // we then downcast because we know the result always fits within 160 bits due to our tick input constraint - // we round up in the division so getTickAtSqrtRatio of the output price is always consistent - sqrtPriceX96 = uint160( - (ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1) - ); - } - } - - /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio - /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may - /// ever return. - /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96 - /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio - function getTickAtSqrtRatio(uint160 sqrtPriceX96) - internal - pure - returns (int24 tick) - { - unchecked { - // second inequality must be < because the price can never reach the price at the max tick - if ( - !(sqrtPriceX96 >= MIN_SQRT_RATIO && - sqrtPriceX96 < MAX_SQRT_RATIO) - ) revert R(); - uint256 ratio = uint256(sqrtPriceX96) << 32; - - uint256 r = ratio; - uint256 msb = 0; - - assembly { - let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) - msb := or(msb, f) - r := shr(f, r) - } - assembly { - let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF)) - msb := or(msb, f) - r := shr(f, r) - } - assembly { - let f := shl(5, gt(r, 0xFFFFFFFF)) - msb := or(msb, f) - r := shr(f, r) - } - assembly { - let f := shl(4, gt(r, 0xFFFF)) - msb := or(msb, f) - r := shr(f, r) - } - assembly { - let f := shl(3, gt(r, 0xFF)) - msb := or(msb, f) - r := shr(f, r) - } - assembly { - let f := shl(2, gt(r, 0xF)) - msb := or(msb, f) - r := shr(f, r) - } - assembly { - let f := shl(1, gt(r, 0x3)) - msb := or(msb, f) - r := shr(f, r) - } - assembly { - let f := gt(r, 0x1) - msb := or(msb, f) - } - - if (msb >= 128) r = ratio >> (msb - 127); - else r = ratio << (127 - msb); - - int256 log_2 = (int256(msb) - 128) << 64; - - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(63, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(62, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(61, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(60, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(59, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(58, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(57, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(56, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(55, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(54, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(53, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(52, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(51, f)) - r := shr(f, r) - } - assembly { - r := shr(127, mul(r, r)) - let f := shr(128, r) - log_2 := or(log_2, shl(50, f)) - } - - int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number - - int24 tickLow = int24( - (log_sqrt10001 - 3402992956809132418596140100660247210) >> 128 - ); - int24 tickHi = int24( - (log_sqrt10001 + 291339464771989622907027621153398088495) >> 128 - ); - - tick = tickLow == tickHi - ? tickLow - : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 - ? tickHi - : tickLow; - } - } -} diff --git a/contracts/dependencies/uniswap/libraries/UnsafeMath.sol b/contracts/dependencies/uniswap/libraries/UnsafeMath.sol deleted file mode 100644 index eda37a27e..000000000 --- a/contracts/dependencies/uniswap/libraries/UnsafeMath.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; - -/// @title Math functions that do not check inputs or outputs -/// @notice Contains methods that perform common math functions but do not do any overflow or underflow checks -library UnsafeMath { - /// @notice Returns ceil(x / y) - /// @dev division by 0 has unspecified behavior, and must be checked externally - /// @param x The dividend - /// @param y The divisor - /// @return z The quotient, ceil(x / y) - function divRoundingUp(uint256 x, uint256 y) - internal - pure - returns (uint256 z) - { - assembly { - z := add(div(x, y), gt(mod(x, y), 0)) - } - } -} diff --git a/contracts/dependencies/univ3/NoDelegateCall.sol b/contracts/dependencies/uniswapv3-core/NoDelegateCall.sol similarity index 97% rename from contracts/dependencies/univ3/NoDelegateCall.sol rename to contracts/dependencies/uniswapv3-core/NoDelegateCall.sol index 5411979dc..4e76e157c 100644 --- a/contracts/dependencies/univ3/NoDelegateCall.sol +++ b/contracts/dependencies/uniswapv3-core/NoDelegateCall.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity =0.7.6; +pragma solidity ^0.8.0; /// @title Prevents delegatecall to a contract /// @notice Base contract that provides a modifier for preventing delegatecall to methods in a child contract diff --git a/contracts/dependencies/univ3/UniswapV3Factory.sol b/contracts/dependencies/uniswapv3-core/UniswapV3Factory.sol similarity index 83% rename from contracts/dependencies/univ3/UniswapV3Factory.sol rename to contracts/dependencies/uniswapv3-core/UniswapV3Factory.sol index 0ea0b9b7f..62ceab166 100644 --- a/contracts/dependencies/univ3/UniswapV3Factory.sol +++ b/contracts/dependencies/uniswapv3-core/UniswapV3Factory.sol @@ -1,29 +1,23 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity =0.7.6; +pragma solidity ^0.8.0; -import "./interfaces/IUniswapV3Factory.sol"; +import {IUniswapV3Factory} from './interfaces/IUniswapV3Factory.sol'; -import "./UniswapV3PoolDeployer.sol"; -import "./NoDelegateCall.sol"; +import {UniswapV3PoolDeployer} from './UniswapV3PoolDeployer.sol'; +import {NoDelegateCall} from './NoDelegateCall.sol'; -import "./UniswapV3Pool.sol"; +import {UniswapV3Pool} from './UniswapV3Pool.sol'; /// @title Canonical Uniswap V3 factory /// @notice Deploys Uniswap V3 pools and manages ownership and control over pool protocol fees -contract UniswapV3Factory is - IUniswapV3Factory, - UniswapV3PoolDeployer, - NoDelegateCall -{ +contract UniswapV3Factory is IUniswapV3Factory, UniswapV3PoolDeployer, NoDelegateCall { /// @inheritdoc IUniswapV3Factory address public override owner; /// @inheritdoc IUniswapV3Factory mapping(uint24 => int24) public override feeAmountTickSpacing; /// @inheritdoc IUniswapV3Factory - mapping(address => mapping(address => mapping(uint24 => address))) - public - override getPool; + mapping(address => mapping(address => mapping(uint24 => address))) public override getPool; constructor() { owner = msg.sender; @@ -44,9 +38,7 @@ contract UniswapV3Factory is uint24 fee ) external override noDelegateCall returns (address pool) { require(tokenA != tokenB); - (address token0, address token1) = tokenA < tokenB - ? (tokenA, tokenB) - : (tokenB, tokenA); + (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); require(token0 != address(0)); int24 tickSpacing = feeAmountTickSpacing[fee]; require(tickSpacing != 0); diff --git a/contracts/dependencies/univ3/UniswapV3Pool.sol b/contracts/dependencies/uniswapv3-core/UniswapV3Pool.sol similarity index 62% rename from contracts/dependencies/univ3/UniswapV3Pool.sol rename to contracts/dependencies/uniswapv3-core/UniswapV3Pool.sol index 8b61e89ae..42a7b67af 100644 --- a/contracts/dependencies/univ3/UniswapV3Pool.sol +++ b/contracts/dependencies/uniswapv3-core/UniswapV3Pool.sol @@ -1,35 +1,31 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity =0.7.6; - -import "./interfaces/IUniswapV3Pool.sol"; - -import "./NoDelegateCall.sol"; - -import "./libraries/LowGasSafeMath.sol"; -import "./libraries/SafeCast.sol"; -import "./libraries/Tick.sol"; -import "./libraries/TickBitmap.sol"; -import "./libraries/Position.sol"; -import "./libraries/Oracle.sol"; - -import "./libraries/FullMath.sol"; -import "./libraries/FixedPoint128.sol"; -import "./libraries/TransferHelper.sol"; -import "./libraries/TickMath.sol"; -import "./libraries/LiquidityMath.sol"; -import "./libraries/SqrtPriceMath.sol"; -import "./libraries/SwapMath.sol"; - -import "./interfaces/IUniswapV3PoolDeployer.sol"; -import "./interfaces/IUniswapV3Factory.sol"; -import "./interfaces/IERC20Minimal.sol"; -import "./interfaces/callback/IUniswapV3MintCallback.sol"; -import "./interfaces/callback/IUniswapV3SwapCallback.sol"; -import "./interfaces/callback/IUniswapV3FlashCallback.sol"; +pragma solidity ^0.8.0; + +import {IUniswapV3PoolImmutables, IUniswapV3PoolState, IUniswapV3PoolActions, IUniswapV3PoolDerivedState, IUniswapV3PoolOwnerActions, IUniswapV3Pool} from './interfaces/IUniswapV3Pool.sol'; + +import {NoDelegateCall} from './NoDelegateCall.sol'; + +import {SafeCast} from './libraries/SafeCast.sol'; +import {Tick} from './libraries/Tick.sol'; +import {TickBitmap} from './libraries/TickBitmap.sol'; +import {Position} from './libraries/Position.sol'; +import {Oracle} from './libraries/Oracle.sol'; + +import {FullMath} from './libraries/FullMath.sol'; +import {FixedPoint128} from './libraries/FixedPoint128.sol'; +import {TransferHelper} from './libraries/TransferHelper.sol'; +import {TickMath} from './libraries/TickMath.sol'; +import {SqrtPriceMath} from './libraries/SqrtPriceMath.sol'; +import {SwapMath} from './libraries/SwapMath.sol'; + +import {IUniswapV3PoolDeployer} from './interfaces/IUniswapV3PoolDeployer.sol'; +import {IUniswapV3Factory} from './interfaces/IUniswapV3Factory.sol'; +import {IERC20Minimal} from './interfaces/IERC20Minimal.sol'; +import {IUniswapV3MintCallback} from './interfaces/callback/IUniswapV3MintCallback.sol'; +import {IUniswapV3SwapCallback} from './interfaces/callback/IUniswapV3SwapCallback.sol'; +import {IUniswapV3FlashCallback} from './interfaces/callback/IUniswapV3FlashCallback.sol'; contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { - using LowGasSafeMath for uint256; - using LowGasSafeMath for int256; using SafeCast for uint256; using SafeCast for int256; using Tick for mapping(int24 => Tick.Info); @@ -102,7 +98,7 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { /// to a function before the pool is initialized. The reentrancy guard is required throughout the contract because /// we use balance checks to determine the payment status of interactions such as mint, swap and flash. modifier lock() { - require(slot0.unlocked, "LOK"); + if (!slot0.unlocked) revert LOK(); slot0.unlocked = false; _; slot0.unlocked = true; @@ -116,21 +112,17 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { constructor() { int24 _tickSpacing; - (factory, token0, token1, fee, _tickSpacing) = IUniswapV3PoolDeployer( - msg.sender - ).parameters(); + (factory, token0, token1, fee, _tickSpacing) = IUniswapV3PoolDeployer(msg.sender).parameters(); tickSpacing = _tickSpacing; - maxLiquidityPerTick = Tick.tickSpacingToMaxLiquidityPerTick( - _tickSpacing - ); + maxLiquidityPerTick = Tick.tickSpacingToMaxLiquidityPerTick(_tickSpacing); } /// @dev Common checks for valid tick inputs. function checkTicks(int24 tickLower, int24 tickUpper) private pure { - require(tickLower < tickUpper, "TLU"); - require(tickLower >= TickMath.MIN_TICK, "TLM"); - require(tickUpper <= TickMath.MAX_TICK, "TUM"); + if (tickLower >= tickUpper) revert TLU(); + if (tickLower < TickMath.MIN_TICK) revert TLM(); + if (tickUpper > TickMath.MAX_TICK) revert TUM(); } /// @dev Returns the block timestamp truncated to 32 bits, i.e. mod 2**32. This method is overridden in tests. @@ -143,10 +135,7 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { /// check function balance0() private view returns (uint256) { (bool success, bytes memory data) = token0.staticcall( - abi.encodeWithSelector( - IERC20Minimal.balanceOf.selector, - address(this) - ) + abi.encodeWithSelector(IERC20Minimal.balanceOf.selector, address(this)) ); require(success && data.length >= 32); return abi.decode(data, (uint256)); @@ -157,10 +146,7 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { /// check function balance1() private view returns (uint256) { (bool success, bytes memory data) = token1.staticcall( - abi.encodeWithSelector( - IERC20Minimal.balanceOf.selector, - address(this) - ) + abi.encodeWithSelector(IERC20Minimal.balanceOf.selector, address(this)) ); require(success && data.length >= 32); return abi.decode(data, (uint256)); @@ -191,12 +177,7 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { Tick.Info storage lower = ticks[tickLower]; Tick.Info storage upper = ticks[tickUpper]; bool initializedLower; - ( - tickCumulativeLower, - secondsPerLiquidityOutsideLowerX128, - secondsOutsideLower, - initializedLower - ) = ( + (tickCumulativeLower, secondsPerLiquidityOutsideLowerX128, secondsOutsideLower, initializedLower) = ( lower.tickCumulativeOutside, lower.secondsPerLiquidityOutsideX128, lower.secondsOutside, @@ -205,12 +186,7 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { require(initializedLower); bool initializedUpper; - ( - tickCumulativeUpper, - secondsPerLiquidityOutsideUpperX128, - secondsOutsideUpper, - initializedUpper - ) = ( + (tickCumulativeUpper, secondsPerLiquidityOutsideUpperX128, secondsOutsideUpper, initializedUpper) = ( upper.tickCumulativeOutside, upper.secondsPerLiquidityOutsideX128, upper.secondsOutside, @@ -221,19 +197,16 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { Slot0 memory _slot0 = slot0; - if (_slot0.tick < tickLower) { - return ( - tickCumulativeLower - tickCumulativeUpper, - secondsPerLiquidityOutsideLowerX128 - - secondsPerLiquidityOutsideUpperX128, - secondsOutsideLower - secondsOutsideUpper - ); - } else if (_slot0.tick < tickUpper) { - uint32 time = _blockTimestamp(); - ( - int56 tickCumulative, - uint160 secondsPerLiquidityCumulativeX128 - ) = observations.observeSingle( + unchecked { + if (_slot0.tick < tickLower) { + return ( + tickCumulativeLower - tickCumulativeUpper, + secondsPerLiquidityOutsideLowerX128 - secondsPerLiquidityOutsideUpperX128, + secondsOutsideLower - secondsOutsideUpper + ); + } else if (_slot0.tick < tickUpper) { + uint32 time = _blockTimestamp(); + (int56 tickCumulative, uint160 secondsPerLiquidityCumulativeX128) = observations.observeSingle( time, 0, _slot0.tick, @@ -241,20 +214,20 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { liquidity, _slot0.observationCardinality ); - return ( - tickCumulative - tickCumulativeLower - tickCumulativeUpper, - secondsPerLiquidityCumulativeX128 - - secondsPerLiquidityOutsideLowerX128 - - secondsPerLiquidityOutsideUpperX128, - time - secondsOutsideLower - secondsOutsideUpper - ); - } else { - return ( - tickCumulativeUpper - tickCumulativeLower, - secondsPerLiquidityOutsideUpperX128 - - secondsPerLiquidityOutsideLowerX128, - secondsOutsideUpper - secondsOutsideLower - ); + return ( + tickCumulative - tickCumulativeLower - tickCumulativeUpper, + secondsPerLiquidityCumulativeX128 - + secondsPerLiquidityOutsideLowerX128 - + secondsPerLiquidityOutsideUpperX128, + time - secondsOutsideLower - secondsOutsideUpper + ); + } else { + return ( + tickCumulativeUpper - tickCumulativeLower, + secondsPerLiquidityOutsideUpperX128 - secondsPerLiquidityOutsideLowerX128, + secondsOutsideUpper - secondsOutsideLower + ); + } } } @@ -264,10 +237,7 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { view override noDelegateCall - returns ( - int56[] memory tickCumulatives, - uint160[] memory secondsPerLiquidityCumulativeX128s - ) + returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s) { return observations.observe( @@ -281,9 +251,12 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { } /// @inheritdoc IUniswapV3PoolActions - function increaseObservationCardinalityNext( - uint16 observationCardinalityNext - ) external override lock noDelegateCall { + function increaseObservationCardinalityNext(uint16 observationCardinalityNext) + external + override + lock + noDelegateCall + { uint16 observationCardinalityNextOld = slot0.observationCardinalityNext; // for the event uint16 observationCardinalityNextNew = observations.grow( observationCardinalityNextOld, @@ -291,22 +264,17 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { ); slot0.observationCardinalityNext = observationCardinalityNextNew; if (observationCardinalityNextOld != observationCardinalityNextNew) - emit IncreaseObservationCardinalityNext( - observationCardinalityNextOld, - observationCardinalityNextNew - ); + emit IncreaseObservationCardinalityNext(observationCardinalityNextOld, observationCardinalityNextNew); } /// @inheritdoc IUniswapV3PoolActions /// @dev not locked because it initializes unlocked function initialize(uint160 sqrtPriceX96) external override { - require(slot0.sqrtPriceX96 == 0, "AI"); + if (slot0.sqrtPriceX96 != 0) revert AI(); int24 tick = TickMath.getTickAtSqrtRatio(sqrtPriceX96); - (uint16 cardinality, uint16 cardinalityNext) = observations.initialize( - _blockTimestamp() - ); + (uint16 cardinality, uint16 cardinalityNext) = observations.initialize(_blockTimestamp()); slot0 = Slot0({ sqrtPriceX96: sqrtPriceX96, @@ -371,10 +339,7 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { uint128 liquidityBefore = liquidity; // SLOAD for gas optimization // write an oracle entry - ( - slot0.observationIndex, - slot0.observationCardinality - ) = observations.write( + (slot0.observationIndex, slot0.observationCardinality) = observations.write( _slot0.observationIndex, _blockTimestamp(), _slot0.tick, @@ -394,10 +359,9 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { params.liquidityDelta ); - liquidity = LiquidityMath.addDelta( - liquidityBefore, - params.liquidityDelta - ); + liquidity = params.liquidityDelta < 0 + ? liquidityBefore - uint128(-params.liquidityDelta) + : liquidityBefore + uint128(params.liquidityDelta); } else { // current tick is above the passed range; liquidity can only become in range by crossing from right to // left, when we'll need _more_ token1 (it's becoming more valuable) so user must provide it @@ -432,17 +396,14 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { bool flippedUpper; if (liquidityDelta != 0) { uint32 time = _blockTimestamp(); - ( - int56 tickCumulative, - uint160 secondsPerLiquidityCumulativeX128 - ) = observations.observeSingle( - time, - 0, - slot0.tick, - slot0.observationIndex, - liquidity, - slot0.observationCardinality - ); + (int56 tickCumulative, uint160 secondsPerLiquidityCumulativeX128) = observations.observeSingle( + time, + 0, + slot0.tick, + slot0.observationIndex, + liquidity, + slot0.observationCardinality + ); flippedLower = ticks.update( tickLower, @@ -477,21 +438,16 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { } } - (uint256 feeGrowthInside0X128, uint256 feeGrowthInside1X128) = ticks - .getFeeGrowthInside( - tickLower, - tickUpper, - tick, - _feeGrowthGlobal0X128, - _feeGrowthGlobal1X128 - ); - - position.update( - liquidityDelta, - feeGrowthInside0X128, - feeGrowthInside1X128 + (uint256 feeGrowthInside0X128, uint256 feeGrowthInside1X128) = ticks.getFeeGrowthInside( + tickLower, + tickUpper, + tick, + _feeGrowthGlobal0X128, + _feeGrowthGlobal1X128 ); + position.update(liquidityDelta, feeGrowthInside0X128, feeGrowthInside1X128); + // clear any tick data that is no longer needed if (liquidityDelta < 0) { if (flippedLower) { @@ -518,7 +474,7 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { owner: recipient, tickLower: tickLower, tickUpper: tickUpper, - liquidityDelta: int256(amount).toInt128() + liquidityDelta: int256(uint256(amount)).toInt128() }) ); @@ -529,25 +485,11 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { uint256 balance1Before; if (amount0 > 0) balance0Before = balance0(); if (amount1 > 0) balance1Before = balance1(); - IUniswapV3MintCallback(msg.sender).uniswapV3MintCallback( - amount0, - amount1, - data - ); - if (amount0 > 0) - require(balance0Before.add(amount0) <= balance0(), "M0"); - if (amount1 > 0) - require(balance1Before.add(amount1) <= balance1(), "M1"); - - emit Mint( - msg.sender, - recipient, - tickLower, - tickUpper, - amount, - amount0, - amount1 - ); + IUniswapV3MintCallback(msg.sender).uniswapV3MintCallback(amount0, amount1, data); + if (amount0 > 0 && balance0Before + amount0 > balance0()) revert M0(); + if (amount1 > 0 && balance1Before + amount1 > balance1()) revert M1(); + + emit Mint(msg.sender, recipient, tickLower, tickUpper, amount, amount0, amount1); } /// @inheritdoc IUniswapV3PoolActions @@ -559,36 +501,23 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { uint128 amount1Requested ) external override lock returns (uint128 amount0, uint128 amount1) { // we don't need to checkTicks here, because invalid positions will never have non-zero tokensOwed{0,1} - Position.Info storage position = positions.get( - msg.sender, - tickLower, - tickUpper - ); + Position.Info storage position = positions.get(msg.sender, tickLower, tickUpper); - amount0 = amount0Requested > position.tokensOwed0 - ? position.tokensOwed0 - : amount0Requested; - amount1 = amount1Requested > position.tokensOwed1 - ? position.tokensOwed1 - : amount1Requested; + amount0 = amount0Requested > position.tokensOwed0 ? position.tokensOwed0 : amount0Requested; + amount1 = amount1Requested > position.tokensOwed1 ? position.tokensOwed1 : amount1Requested; - if (amount0 > 0) { - position.tokensOwed0 -= amount0; - TransferHelper.safeTransfer(token0, recipient, amount0); - } - if (amount1 > 0) { - position.tokensOwed1 -= amount1; - TransferHelper.safeTransfer(token1, recipient, amount1); + unchecked { + if (amount0 > 0) { + position.tokensOwed0 -= amount0; + TransferHelper.safeTransfer(token0, recipient, amount0); + } + if (amount1 > 0) { + position.tokensOwed1 -= amount1; + TransferHelper.safeTransfer(token1, recipient, amount1); + } } - emit Collect( - msg.sender, - recipient, - tickLower, - tickUpper, - amount0, - amount1 - ); + emit Collect(msg.sender, recipient, tickLower, tickUpper, amount0, amount1); } /// @inheritdoc IUniswapV3PoolActions @@ -598,30 +527,28 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { int24 tickUpper, uint128 amount ) external override lock returns (uint256 amount0, uint256 amount1) { - ( - Position.Info storage position, - int256 amount0Int, - int256 amount1Int - ) = _modifyPosition( + unchecked { + (Position.Info storage position, int256 amount0Int, int256 amount1Int) = _modifyPosition( ModifyPositionParams({ owner: msg.sender, tickLower: tickLower, tickUpper: tickUpper, - liquidityDelta: -int256(amount).toInt128() + liquidityDelta: -int256(uint256(amount)).toInt128() }) ); - amount0 = uint256(-amount0Int); - amount1 = uint256(-amount1Int); + amount0 = uint256(-amount0Int); + amount1 = uint256(-amount1Int); - if (amount0 > 0 || amount1 > 0) { - (position.tokensOwed0, position.tokensOwed1) = ( - position.tokensOwed0 + uint128(amount0), - position.tokensOwed1 + uint128(amount1) - ); - } + if (amount0 > 0 || amount1 > 0) { + (position.tokensOwed0, position.tokensOwed1) = ( + position.tokensOwed0 + uint128(amount0), + position.tokensOwed1 + uint128(amount1) + ); + } - emit Burn(msg.sender, tickLower, tickUpper, amount, amount0, amount1); + emit Burn(msg.sender, tickLower, tickUpper, amount, amount0, amount1); + } } struct SwapCache { @@ -681,24 +608,17 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { int256 amountSpecified, uint160 sqrtPriceLimitX96, bytes calldata data - ) - external - override - noDelegateCall - returns (int256 amount0, int256 amount1) - { - require(amountSpecified != 0, "AS"); + ) external override noDelegateCall returns (int256 amount0, int256 amount1) { + if (amountSpecified == 0) revert AS(); Slot0 memory slot0Start = slot0; - require(slot0Start.unlocked, "LOK"); + if (!slot0Start.unlocked) revert LOK(); require( zeroForOne - ? sqrtPriceLimitX96 < slot0Start.sqrtPriceX96 && - sqrtPriceLimitX96 > TickMath.MIN_SQRT_RATIO - : sqrtPriceLimitX96 > slot0Start.sqrtPriceX96 && - sqrtPriceLimitX96 < TickMath.MAX_SQRT_RATIO, - "SPL" + ? sqrtPriceLimitX96 < slot0Start.sqrtPriceX96 && sqrtPriceLimitX96 > TickMath.MIN_SQRT_RATIO + : sqrtPriceLimitX96 > slot0Start.sqrtPriceX96 && sqrtPriceLimitX96 < TickMath.MAX_SQRT_RATIO, + 'SPL' ); slot0.unlocked = false; @@ -706,9 +626,7 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { SwapCache memory cache = SwapCache({ liquidityStart: liquidity, blockTimestamp: _blockTimestamp(), - feeProtocol: zeroForOne - ? (slot0Start.feeProtocol % 16) - : (slot0Start.feeProtocol >> 4), + feeProtocol: zeroForOne ? (slot0Start.feeProtocol % 16) : (slot0Start.feeProtocol >> 4), secondsPerLiquidityCumulativeX128: 0, tickCumulative: 0, computedLatestObservation: false @@ -721,28 +639,22 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { amountCalculated: 0, sqrtPriceX96: slot0Start.sqrtPriceX96, tick: slot0Start.tick, - feeGrowthGlobalX128: zeroForOne - ? feeGrowthGlobal0X128 - : feeGrowthGlobal1X128, + feeGrowthGlobalX128: zeroForOne ? feeGrowthGlobal0X128 : feeGrowthGlobal1X128, protocolFee: 0, liquidity: cache.liquidityStart }); // continue swapping as long as we haven't used the entire input/output and haven't reached the price limit - while ( - state.amountSpecifiedRemaining != 0 && - state.sqrtPriceX96 != sqrtPriceLimitX96 - ) { + while (state.amountSpecifiedRemaining != 0 && state.sqrtPriceX96 != sqrtPriceLimitX96) { StepComputations memory step; step.sqrtPriceStartX96 = state.sqrtPriceX96; - (step.tickNext, step.initialized) = tickBitmap - .nextInitializedTickWithinOneWord( - state.tick, - tickSpacing, - zeroForOne - ); + (step.tickNext, step.initialized) = tickBitmap.nextInitializedTickWithinOneWord( + state.tick, + tickSpacing, + zeroForOne + ); // ensure that we do not overshoot the min/max tick, as the tick bitmap is not aware of these bounds if (step.tickNext < TickMath.MIN_TICK) { @@ -755,18 +667,9 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { step.sqrtPriceNextX96 = TickMath.getSqrtRatioAtTick(step.tickNext); // compute values to swap to the target tick, price limit, or point where input/output amount is exhausted - ( + (state.sqrtPriceX96, step.amountIn, step.amountOut, step.feeAmount) = SwapMath.computeSwapStep( state.sqrtPriceX96, - step.amountIn, - step.amountOut, - step.feeAmount - ) = SwapMath.computeSwapStep( - state.sqrtPriceX96, - ( - zeroForOne - ? step.sqrtPriceNextX96 < sqrtPriceLimitX96 - : step.sqrtPriceNextX96 > sqrtPriceLimitX96 - ) + (zeroForOne ? step.sqrtPriceNextX96 < sqrtPriceLimitX96 : step.sqrtPriceNextX96 > sqrtPriceLimitX96) ? sqrtPriceLimitX96 : step.sqrtPriceNextX96, state.liquidity, @@ -775,32 +678,33 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { ); if (exactInput) { - state.amountSpecifiedRemaining -= (step.amountIn + - step.feeAmount).toInt256(); - state.amountCalculated = state.amountCalculated.sub( - step.amountOut.toInt256() - ); + // safe because we test that amountSpecified > amountIn + feeAmount in SwapMath + unchecked { + state.amountSpecifiedRemaining -= (step.amountIn + step.feeAmount).toInt256(); + } + state.amountCalculated -= step.amountOut.toInt256(); } else { - state.amountSpecifiedRemaining += step.amountOut.toInt256(); - state.amountCalculated = state.amountCalculated.add( - (step.amountIn + step.feeAmount).toInt256() - ); + unchecked { + state.amountSpecifiedRemaining += step.amountOut.toInt256(); + } + state.amountCalculated += (step.amountIn + step.feeAmount).toInt256(); } // if the protocol fee is on, calculate how much is owed, decrement feeAmount, and increment protocolFee if (cache.feeProtocol > 0) { - uint256 delta = step.feeAmount / cache.feeProtocol; - step.feeAmount -= delta; - state.protocolFee += uint128(delta); + unchecked { + uint256 delta = step.feeAmount / cache.feeProtocol; + step.feeAmount -= delta; + state.protocolFee += uint128(delta); + } } // update global fee tracker - if (state.liquidity > 0) - state.feeGrowthGlobalX128 += FullMath.mulDiv( - step.feeAmount, - FixedPoint128.Q128, - state.liquidity - ); + if (state.liquidity > 0) { + unchecked { + state.feeGrowthGlobalX128 += FullMath.mulDiv(step.feeAmount, FixedPoint128.Q128, state.liquidity); + } + } // shift tick if we reached the next price if (state.sqrtPriceX96 == step.sqrtPriceNextX96) { @@ -809,10 +713,7 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { // check for the placeholder value, which we replace with the actual value the first time the swap // crosses an initialized tick if (!cache.computedLatestObservation) { - ( - cache.tickCumulative, - cache.secondsPerLiquidityCumulativeX128 - ) = observations.observeSingle( + (cache.tickCumulative, cache.secondsPerLiquidityCumulativeX128) = observations.observeSingle( cache.blockTimestamp, 0, slot0Start.tick, @@ -824,31 +725,26 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { } int128 liquidityNet = ticks.cross( step.tickNext, - ( - zeroForOne - ? state.feeGrowthGlobalX128 - : feeGrowthGlobal0X128 - ), - ( - zeroForOne - ? feeGrowthGlobal1X128 - : state.feeGrowthGlobalX128 - ), + (zeroForOne ? state.feeGrowthGlobalX128 : feeGrowthGlobal0X128), + (zeroForOne ? feeGrowthGlobal1X128 : state.feeGrowthGlobalX128), cache.secondsPerLiquidityCumulativeX128, cache.tickCumulative, cache.blockTimestamp ); // if we're moving leftward, we interpret liquidityNet as the opposite sign // safe because liquidityNet cannot be type(int128).min - if (zeroForOne) liquidityNet = -liquidityNet; + unchecked { + if (zeroForOne) liquidityNet = -liquidityNet; + } - state.liquidity = LiquidityMath.addDelta( - state.liquidity, - liquidityNet - ); + state.liquidity = liquidityNet < 0 + ? state.liquidity - uint128(-liquidityNet) + : state.liquidity + uint128(liquidityNet); } - state.tick = zeroForOne ? step.tickNext - 1 : step.tickNext; + unchecked { + state.tick = zeroForOne ? step.tickNext - 1 : step.tickNext; + } } else if (state.sqrtPriceX96 != step.sqrtPriceStartX96) { // recompute unless we're on a lower tick boundary (i.e. already transitioned ticks), and haven't moved state.tick = TickMath.getTickAtSqrtRatio(state.sqrtPriceX96); @@ -857,23 +753,15 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { // update tick and write an oracle entry if the tick change if (state.tick != slot0Start.tick) { - ( - uint16 observationIndex, - uint16 observationCardinality - ) = observations.write( - slot0Start.observationIndex, - cache.blockTimestamp, - slot0Start.tick, - cache.liquidityStart, - slot0Start.observationCardinality, - slot0Start.observationCardinalityNext - ); - ( - slot0.sqrtPriceX96, - slot0.tick, - slot0.observationIndex, - slot0.observationCardinality - ) = ( + (uint16 observationIndex, uint16 observationCardinality) = observations.write( + slot0Start.observationIndex, + cache.blockTimestamp, + slot0Start.tick, + cache.liquidityStart, + slot0Start.observationCardinality, + slot0Start.observationCardinalityNext + ); + (slot0.sqrtPriceX96, slot0.tick, slot0.observationIndex, slot0.observationCardinality) = ( state.sqrtPriceX96, state.tick, observationIndex, @@ -885,71 +773,48 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { } // update liquidity if it changed - if (cache.liquidityStart != state.liquidity) - liquidity = state.liquidity; + if (cache.liquidityStart != state.liquidity) liquidity = state.liquidity; // update fee growth global and, if necessary, protocol fees // overflow is acceptable, protocol has to withdraw before it hits type(uint128).max fees if (zeroForOne) { feeGrowthGlobal0X128 = state.feeGrowthGlobalX128; - if (state.protocolFee > 0) protocolFees.token0 += state.protocolFee; + unchecked { + if (state.protocolFee > 0) protocolFees.token0 += state.protocolFee; + } } else { feeGrowthGlobal1X128 = state.feeGrowthGlobalX128; - if (state.protocolFee > 0) protocolFees.token1 += state.protocolFee; + unchecked { + if (state.protocolFee > 0) protocolFees.token1 += state.protocolFee; + } } - (amount0, amount1) = zeroForOne == exactInput - ? ( - amountSpecified - state.amountSpecifiedRemaining, - state.amountCalculated - ) - : ( - state.amountCalculated, - amountSpecified - state.amountSpecifiedRemaining - ); + unchecked { + (amount0, amount1) = zeroForOne == exactInput + ? (amountSpecified - state.amountSpecifiedRemaining, state.amountCalculated) + : (state.amountCalculated, amountSpecified - state.amountSpecifiedRemaining); + } // do the transfers and collect payment if (zeroForOne) { - if (amount1 < 0) - TransferHelper.safeTransfer( - token1, - recipient, - uint256(-amount1) - ); + unchecked { + if (amount1 < 0) TransferHelper.safeTransfer(token1, recipient, uint256(-amount1)); + } uint256 balance0Before = balance0(); - IUniswapV3SwapCallback(msg.sender).uniswapV3SwapCallback( - amount0, - amount1, - data - ); - require(balance0Before.add(uint256(amount0)) <= balance0(), "IIA"); + IUniswapV3SwapCallback(msg.sender).uniswapV3SwapCallback(amount0, amount1, data); + if (balance0Before + uint256(amount0) > balance0()) revert IIA(); } else { - if (amount0 < 0) - TransferHelper.safeTransfer( - token0, - recipient, - uint256(-amount0) - ); + unchecked { + if (amount0 < 0) TransferHelper.safeTransfer(token0, recipient, uint256(-amount0)); + } uint256 balance1Before = balance1(); - IUniswapV3SwapCallback(msg.sender).uniswapV3SwapCallback( - amount0, - amount1, - data - ); - require(balance1Before.add(uint256(amount1)) <= balance1(), "IIA"); + IUniswapV3SwapCallback(msg.sender).uniswapV3SwapCallback(amount0, amount1, data); + if (balance1Before + uint256(amount1) > balance1()) revert IIA(); } - emit Swap( - msg.sender, - recipient, - amount0, - amount1, - state.sqrtPriceX96, - state.liquidity, - state.tick - ); + emit Swap(msg.sender, recipient, amount0, amount1, state.sqrtPriceX96, state.liquidity, state.tick); slot0.unlocked = true; } @@ -961,77 +826,57 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { bytes calldata data ) external override lock noDelegateCall { uint128 _liquidity = liquidity; - require(_liquidity > 0, "L"); + if (_liquidity <= 0) revert L(); uint256 fee0 = FullMath.mulDivRoundingUp(amount0, fee, 1e6); uint256 fee1 = FullMath.mulDivRoundingUp(amount1, fee, 1e6); uint256 balance0Before = balance0(); uint256 balance1Before = balance1(); - if (amount0 > 0) - TransferHelper.safeTransfer(token0, recipient, amount0); - if (amount1 > 0) - TransferHelper.safeTransfer(token1, recipient, amount1); + if (amount0 > 0) TransferHelper.safeTransfer(token0, recipient, amount0); + if (amount1 > 0) TransferHelper.safeTransfer(token1, recipient, amount1); - IUniswapV3FlashCallback(msg.sender).uniswapV3FlashCallback( - fee0, - fee1, - data - ); + IUniswapV3FlashCallback(msg.sender).uniswapV3FlashCallback(fee0, fee1, data); uint256 balance0After = balance0(); uint256 balance1After = balance1(); - require(balance0Before.add(fee0) <= balance0After, "F0"); - require(balance1Before.add(fee1) <= balance1After, "F1"); - - // sub is safe because we know balanceAfter is gt balanceBefore by at least fee - uint256 paid0 = balance0After - balance0Before; - uint256 paid1 = balance1After - balance1Before; - - if (paid0 > 0) { - uint8 feeProtocol0 = slot0.feeProtocol % 16; - uint256 fees0 = feeProtocol0 == 0 ? 0 : paid0 / feeProtocol0; - if (uint128(fees0) > 0) protocolFees.token0 += uint128(fees0); - feeGrowthGlobal0X128 += FullMath.mulDiv( - paid0 - fees0, - FixedPoint128.Q128, - _liquidity - ); - } - if (paid1 > 0) { - uint8 feeProtocol1 = slot0.feeProtocol >> 4; - uint256 fees1 = feeProtocol1 == 0 ? 0 : paid1 / feeProtocol1; - if (uint128(fees1) > 0) protocolFees.token1 += uint128(fees1); - feeGrowthGlobal1X128 += FullMath.mulDiv( - paid1 - fees1, - FixedPoint128.Q128, - _liquidity - ); - } + if (balance0Before + fee0 > balance0After) revert F0(); + if (balance1Before + fee1 > balance1After) revert F1(); + + unchecked { + // sub is safe because we know balanceAfter is gt balanceBefore by at least fee + uint256 paid0 = balance0After - balance0Before; + uint256 paid1 = balance1After - balance1Before; - emit Flash(msg.sender, recipient, amount0, amount1, paid0, paid1); + if (paid0 > 0) { + uint8 feeProtocol0 = slot0.feeProtocol % 16; + uint256 pFees0 = feeProtocol0 == 0 ? 0 : paid0 / feeProtocol0; + if (uint128(pFees0) > 0) protocolFees.token0 += uint128(pFees0); + feeGrowthGlobal0X128 += FullMath.mulDiv(paid0 - pFees0, FixedPoint128.Q128, _liquidity); + } + if (paid1 > 0) { + uint8 feeProtocol1 = slot0.feeProtocol >> 4; + uint256 pFees1 = feeProtocol1 == 0 ? 0 : paid1 / feeProtocol1; + if (uint128(pFees1) > 0) protocolFees.token1 += uint128(pFees1); + feeGrowthGlobal1X128 += FullMath.mulDiv(paid1 - pFees1, FixedPoint128.Q128, _liquidity); + } + + emit Flash(msg.sender, recipient, amount0, amount1, paid0, paid1); + } } /// @inheritdoc IUniswapV3PoolOwnerActions - function setFeeProtocol(uint8 feeProtocol0, uint8 feeProtocol1) - external - override - lock - onlyFactoryOwner - { - require( - (feeProtocol0 == 0 || (feeProtocol0 >= 4 && feeProtocol0 <= 10)) && - (feeProtocol1 == 0 || (feeProtocol1 >= 4 && feeProtocol1 <= 10)) - ); - uint8 feeProtocolOld = slot0.feeProtocol; - slot0.feeProtocol = feeProtocol0 + (feeProtocol1 << 4); - emit SetFeeProtocol( - feeProtocolOld % 16, - feeProtocolOld >> 4, - feeProtocol0, - feeProtocol1 - ); + function setFeeProtocol(uint8 feeProtocol0, uint8 feeProtocol1) external override lock onlyFactoryOwner { + unchecked { + require( + (feeProtocol0 == 0 || (feeProtocol0 >= 4 && feeProtocol0 <= 10)) && + (feeProtocol1 == 0 || (feeProtocol1 >= 4 && feeProtocol1 <= 10)) + ); + uint8 feeProtocolOld = slot0.feeProtocol; + slot0.feeProtocol = feeProtocol0 + (feeProtocol1 << 4); + emit SetFeeProtocol(feeProtocolOld % 16, feeProtocolOld >> 4, feeProtocol0, feeProtocol1); + } } /// @inheritdoc IUniswapV3PoolOwnerActions @@ -1039,29 +884,21 @@ contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall { address recipient, uint128 amount0Requested, uint128 amount1Requested - ) - external - override - lock - onlyFactoryOwner - returns (uint128 amount0, uint128 amount1) - { - amount0 = amount0Requested > protocolFees.token0 - ? protocolFees.token0 - : amount0Requested; - amount1 = amount1Requested > protocolFees.token1 - ? protocolFees.token1 - : amount1Requested; - - if (amount0 > 0) { - if (amount0 == protocolFees.token0) amount0--; // ensure that the slot is not cleared, for gas savings - protocolFees.token0 -= amount0; - TransferHelper.safeTransfer(token0, recipient, amount0); - } - if (amount1 > 0) { - if (amount1 == protocolFees.token1) amount1--; // ensure that the slot is not cleared, for gas savings - protocolFees.token1 -= amount1; - TransferHelper.safeTransfer(token1, recipient, amount1); + ) external override lock onlyFactoryOwner returns (uint128 amount0, uint128 amount1) { + amount0 = amount0Requested > protocolFees.token0 ? protocolFees.token0 : amount0Requested; + amount1 = amount1Requested > protocolFees.token1 ? protocolFees.token1 : amount1Requested; + + unchecked { + if (amount0 > 0) { + if (amount0 == protocolFees.token0) amount0--; // ensure that the slot is not cleared, for gas savings + protocolFees.token0 -= amount0; + TransferHelper.safeTransfer(token0, recipient, amount0); + } + if (amount1 > 0) { + if (amount1 == protocolFees.token1) amount1--; // ensure that the slot is not cleared, for gas savings + protocolFees.token1 -= amount1; + TransferHelper.safeTransfer(token1, recipient, amount1); + } } emit CollectProtocol(msg.sender, recipient, amount0, amount1); diff --git a/contracts/dependencies/univ3/UniswapV3PoolDeployer.sol b/contracts/dependencies/uniswapv3-core/UniswapV3PoolDeployer.sol similarity index 71% rename from contracts/dependencies/univ3/UniswapV3PoolDeployer.sol rename to contracts/dependencies/uniswapv3-core/UniswapV3PoolDeployer.sol index 8af4b6d27..c313dc728 100644 --- a/contracts/dependencies/univ3/UniswapV3PoolDeployer.sol +++ b/contracts/dependencies/uniswapv3-core/UniswapV3PoolDeployer.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity =0.7.6; +pragma solidity ^0.8.0; -import "./interfaces/IUniswapV3PoolDeployer.sol"; +import {IUniswapV3PoolDeployer} from './interfaces/IUniswapV3PoolDeployer.sol'; -import "./UniswapV3Pool.sol"; +import {UniswapV3Pool} from './UniswapV3Pool.sol'; contract UniswapV3PoolDeployer is IUniswapV3PoolDeployer { struct Parameters { @@ -31,18 +31,8 @@ contract UniswapV3PoolDeployer is IUniswapV3PoolDeployer { uint24 fee, int24 tickSpacing ) internal returns (address pool) { - parameters = Parameters({ - factory: factory, - token0: token0, - token1: token1, - fee: fee, - tickSpacing: tickSpacing - }); - pool = address( - new UniswapV3Pool{ - salt: keccak256(abi.encode(token0, token1, fee)) - }() - ); + parameters = Parameters({factory: factory, token0: token0, token1: token1, fee: fee, tickSpacing: tickSpacing}); + pool = address(new UniswapV3Pool{salt: keccak256(abi.encode(token0, token1, fee))}()); delete parameters; } } diff --git a/contracts/dependencies/univ3/interfaces/IERC20Minimal.sol b/contracts/dependencies/uniswapv3-core/interfaces/IERC20Minimal.sol similarity index 88% rename from contracts/dependencies/univ3/interfaces/IERC20Minimal.sol rename to contracts/dependencies/uniswapv3-core/interfaces/IERC20Minimal.sol index 62477df59..727690d64 100644 --- a/contracts/dependencies/univ3/interfaces/IERC20Minimal.sol +++ b/contracts/dependencies/uniswapv3-core/interfaces/IERC20Minimal.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; +pragma solidity ^0.8.0; /// @title Minimal ERC20 interface for Uniswap /// @notice Contains a subset of the full ERC20 interface that is used in Uniswap V3 @@ -13,18 +13,13 @@ interface IERC20Minimal { /// @param recipient The account that will receive the amount transferred /// @param amount The number of tokens to send from the sender to the recipient /// @return Returns true for a successful transfer, false for an unsuccessful transfer - function transfer(address recipient, uint256 amount) - external - returns (bool); + function transfer(address recipient, uint256 amount) external returns (bool); /// @notice Returns the current allowance given to a spender by an owner /// @param owner The account of the token owner /// @param spender The account of the token spender /// @return The current allowance granted by `owner` to `spender` - function allowance(address owner, address spender) - external - view - returns (uint256); + function allowance(address owner, address spender) external view returns (uint256); /// @notice Sets the allowance of a spender from the `msg.sender` to the value `amount` /// @param spender The account which will be allowed to spend a given amount of the owners tokens @@ -53,9 +48,5 @@ interface IERC20Minimal { /// @param owner The account that approved spending of its tokens /// @param spender The account for which the spending allowance was modified /// @param value The new allowance from the owner to the spender - event Approval( - address indexed owner, - address indexed spender, - uint256 value - ); + event Approval(address indexed owner, address indexed spender, uint256 value); } diff --git a/contracts/dependencies/uniswap/IUniswapV3Factory.sol b/contracts/dependencies/uniswapv3-core/interfaces/IUniswapV3Factory.sol similarity index 99% rename from contracts/dependencies/uniswap/IUniswapV3Factory.sol rename to contracts/dependencies/uniswapv3-core/interfaces/IUniswapV3Factory.sol index 540cfdc68..484bc5fb3 100644 --- a/contracts/dependencies/uniswap/IUniswapV3Factory.sol +++ b/contracts/dependencies/uniswapv3-core/interfaces/IUniswapV3Factory.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; +pragma solidity ^0.8.0; /// @title The interface for the Uniswap V3 Factory /// @notice The Uniswap V3 Factory facilitates creation of Uniswap V3 pools and control over the protocol fees diff --git a/contracts/dependencies/uniswapv3-core/interfaces/IUniswapV3Pool.sol b/contracts/dependencies/uniswapv3-core/interfaces/IUniswapV3Pool.sol new file mode 100644 index 000000000..1cab15754 --- /dev/null +++ b/contracts/dependencies/uniswapv3-core/interfaces/IUniswapV3Pool.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +import {IUniswapV3PoolImmutables} from './pool/IUniswapV3PoolImmutables.sol'; +import {IUniswapV3PoolState} from './pool/IUniswapV3PoolState.sol'; +import {IUniswapV3PoolDerivedState} from './pool/IUniswapV3PoolDerivedState.sol'; +import {IUniswapV3PoolActions} from './pool/IUniswapV3PoolActions.sol'; +import {IUniswapV3PoolOwnerActions} from './pool/IUniswapV3PoolOwnerActions.sol'; +import {IUniswapV3PoolErrors} from './pool/IUniswapV3PoolErrors.sol'; +import {IUniswapV3PoolEvents} from './pool/IUniswapV3PoolEvents.sol'; + +/// @title The interface for a Uniswap V3 Pool +/// @notice A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform +/// to the ERC20 specification +/// @dev The pool interface is broken up into many smaller pieces +interface IUniswapV3Pool is + IUniswapV3PoolImmutables, + IUniswapV3PoolState, + IUniswapV3PoolDerivedState, + IUniswapV3PoolActions, + IUniswapV3PoolOwnerActions, + IUniswapV3PoolErrors, + IUniswapV3PoolEvents +{ + +} diff --git a/contracts/dependencies/univ3/interfaces/IUniswapV3PoolDeployer.sol b/contracts/dependencies/uniswapv3-core/interfaces/IUniswapV3PoolDeployer.sol similarity index 98% rename from contracts/dependencies/univ3/interfaces/IUniswapV3PoolDeployer.sol rename to contracts/dependencies/uniswapv3-core/interfaces/IUniswapV3PoolDeployer.sol index 72096c1ff..17925522d 100644 --- a/contracts/dependencies/univ3/interfaces/IUniswapV3PoolDeployer.sol +++ b/contracts/dependencies/uniswapv3-core/interfaces/IUniswapV3PoolDeployer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; +pragma solidity ^0.8.0; /// @title An interface for a contract that is capable of deploying Uniswap V3 Pools /// @notice A contract that constructs a pool must implement this to pass arguments to the pool diff --git a/contracts/dependencies/uniswap/libraries/LICENSE b/contracts/dependencies/uniswapv3-core/interfaces/LICENSE similarity index 100% rename from contracts/dependencies/uniswap/libraries/LICENSE rename to contracts/dependencies/uniswapv3-core/interfaces/LICENSE diff --git a/contracts/dependencies/univ3/interfaces/callback/IUniswapV3FlashCallback.sol b/contracts/dependencies/uniswapv3-core/interfaces/callback/IUniswapV3FlashCallback.sol similarity index 97% rename from contracts/dependencies/univ3/interfaces/callback/IUniswapV3FlashCallback.sol rename to contracts/dependencies/uniswapv3-core/interfaces/callback/IUniswapV3FlashCallback.sol index 18e54c4e1..159509cad 100644 --- a/contracts/dependencies/univ3/interfaces/callback/IUniswapV3FlashCallback.sol +++ b/contracts/dependencies/uniswapv3-core/interfaces/callback/IUniswapV3FlashCallback.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; +pragma solidity ^0.8.0; /// @title Callback for IUniswapV3PoolActions#flash /// @notice Any contract that calls IUniswapV3PoolActions#flash must implement this interface diff --git a/contracts/dependencies/univ3/interfaces/callback/IUniswapV3MintCallback.sol b/contracts/dependencies/uniswapv3-core/interfaces/callback/IUniswapV3MintCallback.sol similarity index 97% rename from contracts/dependencies/univ3/interfaces/callback/IUniswapV3MintCallback.sol rename to contracts/dependencies/uniswapv3-core/interfaces/callback/IUniswapV3MintCallback.sol index 85447e84f..38e2a3094 100644 --- a/contracts/dependencies/univ3/interfaces/callback/IUniswapV3MintCallback.sol +++ b/contracts/dependencies/uniswapv3-core/interfaces/callback/IUniswapV3MintCallback.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; +pragma solidity ^0.8.0; /// @title Callback for IUniswapV3PoolActions#mint /// @notice Any contract that calls IUniswapV3PoolActions#mint must implement this interface diff --git a/contracts/dependencies/univ3/interfaces/callback/IUniswapV3SwapCallback.sol b/contracts/dependencies/uniswapv3-core/interfaces/callback/IUniswapV3SwapCallback.sol similarity index 98% rename from contracts/dependencies/univ3/interfaces/callback/IUniswapV3SwapCallback.sol rename to contracts/dependencies/uniswapv3-core/interfaces/callback/IUniswapV3SwapCallback.sol index 9f183b22a..bebf74f6c 100644 --- a/contracts/dependencies/univ3/interfaces/callback/IUniswapV3SwapCallback.sol +++ b/contracts/dependencies/uniswapv3-core/interfaces/callback/IUniswapV3SwapCallback.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; +pragma solidity ^0.8.0; /// @title Callback for IUniswapV3PoolActions#swap /// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface diff --git a/contracts/dependencies/univ3/interfaces/pool/IUniswapV3PoolActions.sol b/contracts/dependencies/uniswapv3-core/interfaces/pool/IUniswapV3PoolActions.sol similarity index 97% rename from contracts/dependencies/univ3/interfaces/pool/IUniswapV3PoolActions.sol rename to contracts/dependencies/uniswapv3-core/interfaces/pool/IUniswapV3PoolActions.sol index 3c10a2140..3a5aeedb2 100644 --- a/contracts/dependencies/univ3/interfaces/pool/IUniswapV3PoolActions.sol +++ b/contracts/dependencies/uniswapv3-core/interfaces/pool/IUniswapV3PoolActions.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; +pragma solidity ^0.8.0; /// @title Permissionless pool actions /// @notice Contains pool methods that can be called by anyone @@ -99,7 +99,5 @@ interface IUniswapV3PoolActions { /// @dev This method is no-op if the pool already has an observationCardinalityNext greater than or equal to /// the input observationCardinalityNext. /// @param observationCardinalityNext The desired minimum number of observations for the pool to store - function increaseObservationCardinalityNext( - uint16 observationCardinalityNext - ) external; + function increaseObservationCardinalityNext(uint16 observationCardinalityNext) external; } diff --git a/contracts/dependencies/uniswap/IUniswapV3PoolDerivedState.sol b/contracts/dependencies/uniswapv3-core/interfaces/pool/IUniswapV3PoolDerivedState.sol similarity index 99% rename from contracts/dependencies/uniswap/IUniswapV3PoolDerivedState.sol rename to contracts/dependencies/uniswapv3-core/interfaces/pool/IUniswapV3PoolDerivedState.sol index eda3a0089..3a9078fc6 100644 --- a/contracts/dependencies/uniswap/IUniswapV3PoolDerivedState.sol +++ b/contracts/dependencies/uniswapv3-core/interfaces/pool/IUniswapV3PoolDerivedState.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; +pragma solidity ^0.8.0; /// @title Pool state that is not stored /// @notice Contains view functions to provide information about the pool that is computed rather than stored on the diff --git a/contracts/dependencies/uniswapv3-core/interfaces/pool/IUniswapV3PoolErrors.sol b/contracts/dependencies/uniswapv3-core/interfaces/pool/IUniswapV3PoolErrors.sol new file mode 100644 index 000000000..76eb55239 --- /dev/null +++ b/contracts/dependencies/uniswapv3-core/interfaces/pool/IUniswapV3PoolErrors.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +/// @title Errors emitted by a pool +/// @notice Contains all events emitted by the pool +interface IUniswapV3PoolErrors { + error LOK(); + error TLU(); + error TLM(); + error TUM(); + error AI(); + error M0(); + error M1(); + error AS(); + error IIA(); + error L(); + error F0(); + error F1(); +} diff --git a/contracts/dependencies/univ3/interfaces/pool/IUniswapV3PoolEvents.sol b/contracts/dependencies/uniswapv3-core/interfaces/pool/IUniswapV3PoolEvents.sol similarity index 94% rename from contracts/dependencies/univ3/interfaces/pool/IUniswapV3PoolEvents.sol rename to contracts/dependencies/uniswapv3-core/interfaces/pool/IUniswapV3PoolEvents.sol index 97b26fb61..ade356cb9 100644 --- a/contracts/dependencies/univ3/interfaces/pool/IUniswapV3PoolEvents.sol +++ b/contracts/dependencies/uniswapv3-core/interfaces/pool/IUniswapV3PoolEvents.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; +pragma solidity ^0.8.0; /// @title Events emitted by a pool /// @notice Contains all events emitted by the pool @@ -110,22 +110,12 @@ interface IUniswapV3PoolEvents { /// @param feeProtocol1Old The previous value of the token1 protocol fee /// @param feeProtocol0New The updated value of the token0 protocol fee /// @param feeProtocol1New The updated value of the token1 protocol fee - event SetFeeProtocol( - uint8 feeProtocol0Old, - uint8 feeProtocol1Old, - uint8 feeProtocol0New, - uint8 feeProtocol1New - ); + event SetFeeProtocol(uint8 feeProtocol0Old, uint8 feeProtocol1Old, uint8 feeProtocol0New, uint8 feeProtocol1New); /// @notice Emitted when the collected protocol fees are withdrawn by the factory owner /// @param sender The address that collects the protocol fees /// @param recipient The address that receives the collected protocol fees /// @param amount0 The amount of token0 protocol fees that is withdrawn /// @param amount0 The amount of token1 protocol fees that is withdrawn - event CollectProtocol( - address indexed sender, - address indexed recipient, - uint128 amount0, - uint128 amount1 - ); + event CollectProtocol(address indexed sender, address indexed recipient, uint128 amount0, uint128 amount1); } diff --git a/contracts/dependencies/univ3/interfaces/pool/IUniswapV3PoolImmutables.sol b/contracts/dependencies/uniswapv3-core/interfaces/pool/IUniswapV3PoolImmutables.sol similarity index 98% rename from contracts/dependencies/univ3/interfaces/pool/IUniswapV3PoolImmutables.sol rename to contracts/dependencies/uniswapv3-core/interfaces/pool/IUniswapV3PoolImmutables.sol index c9beb151e..f34e078b2 100644 --- a/contracts/dependencies/univ3/interfaces/pool/IUniswapV3PoolImmutables.sol +++ b/contracts/dependencies/uniswapv3-core/interfaces/pool/IUniswapV3PoolImmutables.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; +pragma solidity ^0.8.0; /// @title Pool state that never changes /// @notice These parameters are fixed for a pool forever, i.e., the methods will always return the same values diff --git a/contracts/dependencies/univ3/interfaces/pool/IUniswapV3PoolOwnerActions.sol b/contracts/dependencies/uniswapv3-core/interfaces/pool/IUniswapV3PoolOwnerActions.sol similarity index 97% rename from contracts/dependencies/univ3/interfaces/pool/IUniswapV3PoolOwnerActions.sol rename to contracts/dependencies/uniswapv3-core/interfaces/pool/IUniswapV3PoolOwnerActions.sol index 2395ed321..9c99a4a95 100644 --- a/contracts/dependencies/univ3/interfaces/pool/IUniswapV3PoolOwnerActions.sol +++ b/contracts/dependencies/uniswapv3-core/interfaces/pool/IUniswapV3PoolOwnerActions.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; +pragma solidity ^0.8.0; /// @title Permissioned pool actions /// @notice Contains pool methods that may only be called by the factory owner diff --git a/contracts/dependencies/uniswap/IUniswapV3PoolState.sol b/contracts/dependencies/uniswapv3-core/interfaces/pool/IUniswapV3PoolState.sol similarity index 70% rename from contracts/dependencies/uniswap/IUniswapV3PoolState.sol rename to contracts/dependencies/uniswapv3-core/interfaces/pool/IUniswapV3PoolState.sol index e70b8983a..68567fe9a 100644 --- a/contracts/dependencies/uniswap/IUniswapV3PoolState.sol +++ b/contracts/dependencies/uniswapv3-core/interfaces/pool/IUniswapV3PoolState.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; +pragma solidity ^0.8.0; /// @title Pool state that can change /// @notice These methods compose the pool's state, and can change with any frequency including multiple times @@ -8,13 +8,13 @@ interface IUniswapV3PoolState { /// @notice The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas /// when accessed externally. /// @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value - /// tick The current tick of the pool, i.e. according to the last tick transition that was run. + /// @return tick The current tick of the pool, i.e. according to the last tick transition that was run. /// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick /// boundary. - /// observationIndex The index of the last oracle observation that was written, - /// observationCardinality The current maximum number of observations stored in the pool, - /// observationCardinalityNext The next maximum number of observations, to be updated when the observation. - /// feeProtocol The protocol fee for both tokens of the pool. + /// @return observationIndex The index of the last oracle observation that was written, + /// @return observationCardinality The current maximum number of observations stored in the pool, + /// @return observationCardinalityNext The next maximum number of observations, to be updated when the observation. + /// @return feeProtocol The protocol fee for both tokens of the pool. /// Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0 /// is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee. /// unlocked Whether the pool is currently locked to reentrancy @@ -45,19 +45,20 @@ interface IUniswapV3PoolState { /// @notice The currently in range liquidity available to the pool /// @dev This value has no relationship to the total liquidity across all ticks + /// @return The liquidity at the current price of the pool function liquidity() external view returns (uint128); /// @notice Look up information about a specific tick in the pool /// @param tick The tick to look up /// @return liquidityGross the total amount of position liquidity that uses the pool either as tick lower or - /// tick upper, - /// liquidityNet how much liquidity changes when the pool price crosses the tick, - /// feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0, - /// feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1, - /// tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick - /// secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from the current tick, - /// secondsOutside the seconds spent on the other side of the tick from the current tick, - /// initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise equal to false. + /// tick upper + /// @return liquidityNet how much liquidity changes when the pool price crosses the tick, + /// @return feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0, + /// @return feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1, + /// @return tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick + /// @return secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from the current tick, + /// @return secondsOutside the seconds spent on the other side of the tick from the current tick, + /// @return initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise equal to false. /// Outside values can only be used if the tick is initialized, i.e. if liquidityGross is greater than 0. /// In addition, these values are only relative and must be used only in comparison to previous snapshots for /// a specific position. @@ -80,16 +81,16 @@ interface IUniswapV3PoolState { /// @notice Returns the information about a position by the position's key /// @param key The position's key is a hash of a preimage composed by the owner, tickLower and tickUpper - /// @return _liquidity The amount of liquidity in the position, - /// Returns feeGrowthInside0LastX128 fee growth of token0 inside the tick range as of the last mint/burn/poke, - /// Returns feeGrowthInside1LastX128 fee growth of token1 inside the tick range as of the last mint/burn/poke, - /// Returns tokensOwed0 the computed amount of token0 owed to the position as of the last mint/burn/poke, - /// Returns tokensOwed1 the computed amount of token1 owed to the position as of the last mint/burn/poke + /// @return liquidity The amount of liquidity in the position, + /// @return feeGrowthInside0LastX128 fee growth of token0 inside the tick range as of the last mint/burn/poke, + /// @return feeGrowthInside1LastX128 fee growth of token1 inside the tick range as of the last mint/burn/poke, + /// @return tokensOwed0 the computed amount of token0 owed to the position as of the last mint/burn/poke, + /// @return tokensOwed1 the computed amount of token1 owed to the position as of the last mint/burn/poke function positions(bytes32 key) external view returns ( - uint128 _liquidity, + uint128 liquidity, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128, uint128 tokensOwed0, @@ -101,9 +102,9 @@ interface IUniswapV3PoolState { /// @dev You most likely want to use #observe() instead of this method to get an observation as of some amount of time /// ago, rather than at a specific index in the array. /// @return blockTimestamp The timestamp of the observation, - /// Returns tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the observation timestamp, - /// Returns secondsPerLiquidityCumulativeX128 the seconds per in range liquidity for the life of the pool as of the observation timestamp, - /// Returns initialized whether the observation has been initialized and the values are safe to use + /// @return tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the observation timestamp, + /// @return secondsPerLiquidityCumulativeX128 the seconds per in range liquidity for the life of the pool as of the observation timestamp, + /// @return initialized whether the observation has been initialized and the values are safe to use function observations(uint256 index) external view @@ -113,7 +114,4 @@ interface IUniswapV3PoolState { uint160 secondsPerLiquidityCumulativeX128, bool initialized ); - - function token0() external view returns (address); - function token1() external view returns (address); } diff --git a/contracts/dependencies/uniswap/libraries/BitMath.sol b/contracts/dependencies/uniswapv3-core/libraries/BitMath.sol similarity index 100% rename from contracts/dependencies/uniswap/libraries/BitMath.sol rename to contracts/dependencies/uniswapv3-core/libraries/BitMath.sol diff --git a/contracts/dependencies/uniswap/libraries/FixedPoint128.sol b/contracts/dependencies/uniswapv3-core/libraries/FixedPoint128.sol similarity index 91% rename from contracts/dependencies/uniswap/libraries/FixedPoint128.sol rename to contracts/dependencies/uniswapv3-core/libraries/FixedPoint128.sol index 6d6948b10..2dbdfc1e5 100644 --- a/contracts/dependencies/uniswap/libraries/FixedPoint128.sol +++ b/contracts/dependencies/uniswapv3-core/libraries/FixedPoint128.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.4.0; +pragma solidity ^0.8.0; /// @title FixedPoint128 /// @notice A library for handling binary fixed point numbers, see https://en.wikipedia.org/wiki/Q_(number_format) diff --git a/contracts/dependencies/uniswap/libraries/FixedPoint96.sol b/contracts/dependencies/uniswapv3-core/libraries/FixedPoint96.sol similarity index 93% rename from contracts/dependencies/uniswap/libraries/FixedPoint96.sol rename to contracts/dependencies/uniswapv3-core/libraries/FixedPoint96.sol index 63b42c294..46ef263de 100644 --- a/contracts/dependencies/uniswap/libraries/FixedPoint96.sol +++ b/contracts/dependencies/uniswapv3-core/libraries/FixedPoint96.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.4.0; +pragma solidity ^0.8.0; /// @title FixedPoint96 /// @notice A library for handling binary fixed point numbers, see https://en.wikipedia.org/wiki/Q_(number_format) diff --git a/contracts/dependencies/uniswap/libraries/FullMath.sol b/contracts/dependencies/uniswapv3-core/libraries/FullMath.sol similarity index 100% rename from contracts/dependencies/uniswap/libraries/FullMath.sol rename to contracts/dependencies/uniswapv3-core/libraries/FullMath.sol diff --git a/contracts/dependencies/uniswap/libraries/Oracle.sol b/contracts/dependencies/uniswapv3-core/libraries/Oracle.sol similarity index 83% rename from contracts/dependencies/uniswap/libraries/Oracle.sol rename to contracts/dependencies/uniswapv3-core/libraries/Oracle.sol index 409e1d253..2aacc9fdb 100644 --- a/contracts/dependencies/uniswap/libraries/Oracle.sol +++ b/contracts/dependencies/uniswapv3-core/libraries/Oracle.sol @@ -41,13 +41,9 @@ library Oracle { return Observation({ blockTimestamp: blockTimestamp, - tickCumulative: last.tickCumulative + - int56(tick) * - int56(uint56(delta)), - secondsPerLiquidityCumulativeX128: last - .secondsPerLiquidityCumulativeX128 + - ((uint160(delta) << 128) / - (liquidity > 0 ? liquidity : 1)), + tickCumulative: last.tickCumulative + int56(tick) * int56(uint56(delta)), + secondsPerLiquidityCumulativeX128: last.secondsPerLiquidityCumulativeX128 + + ((uint160(delta) << 128) / (liquidity > 0 ? liquidity : 1)), initialized: true }); } @@ -97,8 +93,7 @@ library Oracle { Observation memory last = self[index]; // early return if we've already written an observation this block - if (last.blockTimestamp == blockTimestamp) - return (index, cardinality); + if (last.blockTimestamp == blockTimestamp) return (index, cardinality); // if the conditions are right, we can bump the cardinality if (cardinalityNext > cardinality && index == (cardinality - 1)) { @@ -108,12 +103,7 @@ library Oracle { } indexUpdated = (index + 1) % cardinalityUpdated; - self[indexUpdated] = transform( - last, - blockTimestamp, - tick, - liquidity - ); + self[indexUpdated] = transform(last, blockTimestamp, tick, liquidity); } } @@ -177,11 +167,7 @@ library Oracle { uint32 target, uint16 index, uint16 cardinality - ) - private - view - returns (Observation memory beforeOrAt, Observation memory atOrAfter) - { + ) private view returns (Observation memory beforeOrAt, Observation memory atOrAfter) { unchecked { uint256 l = (index + 1) % cardinality; // oldest observation uint256 r = l + cardinality - 1; // newest observation @@ -199,17 +185,10 @@ library Oracle { atOrAfter = self[(i + 1) % cardinality]; - bool targetAtOrAfter = lte( - time, - beforeOrAt.blockTimestamp, - target - ); + bool targetAtOrAfter = lte(time, beforeOrAt.blockTimestamp, target); // check if we've found the answer! - if ( - targetAtOrAfter && - lte(time, target, atOrAfter.blockTimestamp) - ) break; + if (targetAtOrAfter && lte(time, target, atOrAfter.blockTimestamp)) break; if (!targetAtOrAfter) r = i - 1; else l = i + 1; @@ -237,11 +216,7 @@ library Oracle { uint16 index, uint128 liquidity, uint16 cardinality - ) - private - view - returns (Observation memory beforeOrAt, Observation memory atOrAfter) - { + ) private view returns (Observation memory beforeOrAt, Observation memory atOrAfter) { unchecked { // optimistically set before to the newest observation beforeOrAt = self[index]; @@ -253,10 +228,7 @@ library Oracle { return (beforeOrAt, atOrAfter); } else { // otherwise, we need to transform - return ( - beforeOrAt, - transform(beforeOrAt, target, tick, liquidity) - ); + return (beforeOrAt, transform(beforeOrAt, target, tick, liquidity)); } } @@ -293,62 +265,39 @@ library Oracle { uint16 index, uint128 liquidity, uint16 cardinality - ) - internal - view - returns ( - int56 tickCumulative, - uint160 secondsPerLiquidityCumulativeX128 - ) - { + ) internal view returns (int56 tickCumulative, uint160 secondsPerLiquidityCumulativeX128) { unchecked { if (secondsAgo == 0) { Observation memory last = self[index]; - if (last.blockTimestamp != time) - last = transform(last, time, tick, liquidity); - return ( - last.tickCumulative, - last.secondsPerLiquidityCumulativeX128 - ); + if (last.blockTimestamp != time) last = transform(last, time, tick, liquidity); + return (last.tickCumulative, last.secondsPerLiquidityCumulativeX128); } uint32 target = time - secondsAgo; - ( - Observation memory beforeOrAt, - Observation memory atOrAfter - ) = getSurroundingObservations( - self, - time, - target, - tick, - index, - liquidity, - cardinality - ); + (Observation memory beforeOrAt, Observation memory atOrAfter) = getSurroundingObservations( + self, + time, + target, + tick, + index, + liquidity, + cardinality + ); if (target == beforeOrAt.blockTimestamp) { // we're at the left boundary - return ( - beforeOrAt.tickCumulative, - beforeOrAt.secondsPerLiquidityCumulativeX128 - ); + return (beforeOrAt.tickCumulative, beforeOrAt.secondsPerLiquidityCumulativeX128); } else if (target == atOrAfter.blockTimestamp) { // we're at the right boundary - return ( - atOrAfter.tickCumulative, - atOrAfter.secondsPerLiquidityCumulativeX128 - ); + return (atOrAfter.tickCumulative, atOrAfter.secondsPerLiquidityCumulativeX128); } else { // we're in the middle - uint32 observationTimeDelta = atOrAfter.blockTimestamp - - beforeOrAt.blockTimestamp; + uint32 observationTimeDelta = atOrAfter.blockTimestamp - beforeOrAt.blockTimestamp; uint32 targetDelta = target - beforeOrAt.blockTimestamp; return ( beforeOrAt.tickCumulative + - ((atOrAfter.tickCumulative - - beforeOrAt.tickCumulative) / - int56(uint56(observationTimeDelta))) * + ((atOrAfter.tickCumulative - beforeOrAt.tickCumulative) / int56(uint56(observationTimeDelta))) * int56(uint56(targetDelta)), beforeOrAt.secondsPerLiquidityCumulativeX128 + uint160( @@ -381,26 +330,14 @@ library Oracle { uint16 index, uint128 liquidity, uint16 cardinality - ) - internal - view - returns ( - int56[] memory tickCumulatives, - uint160[] memory secondsPerLiquidityCumulativeX128s - ) - { + ) internal view returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s) { unchecked { if (cardinality <= 0) revert I(); tickCumulatives = new int56[](secondsAgos.length); - secondsPerLiquidityCumulativeX128s = new uint160[]( - secondsAgos.length - ); + secondsPerLiquidityCumulativeX128s = new uint160[](secondsAgos.length); for (uint256 i = 0; i < secondsAgos.length; i++) { - ( - tickCumulatives[i], - secondsPerLiquidityCumulativeX128s[i] - ) = observeSingle( + (tickCumulatives[i], secondsPerLiquidityCumulativeX128s[i]) = observeSingle( self, time, secondsAgos[i], diff --git a/contracts/dependencies/uniswap/libraries/Position.sol b/contracts/dependencies/uniswapv3-core/libraries/Position.sol similarity index 94% rename from contracts/dependencies/uniswap/libraries/Position.sol rename to contracts/dependencies/uniswapv3-core/libraries/Position.sol index 2539ff4a0..4e1837058 100644 --- a/contracts/dependencies/uniswap/libraries/Position.sol +++ b/contracts/dependencies/uniswapv3-core/libraries/Position.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; -import {FullMath} from "./FullMath.sol"; -import {FixedPoint128} from "./FixedPoint128.sol"; +import {FullMath} from './FullMath.sol'; +import {FixedPoint128} from './FixedPoint128.sol'; /// @title Position /// @notice Positions represent an owner address' liquidity between a lower and upper tick boundary @@ -34,9 +34,7 @@ library Position { int24 tickLower, int24 tickUpper ) internal view returns (Position.Info storage position) { - position = self[ - keccak256(abi.encodePacked(owner, tickLower, tickUpper)) - ]; + position = self[keccak256(abi.encodePacked(owner, tickLower, tickUpper))]; } /// @notice Credits accumulated fees to a user's position diff --git a/contracts/dependencies/univ3/libraries/SafeCast.sol b/contracts/dependencies/uniswapv3-core/libraries/SafeCast.sol similarity index 97% rename from contracts/dependencies/univ3/libraries/SafeCast.sol rename to contracts/dependencies/uniswapv3-core/libraries/SafeCast.sol index a8ea22987..5affc60a4 100644 --- a/contracts/dependencies/univ3/libraries/SafeCast.sol +++ b/contracts/dependencies/uniswapv3-core/libraries/SafeCast.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; +pragma solidity ^0.8.0; /// @title Safe casting methods /// @notice Contains methods for safely casting between types diff --git a/contracts/dependencies/uniswap/libraries/SqrtPriceMath.sol b/contracts/dependencies/uniswapv3-core/libraries/SqrtPriceMath.sol similarity index 69% rename from contracts/dependencies/uniswap/libraries/SqrtPriceMath.sol rename to contracts/dependencies/uniswapv3-core/libraries/SqrtPriceMath.sol index 0adab14a6..a3369e18d 100644 --- a/contracts/dependencies/uniswap/libraries/SqrtPriceMath.sol +++ b/contracts/dependencies/uniswapv3-core/libraries/SqrtPriceMath.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; -import {SafeCast} from "./SafeCast.sol"; +import {SafeCast} from './SafeCast.sol'; -import {FullMath} from "./FullMath.sol"; -import {UnsafeMath} from "./UnsafeMath.sol"; -import {FixedPoint96} from "./FixedPoint96.sol"; +import {FullMath} from './FullMath.sol'; +import {UnsafeMath} from './UnsafeMath.sol'; +import {FixedPoint96} from './FixedPoint96.sol'; /// @title Functions based on Q64.96 sqrt price and liquidity /// @notice Contains the math that uses square root of price as a Q64.96 and liquidity to compute deltas @@ -40,38 +40,19 @@ library SqrtPriceMath { uint256 denominator = numerator1 + product; if (denominator >= numerator1) // always fits in 160 bits - return - uint160( - FullMath.mulDivRoundingUp( - numerator1, - sqrtPX96, - denominator - ) - ); + return uint160(FullMath.mulDivRoundingUp(numerator1, sqrtPX96, denominator)); } } // denominator is checked for overflow - return - uint160( - UnsafeMath.divRoundingUp( - numerator1, - (numerator1 / sqrtPX96) + amount - ) - ); + return uint160(UnsafeMath.divRoundingUp(numerator1, (numerator1 / sqrtPX96) + amount)); } else { unchecked { uint256 product; // if the product overflows, we know the denominator underflows // in addition, we must check that the denominator does not underflow - require( - (product = amount * sqrtPX96) / amount == sqrtPX96 && - numerator1 > product - ); + require((product = amount * sqrtPX96) / amount == sqrtPX96 && numerator1 > product); uint256 denominator = numerator1 - product; - return - FullMath - .mulDivRoundingUp(numerator1, sqrtPX96, denominator) - .toUint160(); + return FullMath.mulDivRoundingUp(numerator1, sqrtPX96, denominator).toUint160(); } } } @@ -105,15 +86,8 @@ library SqrtPriceMath { } else { uint256 quotient = ( amount <= type(uint160).max - ? UnsafeMath.divRoundingUp( - amount << FixedPoint96.RESOLUTION, - liquidity - ) - : FullMath.mulDivRoundingUp( - amount, - FixedPoint96.Q96, - liquidity - ) + ? UnsafeMath.divRoundingUp(amount << FixedPoint96.RESOLUTION, liquidity) + : FullMath.mulDivRoundingUp(amount, FixedPoint96.Q96, liquidity) ); require(sqrtPX96 > quotient); @@ -143,18 +117,8 @@ library SqrtPriceMath { // round to make sure that we don't pass the target price return zeroForOne - ? getNextSqrtPriceFromAmount0RoundingUp( - sqrtPX96, - liquidity, - amountIn, - true - ) - : getNextSqrtPriceFromAmount1RoundingDown( - sqrtPX96, - liquidity, - amountIn, - true - ); + ? getNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountIn, true) + : getNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountIn, true); } /// @notice Gets the next sqrt price given an output amount of token0 or token1 @@ -176,18 +140,8 @@ library SqrtPriceMath { // round to make sure that we pass the target price return zeroForOne - ? getNextSqrtPriceFromAmount1RoundingDown( - sqrtPX96, - liquidity, - amountOut, - false - ) - : getNextSqrtPriceFromAmount0RoundingUp( - sqrtPX96, - liquidity, - amountOut, - false - ); + ? getNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountOut, false) + : getNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountOut, false); } /// @notice Gets the amount0 delta between two prices @@ -205,8 +159,7 @@ library SqrtPriceMath { bool roundUp ) internal pure returns (uint256 amount0) { unchecked { - if (sqrtRatioAX96 > sqrtRatioBX96) - (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); + if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); uint256 numerator1 = uint256(liquidity) << FixedPoint96.RESOLUTION; uint256 numerator2 = sqrtRatioBX96 - sqrtRatioAX96; @@ -216,15 +169,10 @@ library SqrtPriceMath { return roundUp ? UnsafeMath.divRoundingUp( - FullMath.mulDivRoundingUp( - numerator1, - numerator2, - sqrtRatioBX96 - ), + FullMath.mulDivRoundingUp(numerator1, numerator2, sqrtRatioBX96), sqrtRatioAX96 ) - : FullMath.mulDiv(numerator1, numerator2, sqrtRatioBX96) / - sqrtRatioAX96; + : FullMath.mulDiv(numerator1, numerator2, sqrtRatioBX96) / sqrtRatioAX96; } } @@ -242,21 +190,12 @@ library SqrtPriceMath { bool roundUp ) internal pure returns (uint256 amount1) { unchecked { - if (sqrtRatioAX96 > sqrtRatioBX96) - (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); + if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); return roundUp - ? FullMath.mulDivRoundingUp( - liquidity, - sqrtRatioBX96 - sqrtRatioAX96, - FixedPoint96.Q96 - ) - : FullMath.mulDiv( - liquidity, - sqrtRatioBX96 - sqrtRatioAX96, - FixedPoint96.Q96 - ); + ? FullMath.mulDivRoundingUp(liquidity, sqrtRatioBX96 - sqrtRatioAX96, FixedPoint96.Q96) + : FullMath.mulDiv(liquidity, sqrtRatioBX96 - sqrtRatioAX96, FixedPoint96.Q96); } } @@ -273,18 +212,8 @@ library SqrtPriceMath { unchecked { return liquidity < 0 - ? -getAmount0Delta( - sqrtRatioAX96, - sqrtRatioBX96, - uint128(-liquidity), - false - ).toInt256() - : getAmount0Delta( - sqrtRatioAX96, - sqrtRatioBX96, - uint128(liquidity), - true - ).toInt256(); + ? -getAmount0Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(-liquidity), false).toInt256() + : getAmount0Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(liquidity), true).toInt256(); } } @@ -301,18 +230,8 @@ library SqrtPriceMath { unchecked { return liquidity < 0 - ? -getAmount1Delta( - sqrtRatioAX96, - sqrtRatioBX96, - uint128(-liquidity), - false - ).toInt256() - : getAmount1Delta( - sqrtRatioAX96, - sqrtRatioBX96, - uint128(liquidity), - true - ).toInt256(); + ? -getAmount1Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(-liquidity), false).toInt256() + : getAmount1Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(liquidity), true).toInt256(); } } } diff --git a/contracts/dependencies/uniswap/libraries/SwapMath.sol b/contracts/dependencies/uniswapv3-core/libraries/SwapMath.sol similarity index 59% rename from contracts/dependencies/uniswap/libraries/SwapMath.sol rename to contracts/dependencies/uniswapv3-core/libraries/SwapMath.sol index 3984d4023..ddb8b6859 100644 --- a/contracts/dependencies/uniswap/libraries/SwapMath.sol +++ b/contracts/dependencies/uniswapv3-core/libraries/SwapMath.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; -import {FullMath} from "./FullMath.sol"; -import {SqrtPriceMath} from "./SqrtPriceMath.sol"; +import {FullMath} from './FullMath.sol'; +import {SqrtPriceMath} from './SqrtPriceMath.sol'; /// @title Computes the result of a swap within ticks /// @notice Contains methods for computing the result of a swap within a single tick price range, i.e., a single tick. @@ -39,26 +39,11 @@ library SwapMath { bool exactIn = amountRemaining >= 0; if (exactIn) { - uint256 amountRemainingLessFee = FullMath.mulDiv( - uint256(amountRemaining), - 1e6 - feePips, - 1e6 - ); + uint256 amountRemainingLessFee = FullMath.mulDiv(uint256(amountRemaining), 1e6 - feePips, 1e6); amountIn = zeroForOne - ? SqrtPriceMath.getAmount0Delta( - sqrtRatioTargetX96, - sqrtRatioCurrentX96, - liquidity, - true - ) - : SqrtPriceMath.getAmount1Delta( - sqrtRatioCurrentX96, - sqrtRatioTargetX96, - liquidity, - true - ); - if (amountRemainingLessFee >= amountIn) - sqrtRatioNextX96 = sqrtRatioTargetX96; + ? SqrtPriceMath.getAmount0Delta(sqrtRatioTargetX96, sqrtRatioCurrentX96, liquidity, true) + : SqrtPriceMath.getAmount1Delta(sqrtRatioCurrentX96, sqrtRatioTargetX96, liquidity, true); + if (amountRemainingLessFee >= amountIn) sqrtRatioNextX96 = sqrtRatioTargetX96; else sqrtRatioNextX96 = SqrtPriceMath.getNextSqrtPriceFromInput( sqrtRatioCurrentX96, @@ -68,20 +53,9 @@ library SwapMath { ); } else { amountOut = zeroForOne - ? SqrtPriceMath.getAmount1Delta( - sqrtRatioTargetX96, - sqrtRatioCurrentX96, - liquidity, - false - ) - : SqrtPriceMath.getAmount0Delta( - sqrtRatioCurrentX96, - sqrtRatioTargetX96, - liquidity, - false - ); - if (uint256(-amountRemaining) >= amountOut) - sqrtRatioNextX96 = sqrtRatioTargetX96; + ? SqrtPriceMath.getAmount1Delta(sqrtRatioTargetX96, sqrtRatioCurrentX96, liquidity, false) + : SqrtPriceMath.getAmount0Delta(sqrtRatioCurrentX96, sqrtRatioTargetX96, liquidity, false); + if (uint256(-amountRemaining) >= amountOut) sqrtRatioNextX96 = sqrtRatioTargetX96; else sqrtRatioNextX96 = SqrtPriceMath.getNextSqrtPriceFromOutput( sqrtRatioCurrentX96, @@ -97,37 +71,17 @@ library SwapMath { if (zeroForOne) { amountIn = max && exactIn ? amountIn - : SqrtPriceMath.getAmount0Delta( - sqrtRatioNextX96, - sqrtRatioCurrentX96, - liquidity, - true - ); + : SqrtPriceMath.getAmount0Delta(sqrtRatioNextX96, sqrtRatioCurrentX96, liquidity, true); amountOut = max && !exactIn ? amountOut - : SqrtPriceMath.getAmount1Delta( - sqrtRatioNextX96, - sqrtRatioCurrentX96, - liquidity, - false - ); + : SqrtPriceMath.getAmount1Delta(sqrtRatioNextX96, sqrtRatioCurrentX96, liquidity, false); } else { amountIn = max && exactIn ? amountIn - : SqrtPriceMath.getAmount1Delta( - sqrtRatioCurrentX96, - sqrtRatioNextX96, - liquidity, - true - ); + : SqrtPriceMath.getAmount1Delta(sqrtRatioCurrentX96, sqrtRatioNextX96, liquidity, true); amountOut = max && !exactIn ? amountOut - : SqrtPriceMath.getAmount0Delta( - sqrtRatioCurrentX96, - sqrtRatioNextX96, - liquidity, - false - ); + : SqrtPriceMath.getAmount0Delta(sqrtRatioCurrentX96, sqrtRatioNextX96, liquidity, false); } // cap the output amount to not exceed the remaining output amount @@ -139,11 +93,7 @@ library SwapMath { // we didn't reach the target, so take the remainder of the maximum input as fee feeAmount = uint256(amountRemaining) - amountIn; } else { - feeAmount = FullMath.mulDivRoundingUp( - amountIn, - feePips, - 1e6 - feePips - ); + feeAmount = FullMath.mulDivRoundingUp(amountIn, feePips, 1e6 - feePips); } } } diff --git a/contracts/dependencies/uniswap/libraries/Tick.sol b/contracts/dependencies/uniswapv3-core/libraries/Tick.sol similarity index 83% rename from contracts/dependencies/uniswap/libraries/Tick.sol rename to contracts/dependencies/uniswapv3-core/libraries/Tick.sol index c6190a6ad..97f8c5768 100644 --- a/contracts/dependencies/uniswap/libraries/Tick.sol +++ b/contracts/dependencies/uniswapv3-core/libraries/Tick.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; -import {SafeCast} from "./SafeCast.sol"; +import {SafeCast} from './SafeCast.sol'; -import {TickMath} from "./TickMath.sol"; +import {TickMath} from './TickMath.sol'; /// @title Tick /// @notice Contains functions for managing tick processes and relevant calculations @@ -40,11 +40,7 @@ library Tick { /// @param tickSpacing The amount of required tick separation, realized in multiples of `tickSpacing` /// e.g., a tickSpacing of 3 requires ticks to be initialized every 3rd tick i.e., ..., -6, -3, 0, 3, 6, ... /// @return The max liquidity per tick - function tickSpacingToMaxLiquidityPerTick(int24 tickSpacing) - internal - pure - returns (uint128) - { + function tickSpacingToMaxLiquidityPerTick(int24 tickSpacing) internal pure returns (uint128) { unchecked { int24 minTick = (TickMath.MIN_TICK / tickSpacing) * tickSpacing; int24 maxTick = (TickMath.MAX_TICK / tickSpacing) * tickSpacing; @@ -69,11 +65,7 @@ library Tick { int24 tickCurrent, uint256 feeGrowthGlobal0X128, uint256 feeGrowthGlobal1X128 - ) - internal - view - returns (uint256 feeGrowthInside0X128, uint256 feeGrowthInside1X128) - { + ) internal view returns (uint256 feeGrowthInside0X128, uint256 feeGrowthInside1X128) { unchecked { Info storage lower = self[tickLower]; Info storage upper = self[tickUpper]; @@ -85,12 +77,8 @@ library Tick { feeGrowthBelow0X128 = lower.feeGrowthOutside0X128; feeGrowthBelow1X128 = lower.feeGrowthOutside1X128; } else { - feeGrowthBelow0X128 = - feeGrowthGlobal0X128 - - lower.feeGrowthOutside0X128; - feeGrowthBelow1X128 = - feeGrowthGlobal1X128 - - lower.feeGrowthOutside1X128; + feeGrowthBelow0X128 = feeGrowthGlobal0X128 - lower.feeGrowthOutside0X128; + feeGrowthBelow1X128 = feeGrowthGlobal1X128 - lower.feeGrowthOutside1X128; } // calculate fee growth above @@ -100,22 +88,12 @@ library Tick { feeGrowthAbove0X128 = upper.feeGrowthOutside0X128; feeGrowthAbove1X128 = upper.feeGrowthOutside1X128; } else { - feeGrowthAbove0X128 = - feeGrowthGlobal0X128 - - upper.feeGrowthOutside0X128; - feeGrowthAbove1X128 = - feeGrowthGlobal1X128 - - upper.feeGrowthOutside1X128; + feeGrowthAbove0X128 = feeGrowthGlobal0X128 - upper.feeGrowthOutside0X128; + feeGrowthAbove1X128 = feeGrowthGlobal1X128 - upper.feeGrowthOutside1X128; } - feeGrowthInside0X128 = - feeGrowthGlobal0X128 - - feeGrowthBelow0X128 - - feeGrowthAbove0X128; - feeGrowthInside1X128 = - feeGrowthGlobal1X128 - - feeGrowthBelow1X128 - - feeGrowthAbove1X128; + feeGrowthInside0X128 = feeGrowthGlobal0X128 - feeGrowthBelow0X128 - feeGrowthAbove0X128; + feeGrowthInside1X128 = feeGrowthGlobal1X128 - feeGrowthBelow1X128 - feeGrowthAbove1X128; } } @@ -161,8 +139,7 @@ library Tick { if (tick <= tickCurrent) { info.feeGrowthOutside0X128 = feeGrowthGlobal0X128; info.feeGrowthOutside1X128 = feeGrowthGlobal1X128; - info - .secondsPerLiquidityOutsideX128 = secondsPerLiquidityCumulativeX128; + info.secondsPerLiquidityOutsideX128 = secondsPerLiquidityCumulativeX128; info.tickCumulativeOutside = tickCumulative; info.secondsOutside = time; } @@ -172,17 +149,13 @@ library Tick { info.liquidityGross = liquidityGrossAfter; // when the lower (upper) tick is crossed left to right (right to left), liquidity must be added (removed) - info.liquidityNet = upper - ? info.liquidityNet - liquidityDelta - : info.liquidityNet + liquidityDelta; + info.liquidityNet = upper ? info.liquidityNet - liquidityDelta : info.liquidityNet + liquidityDelta; } /// @notice Clears tick data /// @param self The mapping containing all initialized tick information for initialized ticks /// @param tick The tick that will be cleared - function clear(mapping(int24 => Tick.Info) storage self, int24 tick) - internal - { + function clear(mapping(int24 => Tick.Info) storage self, int24 tick) internal { delete self[tick]; } @@ -206,18 +179,12 @@ library Tick { ) internal returns (int128 liquidityNet) { unchecked { Tick.Info storage info = self[tick]; - info.feeGrowthOutside0X128 = - feeGrowthGlobal0X128 - - info.feeGrowthOutside0X128; - info.feeGrowthOutside1X128 = - feeGrowthGlobal1X128 - - info.feeGrowthOutside1X128; + info.feeGrowthOutside0X128 = feeGrowthGlobal0X128 - info.feeGrowthOutside0X128; + info.feeGrowthOutside1X128 = feeGrowthGlobal1X128 - info.feeGrowthOutside1X128; info.secondsPerLiquidityOutsideX128 = secondsPerLiquidityCumulativeX128 - info.secondsPerLiquidityOutsideX128; - info.tickCumulativeOutside = - tickCumulative - - info.tickCumulativeOutside; + info.tickCumulativeOutside = tickCumulative - info.tickCumulativeOutside; info.secondsOutside = time - info.secondsOutside; liquidityNet = info.liquidityNet; } diff --git a/contracts/dependencies/uniswap/libraries/TickBitmap.sol b/contracts/dependencies/uniswapv3-core/libraries/TickBitmap.sol similarity index 84% rename from contracts/dependencies/uniswap/libraries/TickBitmap.sol rename to contracts/dependencies/uniswapv3-core/libraries/TickBitmap.sol index d75773132..1cc5bb9ce 100644 --- a/contracts/dependencies/uniswap/libraries/TickBitmap.sol +++ b/contracts/dependencies/uniswapv3-core/libraries/TickBitmap.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; -import {BitMath} from "./BitMath.sol"; +import {BitMath} from './BitMath.sol'; /// @title Packed tick initialized state library /// @notice Stores a packed mapping of tick index to its initialized state @@ -11,11 +11,7 @@ library TickBitmap { /// @param tick The tick for which to compute the position /// @return wordPos The key in the mapping containing the word in which the bit is stored /// @return bitPos The bit position in the word where the flag is stored - function position(int24 tick) - private - pure - returns (int16 wordPos, uint8 bitPos) - { + function position(int24 tick) private pure returns (int16 wordPos, uint8 bitPos) { unchecked { wordPos = int16(tick >> 8); bitPos = uint8(int8(tick % 256)); @@ -67,10 +63,7 @@ library TickBitmap { initialized = masked != 0; // overflow/underflow is possible, but prevented externally by limiting both tickSpacing and tick next = initialized - ? (compressed - - int24( - uint24(bitPos - BitMath.mostSignificantBit(masked)) - )) * tickSpacing + ? (compressed - int24(uint24(bitPos - BitMath.mostSignificantBit(masked)))) * tickSpacing : (compressed - int24(uint24(bitPos))) * tickSpacing; } else { // start from the word of the next tick, since the current tick state doesn't matter @@ -83,14 +76,8 @@ library TickBitmap { initialized = masked != 0; // overflow/underflow is possible, but prevented externally by limiting both tickSpacing and tick next = initialized - ? (compressed + - 1 + - int24( - uint24(BitMath.leastSignificantBit(masked) - bitPos) - )) * tickSpacing - : (compressed + - 1 + - int24(uint24(type(uint8).max - bitPos))) * tickSpacing; + ? (compressed + 1 + int24(uint24(BitMath.leastSignificantBit(masked) - bitPos))) * tickSpacing + : (compressed + 1 + int24(uint24(type(uint8).max - bitPos))) * tickSpacing; } } } diff --git a/contracts/dependencies/univ3/libraries/TickMath.sol b/contracts/dependencies/uniswapv3-core/libraries/TickMath.sol similarity index 63% rename from contracts/dependencies/univ3/libraries/TickMath.sol rename to contracts/dependencies/uniswapv3-core/libraries/TickMath.sol index 80b47772d..3715d15dd 100644 --- a/contracts/dependencies/univ3/libraries/TickMath.sol +++ b/contracts/dependencies/uniswapv3-core/libraries/TickMath.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0 <0.8.0; +pragma solidity ^0.8.0; /// @title Math library for computing sqrt prices from ticks and vice versa /// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports @@ -13,74 +13,44 @@ library TickMath { /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK) uint160 internal constant MIN_SQRT_RATIO = 4295128739; /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK) - uint160 internal constant MAX_SQRT_RATIO = - 1461446703485210103287273052203988822378723970342; + uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342; /// @notice Calculates sqrt(1.0001^tick) * 2^96 /// @dev Throws if |tick| > max tick /// @param tick The input tick for the above formula /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0) /// at the given tick - function getSqrtRatioAtTick(int24 tick) - internal - pure - returns (uint160 sqrtPriceX96) - { - uint256 absTick = tick < 0 - ? uint256(-int256(tick)) - : uint256(int256(tick)); - require(absTick <= uint256(MAX_TICK), "T"); + function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) { + uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick)); + require(absTick <= uint256(int256(MAX_TICK)), 'T'); - uint256 ratio = absTick & 0x1 != 0 - ? 0xfffcb933bd6fad37aa2d162d1a594001 - : 0x100000000000000000000000000000000; - if (absTick & 0x2 != 0) - ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128; - if (absTick & 0x4 != 0) - ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128; - if (absTick & 0x8 != 0) - ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128; - if (absTick & 0x10 != 0) - ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128; - if (absTick & 0x20 != 0) - ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128; - if (absTick & 0x40 != 0) - ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128; - if (absTick & 0x80 != 0) - ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128; - if (absTick & 0x100 != 0) - ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128; - if (absTick & 0x200 != 0) - ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128; - if (absTick & 0x400 != 0) - ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128; - if (absTick & 0x800 != 0) - ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128; - if (absTick & 0x1000 != 0) - ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128; - if (absTick & 0x2000 != 0) - ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128; - if (absTick & 0x4000 != 0) - ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128; - if (absTick & 0x8000 != 0) - ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128; - if (absTick & 0x10000 != 0) - ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128; - if (absTick & 0x20000 != 0) - ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128; - if (absTick & 0x40000 != 0) - ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128; - if (absTick & 0x80000 != 0) - ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128; + uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000; + if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128; + if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128; + if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128; + if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128; + if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128; + if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128; + if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128; + if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128; + if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128; + if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128; + if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128; + if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128; + if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128; + if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128; + if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128; + if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128; + if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128; + if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128; + if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128; if (tick > 0) ratio = type(uint256).max / ratio; // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96. // we then downcast because we know the result always fits within 160 bits due to our tick input constraint // we round up in the division so getTickAtSqrtRatio of the output price is always consistent - sqrtPriceX96 = uint160( - (ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1) - ); + sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1)); } /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio @@ -88,16 +58,9 @@ library TickMath { /// ever return. /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96 /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio - function getTickAtSqrtRatio(uint160 sqrtPriceX96) - internal - pure - returns (int24 tick) - { + function getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick) { // second inequality must be < because the price can never reach the price at the max tick - require( - sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO, - "R" - ); + require(sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO, 'R'); uint256 ratio = uint256(sqrtPriceX96) << 32; uint256 r = ratio; @@ -234,17 +197,9 @@ library TickMath { int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number - int24 tickLow = int24( - (log_sqrt10001 - 3402992956809132418596140100660247210) >> 128 - ); - int24 tickHi = int24( - (log_sqrt10001 + 291339464771989622907027621153398088495) >> 128 - ); + int24 tickLow = int24((log_sqrt10001 - 3402992956809132418596140100660247210) >> 128); + int24 tickHi = int24((log_sqrt10001 + 291339464771989622907027621153398088495) >> 128); - tick = tickLow == tickHi - ? tickLow - : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 - ? tickHi - : tickLow; + tick = tickLow == tickHi ? tickLow : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 ? tickHi : tickLow; } } diff --git a/contracts/dependencies/univ3/libraries/TransferHelper.sol b/contracts/dependencies/uniswapv3-core/libraries/TransferHelper.sol similarity index 80% rename from contracts/dependencies/univ3/libraries/TransferHelper.sol rename to contracts/dependencies/uniswapv3-core/libraries/TransferHelper.sol index 981173942..d419a13cd 100644 --- a/contracts/dependencies/univ3/libraries/TransferHelper.sol +++ b/contracts/dependencies/uniswapv3-core/libraries/TransferHelper.sol @@ -1,11 +1,13 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.6.0; +pragma solidity ^0.8.0; -import "../interfaces/IERC20Minimal.sol"; +import {IERC20Minimal} from '../interfaces/IERC20Minimal.sol'; /// @title TransferHelper /// @notice Contains helper methods for interacting with ERC20 tokens that do not consistently return true/false library TransferHelper { + error TF(); + /// @notice Transfers tokens from msg.sender to a recipient /// @dev Calls transfer on token contract, errors with TF if transfer fails /// @param token The contract address of the token which will be transferred @@ -19,9 +21,6 @@ library TransferHelper { (bool success, bytes memory data) = token.call( abi.encodeWithSelector(IERC20Minimal.transfer.selector, to, value) ); - require( - success && (data.length == 0 || abi.decode(data, (bool))), - "TF" - ); + if (!(success && (data.length == 0 || abi.decode(data, (bool))))) revert TF(); } } diff --git a/contracts/dependencies/univ3/libraries/UnsafeMath.sol b/contracts/dependencies/uniswapv3-core/libraries/UnsafeMath.sol similarity index 79% rename from contracts/dependencies/univ3/libraries/UnsafeMath.sol rename to contracts/dependencies/uniswapv3-core/libraries/UnsafeMath.sol index eda37a27e..2d8e199df 100644 --- a/contracts/dependencies/univ3/libraries/UnsafeMath.sol +++ b/contracts/dependencies/uniswapv3-core/libraries/UnsafeMath.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; +pragma solidity ^0.8.0; /// @title Math functions that do not check inputs or outputs /// @notice Contains methods that perform common math functions but do not do any overflow or underflow checks @@ -9,11 +9,7 @@ library UnsafeMath { /// @param x The dividend /// @param y The divisor /// @return z The quotient, ceil(x / y) - function divRoundingUp(uint256 x, uint256 y) - internal - pure - returns (uint256 z) - { + function divRoundingUp(uint256 x, uint256 y) internal pure returns (uint256 z) { assembly { z := add(div(x, y), gt(mod(x, y), 0)) } diff --git a/contracts/dependencies/uniswapv3-periphery/NonfungiblePositionManager.sol b/contracts/dependencies/uniswapv3-periphery/NonfungiblePositionManager.sol new file mode 100644 index 000000000..cbb4cb930 --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/NonfungiblePositionManager.sol @@ -0,0 +1,399 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; +pragma abicoder v2; + +import {IUniswapV3Pool} from '../uniswapv3-core/interfaces/IUniswapV3Pool.sol'; +import '../uniswapv3-core/libraries/FixedPoint128.sol'; +import '../uniswapv3-core/libraries/FullMath.sol'; + +import './interfaces/INonfungiblePositionManager.sol'; +import './interfaces/INonfungibleTokenPositionDescriptor.sol'; +import './libraries/PositionKey.sol'; +import './libraries/PoolAddress.sol'; +import {LiquidityManagement} from './base/LiquidityManagement.sol'; +import './base/PeripheryImmutableState.sol'; +import './base/Multicall.sol'; +import './base/ERC721Permit.sol'; +import {PeripheryValidation} from './base/PeripheryValidation.sol'; +import './base/SelfPermit.sol'; +import {PoolInitializer} from './base/PoolInitializer.sol'; + +/// @title NFT positions +/// @notice Wraps Uniswap V3 positions in the ERC721 non-fungible token interface +contract NonfungiblePositionManager is + INonfungiblePositionManager, + Multicall, + ERC721Permit, + PeripheryImmutableState, + PoolInitializer, + LiquidityManagement, + PeripheryValidation, + SelfPermit +{ + // details about the uniswap position + struct Position { + // the nonce for permits + uint96 nonce; + // the address that is approved for spending this token + address operator; + // the ID of the pool with which this token is connected + uint80 poolId; + // the tick range of the position + int24 tickLower; + int24 tickUpper; + // the liquidity of the position + uint128 liquidity; + // the fee growth of the aggregate position as of the last action on the individual position + uint256 feeGrowthInside0LastX128; + uint256 feeGrowthInside1LastX128; + // how many uncollected tokens are owed to the position, as of the last computation + uint128 tokensOwed0; + uint128 tokensOwed1; + } + + /// @dev IDs of pools assigned by this contract + mapping(address => uint80) private _poolIds; + + /// @dev Pool keys by pool ID, to save on SSTOREs for position data + mapping(uint80 => PoolAddress.PoolKey) private _poolIdToPoolKey; + + /// @dev The token ID position data + mapping(uint256 => Position) private _positions; + + /// @dev The ID of the next token that will be minted. Skips 0 + uint176 private _nextId = 1; + /// @dev The ID of the next pool that is used for the first time. Skips 0 + uint80 private _nextPoolId = 1; + + /// @dev The address of the token descriptor contract, which handles generating token URIs for position tokens + address private immutable _tokenDescriptor; + + constructor( + address _factory, + address _WETH9, + address _tokenDescriptor_ + ) ERC721Permit('Uniswap V3 Positions NFT-V1', 'UNI-V3-POS', '1') PeripheryImmutableState(_factory, _WETH9) { + _tokenDescriptor = _tokenDescriptor_; + } + + /// @inheritdoc INonfungiblePositionManager + function positions(uint256 tokenId) + external + view + override + returns ( + uint96 nonce, + address operator, + address token0, + address token1, + uint24 fee, + int24 tickLower, + int24 tickUpper, + uint128 liquidity, + uint256 feeGrowthInside0LastX128, + uint256 feeGrowthInside1LastX128, + uint128 tokensOwed0, + uint128 tokensOwed1 + ) + { + Position memory position = _positions[tokenId]; + require(position.poolId != 0, 'Invalid token ID'); + PoolAddress.PoolKey memory poolKey = _poolIdToPoolKey[position.poolId]; + return ( + position.nonce, + position.operator, + poolKey.token0, + poolKey.token1, + poolKey.fee, + position.tickLower, + position.tickUpper, + position.liquidity, + position.feeGrowthInside0LastX128, + position.feeGrowthInside1LastX128, + position.tokensOwed0, + position.tokensOwed1 + ); + } + + /// @dev Caches a pool key + function cachePoolKey(address pool, PoolAddress.PoolKey memory poolKey) private returns (uint80 poolId) { + poolId = _poolIds[pool]; + if (poolId == 0) { + _poolIds[pool] = (poolId = _nextPoolId++); + _poolIdToPoolKey[poolId] = poolKey; + } + } + + /// @inheritdoc INonfungiblePositionManager + function mint(MintParams calldata params) + external + payable + override + checkDeadline(params.deadline) + returns ( + uint256 tokenId, + uint128 liquidity, + uint256 amount0, + uint256 amount1 + ) + { + IUniswapV3Pool pool; + (liquidity, amount0, amount1, pool) = addLiquidity( + AddLiquidityParams({ + token0: params.token0, + token1: params.token1, + fee: params.fee, + recipient: address(this), + tickLower: params.tickLower, + tickUpper: params.tickUpper, + amount0Desired: params.amount0Desired, + amount1Desired: params.amount1Desired, + amount0Min: params.amount0Min, + amount1Min: params.amount1Min + }) + ); + + _mint(params.recipient, (tokenId = _nextId++)); + + bytes32 positionKey = PositionKey.compute(address(this), params.tickLower, params.tickUpper); + (, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128, , ) = pool.positions(positionKey); + + // idempotent set + uint80 poolId = cachePoolKey( + address(pool), + PoolAddress.PoolKey({token0: params.token0, token1: params.token1, fee: params.fee}) + ); + + _positions[tokenId] = Position({ + nonce: 0, + operator: address(0), + poolId: poolId, + tickLower: params.tickLower, + tickUpper: params.tickUpper, + liquidity: liquidity, + feeGrowthInside0LastX128: feeGrowthInside0LastX128, + feeGrowthInside1LastX128: feeGrowthInside1LastX128, + tokensOwed0: 0, + tokensOwed1: 0 + }); + + emit IncreaseLiquidity(tokenId, liquidity, amount0, amount1); + } + + modifier isAuthorizedForToken(uint256 tokenId) { + require(_isApprovedOrOwner(msg.sender, tokenId), 'Not approved'); + _; + } + + function tokenURI(uint256 tokenId) public view override(ERC721, IERC721Metadata) returns (string memory) { + require(_exists(tokenId)); + return INonfungibleTokenPositionDescriptor(_tokenDescriptor).tokenURI(this, tokenId); + } + + // save bytecode by removing implementation of unused method + function baseURI() public pure returns (string memory) {} + + /// @inheritdoc INonfungiblePositionManager + function increaseLiquidity(IncreaseLiquidityParams calldata params) + external + payable + override + checkDeadline(params.deadline) + returns ( + uint128 liquidity, + uint256 amount0, + uint256 amount1 + ) + { + Position storage position = _positions[params.tokenId]; + + PoolAddress.PoolKey memory poolKey = _poolIdToPoolKey[position.poolId]; + + IUniswapV3Pool pool; + (liquidity, amount0, amount1, pool) = addLiquidity( + AddLiquidityParams({ + token0: poolKey.token0, + token1: poolKey.token1, + fee: poolKey.fee, + tickLower: position.tickLower, + tickUpper: position.tickUpper, + amount0Desired: params.amount0Desired, + amount1Desired: params.amount1Desired, + amount0Min: params.amount0Min, + amount1Min: params.amount1Min, + recipient: address(this) + }) + ); + + bytes32 positionKey = PositionKey.compute(address(this), position.tickLower, position.tickUpper); + + // this is now updated to the current transaction + (, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128, , ) = pool.positions(positionKey); + + position.tokensOwed0 += uint128( + FullMath.mulDiv( + feeGrowthInside0LastX128 - position.feeGrowthInside0LastX128, + position.liquidity, + FixedPoint128.Q128 + ) + ); + position.tokensOwed1 += uint128( + FullMath.mulDiv( + feeGrowthInside1LastX128 - position.feeGrowthInside1LastX128, + position.liquidity, + FixedPoint128.Q128 + ) + ); + + position.feeGrowthInside0LastX128 = feeGrowthInside0LastX128; + position.feeGrowthInside1LastX128 = feeGrowthInside1LastX128; + position.liquidity += liquidity; + + emit IncreaseLiquidity(params.tokenId, liquidity, amount0, amount1); + } + + /// @inheritdoc INonfungiblePositionManager + function decreaseLiquidity(DecreaseLiquidityParams calldata params) + external + payable + override + isAuthorizedForToken(params.tokenId) + checkDeadline(params.deadline) + returns (uint256 amount0, uint256 amount1) + { + require(params.liquidity > 0); + Position storage position = _positions[params.tokenId]; + + uint128 positionLiquidity = position.liquidity; + require(positionLiquidity >= params.liquidity); + + PoolAddress.PoolKey memory poolKey = _poolIdToPoolKey[position.poolId]; + IUniswapV3Pool pool = IUniswapV3Pool(PoolAddress.computeAddress(factory, poolKey)); + (amount0, amount1) = pool.burn(position.tickLower, position.tickUpper, params.liquidity); + + require(amount0 >= params.amount0Min && amount1 >= params.amount1Min, 'Price slippage check'); + + bytes32 positionKey = PositionKey.compute(address(this), position.tickLower, position.tickUpper); + // this is now updated to the current transaction + (, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128, , ) = pool.positions(positionKey); + + position.tokensOwed0 += + uint128(amount0) + + uint128( + FullMath.mulDiv( + feeGrowthInside0LastX128 - position.feeGrowthInside0LastX128, + positionLiquidity, + FixedPoint128.Q128 + ) + ); + position.tokensOwed1 += + uint128(amount1) + + uint128( + FullMath.mulDiv( + feeGrowthInside1LastX128 - position.feeGrowthInside1LastX128, + positionLiquidity, + FixedPoint128.Q128 + ) + ); + + position.feeGrowthInside0LastX128 = feeGrowthInside0LastX128; + position.feeGrowthInside1LastX128 = feeGrowthInside1LastX128; + // subtraction is safe because we checked positionLiquidity is gte params.liquidity + position.liquidity = positionLiquidity - params.liquidity; + + emit DecreaseLiquidity(params.tokenId, params.liquidity, amount0, amount1); + } + + /// @inheritdoc INonfungiblePositionManager + function collect(CollectParams calldata params) + external + payable + override + isAuthorizedForToken(params.tokenId) + returns (uint256 amount0, uint256 amount1) + { + require(params.amount0Max > 0 || params.amount1Max > 0); + // allow collecting to the nft position manager address with address 0 + address recipient = params.recipient == address(0) ? address(this) : params.recipient; + + Position storage position = _positions[params.tokenId]; + + PoolAddress.PoolKey memory poolKey = _poolIdToPoolKey[position.poolId]; + + IUniswapV3Pool pool = IUniswapV3Pool(PoolAddress.computeAddress(factory, poolKey)); + + (uint128 tokensOwed0, uint128 tokensOwed1) = (position.tokensOwed0, position.tokensOwed1); + + // trigger an update of the position fees owed and fee growth snapshots if it has any liquidity + if (position.liquidity > 0) { + pool.burn(position.tickLower, position.tickUpper, 0); + (, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128, , ) = pool.positions( + PositionKey.compute(address(this), position.tickLower, position.tickUpper) + ); + + tokensOwed0 += uint128( + FullMath.mulDiv( + feeGrowthInside0LastX128 - position.feeGrowthInside0LastX128, + position.liquidity, + FixedPoint128.Q128 + ) + ); + tokensOwed1 += uint128( + FullMath.mulDiv( + feeGrowthInside1LastX128 - position.feeGrowthInside1LastX128, + position.liquidity, + FixedPoint128.Q128 + ) + ); + + position.feeGrowthInside0LastX128 = feeGrowthInside0LastX128; + position.feeGrowthInside1LastX128 = feeGrowthInside1LastX128; + } + + // compute the arguments to give to the pool#collect method + (uint128 amount0Collect, uint128 amount1Collect) = ( + params.amount0Max > tokensOwed0 ? tokensOwed0 : params.amount0Max, + params.amount1Max > tokensOwed1 ? tokensOwed1 : params.amount1Max + ); + + // the actual amounts collected are returned + (amount0, amount1) = pool.collect( + recipient, + position.tickLower, + position.tickUpper, + amount0Collect, + amount1Collect + ); + + // sometimes there will be a few less wei than expected due to rounding down in core, but we just subtract the full amount expected + // instead of the actual amount so we can burn the token + (position.tokensOwed0, position.tokensOwed1) = (tokensOwed0 - amount0Collect, tokensOwed1 - amount1Collect); + + emit Collect(params.tokenId, recipient, amount0Collect, amount1Collect); + } + + /// @inheritdoc INonfungiblePositionManager + function burn(uint256 tokenId) external payable override isAuthorizedForToken(tokenId) { + Position storage position = _positions[tokenId]; + require(position.liquidity == 0 && position.tokensOwed0 == 0 && position.tokensOwed1 == 0, 'Not cleared'); + delete _positions[tokenId]; + _burn(tokenId); + } + + function _getAndIncrementNonce(uint256 tokenId) internal override returns (uint256) { + return uint256(_positions[tokenId].nonce++); + } + + /// @inheritdoc IERC721 + function getApproved(uint256 tokenId) public view override(ERC721, IERC721) returns (address) { + require(_exists(tokenId), 'ERC721: approved query for nonexistent token'); + + return _positions[tokenId].operator; + } + + /// @dev Overrides _approve to use the operator in the position, which is packed with the position permit nonce + function _approve(address to, uint256 tokenId) internal override(ERC721) { + _positions[tokenId].operator = to; + emit Approval(ownerOf(tokenId), to, tokenId); + } +} diff --git a/contracts/dependencies/uniswapv3-periphery/SwapRouter.sol b/contracts/dependencies/uniswapv3-periphery/SwapRouter.sol new file mode 100644 index 000000000..c91566c72 --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/SwapRouter.sol @@ -0,0 +1,241 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; +pragma abicoder v2; + +import '../uniswapv3-core/libraries/SafeCast.sol'; +import '../uniswapv3-core/libraries/TickMath.sol'; +import '../uniswapv3-core/interfaces/IUniswapV3Pool.sol'; + +import './interfaces/ISwapRouter.sol'; +import './base/PeripheryImmutableState.sol'; +import './base/PeripheryValidation.sol'; +import './base/PeripheryPaymentsWithFee.sol'; +import './base/Multicall.sol'; +import './base/SelfPermit.sol'; +import './libraries/Path.sol'; +import './libraries/PoolAddress.sol'; +import {CallbackValidation} from './libraries/CallbackValidation.sol'; +import './interfaces/external/IWETH9.sol'; + +/// @title Uniswap V3 Swap Router +/// @notice Router for stateless execution of swaps against Uniswap V3 +contract SwapRouter is + ISwapRouter, + PeripheryImmutableState, + PeripheryValidation, + PeripheryPaymentsWithFee, + Multicall, + SelfPermit +{ + using Path for bytes; + using SafeCast for uint256; + + /// @dev Used as the placeholder value for amountInCached, because the computed amount in for an exact output swap + /// can never actually be this value + uint256 private constant DEFAULT_AMOUNT_IN_CACHED = type(uint256).max; + + /// @dev Transient storage variable used for returning the computed amount in for an exact output swap. + uint256 private amountInCached = DEFAULT_AMOUNT_IN_CACHED; + + constructor(address _factory, address _WETH9) PeripheryImmutableState(_factory, _WETH9) {} + + /// @dev Returns the pool for the given token pair and fee. The pool contract may or may not exist. + function getPool( + address tokenA, + address tokenB, + uint24 fee + ) private view returns (IUniswapV3Pool) { + return IUniswapV3Pool(PoolAddress.computeAddress(factory, PoolAddress.getPoolKey(tokenA, tokenB, fee))); + } + + struct SwapCallbackData { + bytes path; + address payer; + } + + /// @inheritdoc IUniswapV3SwapCallback + function uniswapV3SwapCallback( + int256 amount0Delta, + int256 amount1Delta, + bytes calldata _data + ) external override { + require(amount0Delta > 0 || amount1Delta > 0); // swaps entirely within 0-liquidity regions are not supported + SwapCallbackData memory data = abi.decode(_data, (SwapCallbackData)); + (address tokenIn, address tokenOut, uint24 fee) = data.path.decodeFirstPool(); + CallbackValidation.verifyCallback(factory, tokenIn, tokenOut, fee); + + (bool isExactInput, uint256 amountToPay) = amount0Delta > 0 + ? (tokenIn < tokenOut, uint256(amount0Delta)) + : (tokenOut < tokenIn, uint256(amount1Delta)); + if (isExactInput) { + pay(tokenIn, data.payer, msg.sender, amountToPay); + } else { + // either initiate the next swap or pay + if (data.path.hasMultiplePools()) { + data.path = data.path.skipToken(); + exactOutputInternal(amountToPay, msg.sender, 0, data); + } else { + amountInCached = amountToPay; + tokenIn = tokenOut; // swap in/out because exact output swaps are reversed + pay(tokenIn, data.payer, msg.sender, amountToPay); + } + } + } + + /// @dev Performs a single exact input swap + function exactInputInternal( + uint256 amountIn, + address recipient, + uint160 sqrtPriceLimitX96, + SwapCallbackData memory data + ) private returns (uint256 amountOut) { + // allow swapping to the router address with address 0 + if (recipient == address(0)) recipient = address(this); + + (address tokenIn, address tokenOut, uint24 fee) = data.path.decodeFirstPool(); + + bool zeroForOne = tokenIn < tokenOut; + + (int256 amount0, int256 amount1) = getPool(tokenIn, tokenOut, fee).swap( + recipient, + zeroForOne, + amountIn.toInt256(), + sqrtPriceLimitX96 == 0 + ? (zeroForOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1) + : sqrtPriceLimitX96, + abi.encode(data) + ); + + return uint256(-(zeroForOne ? amount1 : amount0)); + } + + /// @inheritdoc ISwapRouter + function exactInputSingle(ExactInputSingleParams calldata params) + external + payable + override + checkDeadline(params.deadline) + returns (uint256 amountOut) + { + amountOut = exactInputInternal( + params.amountIn, + params.recipient, + params.sqrtPriceLimitX96, + SwapCallbackData({path: abi.encodePacked(params.tokenIn, params.fee, params.tokenOut), payer: msg.sender}) + ); + require(amountOut >= params.amountOutMinimum, 'Too little received'); + } + + /// @inheritdoc ISwapRouter + function exactInput(ExactInputParams memory params) + external + payable + override + checkDeadline(params.deadline) + returns (uint256 amountOut) + { + address payer = msg.sender; // msg.sender pays for the first hop + + while (true) { + bool hasMultiplePools = params.path.hasMultiplePools(); + + // the outputs of prior swaps become the inputs to subsequent ones + params.amountIn = exactInputInternal( + params.amountIn, + hasMultiplePools ? address(this) : params.recipient, // for intermediate swaps, this contract custodies + 0, + SwapCallbackData({ + path: params.path.getFirstPool(), // only the first pool in the path is necessary + payer: payer + }) + ); + + // decide whether to continue or terminate + if (hasMultiplePools) { + payer = address(this); // at this point, the caller has paid + params.path = params.path.skipToken(); + } else { + amountOut = params.amountIn; + break; + } + } + + require(amountOut >= params.amountOutMinimum, 'Too little received'); + } + + /// @dev Performs a single exact output swap + function exactOutputInternal( + uint256 amountOut, + address recipient, + uint160 sqrtPriceLimitX96, + SwapCallbackData memory data + ) private returns (uint256 amountIn) { + // allow swapping to the router address with address 0 + if (recipient == address(0)) recipient = address(this); + + (address tokenOut, address tokenIn, uint24 fee) = data.path.decodeFirstPool(); + + bool zeroForOne = tokenIn < tokenOut; + + (int256 amount0Delta, int256 amount1Delta) = getPool(tokenIn, tokenOut, fee).swap( + recipient, + zeroForOne, + -amountOut.toInt256(), + sqrtPriceLimitX96 == 0 + ? (zeroForOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1) + : sqrtPriceLimitX96, + abi.encode(data) + ); + + uint256 amountOutReceived; + (amountIn, amountOutReceived) = zeroForOne + ? (uint256(amount0Delta), uint256(-amount1Delta)) + : (uint256(amount1Delta), uint256(-amount0Delta)); + // it's technically possible to not receive the full output amount, + // so if no price limit has been specified, require this possibility away + if (sqrtPriceLimitX96 == 0) require(amountOutReceived == amountOut); + } + + /// @inheritdoc ISwapRouter + function exactOutputSingle(ExactOutputSingleParams calldata params) + external + payable + override + checkDeadline(params.deadline) + returns (uint256 amountIn) + { + // avoid an SLOAD by using the swap return data + amountIn = exactOutputInternal( + params.amountOut, + params.recipient, + params.sqrtPriceLimitX96, + SwapCallbackData({path: abi.encodePacked(params.tokenOut, params.fee, params.tokenIn), payer: msg.sender}) + ); + + require(amountIn <= params.amountInMaximum, 'Too much requested'); + // has to be reset even though we don't use it in the single hop case + amountInCached = DEFAULT_AMOUNT_IN_CACHED; + } + + /// @inheritdoc ISwapRouter + function exactOutput(ExactOutputParams calldata params) + external + payable + override + checkDeadline(params.deadline) + returns (uint256 amountIn) + { + // it's okay that the payer is fixed to msg.sender here, as they're only paying for the "final" exact output + // swap, which happens first, and subsequent swaps are paid for within nested callback frames + exactOutputInternal( + params.amountOut, + params.recipient, + 0, + SwapCallbackData({path: params.path, payer: msg.sender}) + ); + + amountIn = amountInCached; + require(amountIn <= params.amountInMaximum, 'Too much requested'); + amountInCached = DEFAULT_AMOUNT_IN_CACHED; + } +} diff --git a/contracts/dependencies/uniswapv3-periphery/base/BlockTimestamp.sol b/contracts/dependencies/uniswapv3-periphery/base/BlockTimestamp.sol new file mode 100644 index 000000000..d7c6cf2f0 --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/base/BlockTimestamp.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +/// @title Function for getting block timestamp +/// @dev Base contract that is overridden for tests +abstract contract BlockTimestamp { + /// @dev Method that exists purely to be overridden for tests + /// @return The current block timestamp + function _blockTimestamp() internal view virtual returns (uint256) { + return block.timestamp; + } +} diff --git a/contracts/dependencies/uniswapv3-periphery/base/ERC721Permit.sol b/contracts/dependencies/uniswapv3-periphery/base/ERC721Permit.sol new file mode 100644 index 000000000..975df306d --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/base/ERC721Permit.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +import '../../openzeppelin/contracts/ERC721Enumerable.sol'; +import '../../openzeppelin/contracts/Address.sol'; + +import '../libraries/ChainId.sol'; +import '../interfaces/external/IERC1271.sol'; +import '../interfaces/IERC721Permit.sol'; +import './BlockTimestamp.sol'; + +/// @title ERC721 with permit +/// @notice Nonfungible tokens that support an approve via signature, i.e. permit +abstract contract ERC721Permit is BlockTimestamp, ERC721Enumerable, IERC721Permit { + /// @dev Gets the current nonce for a token ID and then increments it, returning the original value + function _getAndIncrementNonce(uint256 tokenId) internal virtual returns (uint256); + + /// @dev The hash of the name used in the permit signature verification + bytes32 private immutable nameHash; + + /// @dev The hash of the version string used in the permit signature verification + bytes32 private immutable versionHash; + + /// @notice Computes the nameHash and versionHash + constructor( + string memory name_, + string memory symbol_, + string memory version_ + ) ERC721(name_, symbol_) { + nameHash = keccak256(bytes(name_)); + versionHash = keccak256(bytes(version_)); + } + + /// @inheritdoc IERC721Permit + function DOMAIN_SEPARATOR() public view override returns (bytes32) { + return + keccak256( + abi.encode( + // keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)') + 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f, + nameHash, + versionHash, + ChainId.get(), + address(this) + ) + ); + } + + /// @inheritdoc IERC721Permit + /// @dev Value is equal to keccak256("Permit(address spender,uint256 tokenId,uint256 nonce,uint256 deadline)"); + bytes32 public constant override PERMIT_TYPEHASH = + 0x49ecf333e5b8c95c40fdafc95c1ad136e8914a8fb55e9dc8bb01eaa83a2df9ad; + + /// @inheritdoc IERC721Permit + function permit( + address spender, + uint256 tokenId, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external payable override { + require(_blockTimestamp() <= deadline, 'Permit expired'); + + bytes32 digest = keccak256( + abi.encodePacked( + '\x19\x01', + DOMAIN_SEPARATOR(), + keccak256(abi.encode(PERMIT_TYPEHASH, spender, tokenId, _getAndIncrementNonce(tokenId), deadline)) + ) + ); + address owner = ownerOf(tokenId); + require(spender != owner, 'ERC721Permit: approval to current owner'); + + if (Address.isContract(owner)) { + require(IERC1271(owner).isValidSignature(digest, abi.encodePacked(r, s, v)) == 0x1626ba7e, 'Unauthorized'); + } else { + address recoveredAddress = ecrecover(digest, v, r, s); + require(recoveredAddress != address(0), 'Invalid signature'); + require(recoveredAddress == owner, 'Unauthorized'); + } + + _approve(spender, tokenId); + } +} diff --git a/contracts/dependencies/uniswapv3-periphery/base/LiquidityManagement.sol b/contracts/dependencies/uniswapv3-periphery/base/LiquidityManagement.sol new file mode 100644 index 000000000..a129ee315 --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/base/LiquidityManagement.sol @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; +pragma abicoder v2; + +import '../../uniswapv3-core/interfaces/IUniswapV3Factory.sol'; +import {IUniswapV3Pool} from '../../uniswapv3-core/interfaces/IUniswapV3Pool.sol'; +import '../../uniswapv3-core/interfaces/callback/IUniswapV3MintCallback.sol'; +import '../../uniswapv3-core/libraries/TickMath.sol'; + +import '../libraries/PoolAddress.sol'; +import '../libraries/CallbackValidation.sol'; +import '../libraries/LiquidityAmounts.sol'; + +import './PeripheryPayments.sol'; +import './PeripheryImmutableState.sol'; + +/// @title Liquidity management functions +/// @notice Internal functions for safely managing liquidity in Uniswap V3 +abstract contract LiquidityManagement is IUniswapV3MintCallback, PeripheryImmutableState, PeripheryPayments { + struct MintCallbackData { + PoolAddress.PoolKey poolKey; + address payer; + } + + /// @inheritdoc IUniswapV3MintCallback + function uniswapV3MintCallback( + uint256 amount0Owed, + uint256 amount1Owed, + bytes calldata data + ) external override { + MintCallbackData memory decoded = abi.decode(data, (MintCallbackData)); + CallbackValidation.verifyCallback(factory, decoded.poolKey); + + if (amount0Owed > 0) pay(decoded.poolKey.token0, decoded.payer, msg.sender, amount0Owed); + if (amount1Owed > 0) pay(decoded.poolKey.token1, decoded.payer, msg.sender, amount1Owed); + } + + struct AddLiquidityParams { + address token0; + address token1; + uint24 fee; + address recipient; + int24 tickLower; + int24 tickUpper; + uint256 amount0Desired; + uint256 amount1Desired; + uint256 amount0Min; + uint256 amount1Min; + } + + /// @notice Add liquidity to an initialized pool + function addLiquidity(AddLiquidityParams memory params) + internal + returns ( + uint128 liquidity, + uint256 amount0, + uint256 amount1, + IUniswapV3Pool pool + ) + { + PoolAddress.PoolKey memory poolKey = PoolAddress.PoolKey({ + token0: params.token0, + token1: params.token1, + fee: params.fee + }); + + pool = IUniswapV3Pool(PoolAddress.computeAddress(factory, poolKey)); + + // compute the liquidity amount + { + (uint160 sqrtPriceX96, , , , , , ) = pool.slot0(); + uint160 sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(params.tickLower); + uint160 sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(params.tickUpper); + + liquidity = LiquidityAmounts.getLiquidityForAmounts( + sqrtPriceX96, + sqrtRatioAX96, + sqrtRatioBX96, + params.amount0Desired, + params.amount1Desired + ); + } + + (amount0, amount1) = pool.mint( + params.recipient, + params.tickLower, + params.tickUpper, + liquidity, + abi.encode(MintCallbackData({poolKey: poolKey, payer: msg.sender})) + ); + + require(amount0 >= params.amount0Min && amount1 >= params.amount1Min, 'Price slippage check'); + } +} diff --git a/contracts/dependencies/uniswapv3-periphery/base/Multicall.sol b/contracts/dependencies/uniswapv3-periphery/base/Multicall.sol new file mode 100644 index 000000000..4d855c25d --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/base/Multicall.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; +pragma abicoder v2; + +import '../interfaces/IMulticall.sol'; + +/// @title Multicall +/// @notice Enables calling multiple methods in a single call to the contract +abstract contract Multicall is IMulticall { + /// @inheritdoc IMulticall + function multicall(bytes[] calldata data) public payable override returns (bytes[] memory results) { + results = new bytes[](data.length); + for (uint256 i = 0; i < data.length; i++) { + (bool success, bytes memory result) = address(this).delegatecall(data[i]); + + if (!success) { + // Next 5 lines from https://ethereum.stackexchange.com/a/83577 + if (result.length < 68) revert(); + assembly { + result := add(result, 0x04) + } + revert(abi.decode(result, (string))); + } + + results[i] = result; + } + } +} diff --git a/contracts/dependencies/uniswapv3-periphery/base/PeripheryImmutableState.sol b/contracts/dependencies/uniswapv3-periphery/base/PeripheryImmutableState.sol new file mode 100644 index 000000000..283b8139e --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/base/PeripheryImmutableState.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +import '../interfaces/IPeripheryImmutableState.sol'; + +/// @title Immutable state +/// @notice Immutable state used by periphery contracts +abstract contract PeripheryImmutableState is IPeripheryImmutableState { + /// @inheritdoc IPeripheryImmutableState + address public immutable override factory; + /// @inheritdoc IPeripheryImmutableState + address public immutable override WETH9; + + constructor(address _factory, address _WETH9) { + factory = _factory; + WETH9 = _WETH9; + } +} diff --git a/contracts/dependencies/uniswapv3-periphery/base/PeripheryPayments.sol b/contracts/dependencies/uniswapv3-periphery/base/PeripheryPayments.sol new file mode 100644 index 000000000..3fa0decc8 --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/base/PeripheryPayments.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +import '../../openzeppelin/contracts/IERC20.sol'; + +import '../interfaces/IPeripheryPayments.sol'; +import '../interfaces/external/IWETH9.sol'; + +import '../libraries/TransferHelper.sol'; + +import './PeripheryImmutableState.sol'; + +abstract contract PeripheryPayments is IPeripheryPayments, PeripheryImmutableState { + receive() external payable { + require(msg.sender == WETH9, 'Not WETH9'); + } + + /// @inheritdoc IPeripheryPayments + function unwrapWETH9(uint256 amountMinimum, address recipient) public payable override { + uint256 balanceWETH9 = IWETH9(WETH9).balanceOf(address(this)); + require(balanceWETH9 >= amountMinimum, 'Insufficient WETH9'); + + if (balanceWETH9 > 0) { + IWETH9(WETH9).withdraw(balanceWETH9); + TransferHelper.safeTransferETH(recipient, balanceWETH9); + } + } + + /// @inheritdoc IPeripheryPayments + function sweepToken( + address token, + uint256 amountMinimum, + address recipient + ) public payable override { + uint256 balanceToken = IERC20(token).balanceOf(address(this)); + require(balanceToken >= amountMinimum, 'Insufficient token'); + + if (balanceToken > 0) { + TransferHelper.safeTransfer(token, recipient, balanceToken); + } + } + + /// @inheritdoc IPeripheryPayments + function refundETH() external payable override { + if (address(this).balance > 0) TransferHelper.safeTransferETH(msg.sender, address(this).balance); + } + + /// @param token The token to pay + /// @param payer The entity that must pay + /// @param recipient The entity that will receive payment + /// @param value The amount to pay + function pay( + address token, + address payer, + address recipient, + uint256 value + ) internal { + if (token == WETH9 && address(this).balance >= value) { + // pay with WETH9 + IWETH9(WETH9).deposit{value: value}(); // wrap only what is needed to pay + IWETH9(WETH9).transfer(recipient, value); + } else if (payer == address(this)) { + // pay with tokens already in the contract (for the exact input multihop case) + TransferHelper.safeTransfer(token, recipient, value); + } else { + // pull payment + TransferHelper.safeTransferFrom(token, payer, recipient, value); + } + } +} diff --git a/contracts/dependencies/uniswapv3-periphery/base/PeripheryPaymentsWithFee.sol b/contracts/dependencies/uniswapv3-periphery/base/PeripheryPaymentsWithFee.sol new file mode 100644 index 000000000..ed7494328 --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/base/PeripheryPaymentsWithFee.sol @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +import '../../openzeppelin/contracts/IERC20.sol'; + +import './PeripheryPayments.sol'; +import '../interfaces/IPeripheryPaymentsWithFee.sol'; + +import '../interfaces/external/IWETH9.sol'; +import '../libraries/TransferHelper.sol'; + +abstract contract PeripheryPaymentsWithFee is PeripheryPayments, IPeripheryPaymentsWithFee { + /// @inheritdoc IPeripheryPaymentsWithFee + function unwrapWETH9WithFee( + uint256 amountMinimum, + address recipient, + uint256 feeBips, + address feeRecipient + ) public payable override { + require(feeBips > 0 && feeBips <= 100); + + uint256 balanceWETH9 = IWETH9(WETH9).balanceOf(address(this)); + require(balanceWETH9 >= amountMinimum, 'Insufficient WETH9'); + + if (balanceWETH9 > 0) { + IWETH9(WETH9).withdraw(balanceWETH9); + uint256 feeAmount = (balanceWETH9 * feeBips) / 10_000; + if (feeAmount > 0) TransferHelper.safeTransferETH(feeRecipient, feeAmount); + TransferHelper.safeTransferETH(recipient, balanceWETH9 - feeAmount); + } + } + + /// @inheritdoc IPeripheryPaymentsWithFee + function sweepTokenWithFee( + address token, + uint256 amountMinimum, + address recipient, + uint256 feeBips, + address feeRecipient + ) public payable override { + require(feeBips > 0 && feeBips <= 100); + + uint256 balanceToken = IERC20(token).balanceOf(address(this)); + require(balanceToken >= amountMinimum, 'Insufficient token'); + + if (balanceToken > 0) { + uint256 feeAmount = (balanceToken * feeBips) / 10_000; + if (feeAmount > 0) TransferHelper.safeTransfer(token, feeRecipient, feeAmount); + TransferHelper.safeTransfer(token, recipient, balanceToken - feeAmount); + } + } +} diff --git a/contracts/dependencies/uniswapv3-periphery/base/PeripheryValidation.sol b/contracts/dependencies/uniswapv3-periphery/base/PeripheryValidation.sol new file mode 100644 index 000000000..d567515e9 --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/base/PeripheryValidation.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +import './BlockTimestamp.sol'; + +abstract contract PeripheryValidation is BlockTimestamp { + modifier checkDeadline(uint256 deadline) { + require(_blockTimestamp() <= deadline, 'Transaction too old'); + _; + } +} diff --git a/contracts/dependencies/uniswapv3-periphery/base/PoolInitializer.sol b/contracts/dependencies/uniswapv3-periphery/base/PoolInitializer.sol new file mode 100644 index 000000000..3c82b1d18 --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/base/PoolInitializer.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +import '../../uniswapv3-core/interfaces/IUniswapV3Factory.sol'; +import '../../uniswapv3-core/interfaces/IUniswapV3Pool.sol'; + +import './PeripheryImmutableState.sol'; +import '../interfaces/IPoolInitializer.sol'; + +/// @title Creates and initializes V3 Pools +abstract contract PoolInitializer is IPoolInitializer, PeripheryImmutableState { + /// @inheritdoc IPoolInitializer + function createAndInitializePoolIfNecessary( + address token0, + address token1, + uint24 fee, + uint160 sqrtPriceX96 + ) external payable override returns (address pool) { + require(token0 < token1); + pool = IUniswapV3Factory(factory).getPool(token0, token1, fee); + + if (pool == address(0)) { + pool = IUniswapV3Factory(factory).createPool(token0, token1, fee); + IUniswapV3Pool(pool).initialize(sqrtPriceX96); + } else { + (uint160 sqrtPriceX96Existing, , , , , , ) = IUniswapV3Pool(pool).slot0(); + if (sqrtPriceX96Existing == 0) { + IUniswapV3Pool(pool).initialize(sqrtPriceX96); + } + } + } +} diff --git a/contracts/dependencies/uniswapv3-periphery/base/SelfPermit.sol b/contracts/dependencies/uniswapv3-periphery/base/SelfPermit.sol new file mode 100644 index 000000000..3d4002c5e --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/base/SelfPermit.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +import '../../openzeppelin/contracts/IERC20.sol'; +import '../../openzeppelin/contracts/draft-IERC20Permit.sol'; + +import '../interfaces/ISelfPermit.sol'; +import '../interfaces/external/IERC20PermitAllowed.sol'; + +/// @title Self Permit +/// @notice Functionality to call permit on any EIP-2612-compliant token for use in the route +/// @dev These functions are expected to be embedded in multicalls to allow EOAs to approve a contract and call a function +/// that requires an approval in a single transaction. +abstract contract SelfPermit is ISelfPermit { + /// @inheritdoc ISelfPermit + function selfPermit( + address token, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) public payable override { + IERC20Permit(token).permit(msg.sender, address(this), value, deadline, v, r, s); + } + + /// @inheritdoc ISelfPermit + function selfPermitIfNecessary( + address token, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external payable override { + if (IERC20(token).allowance(msg.sender, address(this)) < value) selfPermit(token, value, deadline, v, r, s); + } + + /// @inheritdoc ISelfPermit + function selfPermitAllowed( + address token, + uint256 nonce, + uint256 expiry, + uint8 v, + bytes32 r, + bytes32 s + ) public payable override { + IERC20PermitAllowed(token).permit(msg.sender, address(this), nonce, expiry, true, v, r, s); + } + + /// @inheritdoc ISelfPermit + function selfPermitAllowedIfNecessary( + address token, + uint256 nonce, + uint256 expiry, + uint8 v, + bytes32 r, + bytes32 s + ) external payable override { + if (IERC20(token).allowance(msg.sender, address(this)) < type(uint256).max) + selfPermitAllowed(token, nonce, expiry, v, r, s); + } +} diff --git a/contracts/dependencies/uniswapv3-periphery/interfaces/IERC20Metadata.sol b/contracts/dependencies/uniswapv3-periphery/interfaces/IERC20Metadata.sol new file mode 100644 index 000000000..0521267cf --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/interfaces/IERC20Metadata.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +import '../../openzeppelin/contracts/IERC20.sol'; + +/// @title IERC20Metadata +/// @title Interface for ERC20 Metadata +/// @notice Extension to IERC20 that includes token metadata +interface IERC20Metadata is IERC20 { + /// @return The name of the token + function name() external view returns (string memory); + + /// @return The symbol of the token + function symbol() external view returns (string memory); + + /// @return The number of decimal places the token has + function decimals() external view returns (uint8); +} diff --git a/contracts/dependencies/uniswap/IERC721Permit.sol b/contracts/dependencies/uniswapv3-periphery/interfaces/IERC721Permit.sol similarity index 94% rename from contracts/dependencies/uniswap/IERC721Permit.sol rename to contracts/dependencies/uniswapv3-periphery/interfaces/IERC721Permit.sol index 8c4817f3d..ab21c9460 100644 --- a/contracts/dependencies/uniswap/IERC721Permit.sol +++ b/contracts/dependencies/uniswapv3-periphery/interfaces/IERC721Permit.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.7.5; +pragma solidity ^0.8.0; -import "../openzeppelin/contracts/IERC721.sol"; +import '../../openzeppelin/contracts/IERC721.sol'; /// @title ERC721 with permit /// @notice Extension to ERC721 that includes a permit function for signature based approvals diff --git a/contracts/dependencies/uniswap/IMulticall.sol b/contracts/dependencies/uniswapv3-periphery/interfaces/IMulticall.sol similarity index 96% rename from contracts/dependencies/uniswap/IMulticall.sol rename to contracts/dependencies/uniswapv3-periphery/interfaces/IMulticall.sol index 1ea39c692..8b59815c3 100644 --- a/contracts/dependencies/uniswap/IMulticall.sol +++ b/contracts/dependencies/uniswapv3-periphery/interfaces/IMulticall.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.7.5; +pragma solidity ^0.8.0; pragma abicoder v2; /// @title Multicall interface diff --git a/contracts/dependencies/uniswap/INonfungiblePositionManager.sol b/contracts/dependencies/uniswapv3-periphery/interfaces/INonfungiblePositionManager.sol similarity index 90% rename from contracts/dependencies/uniswap/INonfungiblePositionManager.sol rename to contracts/dependencies/uniswapv3-periphery/interfaces/INonfungiblePositionManager.sol index 4a2978dd1..cbb9c7c7a 100644 --- a/contracts/dependencies/uniswap/INonfungiblePositionManager.sol +++ b/contracts/dependencies/uniswapv3-periphery/interfaces/INonfungiblePositionManager.sol @@ -1,15 +1,15 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.7.5; +pragma solidity ^0.8.0; pragma abicoder v2; -import "../openzeppelin/contracts/IERC721Metadata.sol"; -import "../openzeppelin/contracts/IERC721Enumerable.sol"; +import '../../openzeppelin/contracts/IERC721Metadata.sol'; +import '../../openzeppelin/contracts/IERC721Enumerable.sol'; -import "./IPoolInitializer.sol"; -import "./IERC721Permit.sol"; -import "./IPeripheryPayments.sol"; -import "./IPeripheryImmutableState.sol"; -import "./PoolAddress.sol"; +import './IPoolInitializer.sol'; +import './IERC721Permit.sol'; +import './IPeripheryPayments.sol'; +import './IPeripheryImmutableState.sol'; +import '../libraries/PoolAddress.sol'; /// @title Non-fungible token for positions /// @notice Wraps Uniswap V3 positions in a non-fungible token interface which allows for them to be transferred @@ -28,35 +28,20 @@ interface INonfungiblePositionManager is /// @param liquidity The amount by which liquidity for the NFT position was increased /// @param amount0 The amount of token0 that was paid for the increase in liquidity /// @param amount1 The amount of token1 that was paid for the increase in liquidity - event IncreaseLiquidity( - uint256 indexed tokenId, - uint128 liquidity, - uint256 amount0, - uint256 amount1 - ); + event IncreaseLiquidity(uint256 indexed tokenId, uint128 liquidity, uint256 amount0, uint256 amount1); /// @notice Emitted when liquidity is decreased for a position NFT /// @param tokenId The ID of the token for which liquidity was decreased /// @param liquidity The amount by which liquidity for the NFT position was decreased /// @param amount0 The amount of token0 that was accounted for the decrease in liquidity /// @param amount1 The amount of token1 that was accounted for the decrease in liquidity - event DecreaseLiquidity( - uint256 indexed tokenId, - uint128 liquidity, - uint256 amount0, - uint256 amount1 - ); + event DecreaseLiquidity(uint256 indexed tokenId, uint128 liquidity, uint256 amount0, uint256 amount1); /// @notice Emitted when tokens are collected for a position NFT /// @dev The amounts reported may not be exactly equivalent to the amounts transferred, due to rounding behavior /// @param tokenId The ID of the token for which underlying tokens were collected /// @param recipient The address of the account that received the collected tokens /// @param amount0 The amount of token0 owed to the position that was collected /// @param amount1 The amount of token1 owed to the position that was collected - event Collect( - uint256 indexed tokenId, - address recipient, - uint256 amount0, - uint256 amount1 - ); + event Collect(uint256 indexed tokenId, address recipient, uint256 amount0, uint256 amount1); /// @notice Returns the position information associated with a given token ID. /// @dev Throws if the token ID is not valid. @@ -186,10 +171,7 @@ interface INonfungiblePositionManager is /// amount1Max The maximum amount of token1 to collect /// @return amount0 The amount of fees collected in token0 /// @return amount1 The amount of fees collected in token1 - function collect(CollectParams calldata params) - external - payable - returns (uint256 amount0, uint256 amount1); + function collect(CollectParams calldata params) external payable returns (uint256 amount0, uint256 amount1); /// @notice Burns a token ID, which deletes it from the NFT contract. The token must have 0 liquidity and all tokens /// must be collected first. diff --git a/contracts/dependencies/uniswapv3-periphery/interfaces/INonfungibleTokenPositionDescriptor.sol b/contracts/dependencies/uniswapv3-periphery/interfaces/INonfungibleTokenPositionDescriptor.sol new file mode 100644 index 000000000..8a285e668 --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/interfaces/INonfungibleTokenPositionDescriptor.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +import './INonfungiblePositionManager.sol'; + +/// @title Describes position NFT tokens via URI +interface INonfungibleTokenPositionDescriptor { + /// @notice Produces the URI describing a particular token ID for a position manager + /// @dev Note this URI may be a data: URI with the JSON contents directly inlined + /// @param positionManager The position manager for which to describe the token + /// @param tokenId The ID of the token for which to produce a description, which may not be valid + /// @return The URI of the ERC721-compliant metadata + function tokenURI(INonfungiblePositionManager positionManager, uint256 tokenId) + external + view + returns (string memory); +} diff --git a/contracts/dependencies/uniswap/IPeripheryImmutableState.sol b/contracts/dependencies/uniswapv3-periphery/interfaces/IPeripheryImmutableState.sol similarity index 94% rename from contracts/dependencies/uniswap/IPeripheryImmutableState.sol rename to contracts/dependencies/uniswapv3-periphery/interfaces/IPeripheryImmutableState.sol index b3378052d..80d208824 100644 --- a/contracts/dependencies/uniswap/IPeripheryImmutableState.sol +++ b/contracts/dependencies/uniswapv3-periphery/interfaces/IPeripheryImmutableState.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; +pragma solidity ^0.8.0; /// @title Immutable state /// @notice Functions that return immutable state of the router diff --git a/contracts/dependencies/uniswap/IPeripheryPayments.sol b/contracts/dependencies/uniswapv3-periphery/interfaces/IPeripheryPayments.sol similarity index 95% rename from contracts/dependencies/uniswap/IPeripheryPayments.sol rename to contracts/dependencies/uniswapv3-periphery/interfaces/IPeripheryPayments.sol index e26fc441e..e6e6030b3 100644 --- a/contracts/dependencies/uniswap/IPeripheryPayments.sol +++ b/contracts/dependencies/uniswapv3-periphery/interfaces/IPeripheryPayments.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.7.5; +pragma solidity ^0.8.0; /// @title Periphery Payments /// @notice Functions to ease deposits and withdrawals of ETH @@ -8,9 +8,7 @@ interface IPeripheryPayments { /// @dev The amountMinimum parameter prevents malicious contracts from stealing WETH9 from users. /// @param amountMinimum The minimum amount of WETH9 to unwrap /// @param recipient The address receiving ETH - function unwrapWETH9(uint256 amountMinimum, address recipient) - external - payable; + function unwrapWETH9(uint256 amountMinimum, address recipient) external payable; /// @notice Refunds any ETH balance held by this contract to the `msg.sender` /// @dev Useful for bundling with mint or increase liquidity that uses ether, or exact output swaps diff --git a/contracts/dependencies/uniswapv3-periphery/interfaces/IPeripheryPaymentsWithFee.sol b/contracts/dependencies/uniswapv3-periphery/interfaces/IPeripheryPaymentsWithFee.sol new file mode 100644 index 000000000..b85478dde --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/interfaces/IPeripheryPaymentsWithFee.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +import './IPeripheryPayments.sol'; + +/// @title Periphery Payments +/// @notice Functions to ease deposits and withdrawals of ETH +interface IPeripheryPaymentsWithFee is IPeripheryPayments { + /// @notice Unwraps the contract's WETH9 balance and sends it to recipient as ETH, with a percentage between + /// 0 (exclusive), and 1 (inclusive) going to feeRecipient + /// @dev The amountMinimum parameter prevents malicious contracts from stealing WETH9 from users. + function unwrapWETH9WithFee( + uint256 amountMinimum, + address recipient, + uint256 feeBips, + address feeRecipient + ) external payable; + + /// @notice Transfers the full amount of a token held by this contract to recipient, with a percentage between + /// 0 (exclusive) and 1 (inclusive) going to feeRecipient + /// @dev The amountMinimum parameter prevents malicious contracts from stealing the token from users + function sweepTokenWithFee( + address token, + uint256 amountMinimum, + address recipient, + uint256 feeBips, + address feeRecipient + ) external payable; +} diff --git a/contracts/dependencies/uniswap/IPoolInitializer.sol b/contracts/dependencies/uniswapv3-periphery/interfaces/IPoolInitializer.sol similarity index 97% rename from contracts/dependencies/uniswap/IPoolInitializer.sol rename to contracts/dependencies/uniswapv3-periphery/interfaces/IPoolInitializer.sol index d2949b3d6..84715722e 100644 --- a/contracts/dependencies/uniswap/IPoolInitializer.sol +++ b/contracts/dependencies/uniswapv3-periphery/interfaces/IPoolInitializer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.7.5; +pragma solidity ^0.8.0; pragma abicoder v2; /// @title Creates and initializes V3 Pools diff --git a/contracts/dependencies/uniswapv3-periphery/interfaces/IQuoter.sol b/contracts/dependencies/uniswapv3-periphery/interfaces/IQuoter.sol new file mode 100644 index 000000000..684203f2a --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/interfaces/IQuoter.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; +pragma abicoder v2; + +/// @title Quoter Interface +/// @notice Supports quoting the calculated amounts from exact input or exact output swaps +/// @dev These functions are not marked view because they rely on calling non-view functions and reverting +/// to compute the result. They are also not gas efficient and should not be called on-chain. +interface IQuoter { + /// @notice Returns the amount out received for a given exact input swap without executing the swap + /// @param path The path of the swap, i.e. each token pair and the pool fee + /// @param amountIn The amount of the first token to swap + /// @return amountOut The amount of the last token that would be received + function quoteExactInput(bytes memory path, uint256 amountIn) external returns (uint256 amountOut); + + /// @notice Returns the amount out received for a given exact input but for a swap of a single pool + /// @param tokenIn The token being swapped in + /// @param tokenOut The token being swapped out + /// @param fee The fee of the token pool to consider for the pair + /// @param amountIn The desired input amount + /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap + /// @return amountOut The amount of `tokenOut` that would be received + function quoteExactInputSingle( + address tokenIn, + address tokenOut, + uint24 fee, + uint256 amountIn, + uint160 sqrtPriceLimitX96 + ) external returns (uint256 amountOut); + + /// @notice Returns the amount in required for a given exact output swap without executing the swap + /// @param path The path of the swap, i.e. each token pair and the pool fee. Path must be provided in reverse order + /// @param amountOut The amount of the last token to receive + /// @return amountIn The amount of first token required to be paid + function quoteExactOutput(bytes memory path, uint256 amountOut) external returns (uint256 amountIn); + + /// @notice Returns the amount in required to receive the given exact output amount but for a swap of a single pool + /// @param tokenIn The token being swapped in + /// @param tokenOut The token being swapped out + /// @param fee The fee of the token pool to consider for the pair + /// @param amountOut The desired output amount + /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap + /// @return amountIn The amount required as the input for the swap in order to receive `amountOut` + function quoteExactOutputSingle( + address tokenIn, + address tokenOut, + uint24 fee, + uint256 amountOut, + uint160 sqrtPriceLimitX96 + ) external returns (uint256 amountIn); +} diff --git a/contracts/dependencies/uniswapv3-periphery/interfaces/IQuoterV2.sol b/contracts/dependencies/uniswapv3-periphery/interfaces/IQuoterV2.sol new file mode 100644 index 000000000..58b04eefe --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/interfaces/IQuoterV2.sol @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; +pragma abicoder v2; + +/// @title QuoterV2 Interface +/// @notice Supports quoting the calculated amounts from exact input or exact output swaps. +/// @notice For each pool also tells you the number of initialized ticks crossed and the sqrt price of the pool after the swap. +/// @dev These functions are not marked view because they rely on calling non-view functions and reverting +/// to compute the result. They are also not gas efficient and should not be called on-chain. +interface IQuoterV2 { + /// @notice Returns the amount out received for a given exact input swap without executing the swap + /// @param path The path of the swap, i.e. each token pair and the pool fee + /// @param amountIn The amount of the first token to swap + /// @return amountOut The amount of the last token that would be received + /// @return sqrtPriceX96AfterList List of the sqrt price after the swap for each pool in the path + /// @return initializedTicksCrossedList List of the initialized ticks that the swap crossed for each pool in the path + /// @return gasEstimate The estimate of the gas that the swap consumes + function quoteExactInput(bytes memory path, uint256 amountIn) + external + returns ( + uint256 amountOut, + uint160[] memory sqrtPriceX96AfterList, + uint32[] memory initializedTicksCrossedList, + uint256 gasEstimate + ); + + struct QuoteExactInputSingleParams { + address tokenIn; + address tokenOut; + uint256 amountIn; + uint24 fee; + uint160 sqrtPriceLimitX96; + } + + /// @notice Returns the amount out received for a given exact input but for a swap of a single pool + /// @param params The params for the quote, encoded as `QuoteExactInputSingleParams` + /// tokenIn The token being swapped in + /// tokenOut The token being swapped out + /// fee The fee of the token pool to consider for the pair + /// amountIn The desired input amount + /// sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap + /// @return amountOut The amount of `tokenOut` that would be received + /// @return sqrtPriceX96After The sqrt price of the pool after the swap + /// @return initializedTicksCrossed The number of initialized ticks that the swap crossed + /// @return gasEstimate The estimate of the gas that the swap consumes + function quoteExactInputSingle(QuoteExactInputSingleParams memory params) + external + returns ( + uint256 amountOut, + uint160 sqrtPriceX96After, + uint32 initializedTicksCrossed, + uint256 gasEstimate + ); + + /// @notice Returns the amount in required for a given exact output swap without executing the swap + /// @param path The path of the swap, i.e. each token pair and the pool fee. Path must be provided in reverse order + /// @param amountOut The amount of the last token to receive + /// @return amountIn The amount of first token required to be paid + /// @return sqrtPriceX96AfterList List of the sqrt price after the swap for each pool in the path + /// @return initializedTicksCrossedList List of the initialized ticks that the swap crossed for each pool in the path + /// @return gasEstimate The estimate of the gas that the swap consumes + function quoteExactOutput(bytes memory path, uint256 amountOut) + external + returns ( + uint256 amountIn, + uint160[] memory sqrtPriceX96AfterList, + uint32[] memory initializedTicksCrossedList, + uint256 gasEstimate + ); + + struct QuoteExactOutputSingleParams { + address tokenIn; + address tokenOut; + uint256 amount; + uint24 fee; + uint160 sqrtPriceLimitX96; + } + + /// @notice Returns the amount in required to receive the given exact output amount but for a swap of a single pool + /// @param params The params for the quote, encoded as `QuoteExactOutputSingleParams` + /// tokenIn The token being swapped in + /// tokenOut The token being swapped out + /// fee The fee of the token pool to consider for the pair + /// amountOut The desired output amount + /// sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap + /// @return amountIn The amount required as the input for the swap in order to receive `amountOut` + /// @return sqrtPriceX96After The sqrt price of the pool after the swap + /// @return initializedTicksCrossed The number of initialized ticks that the swap crossed + /// @return gasEstimate The estimate of the gas that the swap consumes + function quoteExactOutputSingle(QuoteExactOutputSingleParams memory params) + external + returns ( + uint256 amountIn, + uint160 sqrtPriceX96After, + uint32 initializedTicksCrossed, + uint256 gasEstimate + ); +} diff --git a/contracts/dependencies/uniswapv3-periphery/interfaces/ISelfPermit.sol b/contracts/dependencies/uniswapv3-periphery/interfaces/ISelfPermit.sol new file mode 100644 index 000000000..65b9c76d3 --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/interfaces/ISelfPermit.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +/// @title Self Permit +/// @notice Functionality to call permit on any EIP-2612-compliant token for use in the route +interface ISelfPermit { + /// @notice Permits this contract to spend a given token from `msg.sender` + /// @dev The `owner` is always msg.sender and the `spender` is always address(this). + /// @param token The address of the token spent + /// @param value The amount that can be spent of token + /// @param deadline A timestamp, the current blocktime must be less than or equal to this timestamp + /// @param v Must produce valid secp256k1 signature from the holder along with `r` and `s` + /// @param r Must produce valid secp256k1 signature from the holder along with `v` and `s` + /// @param s Must produce valid secp256k1 signature from the holder along with `r` and `v` + function selfPermit( + address token, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external payable; + + /// @notice Permits this contract to spend a given token from `msg.sender` + /// @dev The `owner` is always msg.sender and the `spender` is always address(this). + /// Can be used instead of #selfPermit to prevent calls from failing due to a frontrun of a call to #selfPermit + /// @param token The address of the token spent + /// @param value The amount that can be spent of token + /// @param deadline A timestamp, the current blocktime must be less than or equal to this timestamp + /// @param v Must produce valid secp256k1 signature from the holder along with `r` and `s` + /// @param r Must produce valid secp256k1 signature from the holder along with `v` and `s` + /// @param s Must produce valid secp256k1 signature from the holder along with `r` and `v` + function selfPermitIfNecessary( + address token, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external payable; + + /// @notice Permits this contract to spend the sender's tokens for permit signatures that have the `allowed` parameter + /// @dev The `owner` is always msg.sender and the `spender` is always address(this) + /// @param token The address of the token spent + /// @param nonce The current nonce of the owner + /// @param expiry The timestamp at which the permit is no longer valid + /// @param v Must produce valid secp256k1 signature from the holder along with `r` and `s` + /// @param r Must produce valid secp256k1 signature from the holder along with `v` and `s` + /// @param s Must produce valid secp256k1 signature from the holder along with `r` and `v` + function selfPermitAllowed( + address token, + uint256 nonce, + uint256 expiry, + uint8 v, + bytes32 r, + bytes32 s + ) external payable; + + /// @notice Permits this contract to spend the sender's tokens for permit signatures that have the `allowed` parameter + /// @dev The `owner` is always msg.sender and the `spender` is always address(this) + /// Can be used instead of #selfPermitAllowed to prevent calls from failing due to a frontrun of a call to #selfPermitAllowed. + /// @param token The address of the token spent + /// @param nonce The current nonce of the owner + /// @param expiry The timestamp at which the permit is no longer valid + /// @param v Must produce valid secp256k1 signature from the holder along with `r` and `s` + /// @param r Must produce valid secp256k1 signature from the holder along with `v` and `s` + /// @param s Must produce valid secp256k1 signature from the holder along with `r` and `v` + function selfPermitAllowedIfNecessary( + address token, + uint256 nonce, + uint256 expiry, + uint8 v, + bytes32 r, + bytes32 s + ) external payable; +} diff --git a/contracts/dependencies/univ3/interfaces/ISwapRouter.sol b/contracts/dependencies/uniswapv3-periphery/interfaces/ISwapRouter.sol similarity index 96% rename from contracts/dependencies/univ3/interfaces/ISwapRouter.sol rename to contracts/dependencies/uniswapv3-periphery/interfaces/ISwapRouter.sol index 7424648e0..6fb25c1b5 100644 --- a/contracts/dependencies/univ3/interfaces/ISwapRouter.sol +++ b/contracts/dependencies/uniswapv3-periphery/interfaces/ISwapRouter.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.7.5; +pragma solidity ^0.8.0; pragma abicoder v2; -import './callback/IUniswapV3SwapCallback.sol'; +import '../../uniswapv3-core/interfaces/callback/IUniswapV3SwapCallback.sol'; /// @title Router token swapping functionality /// @notice Functions for swapping tokens via Uniswap V3 diff --git a/contracts/dependencies/uniswapv3-periphery/interfaces/ITickLens.sol b/contracts/dependencies/uniswapv3-periphery/interfaces/ITickLens.sol new file mode 100644 index 000000000..195d3cd0e --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/interfaces/ITickLens.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; +pragma abicoder v2; + +/// @title Tick Lens +/// @notice Provides functions for fetching chunks of tick data for a pool +/// @dev This avoids the waterfall of fetching the tick bitmap, parsing the bitmap to know which ticks to fetch, and +/// then sending additional multicalls to fetch the tick data +interface ITickLens { + struct PopulatedTick { + int24 tick; + int128 liquidityNet; + uint128 liquidityGross; + } + + /// @notice Get all the tick data for the populated ticks from a word of the tick bitmap of a pool + /// @param pool The address of the pool for which to fetch populated tick data + /// @param tickBitmapIndex The index of the word in the tick bitmap for which to parse the bitmap and + /// fetch all the populated ticks + /// @return populatedTicks An array of tick data for the given word in the tick bitmap + function getPopulatedTicksInWord(address pool, int16 tickBitmapIndex) + external + view + returns (PopulatedTick[] memory populatedTicks); +} diff --git a/contracts/dependencies/uniswapv3-periphery/interfaces/IV3Migrator.sol b/contracts/dependencies/uniswapv3-periphery/interfaces/IV3Migrator.sol new file mode 100644 index 000000000..0fe0bf440 --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/interfaces/IV3Migrator.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; +pragma abicoder v2; + +import './IMulticall.sol'; +import './ISelfPermit.sol'; +import './IPoolInitializer.sol'; + +/// @title V3 Migrator +/// @notice Enables migration of liqudity from Uniswap v2-compatible pairs into Uniswap v3 pools +interface IV3Migrator is IMulticall, ISelfPermit, IPoolInitializer { + struct MigrateParams { + address pair; // the Uniswap v2-compatible pair + uint256 liquidityToMigrate; // expected to be balanceOf(msg.sender) + uint8 percentageToMigrate; // represented as a numerator over 100 + address token0; + address token1; + uint24 fee; + int24 tickLower; + int24 tickUpper; + uint256 amount0Min; // must be discounted by percentageToMigrate + uint256 amount1Min; // must be discounted by percentageToMigrate + address recipient; + uint256 deadline; + bool refundAsETH; + } + + /// @notice Migrates liquidity to v3 by burning v2 liquidity and minting a new position for v3 + /// @dev Slippage protection is enforced via `amount{0,1}Min`, which should be a discount of the expected values of + /// the maximum amount of v3 liquidity that the v2 liquidity can get. For the special case of migrating to an + /// out-of-range position, `amount{0,1}Min` may be set to 0, enforcing that the position remains out of range + /// @param params The params necessary to migrate v2 liquidity, encoded as `MigrateParams` in calldata + function migrate(MigrateParams calldata params) external; +} diff --git a/contracts/dependencies/uniswapv3-periphery/interfaces/external/IERC1271.sol b/contracts/dependencies/uniswapv3-periphery/interfaces/external/IERC1271.sol new file mode 100644 index 000000000..3263bb97b --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/interfaces/external/IERC1271.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +/// @title Interface for verifying contract-based account signatures +/// @notice Interface that verifies provided signature for the data +/// @dev Interface defined by EIP-1271 +interface IERC1271 { + /// @notice Returns whether the provided signature is valid for the provided data + /// @dev MUST return the bytes4 magic value 0x1626ba7e when function passes. + /// MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5). + /// MUST allow external calls. + /// @param hash Hash of the data to be signed + /// @param signature Signature byte array associated with _data + /// @return magicValue The bytes4 magic value 0x1626ba7e + function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); +} diff --git a/contracts/dependencies/uniswapv3-periphery/interfaces/external/IERC20PermitAllowed.sol b/contracts/dependencies/uniswapv3-periphery/interfaces/external/IERC20PermitAllowed.sol new file mode 100644 index 000000000..1b7159391 --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/interfaces/external/IERC20PermitAllowed.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +/// @title Interface for permit +/// @notice Interface used by DAI/CHAI for permit +interface IERC20PermitAllowed { + /// @notice Approve the spender to spend some tokens via the holder signature + /// @dev This is the permit interface used by DAI and CHAI + /// @param holder The address of the token holder, the token owner + /// @param spender The address of the token spender + /// @param nonce The holder's nonce, increases at each call to permit + /// @param expiry The timestamp at which the permit is no longer valid + /// @param allowed Boolean that sets approval amount, true for type(uint256).max and false for 0 + /// @param v Must produce valid secp256k1 signature from the holder along with `r` and `s` + /// @param r Must produce valid secp256k1 signature from the holder along with `v` and `s` + /// @param s Must produce valid secp256k1 signature from the holder along with `r` and `v` + function permit( + address holder, + address spender, + uint256 nonce, + uint256 expiry, + bool allowed, + uint8 v, + bytes32 r, + bytes32 s + ) external; +} diff --git a/contracts/dependencies/uniswapv3-periphery/interfaces/external/IWETH9.sol b/contracts/dependencies/uniswapv3-periphery/interfaces/external/IWETH9.sol new file mode 100644 index 000000000..c6a3b1ee3 --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/interfaces/external/IWETH9.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +import '../../../openzeppelin/contracts/IERC20.sol'; + +/// @title Interface for WETH9 +interface IWETH9 is IERC20 { + /// @notice Deposit ether to get wrapped ether + function deposit() external payable; + + /// @notice Withdraw wrapped ether to get ether + function withdraw(uint256) external; +} diff --git a/contracts/dependencies/uniswapv3-periphery/libraries/BytesLib.sol b/contracts/dependencies/uniswapv3-periphery/libraries/BytesLib.sol new file mode 100644 index 000000000..a2c35cb5a --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/libraries/BytesLib.sol @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * @title Solidity Bytes Arrays Utils + * @author Gonçalo Sá + * + * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. + * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. + */ +pragma solidity ^0.8.0; + +library BytesLib { + function slice( + bytes memory _bytes, + uint256 _start, + uint256 _length + ) internal pure returns (bytes memory) { + require(_length + 31 >= _length, 'slice_overflow'); + require(_bytes.length >= _start + _length, 'slice_outOfBounds'); + + bytes memory tempBytes; + + assembly { + switch iszero(_length) + case 0 { + // Get a location of some free memory and store it in tempBytes as + // Solidity does for memory variables. + tempBytes := mload(0x40) + + // The first word of the slice result is potentially a partial + // word read from the original array. To read it, we calculate + // the length of that partial word and start copying that many + // bytes into the array. The first word we copy will start with + // data we don't care about, but the last `lengthmod` bytes will + // land at the beginning of the contents of the new array. When + // we're done copying, we overwrite the full first word with + // the actual length of the slice. + let lengthmod := and(_length, 31) + + // The multiplication in the next line is necessary + // because when slicing multiples of 32 bytes (lengthmod == 0) + // the following copy loop was copying the origin's length + // and then ending prematurely not copying everything it should. + let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) + let end := add(mc, _length) + + for { + // The multiplication in the next line has the same exact purpose + // as the one above. + let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) + } lt(mc, end) { + mc := add(mc, 0x20) + cc := add(cc, 0x20) + } { + mstore(mc, mload(cc)) + } + + mstore(tempBytes, _length) + + //update free-memory pointer + //allocating the array padded to 32 bytes like the compiler does now + mstore(0x40, and(add(mc, 31), not(31))) + } + //if we want a zero-length slice let's just return a zero-length array + default { + tempBytes := mload(0x40) + //zero out the 32 bytes slice we are about to return + //we need to do it because Solidity does not garbage collect + mstore(tempBytes, 0) + + mstore(0x40, add(tempBytes, 0x20)) + } + } + + return tempBytes; + } + + function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { + require(_bytes.length >= _start + 20, 'toAddress_outOfBounds'); + address tempAddress; + + assembly { + tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) + } + + return tempAddress; + } + + function toUint24(bytes memory _bytes, uint256 _start) internal pure returns (uint24) { + require(_start + 3 >= _start, 'toUint24_overflow'); + require(_bytes.length >= _start + 3, 'toUint24_outOfBounds'); + uint24 tempUint; + + assembly { + tempUint := mload(add(add(_bytes, 0x3), _start)) + } + + return tempUint; + } +} diff --git a/contracts/dependencies/uniswapv3-periphery/libraries/CallbackValidation.sol b/contracts/dependencies/uniswapv3-periphery/libraries/CallbackValidation.sol new file mode 100644 index 000000000..7eb19288b --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/libraries/CallbackValidation.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +import '../../uniswapv3-core/interfaces/IUniswapV3Pool.sol'; +import './PoolAddress.sol'; + +/// @notice Provides validation for callbacks from Uniswap V3 Pools +library CallbackValidation { + /// @notice Returns the address of a valid Uniswap V3 Pool + /// @param factory The contract address of the Uniswap V3 factory + /// @param tokenA The contract address of either token0 or token1 + /// @param tokenB The contract address of the other token + /// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip + /// @return pool The V3 pool contract address + function verifyCallback( + address factory, + address tokenA, + address tokenB, + uint24 fee + ) internal view returns (IUniswapV3Pool pool) { + return verifyCallback(factory, PoolAddress.getPoolKey(tokenA, tokenB, fee)); + } + + /// @notice Returns the address of a valid Uniswap V3 Pool + /// @param factory The contract address of the Uniswap V3 factory + /// @param poolKey The identifying key of the V3 pool + /// @return pool The V3 pool contract address + function verifyCallback(address factory, PoolAddress.PoolKey memory poolKey) + internal + view + returns (IUniswapV3Pool pool) + { + pool = IUniswapV3Pool(PoolAddress.computeAddress(factory, poolKey)); + require(msg.sender == address(pool)); + } +} diff --git a/contracts/dependencies/uniswapv3-periphery/libraries/ChainId.sol b/contracts/dependencies/uniswapv3-periphery/libraries/ChainId.sol new file mode 100644 index 000000000..8c180cfa9 --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/libraries/ChainId.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +/// @title Function for getting the current chain ID +library ChainId { + /// @dev Gets the current chain ID + /// @return chainId The current chain ID + function get() internal view returns (uint256 chainId) { + assembly { + chainId := chainid() + } + } +} diff --git a/contracts/dependencies/uniswap/LiquidityAmounts.sol b/contracts/dependencies/uniswapv3-periphery/libraries/LiquidityAmounts.sol similarity index 63% rename from contracts/dependencies/uniswap/LiquidityAmounts.sol rename to contracts/dependencies/uniswapv3-periphery/libraries/LiquidityAmounts.sol index 92d585acb..521a1b099 100644 --- a/contracts/dependencies/uniswap/LiquidityAmounts.sol +++ b/contracts/dependencies/uniswapv3-periphery/libraries/LiquidityAmounts.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; +pragma solidity ^0.8.0; -import "./libraries/FullMath.sol"; -import "./libraries/FixedPoint96.sol"; +import '../../uniswapv3-core/libraries/FullMath.sol'; +import '../../uniswapv3-core/libraries/FixedPoint96.sol'; /// @title Liquidity amount functions /// @notice Provides functions for computing liquidity amounts from token amounts and prices @@ -25,22 +25,10 @@ library LiquidityAmounts { uint160 sqrtRatioBX96, uint256 amount0 ) internal pure returns (uint128 liquidity) { - if (sqrtRatioAX96 > sqrtRatioBX96) - (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); - uint256 intermediate = FullMath.mulDiv( - sqrtRatioAX96, - sqrtRatioBX96, - FixedPoint96.Q96 - ); + if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); + uint256 intermediate = FullMath.mulDiv(sqrtRatioAX96, sqrtRatioBX96, FixedPoint96.Q96); unchecked { - return - toUint128( - FullMath.mulDiv( - amount0, - intermediate, - sqrtRatioBX96 - sqrtRatioAX96 - ) - ); + return toUint128(FullMath.mulDiv(amount0, intermediate, sqrtRatioBX96 - sqrtRatioAX96)); } } @@ -55,17 +43,9 @@ library LiquidityAmounts { uint160 sqrtRatioBX96, uint256 amount1 ) internal pure returns (uint128 liquidity) { - if (sqrtRatioAX96 > sqrtRatioBX96) - (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); + if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); unchecked { - return - toUint128( - FullMath.mulDiv( - amount1, - FixedPoint96.Q96, - sqrtRatioBX96 - sqrtRatioAX96 - ) - ); + return toUint128(FullMath.mulDiv(amount1, FixedPoint96.Q96, sqrtRatioBX96 - sqrtRatioAX96)); } } @@ -84,34 +64,17 @@ library LiquidityAmounts { uint256 amount0, uint256 amount1 ) internal pure returns (uint128 liquidity) { - if (sqrtRatioAX96 > sqrtRatioBX96) - (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); + if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); if (sqrtRatioX96 <= sqrtRatioAX96) { - liquidity = getLiquidityForAmount0( - sqrtRatioAX96, - sqrtRatioBX96, - amount0 - ); + liquidity = getLiquidityForAmount0(sqrtRatioAX96, sqrtRatioBX96, amount0); } else if (sqrtRatioX96 < sqrtRatioBX96) { - uint128 liquidity0 = getLiquidityForAmount0( - sqrtRatioX96, - sqrtRatioBX96, - amount0 - ); - uint128 liquidity1 = getLiquidityForAmount1( - sqrtRatioAX96, - sqrtRatioX96, - amount1 - ); + uint128 liquidity0 = getLiquidityForAmount0(sqrtRatioX96, sqrtRatioBX96, amount0); + uint128 liquidity1 = getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioX96, amount1); liquidity = liquidity0 < liquidity1 ? liquidity0 : liquidity1; } else { - liquidity = getLiquidityForAmount1( - sqrtRatioAX96, - sqrtRatioBX96, - amount1 - ); + liquidity = getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, amount1); } } @@ -126,8 +89,7 @@ library LiquidityAmounts { uint128 liquidity ) internal pure returns (uint256 amount0) { unchecked { - if (sqrtRatioAX96 > sqrtRatioBX96) - (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); + if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); return FullMath.mulDiv( @@ -148,16 +110,10 @@ library LiquidityAmounts { uint160 sqrtRatioBX96, uint128 liquidity ) internal pure returns (uint256 amount1) { - if (sqrtRatioAX96 > sqrtRatioBX96) - (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); + if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); unchecked { - return - FullMath.mulDiv( - liquidity, - sqrtRatioBX96 - sqrtRatioAX96, - FixedPoint96.Q96 - ); + return FullMath.mulDiv(liquidity, sqrtRatioBX96 - sqrtRatioAX96, FixedPoint96.Q96); } } @@ -175,32 +131,15 @@ library LiquidityAmounts { uint160 sqrtRatioBX96, uint128 liquidity ) internal pure returns (uint256 amount0, uint256 amount1) { - if (sqrtRatioAX96 > sqrtRatioBX96) - (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); + if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); if (sqrtRatioX96 <= sqrtRatioAX96) { - amount0 = getAmount0ForLiquidity( - sqrtRatioAX96, - sqrtRatioBX96, - liquidity - ); + amount0 = getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity); } else if (sqrtRatioX96 < sqrtRatioBX96) { - amount0 = getAmount0ForLiquidity( - sqrtRatioX96, - sqrtRatioBX96, - liquidity - ); - amount1 = getAmount1ForLiquidity( - sqrtRatioAX96, - sqrtRatioX96, - liquidity - ); + amount0 = getAmount0ForLiquidity(sqrtRatioX96, sqrtRatioBX96, liquidity); + amount1 = getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioX96, liquidity); } else { - amount1 = getAmount1ForLiquidity( - sqrtRatioAX96, - sqrtRatioBX96, - liquidity - ); + amount1 = getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity); } } } diff --git a/contracts/dependencies/uniswapv3-periphery/libraries/Path.sol b/contracts/dependencies/uniswapv3-periphery/libraries/Path.sol new file mode 100644 index 000000000..e92feadd8 --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/libraries/Path.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +import './BytesLib.sol'; + +/// @title Functions for manipulating path data for multihop swaps +library Path { + using BytesLib for bytes; + + /// @dev The length of the bytes encoded address + uint256 private constant ADDR_SIZE = 20; + /// @dev The length of the bytes encoded fee + uint256 private constant FEE_SIZE = 3; + + /// @dev The offset of a single token address and pool fee + uint256 private constant NEXT_OFFSET = ADDR_SIZE + FEE_SIZE; + /// @dev The offset of an encoded pool key + uint256 private constant POP_OFFSET = NEXT_OFFSET + ADDR_SIZE; + /// @dev The minimum length of an encoding that contains 2 or more pools + uint256 private constant MULTIPLE_POOLS_MIN_LENGTH = POP_OFFSET + NEXT_OFFSET; + + /// @notice Returns true iff the path contains two or more pools + /// @param path The encoded swap path + /// @return True if path contains two or more pools, otherwise false + function hasMultiplePools(bytes memory path) internal pure returns (bool) { + return path.length >= MULTIPLE_POOLS_MIN_LENGTH; + } + + /// @notice Returns the number of pools in the path + /// @param path The encoded swap path + /// @return The number of pools in the path + function numPools(bytes memory path) internal pure returns (uint256) { + // Ignore the first token address. From then on every fee and token offset indicates a pool. + return ((path.length - ADDR_SIZE) / NEXT_OFFSET); + } + + /// @notice Decodes the first pool in path + /// @param path The bytes encoded swap path + /// @return tokenA The first token of the given pool + /// @return tokenB The second token of the given pool + /// @return fee The fee level of the pool + function decodeFirstPool(bytes memory path) + internal + pure + returns ( + address tokenA, + address tokenB, + uint24 fee + ) + { + tokenA = path.toAddress(0); + fee = path.toUint24(ADDR_SIZE); + tokenB = path.toAddress(NEXT_OFFSET); + } + + /// @notice Gets the segment corresponding to the first pool in the path + /// @param path The bytes encoded swap path + /// @return The segment containing all data necessary to target the first pool in the path + function getFirstPool(bytes memory path) internal pure returns (bytes memory) { + return path.slice(0, POP_OFFSET); + } + + /// @notice Skips a token + fee element from the buffer and returns the remainder + /// @param path The swap path + /// @return The remaining token + fee elements in the path + function skipToken(bytes memory path) internal pure returns (bytes memory) { + return path.slice(NEXT_OFFSET, path.length - NEXT_OFFSET); + } +} diff --git a/contracts/dependencies/uniswap/PoolAddress.sol b/contracts/dependencies/uniswapv3-periphery/libraries/PoolAddress.sol similarity index 77% rename from contracts/dependencies/uniswap/PoolAddress.sol rename to contracts/dependencies/uniswapv3-periphery/libraries/PoolAddress.sol index 2c5e126b3..b4696a399 100644 --- a/contracts/dependencies/uniswap/PoolAddress.sol +++ b/contracts/dependencies/uniswapv3-periphery/libraries/PoolAddress.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; +pragma solidity ^0.8.0; + +import {UniswapV3Pool} from "../../uniswapv3-core/UniswapV3Pool.sol"; + /// @title Provides functions for deriving a pool address from the factory, tokens, and the fee library PoolAddress { - bytes32 internal constant POOL_INIT_CODE_HASH = - 0xa598dd2fba360510c5a8f02f44423a4468e902df5857dbce3ca162a43a3a31ff; - /// @notice The identifying key of the pool struct PoolKey { address token0; @@ -31,23 +31,17 @@ library PoolAddress { /// @param factory The Uniswap V3 factory contract address /// @param key The PoolKey /// @return pool The contract address of the V3 pool - function computeAddress(address factory, PoolKey memory key) - internal - pure - returns (address pool) - { + function computeAddress(address factory, PoolKey memory key) internal pure returns (address pool) { require(key.token0 < key.token1); pool = address( uint160( uint256( keccak256( abi.encodePacked( - hex"ff", + hex'ff', factory, - keccak256( - abi.encode(key.token0, key.token1, key.fee) - ), - POOL_INIT_CODE_HASH + keccak256(abi.encode(key.token0, key.token1, key.fee)), + keccak256(type(UniswapV3Pool).creationCode) ) ) ) diff --git a/contracts/dependencies/uniswapv3-periphery/libraries/PositionKey.sol b/contracts/dependencies/uniswapv3-periphery/libraries/PositionKey.sol new file mode 100644 index 000000000..6f5790325 --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/libraries/PositionKey.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +library PositionKey { + /// @dev Returns the key of the position in the core library + function compute( + address owner, + int24 tickLower, + int24 tickUpper + ) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(owner, tickLower, tickUpper)); + } +} diff --git a/contracts/dependencies/uniswapv3-periphery/libraries/TransferHelper.sol b/contracts/dependencies/uniswapv3-periphery/libraries/TransferHelper.sol new file mode 100644 index 000000000..0312ca6d5 --- /dev/null +++ b/contracts/dependencies/uniswapv3-periphery/libraries/TransferHelper.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +import '../../openzeppelin/contracts/IERC20.sol'; + +library TransferHelper { + /// @notice Transfers tokens from the targeted address to the given destination + /// @notice Errors with 'STF' if transfer fails + /// @param token The contract address of the token to be transferred + /// @param from The originating address from which the tokens will be transferred + /// @param to The destination address of the transfer + /// @param value The amount to be transferred + function safeTransferFrom( + address token, + address from, + address to, + uint256 value + ) internal { + (bool success, bytes memory data) = token.call( + abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value) + ); + require(success && (data.length == 0 || abi.decode(data, (bool))), 'STF'); + } + + /// @notice Transfers tokens from msg.sender to a recipient + /// @dev Errors with ST if transfer fails + /// @param token The contract address of the token which will be transferred + /// @param to The recipient of the transfer + /// @param value The value of the transfer + function safeTransfer( + address token, + address to, + uint256 value + ) internal { + (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value)); + require(success && (data.length == 0 || abi.decode(data, (bool))), 'ST'); + } + + /// @notice Approves the stipulated contract to spend the given allowance in the given token + /// @dev Errors with 'SA' if transfer fails + /// @param token The contract address of the token to be approved + /// @param to The target of the approval + /// @param value The amount of the given token the target will be allowed to spend + function safeApprove( + address token, + address to, + uint256 value + ) internal { + (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value)); + require(success && (data.length == 0 || abi.decode(data, (bool))), 'SA'); + } + + /// @notice Transfers ETH to the recipient address + /// @dev Fails with `STE` + /// @param to The destination of the transfer + /// @param value The value to be transferred + function safeTransferETH(address to, uint256 value) internal { + (bool success, ) = to.call{value: value}(new bytes(0)); + require(success, 'STE'); + } +} diff --git a/contracts/dependencies/univ3/interfaces/IUniswapV3Factory.sol b/contracts/dependencies/univ3/interfaces/IUniswapV3Factory.sol deleted file mode 100644 index 540cfdc68..000000000 --- a/contracts/dependencies/univ3/interfaces/IUniswapV3Factory.sol +++ /dev/null @@ -1,78 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; - -/// @title The interface for the Uniswap V3 Factory -/// @notice The Uniswap V3 Factory facilitates creation of Uniswap V3 pools and control over the protocol fees -interface IUniswapV3Factory { - /// @notice Emitted when the owner of the factory is changed - /// @param oldOwner The owner before the owner was changed - /// @param newOwner The owner after the owner was changed - event OwnerChanged(address indexed oldOwner, address indexed newOwner); - - /// @notice Emitted when a pool is created - /// @param token0 The first token of the pool by address sort order - /// @param token1 The second token of the pool by address sort order - /// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip - /// @param tickSpacing The minimum number of ticks between initialized ticks - /// @param pool The address of the created pool - event PoolCreated( - address indexed token0, - address indexed token1, - uint24 indexed fee, - int24 tickSpacing, - address pool - ); - - /// @notice Emitted when a new fee amount is enabled for pool creation via the factory - /// @param fee The enabled fee, denominated in hundredths of a bip - /// @param tickSpacing The minimum number of ticks between initialized ticks for pools created with the given fee - event FeeAmountEnabled(uint24 indexed fee, int24 indexed tickSpacing); - - /// @notice Returns the current owner of the factory - /// @dev Can be changed by the current owner via setOwner - /// @return The address of the factory owner - function owner() external view returns (address); - - /// @notice Returns the tick spacing for a given fee amount, if enabled, or 0 if not enabled - /// @dev A fee amount can never be removed, so this value should be hard coded or cached in the calling context - /// @param fee The enabled fee, denominated in hundredths of a bip. Returns 0 in case of unenabled fee - /// @return The tick spacing - function feeAmountTickSpacing(uint24 fee) external view returns (int24); - - /// @notice Returns the pool address for a given pair of tokens and a fee, or address 0 if it does not exist - /// @dev tokenA and tokenB may be passed in either token0/token1 or token1/token0 order - /// @param tokenA The contract address of either token0 or token1 - /// @param tokenB The contract address of the other token - /// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip - /// @return pool The pool address - function getPool( - address tokenA, - address tokenB, - uint24 fee - ) external view returns (address pool); - - /// @notice Creates a pool for the given two tokens and fee - /// @param tokenA One of the two tokens in the desired pool - /// @param tokenB The other of the two tokens in the desired pool - /// @param fee The desired fee for the pool - /// @dev tokenA and tokenB may be passed in either order: token0/token1 or token1/token0. tickSpacing is retrieved - /// from the fee. The call will revert if the pool already exists, the fee is invalid, or the token arguments - /// are invalid. - /// @return pool The address of the newly created pool - function createPool( - address tokenA, - address tokenB, - uint24 fee - ) external returns (address pool); - - /// @notice Updates the owner of the factory - /// @dev Must be called by the current owner - /// @param _owner The new owner of the factory - function setOwner(address _owner) external; - - /// @notice Enables a fee amount with the given tickSpacing - /// @dev Fee amounts may never be removed once enabled - /// @param fee The fee amount to enable, denominated in hundredths of a bip (i.e. 1e-6) - /// @param tickSpacing The spacing between ticks to be enforced for all pools created with the given fee amount - function enableFeeAmount(uint24 fee, int24 tickSpacing) external; -} diff --git a/contracts/dependencies/univ3/interfaces/IUniswapV3Pool.sol b/contracts/dependencies/univ3/interfaces/IUniswapV3Pool.sol deleted file mode 100644 index a2239bd86..000000000 --- a/contracts/dependencies/univ3/interfaces/IUniswapV3Pool.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; - -import "./pool/IUniswapV3PoolImmutables.sol"; -import "./pool/IUniswapV3PoolState.sol"; -import "./pool/IUniswapV3PoolDerivedState.sol"; -import "./pool/IUniswapV3PoolActions.sol"; -import "./pool/IUniswapV3PoolOwnerActions.sol"; -import "./pool/IUniswapV3PoolEvents.sol"; - -/// @title The interface for a Uniswap V3 Pool -/// @notice A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform -/// to the ERC20 specification -/// @dev The pool interface is broken up into many smaller pieces -interface IUniswapV3Pool is - IUniswapV3PoolImmutables, - IUniswapV3PoolState, - IUniswapV3PoolDerivedState, - IUniswapV3PoolActions, - IUniswapV3PoolOwnerActions, - IUniswapV3PoolEvents -{ - -} diff --git a/contracts/dependencies/univ3/interfaces/LICENSE b/contracts/dependencies/univ3/interfaces/LICENSE deleted file mode 100644 index 7f6aca78c..000000000 --- a/contracts/dependencies/univ3/interfaces/LICENSE +++ /dev/null @@ -1,445 +0,0 @@ -This software is available under your choice of the GNU General Public -License, version 2 or later, or the Business Source License, as set -forth below. - - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. - - -Business Source License 1.1 - -License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved. -"Business Source License" is a trademark of MariaDB Corporation Ab. - ------------------------------------------------------------------------------ - -Parameters - -Licensor: Uniswap Labs - -Licensed Work: Uniswap V3 Core - The Licensed Work is (c) 2021 Uniswap Labs - -Additional Use Grant: Any uses listed and defined at - v3-core-license-grants.uniswap.eth - -Change Date: The earlier of 2023-04-01 or a date specified at - v3-core-license-date.uniswap.eth - -Change License: GNU General Public License v2.0 or later - ------------------------------------------------------------------------------ - -Terms - -The Licensor hereby grants you the right to copy, modify, create derivative -works, redistribute, and make non-production use of the Licensed Work. The -Licensor may make an Additional Use Grant, above, permitting limited -production use. - -Effective on the Change Date, or the fourth anniversary of the first publicly -available distribution of a specific version of the Licensed Work under this -License, whichever comes first, the Licensor hereby grants you rights under -the terms of the Change License, and the rights granted in the paragraph -above terminate. - -If your use of the Licensed Work does not comply with the requirements -currently in effect as described in this License, you must purchase a -commercial license from the Licensor, its affiliated entities, or authorized -resellers, or you must refrain from using the Licensed Work. - -All copies of the original and modified Licensed Work, and derivative works -of the Licensed Work, are subject to this License. This License applies -separately for each version of the Licensed Work and the Change Date may vary -for each version of the Licensed Work released by Licensor. - -You must conspicuously display this License on each original or modified copy -of the Licensed Work. If you receive the Licensed Work in original or -modified form from a third party, the terms and conditions set forth in this -License apply to your use of that work. - -Any use of the Licensed Work in violation of this License will automatically -terminate your rights under this License for the current and all other -versions of the Licensed Work. - -This License does not grant you any right in any trademark or logo of -Licensor or its affiliates (provided that you may use a trademark or logo of -Licensor as expressly required by this License). - -TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON -AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, -EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND -TITLE. - -MariaDB hereby grants you permission to use this License’s text to license -your works, and to refer to it using the trademark "Business Source License", -as long as you comply with the Covenants of Licensor below. - ------------------------------------------------------------------------------ - -Covenants of Licensor - -In consideration of the right to use this License’s text and the "Business -Source License" name and trademark, Licensor covenants to MariaDB, and to all -other recipients of the licensed work to be provided by Licensor: - -1. To specify as the Change License the GPL Version 2.0 or any later version, - or a license that is compatible with GPL Version 2.0 or a later version, - where "compatible" means that software provided under the Change License can - be included in a program with software provided under GPL Version 2.0 or a - later version. Licensor may specify additional Change Licenses without - limitation. - -2. To either: (a) specify an additional grant of rights to use that does not - impose any additional restriction on the right granted in this License, as - the Additional Use Grant; or (b) insert the text "None". - -3. To specify a Change Date. - -4. Not to modify this License in any other way. - ------------------------------------------------------------------------------ - -Notice - -The Business Source License (this document, or the "License") is not an Open -Source license. However, the Licensed Work will eventually be made available -under an Open Source License, as stated in this License. diff --git a/contracts/dependencies/univ3/interfaces/pool/IUniswapV3PoolDerivedState.sol b/contracts/dependencies/univ3/interfaces/pool/IUniswapV3PoolDerivedState.sol deleted file mode 100644 index c851ec996..000000000 --- a/contracts/dependencies/univ3/interfaces/pool/IUniswapV3PoolDerivedState.sol +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; - -/// @title Pool state that is not stored -/// @notice Contains view functions to provide information about the pool that is computed rather than stored on the -/// blockchain. The functions here may have variable gas costs. -interface IUniswapV3PoolDerivedState { - /// @notice Returns the cumulative tick and liquidity as of each timestamp `secondsAgo` from the current block timestamp - /// @dev To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing - /// the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick, - /// you must call it with secondsAgos = [3600, 0]. - /// @dev The time weighted average tick represents the geometric time weighted average price of the pool, in - /// log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio. - /// @param secondsAgos From how long ago each cumulative tick and liquidity value should be returned - /// @return tickCumulatives Cumulative tick values as of each `secondsAgos` from the current block timestamp - /// @return secondsPerLiquidityCumulativeX128s Cumulative seconds per liquidity-in-range value as of each `secondsAgos` from the current block - /// timestamp - function observe(uint32[] calldata secondsAgos) - external - view - returns ( - int56[] memory tickCumulatives, - uint160[] memory secondsPerLiquidityCumulativeX128s - ); - - /// @notice Returns a snapshot of the tick cumulative, seconds per liquidity and seconds inside a tick range - /// @dev Snapshots must only be compared to other snapshots, taken over a period for which a position existed. - /// I.e., snapshots cannot be compared if a position is not held for the entire period between when the first - /// snapshot is taken and the second snapshot is taken. - /// @param tickLower The lower tick of the range - /// @param tickUpper The upper tick of the range - /// @return tickCumulativeInside The snapshot of the tick accumulator for the range - /// @return secondsPerLiquidityInsideX128 The snapshot of seconds per liquidity for the range - /// @return secondsInside The snapshot of seconds per liquidity for the range - function snapshotCumulativesInside(int24 tickLower, int24 tickUpper) - external - view - returns ( - int56 tickCumulativeInside, - uint160 secondsPerLiquidityInsideX128, - uint32 secondsInside - ); -} diff --git a/contracts/dependencies/univ3/interfaces/pool/IUniswapV3PoolState.sol b/contracts/dependencies/univ3/interfaces/pool/IUniswapV3PoolState.sol deleted file mode 100644 index 1278de31e..000000000 --- a/contracts/dependencies/univ3/interfaces/pool/IUniswapV3PoolState.sol +++ /dev/null @@ -1,119 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; - -/// @title Pool state that can change -/// @notice These methods compose the pool's state, and can change with any frequency including multiple times -/// per transaction -interface IUniswapV3PoolState { - /// @notice The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas - /// when accessed externally. - /// @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value - /// tick The current tick of the pool, i.e. according to the last tick transition that was run. - /// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick - /// boundary. - /// observationIndex The index of the last oracle observation that was written, - /// observationCardinality The current maximum number of observations stored in the pool, - /// observationCardinalityNext The next maximum number of observations, to be updated when the observation. - /// feeProtocol The protocol fee for both tokens of the pool. - /// Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0 - /// is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee. - /// unlocked Whether the pool is currently locked to reentrancy - function slot0() - external - view - returns ( - uint160 sqrtPriceX96, - int24 tick, - uint16 observationIndex, - uint16 observationCardinality, - uint16 observationCardinalityNext, - uint8 feeProtocol, - bool unlocked - ); - - /// @notice The fee growth as a Q128.128 fees of token0 collected per unit of liquidity for the entire life of the pool - /// @dev This value can overflow the uint256 - function feeGrowthGlobal0X128() external view returns (uint256); - - /// @notice The fee growth as a Q128.128 fees of token1 collected per unit of liquidity for the entire life of the pool - /// @dev This value can overflow the uint256 - function feeGrowthGlobal1X128() external view returns (uint256); - - /// @notice The amounts of token0 and token1 that are owed to the protocol - /// @dev Protocol fees will never exceed uint128 max in either token - function protocolFees() - external - view - returns (uint128 token0, uint128 token1); - - /// @notice The currently in range liquidity available to the pool - /// @dev This value has no relationship to the total liquidity across all ticks - function liquidity() external view returns (uint128); - - /// @notice Look up information about a specific tick in the pool - /// @param tick The tick to look up - /// @return liquidityGross the total amount of position liquidity that uses the pool either as tick lower or - /// tick upper, - /// liquidityNet how much liquidity changes when the pool price crosses the tick, - /// feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0, - /// feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1, - /// tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick - /// secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from the current tick, - /// secondsOutside the seconds spent on the other side of the tick from the current tick, - /// initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise equal to false. - /// Outside values can only be used if the tick is initialized, i.e. if liquidityGross is greater than 0. - /// In addition, these values are only relative and must be used only in comparison to previous snapshots for - /// a specific position. - function ticks(int24 tick) - external - view - returns ( - uint128 liquidityGross, - int128 liquidityNet, - uint256 feeGrowthOutside0X128, - uint256 feeGrowthOutside1X128, - int56 tickCumulativeOutside, - uint160 secondsPerLiquidityOutsideX128, - uint32 secondsOutside, - bool initialized - ); - - /// @notice Returns 256 packed tick initialized boolean values. See TickBitmap for more information - function tickBitmap(int16 wordPosition) external view returns (uint256); - - /// @notice Returns the information about a position by the position's key - /// @param key The position's key is a hash of a preimage composed by the owner, tickLower and tickUpper - /// @return _liquidity The amount of liquidity in the position, - /// Returns feeGrowthInside0LastX128 fee growth of token0 inside the tick range as of the last mint/burn/poke, - /// Returns feeGrowthInside1LastX128 fee growth of token1 inside the tick range as of the last mint/burn/poke, - /// Returns tokensOwed0 the computed amount of token0 owed to the position as of the last mint/burn/poke, - /// Returns tokensOwed1 the computed amount of token1 owed to the position as of the last mint/burn/poke - function positions(bytes32 key) - external - view - returns ( - uint128 _liquidity, - uint256 feeGrowthInside0LastX128, - uint256 feeGrowthInside1LastX128, - uint128 tokensOwed0, - uint128 tokensOwed1 - ); - - /// @notice Returns data about a specific observation index - /// @param index The element of the observations array to fetch - /// @dev You most likely want to use #observe() instead of this method to get an observation as of some amount of time - /// ago, rather than at a specific index in the array. - /// @return blockTimestamp The timestamp of the observation, - /// Returns tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the observation timestamp, - /// Returns secondsPerLiquidityCumulativeX128 the seconds per in range liquidity for the life of the pool as of the observation timestamp, - /// Returns initialized whether the observation has been initialized and the values are safe to use - function observations(uint256 index) - external - view - returns ( - uint32 blockTimestamp, - int56 tickCumulative, - uint160 secondsPerLiquidityCumulativeX128, - bool initialized - ); -} diff --git a/contracts/dependencies/univ3/libraries/BitMath.sol b/contracts/dependencies/univ3/libraries/BitMath.sol deleted file mode 100644 index 3a7216c7b..000000000 --- a/contracts/dependencies/univ3/libraries/BitMath.sol +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; - -/// @title BitMath -/// @dev This library provides functionality for computing bit properties of an unsigned integer -library BitMath { - /// @notice Returns the index of the most significant bit of the number, - /// where the least significant bit is at index 0 and the most significant bit is at index 255 - /// @dev The function satisfies the property: - /// x >= 2**mostSignificantBit(x) and x < 2**(mostSignificantBit(x)+1) - /// @param x the value for which to compute the most significant bit, must be greater than 0 - /// @return r the index of the most significant bit - function mostSignificantBit(uint256 x) internal pure returns (uint8 r) { - require(x > 0); - - if (x >= 0x100000000000000000000000000000000) { - x >>= 128; - r += 128; - } - if (x >= 0x10000000000000000) { - x >>= 64; - r += 64; - } - if (x >= 0x100000000) { - x >>= 32; - r += 32; - } - if (x >= 0x10000) { - x >>= 16; - r += 16; - } - if (x >= 0x100) { - x >>= 8; - r += 8; - } - if (x >= 0x10) { - x >>= 4; - r += 4; - } - if (x >= 0x4) { - x >>= 2; - r += 2; - } - if (x >= 0x2) r += 1; - } - - /// @notice Returns the index of the least significant bit of the number, - /// where the least significant bit is at index 0 and the most significant bit is at index 255 - /// @dev The function satisfies the property: - /// (x & 2**leastSignificantBit(x)) != 0 and (x & (2**(leastSignificantBit(x)) - 1)) == 0) - /// @param x the value for which to compute the least significant bit, must be greater than 0 - /// @return r the index of the least significant bit - function leastSignificantBit(uint256 x) internal pure returns (uint8 r) { - require(x > 0); - - r = 255; - if (x & type(uint128).max > 0) { - r -= 128; - } else { - x >>= 128; - } - if (x & type(uint64).max > 0) { - r -= 64; - } else { - x >>= 64; - } - if (x & type(uint32).max > 0) { - r -= 32; - } else { - x >>= 32; - } - if (x & type(uint16).max > 0) { - r -= 16; - } else { - x >>= 16; - } - if (x & type(uint8).max > 0) { - r -= 8; - } else { - x >>= 8; - } - if (x & 0xf > 0) { - r -= 4; - } else { - x >>= 4; - } - if (x & 0x3 > 0) { - r -= 2; - } else { - x >>= 2; - } - if (x & 0x1 > 0) r -= 1; - } -} diff --git a/contracts/dependencies/univ3/libraries/FixedPoint128.sol b/contracts/dependencies/univ3/libraries/FixedPoint128.sol deleted file mode 100644 index 6d6948b10..000000000 --- a/contracts/dependencies/univ3/libraries/FixedPoint128.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.4.0; - -/// @title FixedPoint128 -/// @notice A library for handling binary fixed point numbers, see https://en.wikipedia.org/wiki/Q_(number_format) -library FixedPoint128 { - uint256 internal constant Q128 = 0x100000000000000000000000000000000; -} diff --git a/contracts/dependencies/univ3/libraries/FixedPoint96.sol b/contracts/dependencies/univ3/libraries/FixedPoint96.sol deleted file mode 100644 index 63b42c294..000000000 --- a/contracts/dependencies/univ3/libraries/FixedPoint96.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.4.0; - -/// @title FixedPoint96 -/// @notice A library for handling binary fixed point numbers, see https://en.wikipedia.org/wiki/Q_(number_format) -/// @dev Used in SqrtPriceMath.sol -library FixedPoint96 { - uint8 internal constant RESOLUTION = 96; - uint256 internal constant Q96 = 0x1000000000000000000000000; -} diff --git a/contracts/dependencies/univ3/libraries/FullMath.sol b/contracts/dependencies/univ3/libraries/FullMath.sol deleted file mode 100644 index 9985059e2..000000000 --- a/contracts/dependencies/univ3/libraries/FullMath.sol +++ /dev/null @@ -1,124 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.4.0 <0.8.0; - -/// @title Contains 512-bit math functions -/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision -/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits -library FullMath { - /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 - /// @param a The multiplicand - /// @param b The multiplier - /// @param denominator The divisor - /// @return result The 256-bit result - /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv - function mulDiv( - uint256 a, - uint256 b, - uint256 denominator - ) internal pure returns (uint256 result) { - // 512-bit multiply [prod1 prod0] = a * b - // Compute the product mod 2**256 and mod 2**256 - 1 - // then use the Chinese Remainder Theorem to reconstruct - // the 512 bit result. The result is stored in two 256 - // variables such that product = prod1 * 2**256 + prod0 - uint256 prod0; // Least significant 256 bits of the product - uint256 prod1; // Most significant 256 bits of the product - assembly { - let mm := mulmod(a, b, not(0)) - prod0 := mul(a, b) - prod1 := sub(sub(mm, prod0), lt(mm, prod0)) - } - - // Handle non-overflow cases, 256 by 256 division - if (prod1 == 0) { - require(denominator > 0); - assembly { - result := div(prod0, denominator) - } - return result; - } - - // Make sure the result is less than 2**256. - // Also prevents denominator == 0 - require(denominator > prod1); - - /////////////////////////////////////////////// - // 512 by 256 division. - /////////////////////////////////////////////// - - // Make division exact by subtracting the remainder from [prod1 prod0] - // Compute remainder using mulmod - uint256 remainder; - assembly { - remainder := mulmod(a, b, denominator) - } - // Subtract 256 bit number from 512 bit number - assembly { - prod1 := sub(prod1, gt(remainder, prod0)) - prod0 := sub(prod0, remainder) - } - - // Factor powers of two out of denominator - // Compute largest power of two divisor of denominator. - // Always >= 1. - uint256 twos = -denominator & denominator; - // Divide denominator by power of two - assembly { - denominator := div(denominator, twos) - } - - // Divide [prod1 prod0] by the factors of two - assembly { - prod0 := div(prod0, twos) - } - // Shift in bits from prod1 into prod0. For this we need - // to flip `twos` such that it is 2**256 / twos. - // If twos is zero, then it becomes one - assembly { - twos := add(div(sub(0, twos), twos), 1) - } - prod0 |= prod1 * twos; - - // Invert denominator mod 2**256 - // Now that denominator is an odd number, it has an inverse - // modulo 2**256 such that denominator * inv = 1 mod 2**256. - // Compute the inverse by starting with a seed that is correct - // correct for four bits. That is, denominator * inv = 1 mod 2**4 - uint256 inv = (3 * denominator) ^ 2; - // Now use Newton-Raphson iteration to improve the precision. - // Thanks to Hensel's lifting lemma, this also works in modular - // arithmetic, doubling the correct bits in each step. - inv *= 2 - denominator * inv; // inverse mod 2**8 - inv *= 2 - denominator * inv; // inverse mod 2**16 - inv *= 2 - denominator * inv; // inverse mod 2**32 - inv *= 2 - denominator * inv; // inverse mod 2**64 - inv *= 2 - denominator * inv; // inverse mod 2**128 - inv *= 2 - denominator * inv; // inverse mod 2**256 - - // Because the division is now exact we can divide by multiplying - // with the modular inverse of denominator. This will give us the - // correct result modulo 2**256. Since the precoditions guarantee - // that the outcome is less than 2**256, this is the final result. - // We don't need to compute the high bits of the result and prod1 - // is no longer required. - result = prod0 * inv; - return result; - } - - /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 - /// @param a The multiplicand - /// @param b The multiplier - /// @param denominator The divisor - /// @return result The 256-bit result - function mulDivRoundingUp( - uint256 a, - uint256 b, - uint256 denominator - ) internal pure returns (uint256 result) { - result = mulDiv(a, b, denominator); - if (mulmod(a, b, denominator) > 0) { - require(result < type(uint256).max); - result++; - } - } -} diff --git a/contracts/dependencies/univ3/libraries/LICENSE b/contracts/dependencies/univ3/libraries/LICENSE deleted file mode 100644 index 7f6aca78c..000000000 --- a/contracts/dependencies/univ3/libraries/LICENSE +++ /dev/null @@ -1,445 +0,0 @@ -This software is available under your choice of the GNU General Public -License, version 2 or later, or the Business Source License, as set -forth below. - - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. - - -Business Source License 1.1 - -License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved. -"Business Source License" is a trademark of MariaDB Corporation Ab. - ------------------------------------------------------------------------------ - -Parameters - -Licensor: Uniswap Labs - -Licensed Work: Uniswap V3 Core - The Licensed Work is (c) 2021 Uniswap Labs - -Additional Use Grant: Any uses listed and defined at - v3-core-license-grants.uniswap.eth - -Change Date: The earlier of 2023-04-01 or a date specified at - v3-core-license-date.uniswap.eth - -Change License: GNU General Public License v2.0 or later - ------------------------------------------------------------------------------ - -Terms - -The Licensor hereby grants you the right to copy, modify, create derivative -works, redistribute, and make non-production use of the Licensed Work. The -Licensor may make an Additional Use Grant, above, permitting limited -production use. - -Effective on the Change Date, or the fourth anniversary of the first publicly -available distribution of a specific version of the Licensed Work under this -License, whichever comes first, the Licensor hereby grants you rights under -the terms of the Change License, and the rights granted in the paragraph -above terminate. - -If your use of the Licensed Work does not comply with the requirements -currently in effect as described in this License, you must purchase a -commercial license from the Licensor, its affiliated entities, or authorized -resellers, or you must refrain from using the Licensed Work. - -All copies of the original and modified Licensed Work, and derivative works -of the Licensed Work, are subject to this License. This License applies -separately for each version of the Licensed Work and the Change Date may vary -for each version of the Licensed Work released by Licensor. - -You must conspicuously display this License on each original or modified copy -of the Licensed Work. If you receive the Licensed Work in original or -modified form from a third party, the terms and conditions set forth in this -License apply to your use of that work. - -Any use of the Licensed Work in violation of this License will automatically -terminate your rights under this License for the current and all other -versions of the Licensed Work. - -This License does not grant you any right in any trademark or logo of -Licensor or its affiliates (provided that you may use a trademark or logo of -Licensor as expressly required by this License). - -TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON -AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, -EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND -TITLE. - -MariaDB hereby grants you permission to use this License’s text to license -your works, and to refer to it using the trademark "Business Source License", -as long as you comply with the Covenants of Licensor below. - ------------------------------------------------------------------------------ - -Covenants of Licensor - -In consideration of the right to use this License’s text and the "Business -Source License" name and trademark, Licensor covenants to MariaDB, and to all -other recipients of the licensed work to be provided by Licensor: - -1. To specify as the Change License the GPL Version 2.0 or any later version, - or a license that is compatible with GPL Version 2.0 or a later version, - where "compatible" means that software provided under the Change License can - be included in a program with software provided under GPL Version 2.0 or a - later version. Licensor may specify additional Change Licenses without - limitation. - -2. To either: (a) specify an additional grant of rights to use that does not - impose any additional restriction on the right granted in this License, as - the Additional Use Grant; or (b) insert the text "None". - -3. To specify a Change Date. - -4. Not to modify this License in any other way. - ------------------------------------------------------------------------------ - -Notice - -The Business Source License (this document, or the "License") is not an Open -Source license. However, the Licensed Work will eventually be made available -under an Open Source License, as stated in this License. diff --git a/contracts/dependencies/univ3/libraries/LICENSE_MIT b/contracts/dependencies/univ3/libraries/LICENSE_MIT deleted file mode 100644 index bf4f90a28..000000000 --- a/contracts/dependencies/univ3/libraries/LICENSE_MIT +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2021 Remco Bloemen - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/contracts/dependencies/univ3/libraries/LiquidityMath.sol b/contracts/dependencies/univ3/libraries/LiquidityMath.sol deleted file mode 100644 index 8aeb935ed..000000000 --- a/contracts/dependencies/univ3/libraries/LiquidityMath.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.5.0; - -/// @title Math library for liquidity -library LiquidityMath { - /// @notice Add a signed liquidity delta to liquidity and revert if it overflows or underflows - /// @param x The liquidity before change - /// @param y The delta by which liquidity should be changed - /// @return z The liquidity delta - function addDelta(uint128 x, int128 y) internal pure returns (uint128 z) { - if (y < 0) { - require((z = x - uint128(-y)) < x, "LS"); - } else { - require((z = x + uint128(y)) >= x, "LA"); - } - } -} diff --git a/contracts/dependencies/univ3/libraries/LowGasSafeMath.sol b/contracts/dependencies/univ3/libraries/LowGasSafeMath.sol deleted file mode 100644 index dbc817c2e..000000000 --- a/contracts/dependencies/univ3/libraries/LowGasSafeMath.sol +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity >=0.7.0; - -/// @title Optimized overflow and underflow safe math operations -/// @notice Contains methods for doing math operations that revert on overflow or underflow for minimal gas cost -library LowGasSafeMath { - /// @notice Returns x + y, reverts if sum overflows uint256 - /// @param x The augend - /// @param y The addend - /// @return z The sum of x and y - function add(uint256 x, uint256 y) internal pure returns (uint256 z) { - require((z = x + y) >= x); - } - - /// @notice Returns x - y, reverts if underflows - /// @param x The minuend - /// @param y The subtrahend - /// @return z The difference of x and y - function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { - require((z = x - y) <= x); - } - - /// @notice Returns x * y, reverts if overflows - /// @param x The multiplicand - /// @param y The multiplier - /// @return z The product of x and y - function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { - require(x == 0 || (z = x * y) / x == y); - } - - /// @notice Returns x + y, reverts if overflows or underflows - /// @param x The augend - /// @param y The addend - /// @return z The sum of x and y - function add(int256 x, int256 y) internal pure returns (int256 z) { - require((z = x + y) >= x == (y >= 0)); - } - - /// @notice Returns x - y, reverts if overflows or underflows - /// @param x The minuend - /// @param y The subtrahend - /// @return z The difference of x and y - function sub(int256 x, int256 y) internal pure returns (int256 z) { - require((z = x - y) <= x == (y >= 0)); - } -} diff --git a/contracts/dependencies/univ3/libraries/Oracle.sol b/contracts/dependencies/univ3/libraries/Oracle.sol deleted file mode 100644 index bf4ada318..000000000 --- a/contracts/dependencies/univ3/libraries/Oracle.sol +++ /dev/null @@ -1,378 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity >=0.5.0 <0.8.0; - -/// @title Oracle -/// @notice Provides price and liquidity data useful for a wide variety of system designs -/// @dev Instances of stored oracle data, "observations", are collected in the oracle array -/// Every pool is initialized with an oracle array length of 1. Anyone can pay the SSTOREs to increase the -/// maximum length of the oracle array. New slots will be added when the array is fully populated. -/// Observations are overwritten when the full length of the oracle array is populated. -/// The most recent observation is available, independent of the length of the oracle array, by passing 0 to observe() -library Oracle { - struct Observation { - // the block timestamp of the observation - uint32 blockTimestamp; - // the tick accumulator, i.e. tick * time elapsed since the pool was first initialized - int56 tickCumulative; - // the seconds per liquidity, i.e. seconds elapsed / max(1, liquidity) since the pool was first initialized - uint160 secondsPerLiquidityCumulativeX128; - // whether or not the observation is initialized - bool initialized; - } - - /// @notice Transforms a previous observation into a new observation, given the passage of time and the current tick and liquidity values - /// @dev blockTimestamp _must_ be chronologically equal to or greater than last.blockTimestamp, safe for 0 or 1 overflows - /// @param last The specified observation to be transformed - /// @param blockTimestamp The timestamp of the new observation - /// @param tick The active tick at the time of the new observation - /// @param liquidity The total in-range liquidity at the time of the new observation - /// @return Observation The newly populated observation - function transform( - Observation memory last, - uint32 blockTimestamp, - int24 tick, - uint128 liquidity - ) private pure returns (Observation memory) { - uint32 delta = blockTimestamp - last.blockTimestamp; - return - Observation({ - blockTimestamp: blockTimestamp, - tickCumulative: last.tickCumulative + int56(tick) * delta, - secondsPerLiquidityCumulativeX128: last - .secondsPerLiquidityCumulativeX128 + - ((uint160(delta) << 128) / (liquidity > 0 ? liquidity : 1)), - initialized: true - }); - } - - /// @notice Initialize the oracle array by writing the first slot. Called once for the lifecycle of the observations array - /// @param self The stored oracle array - /// @param time The time of the oracle initialization, via block.timestamp truncated to uint32 - /// @return cardinality The number of populated elements in the oracle array - /// @return cardinalityNext The new length of the oracle array, independent of population - function initialize(Observation[65535] storage self, uint32 time) - internal - returns (uint16 cardinality, uint16 cardinalityNext) - { - self[0] = Observation({ - blockTimestamp: time, - tickCumulative: 0, - secondsPerLiquidityCumulativeX128: 0, - initialized: true - }); - return (1, 1); - } - - /// @notice Writes an oracle observation to the array - /// @dev Writable at most once per block. Index represents the most recently written element. cardinality and index must be tracked externally. - /// If the index is at the end of the allowable array length (according to cardinality), and the next cardinality - /// is greater than the current one, cardinality may be increased. This restriction is created to preserve ordering. - /// @param self The stored oracle array - /// @param index The index of the observation that was most recently written to the observations array - /// @param blockTimestamp The timestamp of the new observation - /// @param tick The active tick at the time of the new observation - /// @param liquidity The total in-range liquidity at the time of the new observation - /// @param cardinality The number of populated elements in the oracle array - /// @param cardinalityNext The new length of the oracle array, independent of population - /// @return indexUpdated The new index of the most recently written element in the oracle array - /// @return cardinalityUpdated The new cardinality of the oracle array - function write( - Observation[65535] storage self, - uint16 index, - uint32 blockTimestamp, - int24 tick, - uint128 liquidity, - uint16 cardinality, - uint16 cardinalityNext - ) internal returns (uint16 indexUpdated, uint16 cardinalityUpdated) { - Observation memory last = self[index]; - - // early return if we've already written an observation this block - if (last.blockTimestamp == blockTimestamp) return (index, cardinality); - - // if the conditions are right, we can bump the cardinality - if (cardinalityNext > cardinality && index == (cardinality - 1)) { - cardinalityUpdated = cardinalityNext; - } else { - cardinalityUpdated = cardinality; - } - - indexUpdated = (index + 1) % cardinalityUpdated; - self[indexUpdated] = transform(last, blockTimestamp, tick, liquidity); - } - - /// @notice Prepares the oracle array to store up to `next` observations - /// @param self The stored oracle array - /// @param current The current next cardinality of the oracle array - /// @param next The proposed next cardinality which will be populated in the oracle array - /// @return next The next cardinality which will be populated in the oracle array - function grow( - Observation[65535] storage self, - uint16 current, - uint16 next - ) internal returns (uint16) { - require(current > 0, "I"); - // no-op if the passed next value isn't greater than the current next value - if (next <= current) return current; - // store in each slot to prevent fresh SSTOREs in swaps - // this data will not be used because the initialized boolean is still false - for (uint16 i = current; i < next; i++) self[i].blockTimestamp = 1; - return next; - } - - /// @notice comparator for 32-bit timestamps - /// @dev safe for 0 or 1 overflows, a and b _must_ be chronologically before or equal to time - /// @param time A timestamp truncated to 32 bits - /// @param a A comparison timestamp from which to determine the relative position of `time` - /// @param b From which to determine the relative position of `time` - /// @return bool Whether `a` is chronologically <= `b` - function lte( - uint32 time, - uint32 a, - uint32 b - ) private pure returns (bool) { - // if there hasn't been overflow, no need to adjust - if (a <= time && b <= time) return a <= b; - - uint256 aAdjusted = a > time ? a : a + 2**32; - uint256 bAdjusted = b > time ? b : b + 2**32; - - return aAdjusted <= bAdjusted; - } - - /// @notice Fetches the observations beforeOrAt and atOrAfter a target, i.e. where [beforeOrAt, atOrAfter] is satisfied. - /// The result may be the same observation, or adjacent observations. - /// @dev The answer must be contained in the array, used when the target is located within the stored observation - /// boundaries: older than the most recent observation and younger, or the same age as, the oldest observation - /// @param self The stored oracle array - /// @param time The current block.timestamp - /// @param target The timestamp at which the reserved observation should be for - /// @param index The index of the observation that was most recently written to the observations array - /// @param cardinality The number of populated elements in the oracle array - /// @return beforeOrAt The observation recorded before, or at, the target - /// @return atOrAfter The observation recorded at, or after, the target - function binarySearch( - Observation[65535] storage self, - uint32 time, - uint32 target, - uint16 index, - uint16 cardinality - ) - private - view - returns (Observation memory beforeOrAt, Observation memory atOrAfter) - { - uint256 l = (index + 1) % cardinality; // oldest observation - uint256 r = l + cardinality - 1; // newest observation - uint256 i; - while (true) { - i = (l + r) / 2; - - beforeOrAt = self[i % cardinality]; - - // we've landed on an uninitialized tick, keep searching higher (more recently) - if (!beforeOrAt.initialized) { - l = i + 1; - continue; - } - - atOrAfter = self[(i + 1) % cardinality]; - - bool targetAtOrAfter = lte(time, beforeOrAt.blockTimestamp, target); - - // check if we've found the answer! - if (targetAtOrAfter && lte(time, target, atOrAfter.blockTimestamp)) - break; - - if (!targetAtOrAfter) r = i - 1; - else l = i + 1; - } - } - - /// @notice Fetches the observations beforeOrAt and atOrAfter a given target, i.e. where [beforeOrAt, atOrAfter] is satisfied - /// @dev Assumes there is at least 1 initialized observation. - /// Used by observeSingle() to compute the counterfactual accumulator values as of a given block timestamp. - /// @param self The stored oracle array - /// @param time The current block.timestamp - /// @param target The timestamp at which the reserved observation should be for - /// @param tick The active tick at the time of the returned or simulated observation - /// @param index The index of the observation that was most recently written to the observations array - /// @param liquidity The total pool liquidity at the time of the call - /// @param cardinality The number of populated elements in the oracle array - /// @return beforeOrAt The observation which occurred at, or before, the given timestamp - /// @return atOrAfter The observation which occurred at, or after, the given timestamp - function getSurroundingObservations( - Observation[65535] storage self, - uint32 time, - uint32 target, - int24 tick, - uint16 index, - uint128 liquidity, - uint16 cardinality - ) - private - view - returns (Observation memory beforeOrAt, Observation memory atOrAfter) - { - // optimistically set before to the newest observation - beforeOrAt = self[index]; - - // if the target is chronologically at or after the newest observation, we can early return - if (lte(time, beforeOrAt.blockTimestamp, target)) { - if (beforeOrAt.blockTimestamp == target) { - // if newest observation equals target, we're in the same block, so we can ignore atOrAfter - return (beforeOrAt, atOrAfter); - } else { - // otherwise, we need to transform - return ( - beforeOrAt, - transform(beforeOrAt, target, tick, liquidity) - ); - } - } - - // now, set before to the oldest observation - beforeOrAt = self[(index + 1) % cardinality]; - if (!beforeOrAt.initialized) beforeOrAt = self[0]; - - // ensure that the target is chronologically at or after the oldest observation - require(lte(time, beforeOrAt.blockTimestamp, target), "OLD"); - - // if we've reached this point, we have to binary search - return binarySearch(self, time, target, index, cardinality); - } - - /// @dev Reverts if an observation at or before the desired observation timestamp does not exist. - /// 0 may be passed as `secondsAgo' to return the current cumulative values. - /// If called with a timestamp falling between two observations, returns the counterfactual accumulator values - /// at exactly the timestamp between the two observations. - /// @param self The stored oracle array - /// @param time The current block timestamp - /// @param secondsAgo The amount of time to look back, in seconds, at which point to return an observation - /// @param tick The current tick - /// @param index The index of the observation that was most recently written to the observations array - /// @param liquidity The current in-range pool liquidity - /// @param cardinality The number of populated elements in the oracle array - /// @return tickCumulative The tick * time elapsed since the pool was first initialized, as of `secondsAgo` - /// @return secondsPerLiquidityCumulativeX128 The time elapsed / max(1, liquidity) since the pool was first initialized, as of `secondsAgo` - function observeSingle( - Observation[65535] storage self, - uint32 time, - uint32 secondsAgo, - int24 tick, - uint16 index, - uint128 liquidity, - uint16 cardinality - ) - internal - view - returns ( - int56 tickCumulative, - uint160 secondsPerLiquidityCumulativeX128 - ) - { - if (secondsAgo == 0) { - Observation memory last = self[index]; - if (last.blockTimestamp != time) - last = transform(last, time, tick, liquidity); - return ( - last.tickCumulative, - last.secondsPerLiquidityCumulativeX128 - ); - } - - uint32 target = time - secondsAgo; - - ( - Observation memory beforeOrAt, - Observation memory atOrAfter - ) = getSurroundingObservations( - self, - time, - target, - tick, - index, - liquidity, - cardinality - ); - - if (target == beforeOrAt.blockTimestamp) { - // we're at the left boundary - return ( - beforeOrAt.tickCumulative, - beforeOrAt.secondsPerLiquidityCumulativeX128 - ); - } else if (target == atOrAfter.blockTimestamp) { - // we're at the right boundary - return ( - atOrAfter.tickCumulative, - atOrAfter.secondsPerLiquidityCumulativeX128 - ); - } else { - // we're in the middle - uint32 observationTimeDelta = atOrAfter.blockTimestamp - - beforeOrAt.blockTimestamp; - uint32 targetDelta = target - beforeOrAt.blockTimestamp; - return ( - beforeOrAt.tickCumulative + - ((atOrAfter.tickCumulative - beforeOrAt.tickCumulative) / - observationTimeDelta) * - targetDelta, - beforeOrAt.secondsPerLiquidityCumulativeX128 + - uint160( - (uint256( - atOrAfter.secondsPerLiquidityCumulativeX128 - - beforeOrAt.secondsPerLiquidityCumulativeX128 - ) * targetDelta) / observationTimeDelta - ) - ); - } - } - - /// @notice Returns the accumulator values as of each time seconds ago from the given time in the array of `secondsAgos` - /// @dev Reverts if `secondsAgos` > oldest observation - /// @param self The stored oracle array - /// @param time The current block.timestamp - /// @param secondsAgos Each amount of time to look back, in seconds, at which point to return an observation - /// @param tick The current tick - /// @param index The index of the observation that was most recently written to the observations array - /// @param liquidity The current in-range pool liquidity - /// @param cardinality The number of populated elements in the oracle array - /// @return tickCumulatives The tick * time elapsed since the pool was first initialized, as of each `secondsAgo` - /// @return secondsPerLiquidityCumulativeX128s The cumulative seconds / max(1, liquidity) since the pool was first initialized, as of each `secondsAgo` - function observe( - Observation[65535] storage self, - uint32 time, - uint32[] memory secondsAgos, - int24 tick, - uint16 index, - uint128 liquidity, - uint16 cardinality - ) - internal - view - returns ( - int56[] memory tickCumulatives, - uint160[] memory secondsPerLiquidityCumulativeX128s - ) - { - require(cardinality > 0, "I"); - - tickCumulatives = new int56[](secondsAgos.length); - secondsPerLiquidityCumulativeX128s = new uint160[](secondsAgos.length); - for (uint256 i = 0; i < secondsAgos.length; i++) { - ( - tickCumulatives[i], - secondsPerLiquidityCumulativeX128s[i] - ) = observeSingle( - self, - time, - secondsAgos[i], - tick, - index, - liquidity, - cardinality - ); - } - } -} diff --git a/contracts/dependencies/univ3/libraries/Position.sol b/contracts/dependencies/univ3/libraries/Position.sol deleted file mode 100644 index 392f35ac5..000000000 --- a/contracts/dependencies/univ3/libraries/Position.sol +++ /dev/null @@ -1,91 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity >=0.5.0 <0.8.0; - -import "./FullMath.sol"; -import "./FixedPoint128.sol"; -import "./LiquidityMath.sol"; - -/// @title Position -/// @notice Positions represent an owner address' liquidity between a lower and upper tick boundary -/// @dev Positions store additional state for tracking fees owed to the position -library Position { - // info stored for each user's position - struct Info { - // the amount of liquidity owned by this position - uint128 liquidity; - // fee growth per unit of liquidity as of the last update to liquidity or fees owed - uint256 feeGrowthInside0LastX128; - uint256 feeGrowthInside1LastX128; - // the fees owed to the position owner in token0/token1 - uint128 tokensOwed0; - uint128 tokensOwed1; - } - - /// @notice Returns the Info struct of a position, given an owner and position boundaries - /// @param self The mapping containing all user positions - /// @param owner The address of the position owner - /// @param tickLower The lower tick boundary of the position - /// @param tickUpper The upper tick boundary of the position - /// @return position The position info struct of the given owners' position - function get( - mapping(bytes32 => Info) storage self, - address owner, - int24 tickLower, - int24 tickUpper - ) internal view returns (Position.Info storage position) { - position = self[ - keccak256(abi.encodePacked(owner, tickLower, tickUpper)) - ]; - } - - /// @notice Credits accumulated fees to a user's position - /// @param self The individual position to update - /// @param liquidityDelta The change in pool liquidity as a result of the position update - /// @param feeGrowthInside0X128 The all-time fee growth in token0, per unit of liquidity, inside the position's tick boundaries - /// @param feeGrowthInside1X128 The all-time fee growth in token1, per unit of liquidity, inside the position's tick boundaries - function update( - Info storage self, - int128 liquidityDelta, - uint256 feeGrowthInside0X128, - uint256 feeGrowthInside1X128 - ) internal { - Info memory _self = self; - - uint128 liquidityNext; - if (liquidityDelta == 0) { - require(_self.liquidity > 0, "NP"); // disallow pokes for 0 liquidity positions - liquidityNext = _self.liquidity; - } else { - liquidityNext = LiquidityMath.addDelta( - _self.liquidity, - liquidityDelta - ); - } - - // calculate accumulated fees - uint128 tokensOwed0 = uint128( - FullMath.mulDiv( - feeGrowthInside0X128 - _self.feeGrowthInside0LastX128, - _self.liquidity, - FixedPoint128.Q128 - ) - ); - uint128 tokensOwed1 = uint128( - FullMath.mulDiv( - feeGrowthInside1X128 - _self.feeGrowthInside1LastX128, - _self.liquidity, - FixedPoint128.Q128 - ) - ); - - // update the position - if (liquidityDelta != 0) self.liquidity = liquidityNext; - self.feeGrowthInside0LastX128 = feeGrowthInside0X128; - self.feeGrowthInside1LastX128 = feeGrowthInside1X128; - if (tokensOwed0 > 0 || tokensOwed1 > 0) { - // overflow is acceptable, have to withdraw before you hit type(uint128).max fees - self.tokensOwed0 += tokensOwed0; - self.tokensOwed1 += tokensOwed1; - } - } -} diff --git a/contracts/dependencies/univ3/libraries/SqrtPriceMath.sol b/contracts/dependencies/univ3/libraries/SqrtPriceMath.sol deleted file mode 100644 index a1e97426b..000000000 --- a/contracts/dependencies/univ3/libraries/SqrtPriceMath.sol +++ /dev/null @@ -1,306 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity >=0.5.0; - -import "./LowGasSafeMath.sol"; -import "./SafeCast.sol"; - -import "./FullMath.sol"; -import "./UnsafeMath.sol"; -import "./FixedPoint96.sol"; - -/// @title Functions based on Q64.96 sqrt price and liquidity -/// @notice Contains the math that uses square root of price as a Q64.96 and liquidity to compute deltas -library SqrtPriceMath { - using LowGasSafeMath for uint256; - using SafeCast for uint256; - - /// @notice Gets the next sqrt price given a delta of token0 - /// @dev Always rounds up, because in the exact output case (increasing price) we need to move the price at least - /// far enough to get the desired output amount, and in the exact input case (decreasing price) we need to move the - /// price less in order to not send too much output. - /// The most precise formula for this is liquidity * sqrtPX96 / (liquidity +- amount * sqrtPX96), - /// if this is impossible because of overflow, we calculate liquidity / (liquidity / sqrtPX96 +- amount). - /// @param sqrtPX96 The starting price, i.e. before accounting for the token0 delta - /// @param liquidity The amount of usable liquidity - /// @param amount How much of token0 to add or remove from virtual reserves - /// @param add Whether to add or remove the amount of token0 - /// @return The price after adding or removing amount, depending on add - function getNextSqrtPriceFromAmount0RoundingUp( - uint160 sqrtPX96, - uint128 liquidity, - uint256 amount, - bool add - ) internal pure returns (uint160) { - // we short circuit amount == 0 because the result is otherwise not guaranteed to equal the input price - if (amount == 0) return sqrtPX96; - uint256 numerator1 = uint256(liquidity) << FixedPoint96.RESOLUTION; - - if (add) { - uint256 product; - if ((product = amount * sqrtPX96) / amount == sqrtPX96) { - uint256 denominator = numerator1 + product; - if (denominator >= numerator1) - // always fits in 160 bits - return - uint160( - FullMath.mulDivRoundingUp( - numerator1, - sqrtPX96, - denominator - ) - ); - } - - return - uint160( - UnsafeMath.divRoundingUp( - numerator1, - (numerator1 / sqrtPX96).add(amount) - ) - ); - } else { - uint256 product; - // if the product overflows, we know the denominator underflows - // in addition, we must check that the denominator does not underflow - require( - (product = amount * sqrtPX96) / amount == sqrtPX96 && - numerator1 > product - ); - uint256 denominator = numerator1 - product; - return - FullMath - .mulDivRoundingUp(numerator1, sqrtPX96, denominator) - .toUint160(); - } - } - - /// @notice Gets the next sqrt price given a delta of token1 - /// @dev Always rounds down, because in the exact output case (decreasing price) we need to move the price at least - /// far enough to get the desired output amount, and in the exact input case (increasing price) we need to move the - /// price less in order to not send too much output. - /// The formula we compute is within <1 wei of the lossless version: sqrtPX96 +- amount / liquidity - /// @param sqrtPX96 The starting price, i.e., before accounting for the token1 delta - /// @param liquidity The amount of usable liquidity - /// @param amount How much of token1 to add, or remove, from virtual reserves - /// @param add Whether to add, or remove, the amount of token1 - /// @return The price after adding or removing `amount` - function getNextSqrtPriceFromAmount1RoundingDown( - uint160 sqrtPX96, - uint128 liquidity, - uint256 amount, - bool add - ) internal pure returns (uint160) { - // if we're adding (subtracting), rounding down requires rounding the quotient down (up) - // in both cases, avoid a mulDiv for most inputs - if (add) { - uint256 quotient = ( - amount <= type(uint160).max - ? (amount << FixedPoint96.RESOLUTION) / liquidity - : FullMath.mulDiv(amount, FixedPoint96.Q96, liquidity) - ); - - return uint256(sqrtPX96).add(quotient).toUint160(); - } else { - uint256 quotient = ( - amount <= type(uint160).max - ? UnsafeMath.divRoundingUp( - amount << FixedPoint96.RESOLUTION, - liquidity - ) - : FullMath.mulDivRoundingUp( - amount, - FixedPoint96.Q96, - liquidity - ) - ); - - require(sqrtPX96 > quotient); - // always fits 160 bits - return uint160(sqrtPX96 - quotient); - } - } - - /// @notice Gets the next sqrt price given an input amount of token0 or token1 - /// @dev Throws if price or liquidity are 0, or if the next price is out of bounds - /// @param sqrtPX96 The starting price, i.e., before accounting for the input amount - /// @param liquidity The amount of usable liquidity - /// @param amountIn How much of token0, or token1, is being swapped in - /// @param zeroForOne Whether the amount in is token0 or token1 - /// @return sqrtQX96 The price after adding the input amount to token0 or token1 - function getNextSqrtPriceFromInput( - uint160 sqrtPX96, - uint128 liquidity, - uint256 amountIn, - bool zeroForOne - ) internal pure returns (uint160 sqrtQX96) { - require(sqrtPX96 > 0); - require(liquidity > 0); - - // round to make sure that we don't pass the target price - return - zeroForOne - ? getNextSqrtPriceFromAmount0RoundingUp( - sqrtPX96, - liquidity, - amountIn, - true - ) - : getNextSqrtPriceFromAmount1RoundingDown( - sqrtPX96, - liquidity, - amountIn, - true - ); - } - - /// @notice Gets the next sqrt price given an output amount of token0 or token1 - /// @dev Throws if price or liquidity are 0 or the next price is out of bounds - /// @param sqrtPX96 The starting price before accounting for the output amount - /// @param liquidity The amount of usable liquidity - /// @param amountOut How much of token0, or token1, is being swapped out - /// @param zeroForOne Whether the amount out is token0 or token1 - /// @return sqrtQX96 The price after removing the output amount of token0 or token1 - function getNextSqrtPriceFromOutput( - uint160 sqrtPX96, - uint128 liquidity, - uint256 amountOut, - bool zeroForOne - ) internal pure returns (uint160 sqrtQX96) { - require(sqrtPX96 > 0); - require(liquidity > 0); - - // round to make sure that we pass the target price - return - zeroForOne - ? getNextSqrtPriceFromAmount1RoundingDown( - sqrtPX96, - liquidity, - amountOut, - false - ) - : getNextSqrtPriceFromAmount0RoundingUp( - sqrtPX96, - liquidity, - amountOut, - false - ); - } - - /// @notice Gets the amount0 delta between two prices - /// @dev Calculates liquidity / sqrt(lower) - liquidity / sqrt(upper), - /// i.e. liquidity * (sqrt(upper) - sqrt(lower)) / (sqrt(upper) * sqrt(lower)) - /// @param sqrtRatioAX96 A sqrt price - /// @param sqrtRatioBX96 Another sqrt price - /// @param liquidity The amount of usable liquidity - /// @param roundUp Whether to round the amount up or down - /// @return amount0 Amount of token0 required to cover a position of size liquidity between the two passed prices - function getAmount0Delta( - uint160 sqrtRatioAX96, - uint160 sqrtRatioBX96, - uint128 liquidity, - bool roundUp - ) internal pure returns (uint256 amount0) { - if (sqrtRatioAX96 > sqrtRatioBX96) - (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); - - uint256 numerator1 = uint256(liquidity) << FixedPoint96.RESOLUTION; - uint256 numerator2 = sqrtRatioBX96 - sqrtRatioAX96; - - require(sqrtRatioAX96 > 0); - - return - roundUp - ? UnsafeMath.divRoundingUp( - FullMath.mulDivRoundingUp( - numerator1, - numerator2, - sqrtRatioBX96 - ), - sqrtRatioAX96 - ) - : FullMath.mulDiv(numerator1, numerator2, sqrtRatioBX96) / - sqrtRatioAX96; - } - - /// @notice Gets the amount1 delta between two prices - /// @dev Calculates liquidity * (sqrt(upper) - sqrt(lower)) - /// @param sqrtRatioAX96 A sqrt price - /// @param sqrtRatioBX96 Another sqrt price - /// @param liquidity The amount of usable liquidity - /// @param roundUp Whether to round the amount up, or down - /// @return amount1 Amount of token1 required to cover a position of size liquidity between the two passed prices - function getAmount1Delta( - uint160 sqrtRatioAX96, - uint160 sqrtRatioBX96, - uint128 liquidity, - bool roundUp - ) internal pure returns (uint256 amount1) { - if (sqrtRatioAX96 > sqrtRatioBX96) - (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); - - return - roundUp - ? FullMath.mulDivRoundingUp( - liquidity, - sqrtRatioBX96 - sqrtRatioAX96, - FixedPoint96.Q96 - ) - : FullMath.mulDiv( - liquidity, - sqrtRatioBX96 - sqrtRatioAX96, - FixedPoint96.Q96 - ); - } - - /// @notice Helper that gets signed token0 delta - /// @param sqrtRatioAX96 A sqrt price - /// @param sqrtRatioBX96 Another sqrt price - /// @param liquidity The change in liquidity for which to compute the amount0 delta - /// @return amount0 Amount of token0 corresponding to the passed liquidityDelta between the two prices - function getAmount0Delta( - uint160 sqrtRatioAX96, - uint160 sqrtRatioBX96, - int128 liquidity - ) internal pure returns (int256 amount0) { - return - liquidity < 0 - ? -getAmount0Delta( - sqrtRatioAX96, - sqrtRatioBX96, - uint128(-liquidity), - false - ).toInt256() - : getAmount0Delta( - sqrtRatioAX96, - sqrtRatioBX96, - uint128(liquidity), - true - ).toInt256(); - } - - /// @notice Helper that gets signed token1 delta - /// @param sqrtRatioAX96 A sqrt price - /// @param sqrtRatioBX96 Another sqrt price - /// @param liquidity The change in liquidity for which to compute the amount1 delta - /// @return amount1 Amount of token1 corresponding to the passed liquidityDelta between the two prices - function getAmount1Delta( - uint160 sqrtRatioAX96, - uint160 sqrtRatioBX96, - int128 liquidity - ) internal pure returns (int256 amount1) { - return - liquidity < 0 - ? -getAmount1Delta( - sqrtRatioAX96, - sqrtRatioBX96, - uint128(-liquidity), - false - ).toInt256() - : getAmount1Delta( - sqrtRatioAX96, - sqrtRatioBX96, - uint128(liquidity), - true - ).toInt256(); - } -} diff --git a/contracts/dependencies/univ3/libraries/SwapMath.sol b/contracts/dependencies/univ3/libraries/SwapMath.sol deleted file mode 100644 index ed9073206..000000000 --- a/contracts/dependencies/univ3/libraries/SwapMath.sol +++ /dev/null @@ -1,148 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity >=0.5.0; - -import "./FullMath.sol"; -import "./SqrtPriceMath.sol"; - -/// @title Computes the result of a swap within ticks -/// @notice Contains methods for computing the result of a swap within a single tick price range, i.e., a single tick. -library SwapMath { - /// @notice Computes the result of swapping some amount in, or amount out, given the parameters of the swap - /// @dev The fee, plus the amount in, will never exceed the amount remaining if the swap's `amountSpecified` is positive - /// @param sqrtRatioCurrentX96 The current sqrt price of the pool - /// @param sqrtRatioTargetX96 The price that cannot be exceeded, from which the direction of the swap is inferred - /// @param liquidity The usable liquidity - /// @param amountRemaining How much input or output amount is remaining to be swapped in/out - /// @param feePips The fee taken from the input amount, expressed in hundredths of a bip - /// @return sqrtRatioNextX96 The price after swapping the amount in/out, not to exceed the price target - /// @return amountIn The amount to be swapped in, of either token0 or token1, based on the direction of the swap - /// @return amountOut The amount to be received, of either token0 or token1, based on the direction of the swap - /// @return feeAmount The amount of input that will be taken as a fee - function computeSwapStep( - uint160 sqrtRatioCurrentX96, - uint160 sqrtRatioTargetX96, - uint128 liquidity, - int256 amountRemaining, - uint24 feePips - ) - internal - pure - returns ( - uint160 sqrtRatioNextX96, - uint256 amountIn, - uint256 amountOut, - uint256 feeAmount - ) - { - bool zeroForOne = sqrtRatioCurrentX96 >= sqrtRatioTargetX96; - bool exactIn = amountRemaining >= 0; - - if (exactIn) { - uint256 amountRemainingLessFee = FullMath.mulDiv( - uint256(amountRemaining), - 1e6 - feePips, - 1e6 - ); - amountIn = zeroForOne - ? SqrtPriceMath.getAmount0Delta( - sqrtRatioTargetX96, - sqrtRatioCurrentX96, - liquidity, - true - ) - : SqrtPriceMath.getAmount1Delta( - sqrtRatioCurrentX96, - sqrtRatioTargetX96, - liquidity, - true - ); - if (amountRemainingLessFee >= amountIn) - sqrtRatioNextX96 = sqrtRatioTargetX96; - else - sqrtRatioNextX96 = SqrtPriceMath.getNextSqrtPriceFromInput( - sqrtRatioCurrentX96, - liquidity, - amountRemainingLessFee, - zeroForOne - ); - } else { - amountOut = zeroForOne - ? SqrtPriceMath.getAmount1Delta( - sqrtRatioTargetX96, - sqrtRatioCurrentX96, - liquidity, - false - ) - : SqrtPriceMath.getAmount0Delta( - sqrtRatioCurrentX96, - sqrtRatioTargetX96, - liquidity, - false - ); - if (uint256(-amountRemaining) >= amountOut) - sqrtRatioNextX96 = sqrtRatioTargetX96; - else - sqrtRatioNextX96 = SqrtPriceMath.getNextSqrtPriceFromOutput( - sqrtRatioCurrentX96, - liquidity, - uint256(-amountRemaining), - zeroForOne - ); - } - - bool max = sqrtRatioTargetX96 == sqrtRatioNextX96; - - // get the input/output amounts - if (zeroForOne) { - amountIn = max && exactIn - ? amountIn - : SqrtPriceMath.getAmount0Delta( - sqrtRatioNextX96, - sqrtRatioCurrentX96, - liquidity, - true - ); - amountOut = max && !exactIn - ? amountOut - : SqrtPriceMath.getAmount1Delta( - sqrtRatioNextX96, - sqrtRatioCurrentX96, - liquidity, - false - ); - } else { - amountIn = max && exactIn - ? amountIn - : SqrtPriceMath.getAmount1Delta( - sqrtRatioCurrentX96, - sqrtRatioNextX96, - liquidity, - true - ); - amountOut = max && !exactIn - ? amountOut - : SqrtPriceMath.getAmount0Delta( - sqrtRatioCurrentX96, - sqrtRatioNextX96, - liquidity, - false - ); - } - - // cap the output amount to not exceed the remaining output amount - if (!exactIn && amountOut > uint256(-amountRemaining)) { - amountOut = uint256(-amountRemaining); - } - - if (exactIn && sqrtRatioNextX96 != sqrtRatioTargetX96) { - // we didn't reach the target, so take the remainder of the maximum input as fee - feeAmount = uint256(amountRemaining) - amountIn; - } else { - feeAmount = FullMath.mulDivRoundingUp( - amountIn, - feePips, - 1e6 - feePips - ); - } - } -} diff --git a/contracts/dependencies/univ3/libraries/Tick.sol b/contracts/dependencies/univ3/libraries/Tick.sol deleted file mode 100644 index b79346db1..000000000 --- a/contracts/dependencies/univ3/libraries/Tick.sol +++ /dev/null @@ -1,221 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity >=0.5.0 <0.8.0; - -import "./LowGasSafeMath.sol"; -import "./SafeCast.sol"; - -import "./TickMath.sol"; -import "./LiquidityMath.sol"; - -/// @title Tick -/// @notice Contains functions for managing tick processes and relevant calculations -library Tick { - using LowGasSafeMath for int256; - using SafeCast for int256; - - // info stored for each initialized individual tick - struct Info { - // the total position liquidity that references this tick - uint128 liquidityGross; - // amount of net liquidity added (subtracted) when tick is crossed from left to right (right to left), - int128 liquidityNet; - // fee growth per unit of liquidity on the _other_ side of this tick (relative to the current tick) - // only has relative meaning, not absolute — the value depends on when the tick is initialized - uint256 feeGrowthOutside0X128; - uint256 feeGrowthOutside1X128; - // the cumulative tick value on the other side of the tick - int56 tickCumulativeOutside; - // the seconds per unit of liquidity on the _other_ side of this tick (relative to the current tick) - // only has relative meaning, not absolute — the value depends on when the tick is initialized - uint160 secondsPerLiquidityOutsideX128; - // the seconds spent on the other side of the tick (relative to the current tick) - // only has relative meaning, not absolute — the value depends on when the tick is initialized - uint32 secondsOutside; - // true iff the tick is initialized, i.e. the value is exactly equivalent to the expression liquidityGross != 0 - // these 8 bits are set to prevent fresh sstores when crossing newly initialized ticks - bool initialized; - } - - /// @notice Derives max liquidity per tick from given tick spacing - /// @dev Executed within the pool constructor - /// @param tickSpacing The amount of required tick separation, realized in multiples of `tickSpacing` - /// e.g., a tickSpacing of 3 requires ticks to be initialized every 3rd tick i.e., ..., -6, -3, 0, 3, 6, ... - /// @return The max liquidity per tick - function tickSpacingToMaxLiquidityPerTick(int24 tickSpacing) - internal - pure - returns (uint128) - { - int24 minTick = (TickMath.MIN_TICK / tickSpacing) * tickSpacing; - int24 maxTick = (TickMath.MAX_TICK / tickSpacing) * tickSpacing; - uint24 numTicks = uint24((maxTick - minTick) / tickSpacing) + 1; - return type(uint128).max / numTicks; - } - - /// @notice Retrieves fee growth data - /// @param self The mapping containing all tick information for initialized ticks - /// @param tickLower The lower tick boundary of the position - /// @param tickUpper The upper tick boundary of the position - /// @param tickCurrent The current tick - /// @param feeGrowthGlobal0X128 The all-time global fee growth, per unit of liquidity, in token0 - /// @param feeGrowthGlobal1X128 The all-time global fee growth, per unit of liquidity, in token1 - /// @return feeGrowthInside0X128 The all-time fee growth in token0, per unit of liquidity, inside the position's tick boundaries - /// @return feeGrowthInside1X128 The all-time fee growth in token1, per unit of liquidity, inside the position's tick boundaries - function getFeeGrowthInside( - mapping(int24 => Tick.Info) storage self, - int24 tickLower, - int24 tickUpper, - int24 tickCurrent, - uint256 feeGrowthGlobal0X128, - uint256 feeGrowthGlobal1X128 - ) - internal - view - returns (uint256 feeGrowthInside0X128, uint256 feeGrowthInside1X128) - { - Info storage lower = self[tickLower]; - Info storage upper = self[tickUpper]; - - // calculate fee growth below - uint256 feeGrowthBelow0X128; - uint256 feeGrowthBelow1X128; - if (tickCurrent >= tickLower) { - feeGrowthBelow0X128 = lower.feeGrowthOutside0X128; - feeGrowthBelow1X128 = lower.feeGrowthOutside1X128; - } else { - feeGrowthBelow0X128 = - feeGrowthGlobal0X128 - - lower.feeGrowthOutside0X128; - feeGrowthBelow1X128 = - feeGrowthGlobal1X128 - - lower.feeGrowthOutside1X128; - } - - // calculate fee growth above - uint256 feeGrowthAbove0X128; - uint256 feeGrowthAbove1X128; - if (tickCurrent < tickUpper) { - feeGrowthAbove0X128 = upper.feeGrowthOutside0X128; - feeGrowthAbove1X128 = upper.feeGrowthOutside1X128; - } else { - feeGrowthAbove0X128 = - feeGrowthGlobal0X128 - - upper.feeGrowthOutside0X128; - feeGrowthAbove1X128 = - feeGrowthGlobal1X128 - - upper.feeGrowthOutside1X128; - } - - feeGrowthInside0X128 = - feeGrowthGlobal0X128 - - feeGrowthBelow0X128 - - feeGrowthAbove0X128; - feeGrowthInside1X128 = - feeGrowthGlobal1X128 - - feeGrowthBelow1X128 - - feeGrowthAbove1X128; - } - - /// @notice Updates a tick and returns true if the tick was flipped from initialized to uninitialized, or vice versa - /// @param self The mapping containing all tick information for initialized ticks - /// @param tick The tick that will be updated - /// @param tickCurrent The current tick - /// @param liquidityDelta A new amount of liquidity to be added (subtracted) when tick is crossed from left to right (right to left) - /// @param feeGrowthGlobal0X128 The all-time global fee growth, per unit of liquidity, in token0 - /// @param feeGrowthGlobal1X128 The all-time global fee growth, per unit of liquidity, in token1 - /// @param secondsPerLiquidityCumulativeX128 The all-time seconds per max(1, liquidity) of the pool - /// @param tickCumulative The tick * time elapsed since the pool was first initialized - /// @param time The current block timestamp cast to a uint32 - /// @param upper true for updating a position's upper tick, or false for updating a position's lower tick - /// @param maxLiquidity The maximum liquidity allocation for a single tick - /// @return flipped Whether the tick was flipped from initialized to uninitialized, or vice versa - function update( - mapping(int24 => Tick.Info) storage self, - int24 tick, - int24 tickCurrent, - int128 liquidityDelta, - uint256 feeGrowthGlobal0X128, - uint256 feeGrowthGlobal1X128, - uint160 secondsPerLiquidityCumulativeX128, - int56 tickCumulative, - uint32 time, - bool upper, - uint128 maxLiquidity - ) internal returns (bool flipped) { - Tick.Info storage info = self[tick]; - - uint128 liquidityGrossBefore = info.liquidityGross; - uint128 liquidityGrossAfter = LiquidityMath.addDelta( - liquidityGrossBefore, - liquidityDelta - ); - - require(liquidityGrossAfter <= maxLiquidity, "LO"); - - flipped = (liquidityGrossAfter == 0) != (liquidityGrossBefore == 0); - - if (liquidityGrossBefore == 0) { - // by convention, we assume that all growth before a tick was initialized happened _below_ the tick - if (tick <= tickCurrent) { - info.feeGrowthOutside0X128 = feeGrowthGlobal0X128; - info.feeGrowthOutside1X128 = feeGrowthGlobal1X128; - info - .secondsPerLiquidityOutsideX128 = secondsPerLiquidityCumulativeX128; - info.tickCumulativeOutside = tickCumulative; - info.secondsOutside = time; - } - info.initialized = true; - } - - info.liquidityGross = liquidityGrossAfter; - - // when the lower (upper) tick is crossed left to right (right to left), liquidity must be added (removed) - info.liquidityNet = upper - ? int256(info.liquidityNet).sub(liquidityDelta).toInt128() - : int256(info.liquidityNet).add(liquidityDelta).toInt128(); - } - - /// @notice Clears tick data - /// @param self The mapping containing all initialized tick information for initialized ticks - /// @param tick The tick that will be cleared - function clear(mapping(int24 => Tick.Info) storage self, int24 tick) - internal - { - delete self[tick]; - } - - /// @notice Transitions to next tick as needed by price movement - /// @param self The mapping containing all tick information for initialized ticks - /// @param tick The destination tick of the transition - /// @param feeGrowthGlobal0X128 The all-time global fee growth, per unit of liquidity, in token0 - /// @param feeGrowthGlobal1X128 The all-time global fee growth, per unit of liquidity, in token1 - /// @param secondsPerLiquidityCumulativeX128 The current seconds per liquidity - /// @param tickCumulative The tick * time elapsed since the pool was first initialized - /// @param time The current block.timestamp - /// @return liquidityNet The amount of liquidity added (subtracted) when tick is crossed from left to right (right to left) - function cross( - mapping(int24 => Tick.Info) storage self, - int24 tick, - uint256 feeGrowthGlobal0X128, - uint256 feeGrowthGlobal1X128, - uint160 secondsPerLiquidityCumulativeX128, - int56 tickCumulative, - uint32 time - ) internal returns (int128 liquidityNet) { - Tick.Info storage info = self[tick]; - info.feeGrowthOutside0X128 = - feeGrowthGlobal0X128 - - info.feeGrowthOutside0X128; - info.feeGrowthOutside1X128 = - feeGrowthGlobal1X128 - - info.feeGrowthOutside1X128; - info.secondsPerLiquidityOutsideX128 = - secondsPerLiquidityCumulativeX128 - - info.secondsPerLiquidityOutsideX128; - info.tickCumulativeOutside = - tickCumulative - - info.tickCumulativeOutside; - info.secondsOutside = time - info.secondsOutside; - liquidityNet = info.liquidityNet; - } -} diff --git a/contracts/dependencies/univ3/libraries/TickBitmap.sol b/contracts/dependencies/univ3/libraries/TickBitmap.sol deleted file mode 100644 index 11e124fa2..000000000 --- a/contracts/dependencies/univ3/libraries/TickBitmap.sol +++ /dev/null @@ -1,88 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity >=0.5.0 <0.8.0; - -import "./BitMath.sol"; - -/// @title Packed tick initialized state library -/// @notice Stores a packed mapping of tick index to its initialized state -/// @dev The mapping uses int16 for keys since ticks are represented as int24 and there are 256 (2^8) values per word. -library TickBitmap { - /// @notice Computes the position in the mapping where the initialized bit for a tick lives - /// @param tick The tick for which to compute the position - /// @return wordPos The key in the mapping containing the word in which the bit is stored - /// @return bitPos The bit position in the word where the flag is stored - function position(int24 tick) - private - pure - returns (int16 wordPos, uint8 bitPos) - { - wordPos = int16(tick >> 8); - bitPos = uint8(tick % 256); - } - - /// @notice Flips the initialized state for a given tick from false to true, or vice versa - /// @param self The mapping in which to flip the tick - /// @param tick The tick to flip - /// @param tickSpacing The spacing between usable ticks - function flipTick( - mapping(int16 => uint256) storage self, - int24 tick, - int24 tickSpacing - ) internal { - require(tick % tickSpacing == 0); // ensure that the tick is spaced - (int16 wordPos, uint8 bitPos) = position(tick / tickSpacing); - uint256 mask = 1 << bitPos; - self[wordPos] ^= mask; - } - - /// @notice Returns the next initialized tick contained in the same word (or adjacent word) as the tick that is either - /// to the left (less than or equal to) or right (greater than) of the given tick - /// @param self The mapping in which to compute the next initialized tick - /// @param tick The starting tick - /// @param tickSpacing The spacing between usable ticks - /// @param lte Whether to search for the next initialized tick to the left (less than or equal to the starting tick) - /// @return next The next initialized or uninitialized tick up to 256 ticks away from the current tick - /// @return initialized Whether the next tick is initialized, as the function only searches within up to 256 ticks - function nextInitializedTickWithinOneWord( - mapping(int16 => uint256) storage self, - int24 tick, - int24 tickSpacing, - bool lte - ) internal view returns (int24 next, bool initialized) { - int24 compressed = tick / tickSpacing; - if (tick < 0 && tick % tickSpacing != 0) compressed--; // round towards negative infinity - - if (lte) { - (int16 wordPos, uint8 bitPos) = position(compressed); - // all the 1s at or to the right of the current bitPos - uint256 mask = (1 << bitPos) - 1 + (1 << bitPos); - uint256 masked = self[wordPos] & mask; - - // if there are no initialized ticks to the right of or at the current tick, return rightmost in the word - initialized = masked != 0; - // overflow/underflow is possible, but prevented externally by limiting both tickSpacing and tick - next = initialized - ? (compressed - - int24(bitPos - BitMath.mostSignificantBit(masked))) * - tickSpacing - : (compressed - int24(bitPos)) * tickSpacing; - } else { - // start from the word of the next tick, since the current tick state doesn't matter - (int16 wordPos, uint8 bitPos) = position(compressed + 1); - // all the 1s at or to the left of the bitPos - uint256 mask = ~((1 << bitPos) - 1); - uint256 masked = self[wordPos] & mask; - - // if there are no initialized ticks to the left of the current tick, return leftmost in the word - initialized = masked != 0; - // overflow/underflow is possible, but prevented externally by limiting both tickSpacing and tick - next = initialized - ? (compressed + - 1 + - int24(BitMath.leastSignificantBit(masked) - bitPos)) * - tickSpacing - : (compressed + 1 + int24(type(uint8).max - bitPos)) * - tickSpacing; - } - } -} diff --git a/contracts/dependencies/weth/WETH9.sol b/contracts/dependencies/weth/WETH9.sol index 7291326ee..a891795ea 100644 --- a/contracts/dependencies/weth/WETH9.sol +++ b/contracts/dependencies/weth/WETH9.sol @@ -13,7 +13,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; contract WETH9 { string public name = "Wrapped Ether"; @@ -40,7 +40,8 @@ contract WETH9 { function withdraw(uint256 wad) public { require(balanceOf[msg.sender] >= wad); balanceOf[msg.sender] -= wad; - payable(msg.sender).transfer(wad); + (bool success, ) = msg.sender.call{value: wad}(new bytes(0)); + require(success, "ETH_TRANSFER_FAILED"); // msg.sender would have ethereum emit Withdrawal(msg.sender, wad); } diff --git a/contracts/dependencies/yoga-labs/ApeCoinStaking.sol b/contracts/dependencies/yoga-labs/ApeCoinStaking.sol index fcacbf84b..554ae76b4 100644 --- a/contracts/dependencies/yoga-labs/ApeCoinStaking.sol +++ b/contracts/dependencies/yoga-labs/ApeCoinStaking.sol @@ -1,6 +1,6 @@ //SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "../openzeppelin/contracts/IERC20.sol"; import "../openzeppelin/contracts/SafeERC20.sol"; diff --git a/contracts/deployments/ReservesSetupHelper.sol b/contracts/deployments/ReservesSetupHelper.sol index 72f0e3a13..cedd0541c 100644 --- a/contracts/deployments/ReservesSetupHelper.sol +++ b/contracts/deployments/ReservesSetupHelper.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {PoolConfigurator} from "../protocol/pool/PoolConfigurator.sol"; import {Ownable} from "../dependencies/openzeppelin/contracts/Ownable.sol"; diff --git a/contracts/governance/ExecutorWithTimelock.sol b/contracts/governance/ExecutorWithTimelock.sol index 91e2f178e..55eb3c90e 100644 --- a/contracts/governance/ExecutorWithTimelock.sol +++ b/contracts/governance/ExecutorWithTimelock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; pragma abicoder v2; import {IExecutorWithTimelock} from "../interfaces/IExecutorWithTimelock.sol"; diff --git a/contracts/interfaces/IACLManager.sol b/contracts/interfaces/IACLManager.sol index c5e5cdfb0..ad8a5d818 100644 --- a/contracts/interfaces/IACLManager.sol +++ b/contracts/interfaces/IACLManager.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPoolAddressesProvider} from "./IPoolAddressesProvider.sol"; diff --git a/contracts/interfaces/IAToken.sol b/contracts/interfaces/IAToken.sol index 97ef47437..1e31906d0 100644 --- a/contracts/interfaces/IAToken.sol +++ b/contracts/interfaces/IAToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPool} from "./IPool.sol"; diff --git a/contracts/interfaces/IApeCoinPool.sol b/contracts/interfaces/IApeCoinPool.sol new file mode 100644 index 000000000..f5157b752 --- /dev/null +++ b/contracts/interfaces/IApeCoinPool.sol @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity ^0.8.0; + +interface IApeCoinPool { + struct ApeCoinDepositInfo { + //deposit for + address onBehalf; + //user payment token + address cashToken; + //user cash amount + uint256 cashAmount; + //isBAYC if Ape is BAYC + bool isBAYC; + //Ape token ids + uint32[] tokenIds; + } + + struct ApeCoinPairDepositInfo { + //deposit for + address onBehalf; + //user payment token + address cashToken; + //user cash amount + uint256 cashAmount; + //isBAYC if Ape is BAYC + bool isBAYC; + //Ape token ids + uint32[] apeTokenIds; + //BAKC token ids + uint32[] bakcTokenIds; + } + + struct ApeCoinWithdrawInfo { + //user receive token + address cashToken; + //user receive token amount + uint256 cashAmount; + //isBAYC if Ape is BAYC + bool isBAYC; + //Ape token ids + uint32[] tokenIds; + } + + struct ApeCoinPairWithdrawInfo { + //user receive token + address cashToken; + //user receive token amount + uint256 cashAmount; + //isBAYC if Ape is BAYC + bool isBAYC; + //Ape token ids + uint32[] apeTokenIds; + //BAKC token ids + uint32[] bakcTokenIds; + } + + event ApeCoinPoolDeposited(bool isBAYC, uint256 tokenId); + event ApeCoinPoolCompounded(bool isBAYC, uint256 tokenId); + event ApeCoinPoolWithdrew(bool isBAYC, uint256 tokenId); + event ApeCoinPairPoolDeposited( + bool isBAYC, + uint256 apeTokenId, + uint256 bakcTokenId + ); + event ApeCoinPairPoolCompounded( + bool isBAYC, + uint256 apeTokenId, + uint256 bakcTokenId + ); + event ApeCoinPairPoolWithdrew( + bool isBAYC, + uint256 apeTokenId, + uint256 bakcTokenId + ); + + /** + * @notice deposit Ape and ape coin position to Ape coin Pool. + * @param depositInfo Detail deposit info + **/ + function depositApeCoinPool(ApeCoinDepositInfo calldata depositInfo) + external; + + /** + * @notice claim Ape staking reward from ApeCoinStaking and compound as cApe for user + * only ape staking bot can call this function + * @param isBAYC if Ape is BAYC + * @param tokenIds Ape token ids + */ + function compoundApeCoinPool(bool isBAYC, uint32[] calldata tokenIds) + external; + + /** + * @notice withdraw Ape and ape coin position from Ape coin Pool + * @param withdrawInfo Detail withdraw info + */ + function withdrawApeCoinPool(ApeCoinWithdrawInfo calldata withdrawInfo) + external; + + /** + * @notice deposit Ape and ape coin position to Ape coin Pool. + * @param depositInfo Detail deposit info + **/ + function depositApeCoinPairPool(ApeCoinPairDepositInfo calldata depositInfo) + external; + + /** + * @notice claim Ape pair staking reward from ApeCoinStaking and compound as cApe for user + * only ape staking bot can call this function + * @param isBAYC if Ape is BAYC + * @param apeTokenIds Ape token ids + * @param bakcTokenIds BAKC token ids + */ + function compoundApeCoinPairPool( + bool isBAYC, + uint32[] calldata apeTokenIds, + uint32[] calldata bakcTokenIds + ) external; + + /** + * @notice withdraw Ape, BAKC and ape coin position from Ape coin Pair Pool + * @param withdrawInfo Detail withdraw info + */ + function withdrawApeCoinPairPool( + ApeCoinPairWithdrawInfo calldata withdrawInfo + ) external; + + /** + * @notice Callback function for Ape nToken owner change, will auto claim owner's pending reward or ApeCoin pool position + * @param isBAYC if Ape is BAYC + * @param tokenIds Ape token ids + */ + function nApeOwnerChangeCallback(bool isBAYC, uint32[] calldata tokenIds) + external; + + /** + * @notice Callback function for BAKC nToken owner change, will auto claim owner's pending reward + * @param tokenIds BAKC tokenIds + */ + function nBakcOwnerChangeCallback(uint32[] calldata tokenIds) external; +} diff --git a/contracts/interfaces/IApeStakingP2P.sol b/contracts/interfaces/IApeStakingP2P.sol new file mode 100644 index 000000000..dcd092598 --- /dev/null +++ b/contracts/interfaces/IApeStakingP2P.sol @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity ^0.8.0; + +interface IApeStakingP2P { + enum StakingType { + BAYCStaking, + MAYCStaking, + BAKCPairStaking + } + + enum ListingOrderStatus { + Pending, + Matched, + Cancelled + } + + struct ListingOrder { + StakingType stakingType; + address offerer; + address token; + uint32 tokenId; + uint32 share; + uint256 startTime; + uint256 endTime; + uint8 v; + bytes32 r; + bytes32 s; + } + + struct MatchedOrder { + StakingType stakingType; + address apeToken; + uint32 apeTokenId; + uint32 apeShare; + uint32 bakcTokenId; + uint32 bakcShare; + address apeCoinOfferer; + uint32 apeCoinShare; + bytes32 apeCoinListingOrderHash; + } + + /** + * @dev Emit an event whenever an listing order is successfully cancelled. + * @param orderHash The hash of the cancelled order. + * @param offerer The offerer of the cancelled order. + */ + event OrderCancelled(bytes32 orderHash, address indexed offerer); + + /** + * @dev Emitted when a order matched. + * @param orderHash The hash of the matched order + **/ + event PairStakingMatched(bytes32 orderHash); + + /** + * @dev Emitted when a matched order break up. + * @param orderHash The hash of the break up order + **/ + event PairStakingBreakUp(bytes32 orderHash); + + /** + * @dev Emitted when user claimed pending cApe reward. + * @param user The address of the user + * @param receiver The address of the cApe receiver + * @param amount The amount of the cApe been claimed + **/ + event CApeClaimed(address user, address receiver, uint256 amount); + + /** + * @dev Emitted when we claimed pending reward for matched order and compound. + * @param orderHash The hash of the break up order + **/ + event OrderClaimedAndCompounded(bytes32 orderHash, uint256 totalReward); + + /** + * @dev Emitted during rescueERC20() + * @param token The address of the token + * @param to The address of the recipient + * @param amount The amount being rescued + **/ + event RescueERC20( + address indexed token, + address indexed to, + uint256 amount + ); + + /** + * @notice Cancel a listing order, order canceled cannot be matched. + * @param listingOrder the detail info of the order to be canceled + */ + function cancelListing(ListingOrder calldata listingOrder) external; + + /** + * @notice match an apeOrder with an apeCoinOrder to pair staking + * @param apeOrder the ape owner's listing order + * @param apeCoinOrder the Ape Coin owner's listing order + * @return orderHash matched order hash + */ + function matchPairStakingList( + ListingOrder calldata apeOrder, + ListingOrder calldata apeCoinOrder + ) external returns (bytes32 orderHash); + + /** + * @notice match an apeOrder, an bakcOrder with an apeCoinOrder to pair staking + * @param apeOrder the ape owner's listing order + * @param bakcOrder the bakc owner's listing order + * @param apeCoinOrder the Ape Coin owner's listing order + * @return orderHash matched order hash + */ + function matchBAKCPairStakingList( + ListingOrder calldata apeOrder, + ListingOrder calldata bakcOrder, + ListingOrder calldata apeCoinOrder + ) external returns (bytes32 orderHash); + + /** + * @notice break up an matched pair staking order, only participant of the matched order can call. + * @param orderHash the hash of the matched order to be break up + */ + function breakUpMatchedOrder(bytes32 orderHash) external; + + /** + * @notice claim pending reward for matched pair staking orders and deposit as cApe for user to compound. + * @param orderHashes the hash of the matched orders to be break up + */ + function claimForMatchedOrderAndCompound(bytes32[] calldata orderHashes) + external; + + /** + * @param user The address of the user + * @return amount Returns the amount of cApe owned by user + */ + function pendingCApeReward(address user) + external + view + returns (uint256 amount); + + /** + * @notice claim user compounded cApe + * @param receiver The address of the cApe receiver + */ + function claimCApeReward(address receiver) external; + + /** + * @notice get Ape Coin Staking cap for every position. + * @param stakingType the pair staking type + * @return Ape Coin Staking cap + */ + function getApeCoinStakingCap(StakingType stakingType) + external + returns (uint256); +} diff --git a/contracts/interfaces/IApeStakingVault.sol b/contracts/interfaces/IApeStakingVault.sol new file mode 100644 index 000000000..c08e9703d --- /dev/null +++ b/contracts/interfaces/IApeStakingVault.sol @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity ^0.8.0; + +interface IApeStakingVault { + struct BAKCPairActionInfo { + uint32[] baycTokenIds; + uint32[] bakcPairBaycTokenIds; + uint32[] maycTokenIds; + uint32[] bakcPairMaycTokenIds; + } + + /** + * @dev Emitted during setSinglePoolApeRewardRatio() + * @param oldRatio The value of the old ApePairStakingRewardRatio + * @param newRatio The value of the new ApePairStakingRewardRatio + **/ + event ApePairStakingRewardRatioUpdated(uint256 oldRatio, uint256 newRatio); + + event PairNFTDeposited( + bool isBAYC, + uint256 apeTokenId, + uint256 bakcTokenId + ); + event PairNFTStaked(bool isBAYC, uint256 apeTokenId, uint256 bakcTokenId); + event PairNFTWithdrew(bool isBAYC, uint256 apeTokenId, uint256 bakcTokenId); + event PairNFTCompounded( + bool isBAYC, + uint256 apeTokenId, + uint256 bakcTokenId + ); + event NFTDeposited(address nft, uint256 tokenId); + event ApeStaked(bool isBAYC, uint256 tokenId); + event BakcStaked(bool isBAYC, uint256 apeTokenId, uint256 bakcTokenId); + event ApeCompounded(bool isBAYC, uint256 tokenId); + event BakcCompounded(bool isBAYC, uint256 apeTokenId, uint256 bakcTokenId); + event NFTWithdrawn(address nft, uint256 tokenId); + + /** + * @notice deposit Ape and BAKC pair into the pool + * @param isBAYC if Ape is BAYC + * @param apeTokenIds Ape token ids + * @param bakcTokenIds BAKC token ids + */ + function depositPairNFT( + bool isBAYC, + uint32[] calldata apeTokenIds, + uint32[] calldata bakcTokenIds + ) external; + + /** + * @notice stake pool's Ape and BAKC pair into ApeCoinStaking + * @param isBAYC if Ape is BAYC + * @param apeTokenIds Ape token ids + * @param bakcTokenIds BAKC token ids + */ + function stakingPairNFT( + bool isBAYC, + uint32[] calldata apeTokenIds, + uint32[] calldata bakcTokenIds + ) external; + + /** + * @notice claim Ape and BAKC pair staking reward from ApeCoinStaking and compound as cApe for user + * only ape staking bot can call this function + * @param isBAYC if Ape is BAYC + * @param apeTokenIds Ape token ids + * @param bakcTokenIds BAKC token ids + */ + function compoundPairNFT( + bool isBAYC, + uint32[] calldata apeTokenIds, + uint32[] calldata bakcTokenIds + ) external; + + /** + * @notice withdraw Ape and BAKC pair from pool + * if the pair is staking it ApeCoinStaking, it will unstake from ApeCoinStaking first. + * @param isBAYC if Ape is BAYC + * @param apeTokenIds Ape token ids + * @param bakcTokenIds BAKC token ids + */ + function withdrawPairNFT( + bool isBAYC, + uint32[] calldata apeTokenIds, + uint32[] calldata bakcTokenIds + ) external; + + /** + * @notice deposit Ape or BAKC into the single pool + * @param nft Ape or BAKC token address + * @param tokenIds nft token ids + */ + function depositNFT(address nft, uint32[] calldata tokenIds) external; + + /** + * @notice stake pool's Ape into ApeCoinStaking + * @param isBAYC if Ape is BAYC + * @param tokenIds Ape token ids + */ + function stakingApe(bool isBAYC, uint32[] calldata tokenIds) external; + + /** + * @notice stake pool's Ape and BAKC into ApeCoinStaking pair staking pool + * @param actionInfo detail staking info + */ + function stakingBAKC(BAKCPairActionInfo calldata actionInfo) external; + + /** + * @notice claim Ape staking reward from ApeCoinStaking and compound as cApe for user + * only ape staking bot can call this function + * @param isBAYC if Ape is BAYC + * @param tokenIds Ape token ids + */ + function compoundApe(bool isBAYC, uint32[] calldata tokenIds) external; + + /** + * @notice claim single pool's Ape and BAKC pair staking reward from ApeCoinStaking and compound as cApe for user + * only ape staking bot can call this function + * @param actionInfo detail staking info + */ + function compoundBAKC(BAKCPairActionInfo calldata actionInfo) external; + + /** + * @notice withdraw nft from single pool + * if the nft is staking it ApeCoinStaking, it will unstake from ApeCoinStaking first. + * @param nft Ape or BAKC token address + * @param tokenIds nft token ids + */ + function withdrawNFT(address nft, uint32[] calldata tokenIds) external; +} diff --git a/contracts/interfaces/IAtomicCollateralizableERC721.sol b/contracts/interfaces/IAtomicCollateralizableERC721.sol index 1160b7074..69d63f144 100644 --- a/contracts/interfaces/IAtomicCollateralizableERC721.sol +++ b/contracts/interfaces/IAtomicCollateralizableERC721.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title IAtomicCollateralizableERC721 diff --git a/contracts/interfaces/IAtomicPriceAggregator.sol b/contracts/interfaces/IAtomicPriceAggregator.sol index 69a7ad3be..5ea7402bf 100644 --- a/contracts/interfaces/IAtomicPriceAggregator.sol +++ b/contracts/interfaces/IAtomicPriceAggregator.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /************ @title IAtomicPriceAggregator interface diff --git a/contracts/interfaces/IAuctionableERC721.sol b/contracts/interfaces/IAuctionableERC721.sol index 7c6d2d0f6..4156e1851 100644 --- a/contracts/interfaces/IAuctionableERC721.sol +++ b/contracts/interfaces/IAuctionableERC721.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {DataTypes} from "../protocol/libraries/types/DataTypes.sol"; /** diff --git a/contracts/interfaces/IAutoCompoundApe.sol b/contracts/interfaces/IAutoCompoundApe.sol index f800425fd..3f072de8a 100644 --- a/contracts/interfaces/IAutoCompoundApe.sol +++ b/contracts/interfaces/IAutoCompoundApe.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "../dependencies/openzeppelin/contracts/IERC20.sol"; diff --git a/contracts/interfaces/IAutoYieldApe.sol b/contracts/interfaces/IAutoYieldApe.sol index 5c1f60eaa..0da8bddc1 100644 --- a/contracts/interfaces/IAutoYieldApe.sol +++ b/contracts/interfaces/IAutoYieldApe.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title AutoYieldApe interface diff --git a/contracts/interfaces/ICApe.sol b/contracts/interfaces/ICApe.sol index a72890114..2add80488 100644 --- a/contracts/interfaces/ICApe.sol +++ b/contracts/interfaces/ICApe.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "../dependencies/openzeppelin/contracts/IERC20.sol"; diff --git a/contracts/interfaces/ICToken.sol b/contracts/interfaces/ICToken.sol index 87476410a..cad0f9b89 100644 --- a/contracts/interfaces/ICToken.sol +++ b/contracts/interfaces/ICToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; interface ICToken { /** diff --git a/contracts/interfaces/ICollateralizableERC721.sol b/contracts/interfaces/ICollateralizableERC721.sol index 332fae490..fcdfd666c 100644 --- a/contracts/interfaces/ICollateralizableERC721.sol +++ b/contracts/interfaces/ICollateralizableERC721.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title ICollateralizableERC721 diff --git a/contracts/interfaces/ICreditDelegationToken.sol b/contracts/interfaces/ICreditDelegationToken.sol index 452f25f2d..494936d1a 100644 --- a/contracts/interfaces/ICreditDelegationToken.sol +++ b/contracts/interfaces/ICreditDelegationToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title ICreditDelegationToken diff --git a/contracts/interfaces/ICurve.sol b/contracts/interfaces/ICurve.sol index 26021b6cd..d4cdfa7ec 100644 --- a/contracts/interfaces/ICurve.sol +++ b/contracts/interfaces/ICurve.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; interface ICurve { function exchange( diff --git a/contracts/interfaces/IDelegation.sol b/contracts/interfaces/IDelegation.sol index d034cefe4..9edaae641 100644 --- a/contracts/interfaces/IDelegation.sol +++ b/contracts/interfaces/IDelegation.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.10; +pragma solidity ^0.8.0; interface IDelegation { function clearDelegate(bytes32 id) external; diff --git a/contracts/interfaces/IDelegationToken.sol b/contracts/interfaces/IDelegationToken.sol index aa496bfe1..b69a2e410 100644 --- a/contracts/interfaces/IDelegationToken.sol +++ b/contracts/interfaces/IDelegationToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title IDelegationToken diff --git a/contracts/interfaces/IEACAggregatorProxy.sol b/contracts/interfaces/IEACAggregatorProxy.sol index 6cc9d84e6..5f8ef5638 100644 --- a/contracts/interfaces/IEACAggregatorProxy.sol +++ b/contracts/interfaces/IEACAggregatorProxy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; interface IEACAggregatorProxy { function decimals() external view returns (uint8); diff --git a/contracts/interfaces/IERC20WithPermit.sol b/contracts/interfaces/IERC20WithPermit.sol index 4a8feba89..80261c8d9 100644 --- a/contracts/interfaces/IERC20WithPermit.sol +++ b/contracts/interfaces/IERC20WithPermit.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC20} from "../dependencies/openzeppelin/contracts/IERC20.sol"; diff --git a/contracts/interfaces/IExchangeRate.sol b/contracts/interfaces/IExchangeRate.sol index 98975b21d..f56338f6f 100644 --- a/contracts/interfaces/IExchangeRate.sol +++ b/contracts/interfaces/IExchangeRate.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; interface IExchangeRate { function getExchangeRate() external view returns (uint256); diff --git a/contracts/interfaces/IExecutorWithTimelock.sol b/contracts/interfaces/IExecutorWithTimelock.sol index 46adcc5bf..4c56b4718 100644 --- a/contracts/interfaces/IExecutorWithTimelock.sol +++ b/contracts/interfaces/IExecutorWithTimelock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; pragma abicoder v2; interface IExecutorWithTimelock { diff --git a/contracts/interfaces/IHotWalletProxy.sol b/contracts/interfaces/IHotWalletProxy.sol index 488208433..b4d542503 100644 --- a/contracts/interfaces/IHotWalletProxy.sol +++ b/contracts/interfaces/IHotWalletProxy.sol @@ -1,4 +1,4 @@ -pragma solidity 0.8.10; +pragma solidity ^0.8.0; interface IHotWalletProxy { function setHotWallet( diff --git a/contracts/interfaces/IInitializableDebtToken.sol b/contracts/interfaces/IInitializableDebtToken.sol index 5e547febf..a402052a2 100644 --- a/contracts/interfaces/IInitializableDebtToken.sol +++ b/contracts/interfaces/IInitializableDebtToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IRewardController} from "./IRewardController.sol"; import {IPool} from "./IPool.sol"; diff --git a/contracts/interfaces/IInitializableNToken.sol b/contracts/interfaces/IInitializableNToken.sol index 227ca5aea..6b931be07 100644 --- a/contracts/interfaces/IInitializableNToken.sol +++ b/contracts/interfaces/IInitializableNToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IRewardController} from "./IRewardController.sol"; import {IPool} from "./IPool.sol"; diff --git a/contracts/interfaces/IInitializablePToken.sol b/contracts/interfaces/IInitializablePToken.sol index f83b1aa72..f78e38561 100644 --- a/contracts/interfaces/IInitializablePToken.sol +++ b/contracts/interfaces/IInitializablePToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IRewardController} from "./IRewardController.sol"; import {IPool} from "./IPool.sol"; diff --git a/contracts/interfaces/ILido.sol b/contracts/interfaces/ILido.sol index 33b76f48c..5dc2ec24e 100644 --- a/contracts/interfaces/ILido.sol +++ b/contracts/interfaces/ILido.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC20Detailed} from "../dependencies/openzeppelin/contracts/IERC20Detailed.sol"; @@ -9,10 +9,20 @@ interface ILido is IERC20Detailed { view returns (uint256); + function getPooledKSMByShares(uint256 _sharesAmount) + external + view + returns (uint256); + function getSharesByPooledEth(uint256 _pooledEth) external view returns (uint256); + function getSharesByPooledKSM(uint256 _pooledEth) + external + view + returns (uint256); + function submit(address _referral) external payable returns (uint256); } diff --git a/contracts/interfaces/IMarketplace.sol b/contracts/interfaces/IMarketplace.sol index 1b0cc2b21..0810475de 100644 --- a/contracts/interfaces/IMarketplace.sol +++ b/contracts/interfaces/IMarketplace.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {DataTypes} from "../protocol/libraries/types/DataTypes.sol"; import {Errors} from "../protocol/libraries/helpers/Errors.sol"; diff --git a/contracts/interfaces/IMatic.sol b/contracts/interfaces/IMatic.sol new file mode 100644 index 000000000..9e7595ce1 --- /dev/null +++ b/contracts/interfaces/IMatic.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity ^0.8.0; + +import {IERC20Detailed} from "../dependencies/openzeppelin/contracts/IERC20Detailed.sol"; + +interface IMatic is IERC20Detailed { + function convertStMaticToMatic(uint256 _sharesAmount) + external + view + returns (uint256); + + function convertMaticToStMatic(uint256 _pooledEth) + external + view + returns (uint256); +} diff --git a/contracts/interfaces/INToken.sol b/contracts/interfaces/INToken.sol index bb30ce129..227a6a919 100644 --- a/contracts/interfaces/INToken.sol +++ b/contracts/interfaces/INToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC721} from "../dependencies/openzeppelin/contracts/IERC721.sol"; import {IERC721Receiver} from "../dependencies/openzeppelin/contracts/IERC721Receiver.sol"; diff --git a/contracts/interfaces/INTokenApeStaking.sol b/contracts/interfaces/INTokenApeStaking.sol deleted file mode 100644 index ce03375fa..000000000 --- a/contracts/interfaces/INTokenApeStaking.sol +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; - -import "../dependencies/yoga-labs/ApeCoinStaking.sol"; -import "./INToken.sol"; - -interface INTokenApeStaking { - function getBAKC() external view returns (IERC721); - - function getApeStaking() external view returns (ApeCoinStaking); - - function depositApeCoin(ApeCoinStaking.SingleNft[] calldata _nfts) external; - - function claimApeCoin(uint256[] calldata _nfts, address _recipient) - external; - - function withdrawApeCoin( - ApeCoinStaking.SingleNft[] calldata _nfts, - address _recipient, - DataTypes.TimeLockParams memory _timeLockParams - ) external; - - function depositBAKC( - ApeCoinStaking.PairNftDepositWithAmount[] calldata _nftPairs - ) external; - - function claimBAKC( - ApeCoinStaking.PairNft[] calldata _nftPairs, - address _recipient - ) external; - - function withdrawBAKC( - ApeCoinStaking.PairNftWithdrawWithAmount[] memory _nftPairs, - address _apeRecipient, - DataTypes.TimeLockParams memory _timeLockParams - ) external; - - function unstakePositionAndRepay(uint256 tokenId, address unstaker) - external; - - function getUserApeStakingAmount(address user) - external - view - returns (uint256); -} diff --git a/contracts/interfaces/INTokenStakefish.sol b/contracts/interfaces/INTokenStakefish.sol index 31ba8a355..6f75eed49 100644 --- a/contracts/interfaces/INTokenStakefish.sol +++ b/contracts/interfaces/INTokenStakefish.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {DataTypes} from "../protocol/libraries/types/DataTypes.sol"; diff --git a/contracts/interfaces/INTokenUniswapV3.sol b/contracts/interfaces/INTokenUniswapV3.sol index ddb633ad7..112de9ad5 100644 --- a/contracts/interfaces/INTokenUniswapV3.sol +++ b/contracts/interfaces/INTokenUniswapV3.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; interface INTokenUniswapV3 { /** diff --git a/contracts/interfaces/IP2PPairStaking.sol b/contracts/interfaces/IP2PPairStaking.sol index c7fa6c664..71ce61838 100644 --- a/contracts/interfaces/IP2PPairStaking.sol +++ b/contracts/interfaces/IP2PPairStaking.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "../dependencies/openzeppelin/contracts/IERC20.sol"; diff --git a/contracts/interfaces/IPToken.sol b/contracts/interfaces/IPToken.sol index 3224ac1b0..213fd2dfe 100644 --- a/contracts/interfaces/IPToken.sol +++ b/contracts/interfaces/IPToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC20} from "../dependencies/openzeppelin/contracts/IERC20.sol"; import {IScaledBalanceToken} from "./IScaledBalanceToken.sol"; diff --git a/contracts/interfaces/IParaApeStaking.sol b/contracts/interfaces/IParaApeStaking.sol new file mode 100644 index 000000000..ca0a676eb --- /dev/null +++ b/contracts/interfaces/IParaApeStaking.sol @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity ^0.8.0; + +import "../dependencies/yoga-labs/ApeCoinStaking.sol"; +import "./IApeStakingVault.sol"; +import "./IApeStakingP2P.sol"; +import "./IApeCoinPool.sol"; + +interface IParaApeStaking is IApeStakingVault, IApeStakingP2P, IApeCoinPool { + struct ApeStakingVaultCacheVars { + address pool; + address bayc; + address mayc; + address bakc; + address nBayc; + address nMayc; + address nBakc; + address apeCoin; + address cApe; + ApeCoinStaking apeCoinStaking; + uint256 baycMatchedCap; + uint256 maycMatchedCap; + uint256 bakcMatchedCap; + //optional + bytes32 DOMAIN_SEPARATOR; + uint256 compoundFee; + address apeToken; + address nApe; + uint256 apeStakingPoolId; + uint256 positionCap; + uint128 accumulatedRewardsPerNft; + uint256 balanceBefore; + uint256 balanceAfter; + uint256 totalClaimedApe; + uint256 apeRewardRatio; + uint256 totalRepay; + uint256 totalCompoundFee; + uint256 cApeExchangeRate; + uint256 latestBorrowIndex; + bool isPaired; + uint16 sApeReserveId; + address nApeOwner; + } + + struct SApeBalance { + //cApe share + uint128 freeShareBalance; + //staked ape coin + uint128 stakedBalance; + } + + struct TokenStatus { + //record tokenId reward debt position + uint128 rewardsDebt; + // identify if tokenId is in pool + bool isInPool; + // pair bakc token, only for pair pool + uint32 bakcTokenId; + // is paird with bakc, only for pair pool + bool isPaired; + } + + struct PoolState { + //pool cape debt token share, max value for uint104 is 2e31, ape coin total supply is 1e27. only for pool staking + uint104 cApeDebtShare; + // accumulated cApe reward for per NFT position + uint104 accumulatedRewardsPerNft; + // total NFT position count, max value for uint24 is 16777216 + uint24 totalPosition; + // total staking position, used for calculate interest debt, . only for pool staking + uint24 stakingPosition; + //tokenId => reward debt position + mapping(uint256 => TokenStatus) tokenStatus; + } + + /** + * @dev Emitted during setApeStakingBot() + * @param oldBot The address of the old compound bot + * @param newBot The address of the new compound bot + **/ + event ApeStakingBotUpdated(address oldBot, address newBot); + + /** + * @dev Emitted during setCompoundFee() + * @param oldValue The old value of compound fee + * @param newValue The new value of compound fee + **/ + event CompoundFeeUpdated(uint64 oldValue, uint64 newValue); + + /** + * @dev Emitted during claimPendingReward() + * @param poolId identify which pool user claimed from + * @param tokenId identify position token id + * @param rewardAmount Reward amount claimed + **/ + event PoolRewardClaimed( + uint256 poolId, + uint256 tokenId, + uint256 rewardAmount + ); + + /** + * @notice Query sApe reserve Id used by ParaApeStaking + */ + function sApeReserveId() external view returns (uint16); + + /** + * @notice Query token status for the specified pool and nft + * @param poolId Identify pool + * @param tokenId The tokenId of the nft + */ + function poolTokenStatus(uint256 poolId, uint256 tokenId) + external + view + returns (IParaApeStaking.TokenStatus memory); + + /** + * @notice Query position pending reward in the pool, will revert if token id is not in the pool + * @param poolId Identify pool + * @param tokenIds The tokenIds of the nft + */ + function getPendingReward(uint256 poolId, uint32[] calldata tokenIds) + external + view + returns (uint256); + + /** + * @notice Claim position pending reward in the pool, will revert if token id is not in the pool + * @param poolId Identify pool + * @param tokenIds The tokenIds of the nft + */ + function claimPendingReward(uint256 poolId, uint32[] calldata tokenIds) + external; + + /** + * @notice Query user's staked sApe balance, staked sApe cannot be liquidated directly + * @param user user address + */ + function stakedSApeBalance(address user) external view returns (uint256); + + /** + * @notice Query user's free sApe balance, free sApe can be liquidated + * @param user user address + */ + function freeSApeBalance(address user) external view returns (uint256); + + /** + * @notice Query user's total sApe balance, total sApe = staked sApe + free sApe + * @param user user address + */ + function totalSApeBalance(address user) external view returns (uint256); + + /** + * @notice transfer free sApe balance from 'from' to 'to', Only psApe can call this function during sApe liquidation + * @param from identify send address + * @param to identify receive address + * @param amount transfer amount + */ + function transferFreeSApeBalance( + address from, + address to, + uint256 amount + ) external; + + /** + * @notice deposit an `amount` of free sApe. + * @param cashAsset The payment asset for the deposit. Can only be ApeCoin or cApe + * @param amount The amount of sApe to be deposit + **/ + function depositFreeSApe(address cashAsset, uint128 amount) external; + + /** + * @notice withdraw an `amount` of free sApe. + * @param receiveAsset The receive asset for the withdraw. Can only be ApeCoin or cApe + * @param amount The amount of sApe to be withdraw + **/ + function withdrawFreeSApe(address receiveAsset, uint128 amount) external; +} diff --git a/contracts/interfaces/IParaProxy.sol b/contracts/interfaces/IParaProxy.sol index 00007fb7f..d029ae189 100644 --- a/contracts/interfaces/IParaProxy.sol +++ b/contracts/interfaces/IParaProxy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; /******************************************************************************\ * EIP-2535: https://eips.ethereum.org/EIPS/eip-2535 diff --git a/contracts/interfaces/IParaSpaceOracle.sol b/contracts/interfaces/IParaSpaceOracle.sol index f7b884e44..7479e87c3 100644 --- a/contracts/interfaces/IParaSpaceOracle.sol +++ b/contracts/interfaces/IParaSpaceOracle.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPriceOracleGetter} from "./IPriceOracleGetter.sol"; import {IPoolAddressesProvider} from "./IPoolAddressesProvider.sol"; diff --git a/contracts/interfaces/IPool.sol b/contracts/interfaces/IPool.sol index ccdbf94d2..d1967066b 100644 --- a/contracts/interfaces/IPool.sol +++ b/contracts/interfaces/IPool.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPoolCore} from "./IPoolCore.sol"; import {IPoolMarketplace} from "./IPoolMarketplace.sol"; diff --git a/contracts/interfaces/IPoolAddressesProvider.sol b/contracts/interfaces/IPoolAddressesProvider.sol index 84708ffea..93205be09 100644 --- a/contracts/interfaces/IPoolAddressesProvider.sol +++ b/contracts/interfaces/IPoolAddressesProvider.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {DataTypes} from "../protocol/libraries/types/DataTypes.sol"; import {IParaProxy} from "../interfaces/IParaProxy.sol"; diff --git a/contracts/interfaces/IPoolAddressesProviderRegistry.sol b/contracts/interfaces/IPoolAddressesProviderRegistry.sol index c24c178c0..e7bcd858b 100644 --- a/contracts/interfaces/IPoolAddressesProviderRegistry.sol +++ b/contracts/interfaces/IPoolAddressesProviderRegistry.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title IPoolAddressesProviderRegistry diff --git a/contracts/interfaces/IPoolApeStaking.sol b/contracts/interfaces/IPoolApeStaking.sol index 60bc62a6a..c789bde8d 100644 --- a/contracts/interfaces/IPoolApeStaking.sol +++ b/contracts/interfaces/IPoolApeStaking.sol @@ -1,7 +1,9 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "../dependencies/yoga-labs/ApeCoinStaking.sol"; +import "./IParaApeStaking.sol"; +import {DataTypes} from "../protocol/libraries/types/DataTypes.sol"; /** * @title IPoolApeStaking @@ -9,128 +11,39 @@ import "../dependencies/yoga-labs/ApeCoinStaking.sol"; * @notice Defines the basic interface for an ParaSpace Ape Staking Pool. **/ interface IPoolApeStaking { - struct StakingInfo { - // Contract address of BAYC/MAYC - address nftAsset; - // address of borrowing asset, can be Ape or cApe - address borrowAsset; - // Borrow amount of Ape from lending pool - uint256 borrowAmount; - // Cash amount of Ape from user wallet - uint256 cashAmount; - } - - /** - * @notice Deposit ape coin to BAYC/MAYC pool or BAKC pool - * @param stakingInfo Detail info of the staking - * @param _nfts Array of BAYC/MAYC NFT's with staked amounts - * @param _nftPairs Array of Paired BAYC/MAYC NFT's with staked amounts - * @param _openSApeCollateralFlag if true and when user current sApe collateral flag is false, we will open it. We don't close the flag here, user should call setUserUseERC20AsCollateral to turn off the flag. - * @dev Need check User health factor > 1. - */ - function borrowApeAndStake( - StakingInfo calldata stakingInfo, - ApeCoinStaking.SingleNft[] calldata _nfts, - ApeCoinStaking.PairNftDepositWithAmount[] calldata _nftPairs, - bool _openSApeCollateralFlag - ) external; - - /** - * @notice Withdraw staked ApeCoin from the BAYC/MAYC pool - * @param nftAsset Contract address of BAYC/MAYC - * @param _nfts Array of BAYC/MAYC NFT's with staked amounts - * @dev Need check User health factor > 1. - */ - function withdrawApeCoin( - address nftAsset, - ApeCoinStaking.SingleNft[] calldata _nfts - ) external; - - /** - * @notice Claim rewards for array of tokenIds from the BAYC/MAYC pool - * @param nftAsset Contract address of BAYC/MAYC - * @param _nfts Array of NFTs owned and committed by the msg.sender - * @dev Need check User health factor > 1. - */ - function claimApeCoin(address nftAsset, uint256[] calldata _nfts) external; - /** - * @notice Withdraw staked ApeCoin from the BAKC pool - * @param nftAsset Contract address of BAYC/MAYC - * @param _nftPairs Array of Paired BAYC/MAYC NFT's with staked amounts - * @dev Need check User health factor > 1. + * @notice return ParaApeStaking contract address */ - function withdrawBAKC( - address nftAsset, - ApeCoinStaking.PairNftWithdrawWithAmount[] memory _nftPairs - ) external; + function paraApeStaking() external view returns (address); /** - * @notice Claim rewards for array of tokenIds from the BAYC/MAYC pool - * @param nftAsset Contract address of BAYC/MAYC - * @param _nftPairs Array of Paired BAYC/MAYC NFT's - * @dev Need check User health factor > 1. + * @notice Borrow cApe from lending pool, only ParaApeStaking contract can call this function + * @param amount Borrow amount of cApe from lending pool */ - function claimBAKC( - address nftAsset, - ApeCoinStaking.PairNft[] calldata _nftPairs - ) external; + function borrowPoolCApe(uint256 amount) external returns (uint256); /** - * @notice Unstake user Ape coin staking position and repay user debt - * @param nftAsset Contract address of BAYC/MAYC - * @param tokenId Token id of the ape staking position on + * @notice Borrow ApeCoin/cApe from lending pool and stake ape in ParaApeStaking apecoin pool + * @param apeCoinDepositInfo Detail deposit info of the apecoin pool + * @param pairDepositInfo Detail deposit info of the apecoin pair pool + * @param asset address of deposit asset, can be ApeCoin or cApe + * @param cashAmount deposit amount from user wallet + * @param borrowAmount Borrow amount of ApeCoin/cApe from lending pool * @dev Need check User health factor > 1. */ - function unstakeApePositionAndRepay(address nftAsset, uint256 tokenId) - external; - - /** - * @notice repay asset and supply asset for user - * @param underlyingAsset Contract address of BAYC/MAYC - * @param onBehalfOf The beneficiary of the repay and supply - * @dev Convenient callback function for unstakeApePositionAndRepay. Only NToken of BAYC/MAYC can call this. - */ - function repayAndSupply( - address underlyingAsset, - address onBehalfOf, - uint256 totalAmount - ) external; - - /** - * @notice Claim user Ape coin reward and deposit to ape compound to get cApe, then deposit cApe to Lending pool for user - * @param nftAsset Contract address of BAYC/MAYC - * @param users array of user address - * @param tokenIds array of user tokenId array - * @param minUsdcApePrice minimum usdc ape relative price - * @param minWethApePrice minimum weth ape relative price - */ - function claimApeAndCompound( - address nftAsset, - address[] calldata users, - uint256[][] calldata tokenIds, - uint256 minUsdcApePrice, - uint256 minWethApePrice - ) external; - - /** - * @notice Claim user BAKC paired Ape coin reward and deposit to ape compound to get cApe, then deposit cApe to Lending pool for user - * @param nftAsset Contract address of BAYC/MAYC - * @param users array of user address - * @param _nftPairs Array of Paired BAYC/MAYC NFT's - * @param minUsdcApePrice minimum usdc ape relative price - * @param minWethApePrice minimum weth ape relative price - */ - function claimPairedApeAndCompound( - address nftAsset, - address[] calldata users, - ApeCoinStaking.PairNft[][] calldata _nftPairs, - uint256 minUsdcApePrice, - uint256 minWethApePrice + function borrowAndStakingApeCoin( + IParaApeStaking.ApeCoinDepositInfo[] calldata apeCoinDepositInfo, + IParaApeStaking.ApeCoinPairDepositInfo[] calldata pairDepositInfo, + address asset, + uint256 cashAmount, + uint256 borrowAmount, + bool openSApeCollateralFlag ) external; /** - * @notice get current incentive fee rate for claiming ape position reward to compound + * @notice calculate TimeLock parameters for the specified asset, only ParaApeStaking contract can call this function */ - function getApeCompoundFeeRate() external returns (uint256); + function calculateTimeLockParams(address asset, uint256 amount) + external + returns (DataTypes.TimeLockParams memory); } diff --git a/contracts/interfaces/IPoolConfigurator.sol b/contracts/interfaces/IPoolConfigurator.sol index 2c6d5e214..4231e3e3d 100644 --- a/contracts/interfaces/IPoolConfigurator.sol +++ b/contracts/interfaces/IPoolConfigurator.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {ConfiguratorInputTypes} from "../protocol/libraries/types/ConfiguratorInputTypes.sol"; diff --git a/contracts/interfaces/IPoolCore.sol b/contracts/interfaces/IPoolCore.sol index 418df20af..19ff64888 100644 --- a/contracts/interfaces/IPoolCore.sol +++ b/contracts/interfaces/IPoolCore.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPoolAddressesProvider} from "./IPoolAddressesProvider.sol"; import {ITimeLock} from "./ITimeLock.sol"; diff --git a/contracts/interfaces/IPoolMarketplace.sol b/contracts/interfaces/IPoolMarketplace.sol index 742e00a61..d38af622c 100644 --- a/contracts/interfaces/IPoolMarketplace.sol +++ b/contracts/interfaces/IPoolMarketplace.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPoolAddressesProvider} from "./IPoolAddressesProvider.sol"; import {DataTypes} from "../protocol/libraries/types/DataTypes.sol"; diff --git a/contracts/interfaces/IPoolParameters.sol b/contracts/interfaces/IPoolParameters.sol index be17782a1..adf94586c 100644 --- a/contracts/interfaces/IPoolParameters.sol +++ b/contracts/interfaces/IPoolParameters.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPoolAddressesProvider} from "./IPoolAddressesProvider.sol"; import {DataTypes} from "../protocol/libraries/types/DataTypes.sol"; @@ -26,19 +26,6 @@ interface IPoolParameters { uint256 variableBorrowIndex ); - /** - * @dev Emitted when the value of claim for yield incentive rate update - **/ - event ClaimApeForYieldIncentiveUpdated(uint256 oldValue, uint256 newValue); - - /** - * @dev Emitted when the address of claim for yield incentive bot update - **/ - event ClaimApeForYieldIncentiveBotUpdated( - address oldValue, - address newValue - ); - /** * @notice Initializes a reserve, activating it, assigning an xToken and debt tokens and an * interest rate strategy @@ -138,35 +125,6 @@ interface IPoolParameters { */ function revokeUnlimitedApprove(address token, address to) external; - /** - * @notice undate fee percentage for claim ape for compound - * @param fee new fee percentage - */ - function setClaimApeForCompoundFee(uint256 fee) external; - - /** - * @notice undate compound bot for claim ape for compound - * @param bot new compound bot - */ - function setClaimApeForCompoundBot(address bot) external; - - /** - * @notice undate ape compound strategy - * @param strategy new compound strategy - */ - function setApeCompoundStrategy( - DataTypes.ApeCompoundStrategy calldata strategy - ) external; - - /** - * @notice get user ape compound strategy - * @param user The user address - */ - function getUserApeCompoundStrategy(address user) - external - view - returns (DataTypes.ApeCompoundStrategy memory); - /** * @notice Set the auction recovery health factor * @param value The new auction health factor diff --git a/contracts/interfaces/IPoolPositionMover.sol b/contracts/interfaces/IPoolPositionMover.sol index ba84b4443..817d3fd02 100644 --- a/contracts/interfaces/IPoolPositionMover.sol +++ b/contracts/interfaces/IPoolPositionMover.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title IPool diff --git a/contracts/interfaces/IPriceOracle.sol b/contracts/interfaces/IPriceOracle.sol index b90ef12d7..ab7045337 100644 --- a/contracts/interfaces/IPriceOracle.sol +++ b/contracts/interfaces/IPriceOracle.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title IPriceOracle diff --git a/contracts/interfaces/IPriceOracleGetter.sol b/contracts/interfaces/IPriceOracleGetter.sol index 46fd2ff51..c7222ceef 100644 --- a/contracts/interfaces/IPriceOracleGetter.sol +++ b/contracts/interfaces/IPriceOracleGetter.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title IPriceOracleGetter diff --git a/contracts/interfaces/IPriceOracleSentinel.sol b/contracts/interfaces/IPriceOracleSentinel.sol index 29d18b7ba..2a02ba3cf 100644 --- a/contracts/interfaces/IPriceOracleSentinel.sol +++ b/contracts/interfaces/IPriceOracleSentinel.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPoolAddressesProvider} from "./IPoolAddressesProvider.sol"; diff --git a/contracts/interfaces/IProtocolDataProvider.sol b/contracts/interfaces/IProtocolDataProvider.sol index 3b703c68c..fc8d2e3fd 100644 --- a/contracts/interfaces/IProtocolDataProvider.sol +++ b/contracts/interfaces/IProtocolDataProvider.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {DataTypes} from "../protocol/libraries/types/DataTypes.sol"; diff --git a/contracts/interfaces/IReserveAuctionStrategy.sol b/contracts/interfaces/IReserveAuctionStrategy.sol index d0dbd5ef9..407630740 100644 --- a/contracts/interfaces/IReserveAuctionStrategy.sol +++ b/contracts/interfaces/IReserveAuctionStrategy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title IReserveAuctionStrategy diff --git a/contracts/interfaces/IReserveInterestRateStrategy.sol b/contracts/interfaces/IReserveInterestRateStrategy.sol index 5f736d52d..106f08d92 100644 --- a/contracts/interfaces/IReserveInterestRateStrategy.sol +++ b/contracts/interfaces/IReserveInterestRateStrategy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {DataTypes} from "../protocol/libraries/types/DataTypes.sol"; diff --git a/contracts/interfaces/IRewardController.sol b/contracts/interfaces/IRewardController.sol index b4393e053..ca9aa8711 100644 --- a/contracts/interfaces/IRewardController.sol +++ b/contracts/interfaces/IRewardController.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title IRewardController diff --git a/contracts/interfaces/ISafe.sol b/contracts/interfaces/ISafe.sol index 8fe0ebab7..111b1846e 100644 --- a/contracts/interfaces/ISafe.sol +++ b/contracts/interfaces/ISafe.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; interface ISafe { function addOwnerWithThreshold(address owner, uint256 _threshold) external; diff --git a/contracts/interfaces/IScaledBalanceToken.sol b/contracts/interfaces/IScaledBalanceToken.sol index b75ca316e..9fe2e3941 100644 --- a/contracts/interfaces/IScaledBalanceToken.sol +++ b/contracts/interfaces/IScaledBalanceToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title IScaledBalanceToken diff --git a/contracts/interfaces/ISequencerOracle.sol b/contracts/interfaces/ISequencerOracle.sol index 8c25ab70a..660695fdc 100644 --- a/contracts/interfaces/ISequencerOracle.sol +++ b/contracts/interfaces/ISequencerOracle.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title ISequencerOracle diff --git a/contracts/interfaces/IStakefishNFTManager.sol b/contracts/interfaces/IStakefishNFTManager.sol index 1c94d499f..233eec7cf 100644 --- a/contracts/interfaces/IStakefishNFTManager.sol +++ b/contracts/interfaces/IStakefishNFTManager.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; interface IStakefishNFTManager { /// @notice Withdraw from NFT - only allowed for ownerOf(tokenId) diff --git a/contracts/interfaces/IStakefishValidator.sol b/contracts/interfaces/IStakefishValidator.sol index 2d0b7a7e9..3f4a4501d 100644 --- a/contracts/interfaces/IStakefishValidator.sol +++ b/contracts/interfaces/IStakefishValidator.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; /// @title The interface for StakefishValidator /// @notice Defines implementation of the wallet (deposit, withdraw, collect fees) diff --git a/contracts/interfaces/ITimeLock.sol b/contracts/interfaces/ITimeLock.sol index ea10eb7a1..be8b3d058 100644 --- a/contracts/interfaces/ITimeLock.sol +++ b/contracts/interfaces/ITimeLock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import {DataTypes} from "../protocol/libraries/types/DataTypes.sol"; diff --git a/contracts/interfaces/ITimeLockStrategy.sol b/contracts/interfaces/ITimeLockStrategy.sol index 767948613..96d129c57 100644 --- a/contracts/interfaces/ITimeLockStrategy.sol +++ b/contracts/interfaces/ITimeLockStrategy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import {DataTypes} from "../protocol/libraries/types/DataTypes.sol"; diff --git a/contracts/interfaces/IToken.sol b/contracts/interfaces/IToken.sol index ff5172569..8368d9f81 100644 --- a/contracts/interfaces/IToken.sol +++ b/contracts/interfaces/IToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; interface IToken { function balanceOf(address) external view returns (uint256); diff --git a/contracts/interfaces/ITokenDelegation.sol b/contracts/interfaces/ITokenDelegation.sol index c16cc150f..c240023ec 100644 --- a/contracts/interfaces/ITokenDelegation.sol +++ b/contracts/interfaces/ITokenDelegation.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; interface ITokenDelegation { /** diff --git a/contracts/interfaces/IUniswapV3OracleWrapper.sol b/contracts/interfaces/IUniswapV3OracleWrapper.sol index 9c039de3e..8e5e2f64e 100644 --- a/contracts/interfaces/IUniswapV3OracleWrapper.sol +++ b/contracts/interfaces/IUniswapV3OracleWrapper.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IAtomicPriceAggregator} from "../interfaces/IAtomicPriceAggregator.sol"; import {IUniswapV3PositionInfoProvider} from "../interfaces/IUniswapV3PositionInfoProvider.sol"; diff --git a/contracts/interfaces/IUniswapV3PositionInfoProvider.sol b/contracts/interfaces/IUniswapV3PositionInfoProvider.sol index 31538dc86..468aac65c 100644 --- a/contracts/interfaces/IUniswapV3PositionInfoProvider.sol +++ b/contracts/interfaces/IUniswapV3PositionInfoProvider.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; struct UinswapV3PositionData { address token0; diff --git a/contracts/interfaces/IVariableDebtToken.sol b/contracts/interfaces/IVariableDebtToken.sol index 937dd9774..2cbcdb449 100644 --- a/contracts/interfaces/IVariableDebtToken.sol +++ b/contracts/interfaces/IVariableDebtToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IScaledBalanceToken} from "./IScaledBalanceToken.sol"; import {IInitializableDebtToken} from "./IInitializableDebtToken.sol"; diff --git a/contracts/interfaces/IVoteDelegator.sol b/contracts/interfaces/IVoteDelegator.sol index f736d5b8d..db8df830c 100644 --- a/contracts/interfaces/IVoteDelegator.sol +++ b/contracts/interfaces/IVoteDelegator.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.10; +pragma solidity ^0.8.0; interface IVoteDelegator { function setVotingDelegate( diff --git a/contracts/interfaces/IX2Y2.sol b/contracts/interfaces/IX2Y2.sol index 7e1e34311..b80aa1e81 100644 --- a/contracts/interfaces/IX2Y2.sol +++ b/contracts/interfaces/IX2Y2.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; interface IX2Y2 { enum Op { diff --git a/contracts/interfaces/IXTokenType.sol b/contracts/interfaces/IXTokenType.sol index accf781fe..79a6df9fb 100644 --- a/contracts/interfaces/IXTokenType.sol +++ b/contracts/interfaces/IXTokenType.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title IXTokenType @@ -34,7 +34,8 @@ enum XTokenType { PhantomData7, PhantomData8, PhantomData9, - PhantomData10 + PhantomData10, + PTokenStKSM } interface IXTokenType { diff --git a/contracts/interfaces/IYieldInfo.sol b/contracts/interfaces/IYieldInfo.sol index fd5d1b760..b298799ad 100644 --- a/contracts/interfaces/IYieldInfo.sol +++ b/contracts/interfaces/IYieldInfo.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; interface IYieldInfo { /** diff --git a/contracts/misc/CLCETHSynchronicityPriceAdapter.sol b/contracts/misc/CLCETHSynchronicityPriceAdapter.sol index 4dca7e82b..1b22f74e2 100644 --- a/contracts/misc/CLCETHSynchronicityPriceAdapter.sol +++ b/contracts/misc/CLCETHSynchronicityPriceAdapter.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import {ICLSynchronicityPriceAdapter} from "../dependencies/chainlink/ICLSynchronicityPriceAdapter.sol"; import {CLExchangeRateSynchronicityPriceAdapter} from "./CLExchangeRateSynchronicityPriceAdapter.sol"; diff --git a/contracts/misc/CLExchangeRateSynchronicityPriceAdapter.sol b/contracts/misc/CLExchangeRateSynchronicityPriceAdapter.sol index 454cb69c8..54b5d7688 100644 --- a/contracts/misc/CLExchangeRateSynchronicityPriceAdapter.sol +++ b/contracts/misc/CLExchangeRateSynchronicityPriceAdapter.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import {ICLSynchronicityPriceAdapter} from "../dependencies/chainlink/ICLSynchronicityPriceAdapter.sol"; import {IExchangeRate} from "../interfaces/IExchangeRate.sol"; diff --git a/contracts/misc/CLFixedPriceSynchronicityPriceAdapter.sol b/contracts/misc/CLFixedPriceSynchronicityPriceAdapter.sol index 166324211..fc5102487 100644 --- a/contracts/misc/CLFixedPriceSynchronicityPriceAdapter.sol +++ b/contracts/misc/CLFixedPriceSynchronicityPriceAdapter.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {ICLSynchronicityPriceAdapter} from "../dependencies/chainlink/ICLSynchronicityPriceAdapter.sol"; diff --git a/contracts/misc/CLwstETHSynchronicityPriceAdapter.sol b/contracts/misc/CLwstETHSynchronicityPriceAdapter.sol index d699b13a1..575a849ef 100644 --- a/contracts/misc/CLwstETHSynchronicityPriceAdapter.sol +++ b/contracts/misc/CLwstETHSynchronicityPriceAdapter.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import {IEACAggregatorProxy} from "../interfaces/IEACAggregatorProxy.sol"; import {ICLSynchronicityPriceAdapter} from "../dependencies/chainlink/ICLSynchronicityPriceAdapter.sol"; diff --git a/contracts/misc/DefaultTimeLockStrategy.sol b/contracts/misc/DefaultTimeLockStrategy.sol index 868914fdd..ff68d0443 100644 --- a/contracts/misc/DefaultTimeLockStrategy.sol +++ b/contracts/misc/DefaultTimeLockStrategy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "../interfaces/ITimeLockStrategy.sol"; import "../protocol/libraries/helpers/Errors.sol"; diff --git a/contracts/misc/ERC20OracleWrapper.sol b/contracts/misc/ERC20OracleWrapper.sol new file mode 100644 index 000000000..384fb68f0 --- /dev/null +++ b/contracts/misc/ERC20OracleWrapper.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.0; + +import {ICLSynchronicityPriceAdapter} from "../dependencies/chainlink/ICLSynchronicityPriceAdapter.sol"; +import {IPyth} from "../dependencies/pyth/IPyth.sol"; + +contract ERC20OracleWrapper is ICLSynchronicityPriceAdapter { + IPyth internal immutable PYTH; + bytes32 internal immutable FEED_ID; + uint256 internal immutable EXPIRATION_PERIOD; + uint8 internal immutable DECIMALS; + + constructor( + address pyth, + bytes32 feedId, + uint256 expirationPeriod, + uint8 decimals + ) { + PYTH = IPyth(pyth); + FEED_ID = feedId; + EXPIRATION_PERIOD = expirationPeriod; + DECIMALS = decimals; + } + + /// @inheritdoc ICLSynchronicityPriceAdapter + function latestAnswer() public view virtual override returns (int256) { + return PYTH.getPriceNoOlderThan(FEED_ID, EXPIRATION_PERIOD).price; + } + + function decimals() external view returns (uint8) { + return DECIMALS; + } +} diff --git a/contracts/misc/ERC721OracleWrapper.sol b/contracts/misc/ERC721OracleWrapper.sol index 865d23457..f9694541a 100644 --- a/contracts/misc/ERC721OracleWrapper.sol +++ b/contracts/misc/ERC721OracleWrapper.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IEACAggregatorProxy} from "../interfaces/IEACAggregatorProxy.sol"; import {Errors} from "../protocol/libraries/helpers/Errors.sol"; diff --git a/contracts/misc/HelperContract.sol b/contracts/misc/HelperContract.sol index 24363ceef..5cff9d808 100644 --- a/contracts/misc/HelperContract.sol +++ b/contracts/misc/HelperContract.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "../dependencies/openzeppelin/upgradeability/Initializable.sol"; import "../dependencies/openzeppelin/upgradeability/OwnableUpgradeable.sol"; diff --git a/contracts/misc/NFTFloorOracle.sol b/contracts/misc/NFTFloorOracle.sol index b83d44ff0..b46855a61 100644 --- a/contracts/misc/NFTFloorOracle.sol +++ b/contracts/misc/NFTFloorOracle.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "../dependencies/openzeppelin/contracts/AccessControl.sol"; import "../dependencies/openzeppelin/upgradeability/Initializable.sol"; diff --git a/contracts/misc/ParaSpaceAirDrop.sol b/contracts/misc/ParaSpaceAirDrop.sol index 9848d486a..607eaafc1 100644 --- a/contracts/misc/ParaSpaceAirDrop.sol +++ b/contracts/misc/ParaSpaceAirDrop.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC20} from "../dependencies/openzeppelin/contracts/IERC20.sol"; import {Ownable} from "../dependencies/openzeppelin/contracts/Ownable.sol"; diff --git a/contracts/misc/ParaSpaceOracle.sol b/contracts/misc/ParaSpaceOracle.sol index cdef1fac5..effcf73e4 100644 --- a/contracts/misc/ParaSpaceOracle.sol +++ b/contracts/misc/ParaSpaceOracle.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IEACAggregatorProxy} from "../interfaces/IEACAggregatorProxy.sol"; diff --git a/contracts/misc/ProtocolDataProvider.sol b/contracts/misc/ProtocolDataProvider.sol index b752f1077..3bd2f7e00 100644 --- a/contracts/misc/ProtocolDataProvider.sol +++ b/contracts/misc/ProtocolDataProvider.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC20Detailed} from "../dependencies/openzeppelin/contracts/IERC20Detailed.sol"; import {IERC721Metadata} from "../dependencies/openzeppelin/contracts/IERC721Metadata.sol"; diff --git a/contracts/misc/TimeLock.sol b/contracts/misc/TimeLock.sol index 229b535d4..65f1d8f46 100644 --- a/contracts/misc/TimeLock.sol +++ b/contracts/misc/TimeLock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import {IERC20} from "../dependencies/openzeppelin/contracts/IERC20.sol"; import {IERC721} from "../dependencies/openzeppelin/contracts/IERC721.sol"; @@ -34,6 +34,7 @@ contract TimeLock is ITimeLock, ReentrancyGuardUpgradeable, IERC721Receiver { address private immutable weth; address private immutable wpunk; address private immutable Punk; + address private immutable PARA_APE_STAKING; /** * @dev Only POOL or callerTag asset's xToken can call functions marked by this modifier. @@ -41,6 +42,7 @@ contract TimeLock is ITimeLock, ReentrancyGuardUpgradeable, IERC721Receiver { modifier onlyValidCaller(address sourceAsset) { require( msg.sender == address(POOL) || + msg.sender == PARA_APE_STAKING || msg.sender == POOL.getReserveXToken(sourceAsset), Errors.CALLER_NOT_ALLOWED ); @@ -72,6 +74,7 @@ contract TimeLock is ITimeLock, ReentrancyGuardUpgradeable, IERC721Receiver { ? IWrappedPunks(_wpunk).punkContract() : address(0); weth = provider.getWETH(); + PARA_APE_STAKING = POOL.paraApeStaking(); } function initialize() public initializer { diff --git a/contracts/misc/UniswapV3OracleWrapper.sol b/contracts/misc/UniswapV3OracleWrapper.sol index 03080a36d..b2407619c 100644 --- a/contracts/misc/UniswapV3OracleWrapper.sol +++ b/contracts/misc/UniswapV3OracleWrapper.sol @@ -1,20 +1,20 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IUniswapV3OracleWrapper} from "../interfaces/IUniswapV3OracleWrapper.sol"; import {IPoolAddressesProvider} from "../interfaces/IPoolAddressesProvider.sol"; import {IPriceOracleGetter} from "../interfaces/IPriceOracleGetter.sol"; -import {IUniswapV3Factory} from "../dependencies/uniswap/IUniswapV3Factory.sol"; -import {IUniswapV3PoolState} from "../dependencies/uniswap/IUniswapV3PoolState.sol"; -import {INonfungiblePositionManager} from "../dependencies/uniswap/INonfungiblePositionManager.sol"; -import {LiquidityAmounts} from "../dependencies/uniswap/LiquidityAmounts.sol"; -import {TickMath} from "../dependencies/uniswap/libraries/TickMath.sol"; +import {IUniswapV3Factory} from "../dependencies/uniswapv3-core/interfaces/IUniswapV3Factory.sol"; +import {IUniswapV3PoolState} from "../dependencies/uniswapv3-core/interfaces/pool/IUniswapV3PoolState.sol"; +import {INonfungiblePositionManager} from "../dependencies/uniswapv3-periphery/interfaces/INonfungiblePositionManager.sol"; +import {LiquidityAmounts} from "../dependencies/uniswapv3-periphery/libraries/LiquidityAmounts.sol"; +import {TickMath} from "../dependencies/uniswapv3-core/libraries/TickMath.sol"; import {SqrtLib} from "../dependencies/math/SqrtLib.sol"; -import {FullMath} from "../dependencies/uniswap/libraries/FullMath.sol"; +import {FullMath} from "../dependencies/uniswapv3-core/libraries/FullMath.sol"; import {IERC20Detailed} from "../dependencies/openzeppelin/contracts/IERC20Detailed.sol"; import {UinswapV3PositionData} from "../interfaces/IUniswapV3PositionInfoProvider.sol"; -import {SafeCast} from "../dependencies/univ3/libraries/SafeCast.sol"; -import {FixedPoint96} from "../dependencies/univ3/libraries/FixedPoint96.sol"; +import {SafeCast} from "../dependencies/uniswapv3-core/libraries/SafeCast.sol"; +import {FixedPoint96} from "../dependencies/uniswapv3-core/libraries/FixedPoint96.sol"; contract UniswapV3OracleWrapper is IUniswapV3OracleWrapper { using SafeCast for uint256; diff --git a/contracts/misc/UniswapV3TwapOracleWrapper.sol b/contracts/misc/UniswapV3TwapOracleWrapper.sol index 3e001e34b..d8fb11b67 100644 --- a/contracts/misc/UniswapV3TwapOracleWrapper.sol +++ b/contracts/misc/UniswapV3TwapOracleWrapper.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; -import {IUniswapV3PoolDerivedState} from "../dependencies/uniswap/IUniswapV3PoolDerivedState.sol"; -import {IUniswapV3PoolState} from "../dependencies/uniswap/IUniswapV3PoolState.sol"; -import {SafeCast} from "../dependencies/univ3/libraries/SafeCast.sol"; +import {IUniswapV3PoolDerivedState} from "../dependencies/uniswapv3-core/interfaces/pool/IUniswapV3PoolDerivedState.sol"; +import {IUniswapV3PoolImmutables} from "../dependencies/uniswapv3-core/interfaces/pool/IUniswapV3PoolImmutables.sol"; +import {SafeCast} from "../dependencies/uniswapv3-core/libraries/SafeCast.sol"; import {ICLSynchronicityPriceAdapter} from "../dependencies/chainlink/ICLSynchronicityPriceAdapter.sol"; -import {TickMath} from "../dependencies/uniswap/libraries/TickMath.sol"; -import {FullMath} from "../dependencies/uniswap/libraries/FullMath.sol"; -import {FixedPoint96} from "../dependencies/univ3/libraries/FixedPoint96.sol"; +import {TickMath} from "../dependencies/uniswapv3-core/libraries/TickMath.sol"; +import {FullMath} from "../dependencies/uniswapv3-core/libraries/FullMath.sol"; +import {FixedPoint96} from "../dependencies/uniswapv3-core/libraries/FixedPoint96.sol"; import {IERC20Detailed} from "../dependencies/openzeppelin/contracts/IERC20Detailed.sol"; contract UniswapV3TwapOracleWrapper is ICLSynchronicityPriceAdapter { @@ -27,8 +27,8 @@ contract UniswapV3TwapOracleWrapper is ICLSynchronicityPriceAdapter { UNISWAP_V3_POOL = _pool; TWAP_WINDOW = twapWindow; - address token0 = IUniswapV3PoolState(_pool).token0(); - address token1 = IUniswapV3PoolState(_pool).token1(); + address token0 = IUniswapV3PoolImmutables(_pool).token0(); + address token1 = IUniswapV3PoolImmutables(_pool).token1(); IS_ASSET_RESERVE_ZERO = token0 != _baseCurrency; ASSET = IS_ASSET_RESERVE_ZERO ? token0 : token1; diff --git a/contracts/misc/flashclaim/AirdropFlashClaimReceiver.sol b/contracts/misc/flashclaim/AirdropFlashClaimReceiver.sol index 1dc126b75..7ff046d93 100644 --- a/contracts/misc/flashclaim/AirdropFlashClaimReceiver.sol +++ b/contracts/misc/flashclaim/AirdropFlashClaimReceiver.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "../interfaces/IFlashClaimReceiver.sol"; import "../../dependencies/openzeppelin/contracts/Address.sol"; @@ -86,10 +86,6 @@ contract AirdropFlashClaimReceiver is (uint256[], address[], uint256[], address, bytes) ); - require( - vars.airdropTokenTypes.length > 0, - "invalid airdrop token type" - ); require( vars.airdropTokenAddresses.length == vars.airdropTokenTypes.length, "invalid airdrop token address length" @@ -218,6 +214,25 @@ contract AirdropFlashClaimReceiver is IERC721(token).safeTransferFrom(address(this), to, id); } + /** + * @notice batch transfer ERC721 Tokens. + * @param token The address of the token + * @param to The address of the recipient + * @param ids The tokenId being transfer + **/ + function batchTransferERC721( + address token, + address to, + uint256[] calldata ids + ) external nonReentrant onlyOwner { + for (uint256 index = 0; index < ids.length; ) { + IERC721(token).safeTransferFrom(address(this), to, ids[index]); + unchecked { + index++; + } + } + } + /** * @notice transfer ERC1155 Token. * @param token The address of the token diff --git a/contracts/misc/flashclaim/UserFlashclaimRegistry.sol b/contracts/misc/flashclaim/UserFlashclaimRegistry.sol index dcfafd3c7..6d1944009 100644 --- a/contracts/misc/flashclaim/UserFlashclaimRegistry.sol +++ b/contracts/misc/flashclaim/UserFlashclaimRegistry.sol @@ -1,18 +1,16 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "./AirdropFlashClaimReceiver.sol"; import "../interfaces/IUserFlashclaimRegistry.sol"; import "../../dependencies/openzeppelin/upgradeability/Clones.sol"; contract UserFlashclaimRegistry is IUserFlashclaimRegistry { - address public immutable pool; mapping(address => address) public userReceivers; address public immutable receiverImplementation; - constructor(address pool_, address receiverImplementation_) { - pool = pool_; + constructor(address receiverImplementation_) { receiverImplementation = receiverImplementation_; } diff --git a/contracts/misc/interfaces/IFlashClaimReceiver.sol b/contracts/misc/interfaces/IFlashClaimReceiver.sol index 34f28c9ca..8c626ee7c 100644 --- a/contracts/misc/interfaces/IFlashClaimReceiver.sol +++ b/contracts/misc/interfaces/IFlashClaimReceiver.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title IFlashClaimReceiver interface diff --git a/contracts/misc/interfaces/IMoonCatsRescue.sol b/contracts/misc/interfaces/IMoonCatsRescue.sol index 11da7a5f7..0af19e9df 100644 --- a/contracts/misc/interfaces/IMoonCatsRescue.sol +++ b/contracts/misc/interfaces/IMoonCatsRescue.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; interface IMoonCatsRescue { function acceptAdoptionOffer(bytes5 catId) external payable; diff --git a/contracts/misc/interfaces/INFTFloorOracle.sol b/contracts/misc/interfaces/INFTFloorOracle.sol index 19d4153b4..9590335b4 100644 --- a/contracts/misc/interfaces/INFTFloorOracle.sol +++ b/contracts/misc/interfaces/INFTFloorOracle.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; interface INFTFloorOracle { function getPrice(address token) external view returns (uint256 price); diff --git a/contracts/misc/interfaces/INFTOracle.sol b/contracts/misc/interfaces/INFTOracle.sol index 77918ecd3..e6429c9e9 100644 --- a/contracts/misc/interfaces/INFTOracle.sol +++ b/contracts/misc/interfaces/INFTOracle.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /************ @title INFTOracle interface diff --git a/contracts/misc/interfaces/IPunks.sol b/contracts/misc/interfaces/IPunks.sol index 7cfd48590..13c25a399 100644 --- a/contracts/misc/interfaces/IPunks.sol +++ b/contracts/misc/interfaces/IPunks.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @dev Interface for a permittable ERC721 contract diff --git a/contracts/misc/interfaces/IUniswapV2Factory.sol b/contracts/misc/interfaces/IUniswapV2Factory.sol index c09037e96..26d743dab 100644 --- a/contracts/misc/interfaces/IUniswapV2Factory.sol +++ b/contracts/misc/interfaces/IUniswapV2Factory.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; interface IUniswapV2Factory { function getPair(address tokenA, address tokenB) diff --git a/contracts/misc/interfaces/IUniswapV2Pair.sol b/contracts/misc/interfaces/IUniswapV2Pair.sol index 85ccad468..95b03f181 100644 --- a/contracts/misc/interfaces/IUniswapV2Pair.sol +++ b/contracts/misc/interfaces/IUniswapV2Pair.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity >=0.5.0; +pragma solidity ^0.8.0; interface IUniswapV2Pair { function getReserves() diff --git a/contracts/misc/interfaces/IUniswapV2Router01.sol b/contracts/misc/interfaces/IUniswapV2Router01.sol index e68d3df06..c3899e3e8 100644 --- a/contracts/misc/interfaces/IUniswapV2Router01.sol +++ b/contracts/misc/interfaces/IUniswapV2Router01.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; interface IUniswapV2Router01 { function getAmountOut( diff --git a/contracts/misc/interfaces/IUserFlashclaimRegistry.sol b/contracts/misc/interfaces/IUserFlashclaimRegistry.sol index edbf92469..94877b2ac 100644 --- a/contracts/misc/interfaces/IUserFlashclaimRegistry.sol +++ b/contracts/misc/interfaces/IUserFlashclaimRegistry.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; interface IUserFlashclaimRegistry { function createReceiver() external; diff --git a/contracts/misc/interfaces/IWETH.sol b/contracts/misc/interfaces/IWETH.sol index 13cf9b644..33ec3a464 100644 --- a/contracts/misc/interfaces/IWETH.sol +++ b/contracts/misc/interfaces/IWETH.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; interface IWETH { function deposit() external payable; diff --git a/contracts/misc/interfaces/IWrappedPunks.sol b/contracts/misc/interfaces/IWrappedPunks.sol index 3417df71c..61abfd518 100644 --- a/contracts/misc/interfaces/IWrappedPunks.sol +++ b/contracts/misc/interfaces/IWrappedPunks.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC721} from "../../../contracts/dependencies/openzeppelin/contracts/IERC721.sol"; diff --git a/contracts/misc/marketplaces/BlurAdapter.sol b/contracts/misc/marketplaces/BlurAdapter.sol index ef4a8fde2..bcc77523d 100644 --- a/contracts/misc/marketplaces/BlurAdapter.sol +++ b/contracts/misc/marketplaces/BlurAdapter.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {DataTypes} from "../../protocol/libraries/types/DataTypes.sol"; import {Errors} from "../../protocol/libraries/helpers/Errors.sol"; diff --git a/contracts/misc/marketplaces/LooksRareAdapter.sol b/contracts/misc/marketplaces/LooksRareAdapter.sol index 8b202886c..f72de6639 100644 --- a/contracts/misc/marketplaces/LooksRareAdapter.sol +++ b/contracts/misc/marketplaces/LooksRareAdapter.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {DataTypes} from "../../protocol/libraries/types/DataTypes.sol"; import {Errors} from "../../protocol/libraries/helpers/Errors.sol"; diff --git a/contracts/misc/marketplaces/SeaportAdapter.sol b/contracts/misc/marketplaces/SeaportAdapter.sol index 69be72f1d..0ff2d25e7 100644 --- a/contracts/misc/marketplaces/SeaportAdapter.sol +++ b/contracts/misc/marketplaces/SeaportAdapter.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {DataTypes} from "../../protocol/libraries/types/DataTypes.sol"; import {Errors} from "../../protocol/libraries/helpers/Errors.sol"; diff --git a/contracts/misc/marketplaces/X2Y2Adapter.sol b/contracts/misc/marketplaces/X2Y2Adapter.sol index 8c0907da8..a9fdadadb 100644 --- a/contracts/misc/marketplaces/X2Y2Adapter.sol +++ b/contracts/misc/marketplaces/X2Y2Adapter.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {DataTypes} from "../../protocol/libraries/types/DataTypes.sol"; import {Errors} from "../../protocol/libraries/helpers/Errors.sol"; diff --git a/contracts/mocks/DepositContract.sol b/contracts/mocks/DepositContract.sol index 778966d62..56ac297f9 100644 --- a/contracts/mocks/DepositContract.sol +++ b/contracts/mocks/DepositContract.sol @@ -9,7 +9,7 @@ // SPDX-License-Identifier: CC0-1.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; // This interface is designed to be compatible with the Vyper version. /// @notice This is the Ethereum 2.0 deposit contract interface. diff --git a/contracts/mocks/MockFeePool.sol b/contracts/mocks/MockFeePool.sol index 5537b407e..30923e4b8 100644 --- a/contracts/mocks/MockFeePool.sol +++ b/contracts/mocks/MockFeePool.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {Helpers} from "../protocol/libraries/helpers/Helpers.sol"; diff --git a/contracts/mocks/MockTestTimeLockStrategy.sol b/contracts/mocks/MockTestTimeLockStrategy.sol index 01deedaf4..85adb5efa 100644 --- a/contracts/mocks/MockTestTimeLockStrategy.sol +++ b/contracts/mocks/MockTestTimeLockStrategy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "../interfaces/ITimeLockStrategy.sol"; diff --git a/contracts/mocks/MockedDelegateRegistry.sol b/contracts/mocks/MockedDelegateRegistry.sol index 9067dac54..fd5bb9585 100644 --- a/contracts/mocks/MockedDelegateRegistry.sol +++ b/contracts/mocks/MockedDelegateRegistry.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.10; +pragma solidity ^0.8.0; contract MockedDelegateRegistry { diff --git a/contracts/mocks/benddao/MockLendPool.sol b/contracts/mocks/benddao/MockLendPool.sol index 0e98f2732..04b13470d 100644 --- a/contracts/mocks/benddao/MockLendPool.sol +++ b/contracts/mocks/benddao/MockLendPool.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {BDaoDataTypes} from "../../dependencies/benddao/contracts/libraries/types/BDaoDataTypes.sol"; import {IERC721} from "../../dependencies/openzeppelin/contracts/IERC721.sol"; diff --git a/contracts/mocks/helpers/MockIncentivesController.sol b/contracts/mocks/helpers/MockIncentivesController.sol index c6480f60a..29f188fd4 100644 --- a/contracts/mocks/helpers/MockIncentivesController.sol +++ b/contracts/mocks/helpers/MockIncentivesController.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IRewardController} from "../../interfaces/IRewardController.sol"; diff --git a/contracts/mocks/helpers/MockPeripheryContract.sol b/contracts/mocks/helpers/MockPeripheryContract.sol index 2c9a9be78..c9ff71694 100644 --- a/contracts/mocks/helpers/MockPeripheryContract.sol +++ b/contracts/mocks/helpers/MockPeripheryContract.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; contract MockPeripheryContractV1 { address private _manager; diff --git a/contracts/mocks/helpers/MockReserveConfiguration.sol b/contracts/mocks/helpers/MockReserveConfiguration.sol index d8f2e61be..c79835489 100644 --- a/contracts/mocks/helpers/MockReserveConfiguration.sol +++ b/contracts/mocks/helpers/MockReserveConfiguration.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {ReserveConfiguration} from "../../protocol/libraries/configuration/ReserveConfiguration.sol"; import {DataTypes} from "../../protocol/libraries/types/DataTypes.sol"; diff --git a/contracts/mocks/helpers/SelfDestructTransfer.sol b/contracts/mocks/helpers/SelfDestructTransfer.sol index 7d989de8e..cc31885a7 100644 --- a/contracts/mocks/helpers/SelfDestructTransfer.sol +++ b/contracts/mocks/helpers/SelfDestructTransfer.sol @@ -1,8 +1,10 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; + +import {Helpers} from "../../protocol/libraries/helpers/Helpers.sol"; contract SelfdestructTransfer { function destroyAndTransfer(address payable to) external payable { - selfdestruct(to); + revert("selfdestruct is deprecated"); } } diff --git a/contracts/mocks/oracle/CLAggregators/MockAggregator.sol b/contracts/mocks/oracle/CLAggregators/MockAggregator.sol index b64ac6cd3..30d0e6560 100644 --- a/contracts/mocks/oracle/CLAggregators/MockAggregator.sol +++ b/contracts/mocks/oracle/CLAggregators/MockAggregator.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IEACAggregatorProxy} from "../../../interfaces/IEACAggregatorProxy.sol"; diff --git a/contracts/mocks/oracle/PriceOracle.sol b/contracts/mocks/oracle/PriceOracle.sol index df3aa64ee..1c42d2384 100644 --- a/contracts/mocks/oracle/PriceOracle.sol +++ b/contracts/mocks/oracle/PriceOracle.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPriceOracle} from "../../interfaces/IPriceOracle.sol"; diff --git a/contracts/mocks/oracle/SequencerOracle.sol b/contracts/mocks/oracle/SequencerOracle.sol index 35cd38b2e..c72aa53f6 100644 --- a/contracts/mocks/oracle/SequencerOracle.sol +++ b/contracts/mocks/oracle/SequencerOracle.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {Ownable} from "../../dependencies/openzeppelin/contracts/Ownable.sol"; import {ISequencerOracle} from "../../interfaces/ISequencerOracle.sol"; diff --git a/contracts/mocks/tests/HotWalletProxy.sol b/contracts/mocks/tests/HotWalletProxy.sol index 0749a7ea5..9954d0271 100644 --- a/contracts/mocks/tests/HotWalletProxy.sol +++ b/contracts/mocks/tests/HotWalletProxy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.4; +pragma solidity ^0.8.0; import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; diff --git a/contracts/mocks/tests/MockAirdropProject.sol b/contracts/mocks/tests/MockAirdropProject.sol index af057ffc0..1943e95c1 100644 --- a/contracts/mocks/tests/MockAirdropProject.sol +++ b/contracts/mocks/tests/MockAirdropProject.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "../tokens/MintableERC20.sol"; import "../tokens/AirdropMintableERC721.sol"; diff --git a/contracts/mocks/tests/MockMultiAssetAirdropProject.sol b/contracts/mocks/tests/MockMultiAssetAirdropProject.sol index 021a05dfd..bca826c1e 100644 --- a/contracts/mocks/tests/MockMultiAssetAirdropProject.sol +++ b/contracts/mocks/tests/MockMultiAssetAirdropProject.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "../tokens/MintableERC20.sol"; import "../tokens/AirdropMintableERC721.sol"; diff --git a/contracts/mocks/tests/MockReserveAuctionStrategy.sol b/contracts/mocks/tests/MockReserveAuctionStrategy.sol index 98f48f94a..b82552486 100644 --- a/contracts/mocks/tests/MockReserveAuctionStrategy.sol +++ b/contracts/mocks/tests/MockReserveAuctionStrategy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC20} from "../../dependencies/openzeppelin/contracts/IERC20.sol"; import {WadRayMath} from "../../protocol/libraries/math/WadRayMath.sol"; diff --git a/contracts/mocks/tests/MockReserveInterestRateStrategy.sol b/contracts/mocks/tests/MockReserveInterestRateStrategy.sol index 82953a7cd..156f92f5a 100644 --- a/contracts/mocks/tests/MockReserveInterestRateStrategy.sol +++ b/contracts/mocks/tests/MockReserveInterestRateStrategy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IReserveInterestRateStrategy} from "../../interfaces/IReserveInterestRateStrategy.sol"; import {IPoolAddressesProvider} from "../../interfaces/IPoolAddressesProvider.sol"; diff --git a/contracts/mocks/tests/WadRayMathWrapper.sol b/contracts/mocks/tests/WadRayMathWrapper.sol index 8ca846d86..0d2e81003 100644 --- a/contracts/mocks/tests/WadRayMathWrapper.sol +++ b/contracts/mocks/tests/WadRayMathWrapper.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {WadRayMath} from "../../protocol/libraries/math/WadRayMath.sol"; diff --git a/contracts/mocks/tokens/AirdropMintableERC721.sol b/contracts/mocks/tokens/AirdropMintableERC721.sol index 26df451be..b1b932fb8 100644 --- a/contracts/mocks/tokens/AirdropMintableERC721.sol +++ b/contracts/mocks/tokens/AirdropMintableERC721.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "../../dependencies/openzeppelin/contracts/ERC721Enumerable.sol"; diff --git a/contracts/mocks/tokens/BAYC.sol b/contracts/mocks/tokens/BAYC.sol index 78ae1d8b2..fcf54c277 100644 --- a/contracts/mocks/tokens/BAYC.sol +++ b/contracts/mocks/tokens/BAYC.sol @@ -1,7 +1,7 @@ /** *Submitted for verification at Etherscan.io on 2021-04-22 */ -pragma solidity 0.8.10; +pragma solidity ^0.8.0; // File: @openzeppelin/contracts/utils/Context.sol diff --git a/contracts/mocks/tokens/BAYCSewerPass.sol b/contracts/mocks/tokens/BAYCSewerPass.sol index 23e0bfde4..d71530b87 100644 --- a/contracts/mocks/tokens/BAYCSewerPass.sol +++ b/contracts/mocks/tokens/BAYCSewerPass.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {Ownable} from "../../../contracts/dependencies/openzeppelin/contracts/Ownable.sol"; diff --git a/contracts/mocks/tokens/BAYCSewerPassClaim.sol b/contracts/mocks/tokens/BAYCSewerPassClaim.sol index cdbaa4be1..3bb3934e1 100644 --- a/contracts/mocks/tokens/BAYCSewerPassClaim.sol +++ b/contracts/mocks/tokens/BAYCSewerPassClaim.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {ReentrancyGuard} from "../../dependencies/openzeppelin/contracts/ReentrancyGuard.sol"; import {IERC721} from "../../dependencies/openzeppelin/contracts/IERC721.sol"; diff --git a/contracts/mocks/tokens/CloneX.sol b/contracts/mocks/tokens/CloneX.sol index 1c0add453..c6059ab18 100644 --- a/contracts/mocks/tokens/CloneX.sol +++ b/contracts/mocks/tokens/CloneX.sol @@ -911,7 +911,7 @@ library Counters { A. Murakami Short Verbiage – User Experience Notice [Document #X-1, https://rtfkt.com/legal-X1] */ -pragma solidity ^0.8.2; +pragma solidity ^0.8.0; abstract contract CloneXRandomizer { function getTokenId(uint256 tokenId) diff --git a/contracts/mocks/tokens/CryptoPunksMarket.sol b/contracts/mocks/tokens/CryptoPunksMarket.sol index 1349b0696..f7b8281ad 100644 --- a/contracts/mocks/tokens/CryptoPunksMarket.sol +++ b/contracts/mocks/tokens/CryptoPunksMarket.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {Ownable} from "../../../contracts/dependencies/openzeppelin/contracts/Ownable.sol"; diff --git a/contracts/mocks/tokens/DOODLES.sol b/contracts/mocks/tokens/DOODLES.sol index 5e65c0a25..79ca7489a 100644 --- a/contracts/mocks/tokens/DOODLES.sol +++ b/contracts/mocks/tokens/DOODLES.sol @@ -3,7 +3,7 @@ // File contracts/Mimetics/IMimeticMetadata.sol -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; interface IMimeticMetadata { struct Generation { @@ -767,7 +767,7 @@ interface IERC721Metadata is IERC721 { // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) -pragma solidity ^0.8.1; +pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type diff --git a/contracts/mocks/tokens/MAYC.sol b/contracts/mocks/tokens/MAYC.sol index deeec2c15..466ef2440 100644 --- a/contracts/mocks/tokens/MAYC.sol +++ b/contracts/mocks/tokens/MAYC.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; abstract contract Context { function _msgSender() internal view virtual returns (address payable) { diff --git a/contracts/mocks/tokens/MintableDelegationERC20.sol b/contracts/mocks/tokens/MintableDelegationERC20.sol index 508bb23b7..375f54bcf 100644 --- a/contracts/mocks/tokens/MintableDelegationERC20.sol +++ b/contracts/mocks/tokens/MintableDelegationERC20.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {ERC20} from "../../dependencies/openzeppelin/contracts/ERC20.sol"; import {IDelegationToken} from "../../interfaces/IDelegationToken.sol"; diff --git a/contracts/mocks/tokens/MintableERC1155.sol b/contracts/mocks/tokens/MintableERC1155.sol index 0bc0cbac6..d1a3c71bb 100644 --- a/contracts/mocks/tokens/MintableERC1155.sol +++ b/contracts/mocks/tokens/MintableERC1155.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "../../dependencies/openzeppelin/contracts/ERC1155.sol"; diff --git a/contracts/mocks/tokens/MintableERC20.sol b/contracts/mocks/tokens/MintableERC20.sol index ec02fb965..1778ab794 100644 --- a/contracts/mocks/tokens/MintableERC20.sol +++ b/contracts/mocks/tokens/MintableERC20.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {ERC20} from "../../dependencies/openzeppelin/contracts/ERC20.sol"; import {IERC20WithPermit} from "../../interfaces/IERC20WithPermit.sol"; diff --git a/contracts/mocks/tokens/MintableERC721.sol b/contracts/mocks/tokens/MintableERC721.sol index 62b297f14..e95cbfd5b 100644 --- a/contracts/mocks/tokens/MintableERC721.sol +++ b/contracts/mocks/tokens/MintableERC721.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol) -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {ERC721Enumerable} from "../../dependencies/openzeppelin/contracts/ERC721Enumerable.sol"; import {ERC721} from "../../dependencies/openzeppelin/contracts/ERC721.sol"; diff --git a/contracts/mocks/tokens/MintableNonEnumerableERC721.sol b/contracts/mocks/tokens/MintableNonEnumerableERC721.sol index e31ac7e4c..8b4ee1108 100644 --- a/contracts/mocks/tokens/MintableNonEnumerableERC721.sol +++ b/contracts/mocks/tokens/MintableNonEnumerableERC721.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol) -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {ERC721} from "../../dependencies/openzeppelin/contracts/ERC721.sol"; import {Context} from "../../dependencies/openzeppelin/contracts/Context.sol"; diff --git a/contracts/mocks/tokens/MockAStETH.sol b/contracts/mocks/tokens/MockAStETH.sol index 9d44ebfb4..c89d18afa 100644 --- a/contracts/mocks/tokens/MockAStETH.sol +++ b/contracts/mocks/tokens/MockAStETH.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {MintableERC20} from "./MintableERC20.sol"; import {WadRayMath} from "../../protocol/libraries/math/WadRayMath.sol"; diff --git a/contracts/mocks/tokens/MockAToken.sol b/contracts/mocks/tokens/MockAToken.sol index 4f6fb58ec..67ce1b934 100644 --- a/contracts/mocks/tokens/MockAToken.sol +++ b/contracts/mocks/tokens/MockAToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {MintableERC20} from "./MintableERC20.sol"; import {WadRayMath} from "../../protocol/libraries/math/WadRayMath.sol"; diff --git a/contracts/mocks/tokens/MockCToken.sol b/contracts/mocks/tokens/MockCToken.sol index a9956d8a1..33788e293 100644 --- a/contracts/mocks/tokens/MockCToken.sol +++ b/contracts/mocks/tokens/MockCToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {MintableERC20} from "./MintableERC20.sol"; import {IERC20Detailed} from "../../dependencies/openzeppelin/contracts/IERC20Detailed.sol"; diff --git a/contracts/mocks/tokens/MockRETH.sol b/contracts/mocks/tokens/MockRETH.sol index 15012925c..0e953400a 100644 --- a/contracts/mocks/tokens/MockRETH.sol +++ b/contracts/mocks/tokens/MockRETH.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {MintableERC20} from "./MintableERC20.sol"; import {WadRayMath} from "../../protocol/libraries/math/WadRayMath.sol"; diff --git a/contracts/mocks/tokens/MockTokenFaucet.sol b/contracts/mocks/tokens/MockTokenFaucet.sol index 03b75784a..ad8dae15b 100644 --- a/contracts/mocks/tokens/MockTokenFaucet.sol +++ b/contracts/mocks/tokens/MockTokenFaucet.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "../../dependencies/openzeppelin/contracts/EnumerableSet.sol"; import "../../dependencies/openzeppelin/contracts/Ownable.sol"; import "../../dependencies/openzeppelin/contracts/IMintableERC20.sol"; diff --git a/contracts/mocks/tokens/Moonbirds.sol b/contracts/mocks/tokens/Moonbirds.sol index cc117475e..6698f0380 100644 --- a/contracts/mocks/tokens/Moonbirds.sol +++ b/contracts/mocks/tokens/Moonbirds.sol @@ -433,7 +433,7 @@ abstract contract Ownable is Context { // MIT // Copyright (c) 2021 the ethier authors (github.com/divergencetech/ethier) -pragma solidity >=0.8.0 <0.9.0; +pragma solidity ^0.8.0; /** @notice ERC721 extension that overrides the OpenZeppelin _baseURI() function to @@ -471,7 +471,7 @@ contract BaseTokenURI is Ownable { // MIT // Copyright (c) 2021 the ethier authors (github.com/divergencetech/ethier) -pragma solidity >=0.8.0 <0.9.0; +pragma solidity ^0.8.0; /// @notice A minimal interface describing OpenSea's Wyvern proxy registry. contract ProxyRegistry { @@ -493,7 +493,7 @@ contract OwnableDelegateProxy { // MIT // Copyright (c) 2021 the ethier authors (github.com/divergencetech/ethier) -pragma solidity >=0.8.0 <0.9.0; +pragma solidity ^0.8.0; // Inspired by BaseOpenSea by Simon Fremaux (@dievardump) but without the need // to pass specific addresses depending on deployment network. @@ -569,7 +569,7 @@ library OpenSeaGasFreeListing { // ERC721A Contracts v4.1.0 // Creator: Chiru Labs -pragma solidity ^0.8.4; +pragma solidity ^0.8.0; /** * @dev Interface of an ERC721A compliant contract. @@ -872,7 +872,7 @@ interface IERC721A { // ERC721A Contracts v4.1.0 // Creator: Chiru Labs -pragma solidity ^0.8.4; +pragma solidity ^0.8.0; /** * @dev ERC721 token receiver interface. @@ -1925,7 +1925,7 @@ contract ERC721A is IERC721A { // MIT // Copyright (c) 2021 the ethier authors (github.com/divergencetech/ethier) -pragma solidity >=0.8.0 <0.9.0; +pragma solidity ^0.8.0; /// @notice Pre-approval of OpenSea proxies for gas-less listing /// @dev This wrapper allows users to revoke the pre-approval of their @@ -2108,7 +2108,7 @@ abstract contract Pausable is Context { // MIT // Copyright (c) 2021 the ethier authors (github.com/divergencetech/ethier) -pragma solidity >=0.8.0 <0.9.0; +pragma solidity ^0.8.0; /// @notice A Pausable contract that can only be toggled by the Owner. contract OwnerPausable is Ownable, Pausable { @@ -2127,7 +2127,7 @@ contract OwnerPausable is Ownable, Pausable { // MIT // Copyright (c) 2022 the ethier authors (github.com/divergencetech/ethier) -pragma solidity >=0.8.0 <0.9.0; +pragma solidity ^0.8.0; /** @notice An ERC721A contract with common functionality: @@ -2246,7 +2246,7 @@ library BitMaps { // MIT // Copyright (c) 2022 the ethier authors (github.com/divergencetech/ethier) -pragma solidity >=0.8.0 <0.9.0; +pragma solidity ^0.8.0; /** @notice Allows holders of ERC721 tokens to redeem rights to some claim; for @@ -2451,7 +2451,7 @@ library ERC721Redeemer { // MIT // Copyright (c) 2021 the ethier authors (github.com/divergencetech/ethier) -pragma solidity >=0.8.0 <0.9.0; +pragma solidity ^0.8.0; /** @notice Provides monotonic increasing and decreasing values, similar to @@ -3024,7 +3024,7 @@ abstract contract AccessControlEnumerable is // File contracts/mocks/tokens/Moonbirds.sol // UNLICENSED -pragma solidity >=0.8.10 <0.9.0; +pragma solidity ^0.8.0; /** * @dev Interface for the NFT Royalty Standard. diff --git a/contracts/mocks/tokens/WETH9Mocked.sol b/contracts/mocks/tokens/WETH9Mocked.sol index 62066e4f2..cb7572dd9 100644 --- a/contracts/mocks/tokens/WETH9Mocked.sol +++ b/contracts/mocks/tokens/WETH9Mocked.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {WETH9} from "../../dependencies/weth/WETH9.sol"; diff --git a/contracts/mocks/tokens/WrappedPunk/ICryptoPunk.sol b/contracts/mocks/tokens/WrappedPunk/ICryptoPunk.sol index b46a540ab..7b8e5460b 100644 --- a/contracts/mocks/tokens/WrappedPunk/ICryptoPunk.sol +++ b/contracts/mocks/tokens/WrappedPunk/ICryptoPunk.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; interface ICryptoPunk { function punkIndexToAddress(uint256 punkIndex) external returns (address); diff --git a/contracts/mocks/tokens/WrappedPunk/UserProxy.sol b/contracts/mocks/tokens/WrappedPunk/UserProxy.sol index 0131a727b..26b9e82c1 100644 --- a/contracts/mocks/tokens/WrappedPunk/UserProxy.sol +++ b/contracts/mocks/tokens/WrappedPunk/UserProxy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; contract UserProxy { address private immutable _owner; diff --git a/contracts/mocks/tokens/WrappedPunk/WPunk.sol b/contracts/mocks/tokens/WrappedPunk/WPunk.sol index 4c6ff7a59..6f2e9325a 100644 --- a/contracts/mocks/tokens/WrappedPunk/WPunk.sol +++ b/contracts/mocks/tokens/WrappedPunk/WPunk.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {Ownable} from "../../../../contracts/dependencies/openzeppelin/contracts/Ownable.sol"; import {ERC721} from "../../../../contracts/dependencies/openzeppelin/contracts/ERC721.sol"; diff --git a/contracts/mocks/tokens/stETHMocked.sol b/contracts/mocks/tokens/stETHMocked.sol index 54fce5959..4e0729ef9 100644 --- a/contracts/mocks/tokens/stETHMocked.sol +++ b/contracts/mocks/tokens/stETHMocked.sol @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: 2020 Lido // SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {SafeMath} from '../../dependencies/openzeppelin/contracts/SafeMath.sol'; import {SafeCast} from '../../dependencies/openzeppelin/contracts/SafeCast.sol'; diff --git a/contracts/mocks/tokens/wstETHMocked.sol b/contracts/mocks/tokens/wstETHMocked.sol index ea58fcc38..1891d0643 100644 --- a/contracts/mocks/tokens/wstETHMocked.sol +++ b/contracts/mocks/tokens/wstETHMocked.sol @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: 2020 Lido // SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {ERC20} from '../../dependencies/openzeppelin/contracts/ERC20.sol'; import {ERC20} from '../../dependencies/openzeppelin/contracts/ERC20.sol'; diff --git a/contracts/mocks/upgradeability/MockInitializableImplementation.sol b/contracts/mocks/upgradeability/MockInitializableImplementation.sol index 8eb8f6306..0a2151e7c 100644 --- a/contracts/mocks/upgradeability/MockInitializableImplementation.sol +++ b/contracts/mocks/upgradeability/MockInitializableImplementation.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {VersionedInitializable} from "../../protocol/libraries/paraspace-upgradeability/VersionedInitializable.sol"; diff --git a/contracts/mocks/upgradeability/MockNToken.sol b/contracts/mocks/upgradeability/MockNToken.sol index d98f9155f..e3477eeb2 100644 --- a/contracts/mocks/upgradeability/MockNToken.sol +++ b/contracts/mocks/upgradeability/MockNToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {NToken} from "../../protocol/tokenization/NToken.sol"; import {IPool} from "../../interfaces/IPool.sol"; diff --git a/contracts/mocks/upgradeability/MockPToken.sol b/contracts/mocks/upgradeability/MockPToken.sol index b405c6e53..afb006e9c 100644 --- a/contracts/mocks/upgradeability/MockPToken.sol +++ b/contracts/mocks/upgradeability/MockPToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {PToken} from "../../protocol/tokenization/PToken.sol"; import {IPool} from "../../interfaces/IPool.sol"; diff --git a/contracts/mocks/upgradeability/MockPoolCore.sol b/contracts/mocks/upgradeability/MockPoolCore.sol index 4db400374..70b16430b 100644 --- a/contracts/mocks/upgradeability/MockPoolCore.sol +++ b/contracts/mocks/upgradeability/MockPoolCore.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {ParaVersionedInitializable} from "../../protocol/libraries/paraspace-upgradeability/ParaVersionedInitializable.sol"; import {Errors} from "../../protocol/libraries/helpers/Errors.sol"; diff --git a/contracts/mocks/upgradeability/MockVariableDebtToken.sol b/contracts/mocks/upgradeability/MockVariableDebtToken.sol index 02e546cc3..a6f25caf1 100644 --- a/contracts/mocks/upgradeability/MockVariableDebtToken.sol +++ b/contracts/mocks/upgradeability/MockVariableDebtToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {VariableDebtToken} from "../../protocol/tokenization/VariableDebtToken.sol"; import {IPool} from "../../interfaces/IPool.sol"; diff --git a/contracts/protocol/configuration/ACLManager.sol b/contracts/protocol/configuration/ACLManager.sol index dee73c48c..f9b007cdc 100644 --- a/contracts/protocol/configuration/ACLManager.sol +++ b/contracts/protocol/configuration/ACLManager.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {AccessControl} from "../../dependencies/openzeppelin/contracts/AccessControl.sol"; import {IPoolAddressesProvider} from "../../interfaces/IPoolAddressesProvider.sol"; diff --git a/contracts/protocol/configuration/PoolAddressesProvider.sol b/contracts/protocol/configuration/PoolAddressesProvider.sol index 5f1e3c849..0333c29db 100644 --- a/contracts/protocol/configuration/PoolAddressesProvider.sol +++ b/contracts/protocol/configuration/PoolAddressesProvider.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {Ownable} from "../../dependencies/openzeppelin/contracts/Ownable.sol"; import {IPoolAddressesProvider} from "../../interfaces/IPoolAddressesProvider.sol"; diff --git a/contracts/protocol/configuration/PoolAddressesProviderRegistry.sol b/contracts/protocol/configuration/PoolAddressesProviderRegistry.sol index 585fa30d4..f15845bdd 100644 --- a/contracts/protocol/configuration/PoolAddressesProviderRegistry.sol +++ b/contracts/protocol/configuration/PoolAddressesProviderRegistry.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {Ownable} from "../../dependencies/openzeppelin/contracts/Ownable.sol"; import {Errors} from "../libraries/helpers/Errors.sol"; diff --git a/contracts/protocol/configuration/PriceOracleSentinel.sol b/contracts/protocol/configuration/PriceOracleSentinel.sol index 32697f7ac..0c05bbf45 100644 --- a/contracts/protocol/configuration/PriceOracleSentinel.sol +++ b/contracts/protocol/configuration/PriceOracleSentinel.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {Errors} from "../libraries/helpers/Errors.sol"; import {IPoolAddressesProvider} from "../../interfaces/IPoolAddressesProvider.sol"; diff --git a/contracts/protocol/libraries/configuration/ReserveConfiguration.sol b/contracts/protocol/libraries/configuration/ReserveConfiguration.sol index 42d7a15f6..2780046d4 100644 --- a/contracts/protocol/libraries/configuration/ReserveConfiguration.sol +++ b/contracts/protocol/libraries/configuration/ReserveConfiguration.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {Errors} from "../helpers/Errors.sol"; import {DataTypes} from "../types/DataTypes.sol"; diff --git a/contracts/protocol/libraries/configuration/UserConfiguration.sol b/contracts/protocol/libraries/configuration/UserConfiguration.sol index 45cfaa3d8..5df6372ff 100644 --- a/contracts/protocol/libraries/configuration/UserConfiguration.sol +++ b/contracts/protocol/libraries/configuration/UserConfiguration.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {Errors} from "../helpers/Errors.sol"; import {DataTypes} from "../types/DataTypes.sol"; diff --git a/contracts/protocol/libraries/helpers/Errors.sol b/contracts/protocol/libraries/helpers/Errors.sol index fa57c774b..540570bfc 100644 --- a/contracts/protocol/libraries/helpers/Errors.sol +++ b/contracts/protocol/libraries/helpers/Errors.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title Errors library @@ -49,7 +49,6 @@ library Errors { string public constant HEALTH_FACTOR_NOT_BELOW_THRESHOLD = "45"; // 'Health factor is not below the threshold' string public constant COLLATERAL_CANNOT_BE_AUCTIONED_OR_LIQUIDATED = "46"; // 'The collateral chosen cannot be auctioned OR liquidated' string public constant SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER = "47"; // 'User did not borrow the specified currency' - string public constant SAME_BLOCK_BORROW_REPAY = "48"; // 'Borrow and repay in same block is not allowed' string public constant BORROW_CAP_EXCEEDED = "50"; // 'Borrow cap is exceeded' string public constant SUPPLY_CAP_EXCEEDED = "51"; // 'Supply cap is exceeded' string public constant XTOKEN_SUPPLY_NOT_ZERO = "54"; // 'PToken supply is not zero' @@ -134,4 +133,26 @@ library Errors { string public constant INVALID_FEE_VALUE = "139"; // invalid fee rate value string public constant TOKEN_NOT_ALLOW_RESCUE = "140"; // token is not allow rescue string public constant CALLER_NOT_ALLOWED = "141"; //The caller of the function is not allowed + + string public constant INVALID_PARAMETER = "170"; //invalid parameter + string public constant APE_POSITION_EXISTED = "171"; //ape staking position already existed + string public constant BAKC_POSITION_EXISTED = "172"; //bakc staking position already existed + string public constant PAIR_POSITION_EXISTED = "173"; //pair staking position already existed + string public constant NOT_PAIRED_APE_AND_BAKC = "174"; //not paired ape and bakc + string public constant NOT_APE_STAKING_BOT = "175"; //not ape staking bot + string public constant NOT_THE_SAME_OWNER = "176"; //not the same owner + string public constant NFT_NOT_ALLOWED = "177"; //nft now allowed + string public constant NFT_NOT_IN_POOL = "178"; //nft not in the pool + string public constant SAPE_FREE_BALANCE_NOT_ENOUGH = "179"; //sape free balance not enough + string public constant NOT_ORDER_OFFERER = "180"; //not order offerer + string public constant ORDER_ALREADY_CANCELLED = "181"; //order already cancelled + string public constant ORDER_NOT_STARTED = "182"; //order not started + string public constant ORDER_EXPIRED = "183"; //order expired + string public constant INVALID_TOKEN = "184"; //invalid token + string public constant INVALID_ORDER_STATUS = "185"; //invalid order status + string public constant INVALID_STAKING_TYPE = "186"; //invalid stake type + string public constant ORDER_TYPE_MATCH_FAILED = "187"; //orders type match failed + string public constant ORDER_SHARE_MATCH_FAILED = "188"; //orders share match failed + string public constant NO_BREAK_UP_PERMISSION = "189"; //no permission to break up + string public constant INVALID_CASH_AMOUNT = "190"; //invalid cash amount } diff --git a/contracts/protocol/libraries/helpers/Helpers.sol b/contracts/protocol/libraries/helpers/Helpers.sol index 3e20ae97b..19669f8b6 100644 --- a/contracts/protocol/libraries/helpers/Helpers.sol +++ b/contracts/protocol/libraries/helpers/Helpers.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC20} from "../../../dependencies/openzeppelin/contracts/IERC20.sol"; import {DataTypes} from "../types/DataTypes.sol"; diff --git a/contracts/protocol/libraries/logic/AuctionLogic.sol b/contracts/protocol/libraries/logic/AuctionLogic.sol index 382bfa753..1e3eed597 100644 --- a/contracts/protocol/libraries/logic/AuctionLogic.sol +++ b/contracts/protocol/libraries/logic/AuctionLogic.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {DataTypes} from "../../libraries/types/DataTypes.sol"; import {ValidationLogic} from "./ValidationLogic.sol"; diff --git a/contracts/protocol/libraries/logic/BorrowLogic.sol b/contracts/protocol/libraries/logic/BorrowLogic.sol index 5ca455ecc..1c3d1e061 100644 --- a/contracts/protocol/libraries/logic/BorrowLogic.sol +++ b/contracts/protocol/libraries/logic/BorrowLogic.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {GPv2SafeERC20} from "../../../dependencies/gnosis/contracts/GPv2SafeERC20.sol"; import {SafeCast} from "../../../dependencies/openzeppelin/contracts/SafeCast.sol"; @@ -129,6 +129,57 @@ library BorrowLogic { ); } + /** + * @notice Implements the borrow without collateral feature. + * @dev Emits the `Borrow()` event + * @param reservesData The state of all the reserves + * @param borrowFor The address borrow the asset + * @param asset The address of the borrow asset + * @param amount The borrow amount + */ + function executeBorrowWithoutCollateral( + mapping(address => DataTypes.ReserveData) storage reservesData, + address borrowFor, + address asset, + uint256 amount + ) external returns (uint256) { + DataTypes.ReserveData storage reserve = reservesData[asset]; + DataTypes.ReserveCache memory reserveCache = reserve.cache(); + + reserve.updateState(reserveCache); + + ValidationLogic.validateBorrowWithoutCollateral(reserveCache, amount); + + (, reserveCache.nextScaledVariableDebt) = IVariableDebtToken( + reserveCache.variableDebtTokenAddress + ).mint( + borrowFor, + borrowFor, + amount, + reserveCache.nextVariableBorrowIndex + ); + + reserve.updateInterestRates(reserveCache, asset, 0, amount); + + DataTypes.TimeLockParams memory timeLockParams; + IPToken(reserveCache.xTokenAddress).transferUnderlyingTo( + borrowFor, + amount, + timeLockParams + ); + + emit Borrow( + asset, + borrowFor, + borrowFor, + amount, + reserve.currentVariableBorrowRate, + 0 + ); + + return reserveCache.nextVariableBorrowIndex; + } + /** * @notice Implements the repay feature. Repaying transfers the underlying back to the xToken and clears the * equivalent amount of debt for the user by burning the corresponding debt token. diff --git a/contracts/protocol/libraries/logic/ConfiguratorLogic.sol b/contracts/protocol/libraries/logic/ConfiguratorLogic.sol index 9db120d8b..600a7a3b3 100644 --- a/contracts/protocol/libraries/logic/ConfiguratorLogic.sol +++ b/contracts/protocol/libraries/logic/ConfiguratorLogic.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPool} from "../../../interfaces/IPool.sol"; import {IInitializablePToken} from "../../../interfaces/IInitializablePToken.sol"; diff --git a/contracts/protocol/libraries/logic/FlashClaimLogic.sol b/contracts/protocol/libraries/logic/FlashClaimLogic.sol index 0e0cbcc27..71564ea9c 100644 --- a/contracts/protocol/libraries/logic/FlashClaimLogic.sol +++ b/contracts/protocol/libraries/logic/FlashClaimLogic.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC721} from "../../../dependencies/openzeppelin/contracts/IERC721.sol"; import {IFlashClaimReceiver} from "../../../misc/interfaces/IFlashClaimReceiver.sol"; @@ -7,7 +7,6 @@ import {INToken} from "../../../interfaces/INToken.sol"; import {DataTypes} from "../types/DataTypes.sol"; import {Errors} from "../helpers/Errors.sol"; import {ValidationLogic} from "./ValidationLogic.sol"; -import "../../../interfaces/INTokenApeStaking.sol"; import {XTokenType, IXTokenType} from "../../../interfaces/IXTokenType.sol"; import {GenericLogic} from "./GenericLogic.sol"; import {ReserveConfiguration} from "../configuration/ReserveConfiguration.sol"; diff --git a/contracts/protocol/libraries/logic/GenericLogic.sol b/contracts/protocol/libraries/logic/GenericLogic.sol index 08cb9e617..c047892f7 100644 --- a/contracts/protocol/libraries/logic/GenericLogic.sol +++ b/contracts/protocol/libraries/logic/GenericLogic.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC20} from "../../../dependencies/openzeppelin/contracts/IERC20.sol"; import {IERC721Enumerable} from "../../../dependencies/openzeppelin/contracts/IERC721Enumerable.sol"; @@ -16,7 +16,7 @@ import {PercentageMath} from "../math/PercentageMath.sol"; import {WadRayMath} from "../math/WadRayMath.sol"; import {DataTypes} from "../types/DataTypes.sol"; import {ReserveLogic} from "./ReserveLogic.sol"; -import {INonfungiblePositionManager} from "../../../dependencies/uniswap/INonfungiblePositionManager.sol"; +import {INonfungiblePositionManager} from "../../../dependencies/uniswapv3-periphery/interfaces/INonfungiblePositionManager.sol"; import {XTokenType, IXTokenType} from "../../../interfaces/IXTokenType.sol"; import {Helpers} from "../../libraries/helpers/Helpers.sol"; diff --git a/contracts/protocol/libraries/logic/LiquidationLogic.sol b/contracts/protocol/libraries/logic/LiquidationLogic.sol index ef994c7ca..90d22a9ef 100644 --- a/contracts/protocol/libraries/logic/LiquidationLogic.sol +++ b/contracts/protocol/libraries/logic/LiquidationLogic.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC20} from "../../../dependencies/openzeppelin/contracts/IERC20.sol"; import {GPv2SafeERC20} from "../../../dependencies/gnosis/contracts/GPv2SafeERC20.sol"; diff --git a/contracts/protocol/libraries/logic/MarketplaceLogic.sol b/contracts/protocol/libraries/logic/MarketplaceLogic.sol index 1dee8e98d..c47e7bf4b 100644 --- a/contracts/protocol/libraries/logic/MarketplaceLogic.sol +++ b/contracts/protocol/libraries/logic/MarketplaceLogic.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {INToken} from "../../../interfaces/INToken.sol"; import {IPoolAddressesProvider} from "../../../interfaces/IPoolAddressesProvider.sol"; diff --git a/contracts/protocol/libraries/logic/PoolLogic.sol b/contracts/protocol/libraries/logic/PoolLogic.sol index 805a0e7aa..7d852653b 100644 --- a/contracts/protocol/libraries/logic/PoolLogic.sol +++ b/contracts/protocol/libraries/logic/PoolLogic.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {GPv2SafeERC20} from "../../../dependencies/gnosis/contracts/GPv2SafeERC20.sol"; import {Address} from "../../../dependencies/openzeppelin/contracts/Address.sol"; diff --git a/contracts/protocol/libraries/logic/PositionMoverLogic.sol b/contracts/protocol/libraries/logic/PositionMoverLogic.sol index 421f408ee..61a03ceba 100644 --- a/contracts/protocol/libraries/logic/PositionMoverLogic.sol +++ b/contracts/protocol/libraries/logic/PositionMoverLogic.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {INToken} from "../../../interfaces/INToken.sol"; import {IPoolAddressesProvider} from "../../../interfaces/IPoolAddressesProvider.sol"; diff --git a/contracts/protocol/libraries/logic/ReserveLogic.sol b/contracts/protocol/libraries/logic/ReserveLogic.sol index 853949ba5..aaed6037b 100644 --- a/contracts/protocol/libraries/logic/ReserveLogic.sol +++ b/contracts/protocol/libraries/logic/ReserveLogic.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC20} from "../../../dependencies/openzeppelin/contracts/IERC20.sol"; import {GPv2SafeERC20} from "../../../dependencies/gnosis/contracts/GPv2SafeERC20.sol"; diff --git a/contracts/protocol/libraries/logic/SupplyLogic.sol b/contracts/protocol/libraries/logic/SupplyLogic.sol index 64a44220b..1aac476bc 100644 --- a/contracts/protocol/libraries/logic/SupplyLogic.sol +++ b/contracts/protocol/libraries/logic/SupplyLogic.sol @@ -1,13 +1,12 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC20} from "../../../dependencies/openzeppelin/contracts/IERC20.sol"; import {IERC721} from "../../../dependencies/openzeppelin/contracts/IERC721.sol"; import {GPv2SafeERC20} from "../../../dependencies/gnosis/contracts/GPv2SafeERC20.sol"; import {IPToken} from "../../../interfaces/IPToken.sol"; -import {INonfungiblePositionManager} from "../../../dependencies/uniswap/INonfungiblePositionManager.sol"; +import {INonfungiblePositionManager} from "../../../dependencies/uniswapv3-periphery/interfaces/INonfungiblePositionManager.sol"; import {INToken} from "../../../interfaces/INToken.sol"; -import {INTokenApeStaking} from "../../../interfaces/INTokenApeStaking.sol"; import {ICollateralizableERC721} from "../../../interfaces/ICollateralizableERC721.sol"; import {IAuctionableERC721} from "../../../interfaces/IAuctionableERC721.sol"; import {ITimeLockStrategy} from "../../../interfaces/ITimeLockStrategy.sol"; diff --git a/contracts/protocol/libraries/logic/ValidationLogic.sol b/contracts/protocol/libraries/logic/ValidationLogic.sol index 6e0d3e511..3000a9abc 100644 --- a/contracts/protocol/libraries/logic/ValidationLogic.sol +++ b/contracts/protocol/libraries/logic/ValidationLogic.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC20} from "../../../dependencies/openzeppelin/contracts/IERC20.sol"; import {IERC721} from "../../../dependencies/openzeppelin/contracts/IERC721.sol"; @@ -26,8 +26,7 @@ import {SafeCast} from "../../../dependencies/openzeppelin/contracts/SafeCast.so import {IToken} from "../../../interfaces/IToken.sol"; import {XTokenType, IXTokenType} from "../../../interfaces/IXTokenType.sol"; import {Helpers} from "../helpers/Helpers.sol"; -import {INonfungiblePositionManager} from "../../../dependencies/uniswap/INonfungiblePositionManager.sol"; -import "../../../interfaces/INTokenApeStaking.sol"; +import {INonfungiblePositionManager} from "../../../dependencies/uniswapv3-periphery/interfaces/INonfungiblePositionManager.sol"; /** * @title ReserveLogic library @@ -244,19 +243,12 @@ library ValidationLogic { DataTypes.AssetType assetType; } - /** - * @notice Validates a borrow action. - * @param reservesData The state of all the reserves - * @param reservesList The addresses of all the active reserves - * @param params Additional params needed for the validation - */ - function validateBorrow( - mapping(address => DataTypes.ReserveData) storage reservesData, - mapping(uint256 => address) storage reservesList, - DataTypes.ValidateBorrowParams memory params - ) internal view { - require(params.amount != 0, Errors.INVALID_AMOUNT); - ValidateBorrowLocalVars memory vars; + function validateBorrowBaseInfo( + DataTypes.ReserveCache memory reserveCache, + uint256 amount, + ValidateBorrowLocalVars memory vars + ) internal pure { + require(amount != 0, Errors.INVALID_AMOUNT); ( vars.isActive, @@ -264,7 +256,7 @@ library ValidationLogic { vars.borrowingEnabled, vars.isPaused, vars.assetType - ) = params.reserveCache.reserveConfiguration.getFlags(); + ) = reserveCache.reserveConfiguration.getFlags(); require( vars.assetType == DataTypes.AssetType.ERC20, @@ -275,33 +267,18 @@ library ValidationLogic { require(!vars.isFrozen, Errors.RESERVE_FROZEN); require(vars.borrowingEnabled, Errors.BORROWING_NOT_ENABLED); - require( - params.priceOracleSentinel == address(0) || - IPriceOracleSentinel(params.priceOracleSentinel) - .isBorrowAllowed(), - Errors.PRICE_ORACLE_SENTINEL_CHECK_FAILED - ); - - vars.reserveDecimals = params - .reserveCache - .reserveConfiguration - .getDecimals(); - vars.borrowCap = params - .reserveCache - .reserveConfiguration - .getBorrowCap(); + vars.reserveDecimals = reserveCache.reserveConfiguration.getDecimals(); + vars.borrowCap = reserveCache.reserveConfiguration.getBorrowCap(); unchecked { vars.assetUnit = 10**vars.reserveDecimals; } if (vars.borrowCap != 0) { - vars.totalSupplyVariableDebt = params - .reserveCache + vars.totalSupplyVariableDebt = reserveCache .currScaledVariableDebt - .rayMul(params.reserveCache.nextVariableBorrowIndex); - - vars.totalDebt = vars.totalSupplyVariableDebt + params.amount; + .rayMul(reserveCache.nextVariableBorrowIndex); + vars.totalDebt = vars.totalSupplyVariableDebt + amount; unchecked { require( vars.totalDebt <= vars.borrowCap * vars.assetUnit, @@ -309,6 +286,36 @@ library ValidationLogic { ); } } + } + + function validateBorrowWithoutCollateral( + DataTypes.ReserveCache memory reserveCache, + uint256 amount + ) internal pure { + ValidateBorrowLocalVars memory vars; + validateBorrowBaseInfo(reserveCache, amount, vars); + } + + /** + * @notice Validates a borrow action. + * @param reservesData The state of all the reserves + * @param reservesList The addresses of all the active reserves + * @param params Additional params needed for the validation + */ + function validateBorrow( + mapping(address => DataTypes.ReserveData) storage reservesData, + mapping(uint256 => address) storage reservesList, + DataTypes.ValidateBorrowParams memory params + ) internal view { + ValidateBorrowLocalVars memory vars; + validateBorrowBaseInfo(params.reserveCache, params.amount, vars); + + require( + params.priceOracleSentinel == address(0) || + IPriceOracleSentinel(params.priceOracleSentinel) + .isBorrowAllowed(), + Errors.PRICE_ORACLE_SENTINEL_CHECK_FAILED + ); ( vars.userCollateralInBaseCurrency, @@ -394,15 +401,6 @@ library ValidationLogic { Errors.INVALID_ASSET_TYPE ); - uint256 variableDebtPreviousIndex = IScaledBalanceToken( - reserveCache.variableDebtTokenAddress - ).getPreviousIndex(onBehalfOf); - - require( - (variableDebtPreviousIndex < reserveCache.nextVariableBorrowIndex), - Errors.SAME_BLOCK_BORROW_REPAY - ); - require((variableDebt != 0), Errors.NO_DEBT_OF_SELECTED_TYPE); } @@ -521,14 +519,6 @@ library ValidationLogic { Errors.LIQUIDATION_AMOUNT_NOT_ENOUGH ); - IXTokenType xToken = IXTokenType( - params.liquidationAssetReserveCache.xTokenAddress - ); - require( - xToken.getXTokenType() != XTokenType.PTokenSApe, - Errors.SAPE_NOT_ALLOWED - ); - ( vars.principalReserveActive, , diff --git a/contracts/protocol/libraries/math/MathUtils.sol b/contracts/protocol/libraries/math/MathUtils.sol index 74625fe74..1632d49ff 100644 --- a/contracts/protocol/libraries/math/MathUtils.sol +++ b/contracts/protocol/libraries/math/MathUtils.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {WadRayMath} from "./WadRayMath.sol"; diff --git a/contracts/protocol/libraries/math/PercentageMath.sol b/contracts/protocol/libraries/math/PercentageMath.sol index f61985017..e106fb5ea 100644 --- a/contracts/protocol/libraries/math/PercentageMath.sol +++ b/contracts/protocol/libraries/math/PercentageMath.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title PercentageMath library diff --git a/contracts/protocol/libraries/math/WadRayMath.sol b/contracts/protocol/libraries/math/WadRayMath.sol index 423dff9b3..079e19dc6 100644 --- a/contracts/protocol/libraries/math/WadRayMath.sol +++ b/contracts/protocol/libraries/math/WadRayMath.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title WadRayMath library diff --git a/contracts/protocol/libraries/paraspace-upgradeability/BaseImmutableAdminUpgradeabilityProxy.sol b/contracts/protocol/libraries/paraspace-upgradeability/BaseImmutableAdminUpgradeabilityProxy.sol index 5d2f23aa0..314d29115 100644 --- a/contracts/protocol/libraries/paraspace-upgradeability/BaseImmutableAdminUpgradeabilityProxy.sol +++ b/contracts/protocol/libraries/paraspace-upgradeability/BaseImmutableAdminUpgradeabilityProxy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {BaseUpgradeabilityProxy} from "../../../dependencies/openzeppelin/upgradeability/BaseUpgradeabilityProxy.sol"; diff --git a/contracts/protocol/libraries/paraspace-upgradeability/InitializableImmutableAdminUpgradeabilityProxy.sol b/contracts/protocol/libraries/paraspace-upgradeability/InitializableImmutableAdminUpgradeabilityProxy.sol index d06884380..bc1c378bf 100644 --- a/contracts/protocol/libraries/paraspace-upgradeability/InitializableImmutableAdminUpgradeabilityProxy.sol +++ b/contracts/protocol/libraries/paraspace-upgradeability/InitializableImmutableAdminUpgradeabilityProxy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {InitializableUpgradeabilityProxy} from "../../../dependencies/openzeppelin/upgradeability/InitializableUpgradeabilityProxy.sol"; import {Proxy} from "../../../dependencies/openzeppelin/upgradeability/Proxy.sol"; diff --git a/contracts/protocol/libraries/paraspace-upgradeability/ParaProxy.sol b/contracts/protocol/libraries/paraspace-upgradeability/ParaProxy.sol index f11fc0f0c..62e8e00ab 100644 --- a/contracts/protocol/libraries/paraspace-upgradeability/ParaProxy.sol +++ b/contracts/protocol/libraries/paraspace-upgradeability/ParaProxy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; /******************************************************************************\ * A custom implementation of EIP-2535 diff --git a/contracts/protocol/libraries/paraspace-upgradeability/ParaReentrancyGuard.sol b/contracts/protocol/libraries/paraspace-upgradeability/ParaReentrancyGuard.sol index 303ca5e5b..168e6cea4 100644 --- a/contracts/protocol/libraries/paraspace-upgradeability/ParaReentrancyGuard.sol +++ b/contracts/protocol/libraries/paraspace-upgradeability/ParaReentrancyGuard.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. diff --git a/contracts/protocol/libraries/paraspace-upgradeability/ParaVersionedInitializable.sol b/contracts/protocol/libraries/paraspace-upgradeability/ParaVersionedInitializable.sol index 459519065..d67ee2010 100644 --- a/contracts/protocol/libraries/paraspace-upgradeability/ParaVersionedInitializable.sol +++ b/contracts/protocol/libraries/paraspace-upgradeability/ParaVersionedInitializable.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title VersionedInitializable diff --git a/contracts/protocol/libraries/paraspace-upgradeability/VersionedInitializable.sol b/contracts/protocol/libraries/paraspace-upgradeability/VersionedInitializable.sol index f39e585f8..8f7c8d3d5 100644 --- a/contracts/protocol/libraries/paraspace-upgradeability/VersionedInitializable.sol +++ b/contracts/protocol/libraries/paraspace-upgradeability/VersionedInitializable.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title VersionedInitializable diff --git a/contracts/protocol/libraries/paraspace-upgradeability/lib/ParaProxyLib.sol b/contracts/protocol/libraries/paraspace-upgradeability/lib/ParaProxyLib.sol index 76b867766..a19208c15 100644 --- a/contracts/protocol/libraries/paraspace-upgradeability/lib/ParaProxyLib.sol +++ b/contracts/protocol/libraries/paraspace-upgradeability/lib/ParaProxyLib.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; /******************************************************************************\ * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 diff --git a/contracts/protocol/libraries/types/ConfiguratorInputTypes.sol b/contracts/protocol/libraries/types/ConfiguratorInputTypes.sol index 850564188..d11e6c5ee 100644 --- a/contracts/protocol/libraries/types/ConfiguratorInputTypes.sol +++ b/contracts/protocol/libraries/types/ConfiguratorInputTypes.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {DataTypes} from "./DataTypes.sol"; diff --git a/contracts/protocol/libraries/types/DataTypes.sol b/contracts/protocol/libraries/types/DataTypes.sol index 0cec1d03a..e68bfd7f5 100644 --- a/contracts/protocol/libraries/types/DataTypes.sol +++ b/contracts/protocol/libraries/types/DataTypes.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {OfferItem, ConsiderationItem} from "../../../dependencies/seaport/contracts/lib/ConsiderationStructs.sol"; import {IStakefishValidator} from "../../../interfaces/IStakefishValidator.sol"; @@ -399,12 +399,6 @@ library DataTypes { uint16 _reservesCount; // Auction recovery health factor uint64 _auctionRecoveryHealthFactor; - // Incentive fee for claim ape reward to compound - uint16 _apeCompoundFee; - // Map of user's ape compound strategies - mapping(address => ApeCompoundStrategy) _apeCompoundStrategies; - // Address of ape compound bot - address _apeCompoundBot; } struct ReserveConfigData { diff --git a/contracts/protocol/pool/DefaultReserveAuctionStrategy.sol b/contracts/protocol/pool/DefaultReserveAuctionStrategy.sol index 26693bac0..46d8219e7 100644 --- a/contracts/protocol/pool/DefaultReserveAuctionStrategy.sol +++ b/contracts/protocol/pool/DefaultReserveAuctionStrategy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC20} from "../../dependencies/openzeppelin/contracts/IERC20.sol"; import {WadRayMath} from "../libraries/math/WadRayMath.sol"; diff --git a/contracts/protocol/pool/DefaultReserveInterestRateStrategy.sol b/contracts/protocol/pool/DefaultReserveInterestRateStrategy.sol index 71076269a..499135476 100644 --- a/contracts/protocol/pool/DefaultReserveInterestRateStrategy.sol +++ b/contracts/protocol/pool/DefaultReserveInterestRateStrategy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC20} from "../../dependencies/openzeppelin/contracts/IERC20.sol"; import {WadRayMath} from "../libraries/math/WadRayMath.sol"; diff --git a/contracts/protocol/pool/PoolApeStaking.sol b/contracts/protocol/pool/PoolApeStaking.sol index 8e9289849..c4ff6c480 100644 --- a/contracts/protocol/pool/PoolApeStaking.sol +++ b/contracts/protocol/pool/PoolApeStaking.sol @@ -1,32 +1,17 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "../libraries/paraspace-upgradeability/ParaReentrancyGuard.sol"; import "../libraries/paraspace-upgradeability/ParaVersionedInitializable.sol"; import {PoolStorage} from "./PoolStorage.sol"; import "../../interfaces/IPoolApeStaking.sol"; -import "../../interfaces/IPToken.sol"; -import "../../dependencies/yoga-labs/ApeCoinStaking.sol"; -import "../../interfaces/IXTokenType.sol"; -import "../../interfaces/INTokenApeStaking.sol"; -import {ValidationLogic} from "../libraries/logic/ValidationLogic.sol"; import {IPoolAddressesProvider} from "../../interfaces/IPoolAddressesProvider.sol"; import {IPool} from "../../interfaces/IPool.sol"; import {Errors} from "../libraries/helpers/Errors.sol"; -import {ReserveLogic} from "../libraries/logic/ReserveLogic.sol"; -import {GenericLogic} from "../libraries/logic/GenericLogic.sol"; -import {UserConfiguration} from "../libraries/configuration/UserConfiguration.sol"; -import {ApeStakingLogic} from "../tokenization/libraries/ApeStakingLogic.sol"; +import {DataTypes} from "../libraries/types/DataTypes.sol"; import "../libraries/logic/BorrowLogic.sol"; -import "../libraries/logic/SupplyLogic.sol"; -import "../../dependencies/openzeppelin/contracts/SafeCast.sol"; -import {IAutoCompoundApe} from "../../interfaces/IAutoCompoundApe.sol"; -import {PercentageMath} from "../libraries/math/PercentageMath.sol"; -import {WadRayMath} from "../libraries/math/WadRayMath.sol"; -import {Math} from "../../dependencies/openzeppelin/contracts/Math.sol"; -import {ISwapRouter} from "../../dependencies/univ3/interfaces/ISwapRouter.sol"; -import {IPriceOracleGetter} from "../../interfaces/IPriceOracleGetter.sol"; -import {Helpers} from "../libraries/helpers/Helpers.sol"; +import {GenericLogic} from "../libraries/logic/GenericLogic.sol"; +import "../../interfaces/IParaApeStaking.sol"; contract PoolApeStaking is ParaVersionedInitializable, @@ -34,50 +19,12 @@ contract PoolApeStaking is PoolStorage, IPoolApeStaking { - using ReserveLogic for DataTypes.ReserveData; - using UserConfiguration for DataTypes.UserConfigurationMap; - using SafeERC20 for IERC20; - using ReserveConfiguration for DataTypes.ReserveConfigurationMap; - using SafeCast for uint256; - using PercentageMath for uint256; - using WadRayMath for uint256; - - IPoolAddressesProvider internal immutable ADDRESSES_PROVIDER; - IAutoCompoundApe internal immutable APE_COMPOUND; - IERC20 internal immutable APE_COIN; uint256 internal constant POOL_REVISION = 149; - IERC20 internal immutable USDC; - ISwapRouter internal immutable SWAP_ROUTER; - uint24 internal immutable APE_WETH_FEE; - uint24 internal immutable WETH_USDC_FEE; - address internal immutable WETH; - - event ReserveUsedAsCollateralEnabled( - address indexed reserve, - address indexed user - ); - - struct ApeStakingLocalVars { - address xTokenAddress; - IERC721 bakcContract; - address bakcNToken; - uint256 balanceBefore; - uint256 balanceAfter; - uint256[] amounts; - uint256[] swapAmounts; - address[] transferredTokenOwners; - DataTypes.ApeCompoundStrategy[] options; - uint256 totalAmount; - uint256 compoundFee; - address compoundBot; - uint256 totalUsdcSwapAmount; - uint256 totalWethSwapAmount; - uint256 usdcApePrice; - uint256 wethApePrice; - address pUSDCAddress; - address pWETHAddress; - } + IPoolAddressesProvider internal immutable ADDRESSES_PROVIDER; + address internal immutable APE_COIN; + address internal immutable APE_COMPOUND; + address internal immutable PARA_APE_STAKING; /** * @dev Constructor. @@ -85,22 +32,14 @@ contract PoolApeStaking is */ constructor( IPoolAddressesProvider provider, - IAutoCompoundApe apeCompound, - IERC20 apeCoin, - IERC20 usdc, - ISwapRouter uniswapV3SwapRouter, - address weth, - uint24 apeWethFee, - uint24 wethUsdcFee + address apeCoin, + address apeCompound, + address apeStakingVault ) { ADDRESSES_PROVIDER = provider; - APE_COMPOUND = apeCompound; APE_COIN = apeCoin; - USDC = IERC20(usdc); - SWAP_ROUTER = ISwapRouter(uniswapV3SwapRouter); - WETH = weth; - APE_WETH_FEE = apeWethFee; - WETH_USDC_FEE = wethUsdcFee; + APE_COMPOUND = apeCompound; + PARA_APE_STAKING = apeStakingVault; } function getRevision() internal pure virtual override returns (uint256) { @@ -108,328 +47,133 @@ contract PoolApeStaking is } /// @inheritdoc IPoolApeStaking - function withdrawApeCoin( - address nftAsset, - ApeCoinStaking.SingleNft[] calldata _nfts - ) external nonReentrant { - DataTypes.PoolStorage storage ps = poolStorage(); - _checkSApeIsNotPaused(ps); - - DataTypes.ReserveData storage nftReserve = ps._reserves[nftAsset]; - address xTokenAddress = nftReserve.xTokenAddress; - INToken nToken = INToken(xTokenAddress); - uint256 totalWithdrawAmount = 0; - uint256 arrayLength = _nfts.length; - for (uint256 index = 0; index < arrayLength; index++) { - require( - nToken.ownerOf(_nfts[index].tokenId) == msg.sender, - Errors.NOT_THE_OWNER - ); - totalWithdrawAmount += _nfts[index].amount; - } - - DataTypes.TimeLockParams memory timeLockParams = GenericLogic - .calculateTimeLockParams( - ps._reserves[address(APE_COIN)], - DataTypes.TimeLockFactorParams({ - assetType: DataTypes.AssetType.ERC20, - asset: address(APE_COIN), - amount: totalWithdrawAmount - }) - ); - INTokenApeStaking(xTokenAddress).withdrawApeCoin( - _nfts, - msg.sender, - timeLockParams - ); - - DataTypes.UserConfigurationMap memory userConfig = ps._usersConfig[ - msg.sender - ]; - DataTypes.ReserveData storage reserve = ps._reserves[ - DataTypes.SApeAddress - ]; - if (userConfig.isUsingAsCollateral(reserve.id)) { - _checkUserHf(ps, userConfig, msg.sender, true); - } + function paraApeStaking() external view returns (address) { + return PARA_APE_STAKING; } /// @inheritdoc IPoolApeStaking - function claimApeCoin(address nftAsset, uint256[] calldata _nfts) + function borrowPoolCApe(uint256 amount) external nonReentrant + returns (uint256) { + require(msg.sender == PARA_APE_STAKING, Errors.CALLER_NOT_ALLOWED); DataTypes.PoolStorage storage ps = poolStorage(); - _checkSApeIsNotPaused(ps); - DataTypes.ReserveData storage nftReserve = ps._reserves[nftAsset]; - address xTokenAddress = nftReserve.xTokenAddress; - INToken nToken = INToken(xTokenAddress); - for (uint256 index = 0; index < _nfts.length; index++) { - require( - nToken.ownerOf(_nfts[index]) == msg.sender, - Errors.NOT_THE_OWNER - ); - } - INTokenApeStaking(xTokenAddress).claimApeCoin(_nfts, msg.sender); + uint256 latestBorrowIndex = BorrowLogic.executeBorrowWithoutCollateral( + ps._reserves, + PARA_APE_STAKING, + APE_COMPOUND, + amount + ); + + return latestBorrowIndex; } /// @inheritdoc IPoolApeStaking - function withdrawBAKC( - address nftAsset, - ApeCoinStaking.PairNftWithdrawWithAmount[] calldata _nftPairs - ) external nonReentrant { + function calculateTimeLockParams(address asset, uint256 amount) + external + returns (DataTypes.TimeLockParams memory) + { + require(msg.sender == PARA_APE_STAKING, Errors.CALLER_NOT_ALLOWED); DataTypes.PoolStorage storage ps = poolStorage(); - _checkSApeIsNotPaused(ps); - - ApeStakingLocalVars memory localVar = _generalCache(ps, nftAsset); - uint256 arrayLength = _nftPairs.length; - localVar.transferredTokenOwners = new address[](arrayLength); - uint256[] memory transferredTokenIds = new uint256[](arrayLength); - uint256 actualTransferAmount = 0; - uint256 totalWithdrawAmount = 0; - for (uint256 index = 0; index < arrayLength; index++) { - require( - INToken(localVar.xTokenAddress).ownerOf( - _nftPairs[index].mainTokenId - ) == msg.sender, - Errors.NOT_THE_OWNER - ); - - if ( - !_nftPairs[index].isUncommit || - localVar.bakcContract.ownerOf(_nftPairs[index].bakcTokenId) == - localVar.bakcNToken - ) { - localVar.transferredTokenOwners[ - actualTransferAmount - ] = _validateBAKCOwnerAndTransfer( - localVar, - _nftPairs[index].bakcTokenId, - msg.sender - ); - transferredTokenIds[actualTransferAmount] = _nftPairs[index] - .bakcTokenId; - actualTransferAmount++; - } - - totalWithdrawAmount += _nftPairs[index].amount; - } DataTypes.TimeLockParams memory timeLockParams = GenericLogic .calculateTimeLockParams( - ps._reserves[address(APE_COIN)], + ps._reserves[asset], DataTypes.TimeLockFactorParams({ assetType: DataTypes.AssetType.ERC20, - asset: address(APE_COIN), - amount: totalWithdrawAmount + asset: asset, + amount: amount }) ); - INTokenApeStaking(localVar.xTokenAddress).withdrawBAKC( - _nftPairs, - msg.sender, - timeLockParams - ); - - ////transfer BAKC back for user - for (uint256 index = 0; index < actualTransferAmount; index++) { - localVar.bakcContract.safeTransferFrom( - localVar.xTokenAddress, - localVar.transferredTokenOwners[index], - transferredTokenIds[index] - ); - } - - DataTypes.UserConfigurationMap memory userConfig = ps._usersConfig[ - msg.sender - ]; - DataTypes.ReserveData storage reserve = ps._reserves[ - DataTypes.SApeAddress - ]; - if (userConfig.isUsingAsCollateral(reserve.id)) { - _checkUserHf(ps, userConfig, msg.sender, true); - } - } - - /// @inheritdoc IPoolApeStaking - function claimBAKC( - address nftAsset, - ApeCoinStaking.PairNft[] calldata _nftPairs - ) external nonReentrant { - DataTypes.PoolStorage storage ps = poolStorage(); - _checkSApeIsNotPaused(ps); - - ApeStakingLocalVars memory localVar = _generalCache(ps, nftAsset); - uint256 arrayLength = _nftPairs.length; - localVar.transferredTokenOwners = new address[](arrayLength); - - for (uint256 index = 0; index < arrayLength; index++) { - require( - INToken(localVar.xTokenAddress).ownerOf( - _nftPairs[index].mainTokenId - ) == msg.sender, - Errors.NOT_THE_OWNER - ); - - localVar.transferredTokenOwners[ - index - ] = _validateBAKCOwnerAndTransfer( - localVar, - _nftPairs[index].bakcTokenId, - msg.sender - ); - } - - INTokenApeStaking(localVar.xTokenAddress).claimBAKC( - _nftPairs, - msg.sender - ); - - //transfer BAKC back for user - for (uint256 index = 0; index < arrayLength; index++) { - localVar.bakcContract.safeTransferFrom( - localVar.xTokenAddress, - localVar.transferredTokenOwners[index], - _nftPairs[index].bakcTokenId - ); - } + return timeLockParams; } /// @inheritdoc IPoolApeStaking - function borrowApeAndStake( - StakingInfo calldata stakingInfo, - ApeCoinStaking.SingleNft[] calldata _nfts, - ApeCoinStaking.PairNftDepositWithAmount[] calldata _nftPairs, - bool _openSApeCollateralFlag + function borrowAndStakingApeCoin( + IParaApeStaking.ApeCoinDepositInfo[] calldata apeCoinDepositInfo, + IParaApeStaking.ApeCoinPairDepositInfo[] calldata pairDepositInfo, + address asset, + uint256 cashAmount, + uint256 borrowAmount, + bool openSApeCollateralFlag ) external nonReentrant { - DataTypes.PoolStorage storage ps = poolStorage(); - _checkSApeIsNotPaused(ps); - require( - stakingInfo.borrowAsset == address(APE_COIN) || - stakingInfo.borrowAsset == address(APE_COMPOUND), + asset == APE_COIN || asset == APE_COMPOUND, Errors.INVALID_ASSET_TYPE ); + DataTypes.PoolStorage storage ps = poolStorage(); + address msgSender = msg.sender; - ApeStakingLocalVars memory localVar = _generalCache( - ps, - stakingInfo.nftAsset - ); - localVar.transferredTokenOwners = new address[](_nftPairs.length); - localVar.balanceBefore = APE_COIN.balanceOf(localVar.xTokenAddress); + uint256 balanceBefore = IERC20(asset).balanceOf(address(this)); + // 1, prepare cash part. + if (cashAmount > 0) { + IERC20(asset).transferFrom(msg.sender, address(this), cashAmount); + } - DataTypes.ReserveData storage borrowAssetReserve = ps._reserves[ - stakingInfo.borrowAsset - ]; - // 1, handle borrow part - if (stakingInfo.borrowAmount > 0) { + // 2, prepare borrow part. + if (borrowAmount > 0) { + DataTypes.ReserveData storage borrowAssetReserve = ps._reserves[ + asset + ]; // no time lock needed here DataTypes.TimeLockParams memory timeLockParams; - if (stakingInfo.borrowAsset == address(APE_COIN)) { - IPToken(borrowAssetReserve.xTokenAddress).transferUnderlyingTo( - localVar.xTokenAddress, - stakingInfo.borrowAmount, - timeLockParams - ); - } else { - IPToken(borrowAssetReserve.xTokenAddress).transferUnderlyingTo( - address(this), - stakingInfo.borrowAmount, - timeLockParams - ); - APE_COMPOUND.withdraw(stakingInfo.borrowAmount); - APE_COIN.safeTransfer( - localVar.xTokenAddress, - stakingInfo.borrowAmount - ); - } - } - - // 2, send cash part to xTokenAddress - if (stakingInfo.cashAmount > 0) { - APE_COIN.safeTransferFrom( - msg.sender, - localVar.xTokenAddress, - stakingInfo.cashAmount + IPToken(borrowAssetReserve.xTokenAddress).transferUnderlyingTo( + address(this), + borrowAmount, + timeLockParams ); } - // 3, deposit bayc or mayc pool - { - uint256 nftsLength = _nfts.length; - for (uint256 index = 0; index < nftsLength; index++) { - require( - INToken(localVar.xTokenAddress).ownerOf( - _nfts[index].tokenId - ) == msg.sender, - Errors.NOT_THE_OWNER - ); - } - - if (nftsLength > 0) { - INTokenApeStaking(localVar.xTokenAddress).depositApeCoin(_nfts); - } + // 3, stake + uint256 arrayLength = apeCoinDepositInfo.length; + for (uint256 index = 0; index < arrayLength; index++) { + IParaApeStaking.ApeCoinDepositInfo + calldata depositInfo = apeCoinDepositInfo[index]; + require( + msgSender == depositInfo.onBehalf, + Errors.CALLER_NOT_ALLOWED + ); + IParaApeStaking(PARA_APE_STAKING).depositApeCoinPool(depositInfo); } - - // 4, deposit bakc pool - { - uint256 nftPairsLength = _nftPairs.length; - for (uint256 index = 0; index < nftPairsLength; index++) { - require( - INToken(localVar.xTokenAddress).ownerOf( - _nftPairs[index].mainTokenId - ) == msg.sender, - Errors.NOT_THE_OWNER - ); - - localVar.transferredTokenOwners[ - index - ] = _validateBAKCOwnerAndTransfer( - localVar, - _nftPairs[index].bakcTokenId, - msg.sender - ); - } - - if (nftPairsLength > 0) { - INTokenApeStaking(localVar.xTokenAddress).depositBAKC( - _nftPairs - ); - } - //transfer BAKC back for user - for (uint256 index = 0; index < nftPairsLength; index++) { - localVar.bakcContract.safeTransferFrom( - localVar.xTokenAddress, - localVar.transferredTokenOwners[index], - _nftPairs[index].bakcTokenId - ); - } + arrayLength = pairDepositInfo.length; + for (uint256 index = 0; index < arrayLength; index++) { + IParaApeStaking.ApeCoinPairDepositInfo + calldata depositInfo = pairDepositInfo[index]; + require( + msgSender == depositInfo.onBehalf, + Errors.CALLER_NOT_ALLOWED + ); + IParaApeStaking(PARA_APE_STAKING).depositApeCoinPairPool( + depositInfo + ); } - //5 check if need to collateralize sAPE - if (_openSApeCollateralFlag) { + // 4, check if need to collateralize sAPE + if (openSApeCollateralFlag) { DataTypes.UserConfigurationMap storage userConfig = ps._usersConfig[ - msg.sender + msgSender ]; Helpers.setAssetUsedAsCollateral( userConfig, ps._reserves, DataTypes.SApeAddress, - msg.sender + msgSender ); } - // 6 mint debt token - if (stakingInfo.borrowAmount > 0) { + // 5, execute borrow + if (borrowAmount > 0) { BorrowLogic.executeBorrow( ps._reserves, ps._reservesList, - ps._usersConfig[msg.sender], + ps._usersConfig[msgSender], DataTypes.ExecuteBorrowParams({ - asset: stakingInfo.borrowAsset, - user: msg.sender, - onBehalfOf: msg.sender, - amount: stakingInfo.borrowAmount, + asset: asset, + user: msgSender, + onBehalfOf: msgSender, + amount: borrowAmount, referralCode: 0, releaseUnderlying: false, reservesCount: ps._reservesCount, @@ -440,496 +184,7 @@ contract PoolApeStaking is ); } - //7 checkout ape balance - require( - APE_COIN.balanceOf(localVar.xTokenAddress) == - localVar.balanceBefore, - Errors.TOTAL_STAKING_AMOUNT_WRONG - ); - } - - /// @inheritdoc IPoolApeStaking - function unstakeApePositionAndRepay(address nftAsset, uint256 tokenId) - external - nonReentrant - { - DataTypes.PoolStorage storage ps = poolStorage(); - DataTypes.ReserveData storage nftReserve = ps._reserves[nftAsset]; - address xTokenAddress = nftReserve.xTokenAddress; - address incentiveReceiver = address(0); - address positionOwner = INToken(xTokenAddress).ownerOf(tokenId); - if (msg.sender != positionOwner) { - DataTypes.UserConfigurationMap memory userConfig = ps._usersConfig[ - positionOwner - ]; - _checkUserHf(ps, userConfig, positionOwner, false); - incentiveReceiver = msg.sender; - } - - INTokenApeStaking(xTokenAddress).unstakePositionAndRepay( - tokenId, - incentiveReceiver - ); - } - - /// @inheritdoc IPoolApeStaking - function repayAndSupply( - address underlyingAsset, - address onBehalfOf, - uint256 totalAmount - ) external { - DataTypes.PoolStorage storage ps = poolStorage(); - require( - msg.sender == ps._reserves[underlyingAsset].xTokenAddress, - Errors.CALLER_NOT_XTOKEN - ); - - // 1, deposit APE as cAPE - APE_COIN.safeTransferFrom(msg.sender, address(this), totalAmount); - APE_COMPOUND.deposit(address(this), totalAmount); - - // 2, repay cAPE and supply cAPE for user - _repayAndSupplyForUser( - ps, - address(APE_COMPOUND), - address(this), - onBehalfOf, - totalAmount - ); - } - - /// @inheritdoc IPoolApeStaking - function claimApeAndCompound( - address nftAsset, - address[] calldata users, - uint256[][] calldata tokenIds, - uint256 minUsdcApePrice, - uint256 minWethApePrice - ) external nonReentrant { - require( - users.length == tokenIds.length, - Errors.INCONSISTENT_PARAMS_LENGTH - ); - DataTypes.PoolStorage storage ps = poolStorage(); - ApeStakingLocalVars memory localVar = _compoundCache( - ps, - nftAsset, - users.length - ); - require(msg.sender == localVar.compoundBot, Errors.CALLER_NOT_OPERATOR); - - for (uint256 i = 0; i < users.length; i++) { - for (uint256 j = 0; j < tokenIds[i].length; j++) { - require( - users[i] == - INToken(localVar.xTokenAddress).ownerOf(tokenIds[i][j]), - Errors.NOT_THE_OWNER - ); - } - - INTokenApeStaking(localVar.xTokenAddress).claimApeCoin( - tokenIds[i], - address(this) - ); - - _addUserToCompoundCache(ps, localVar, i, users[i]); - } - - _compoundForUsers( - ps, - localVar, - users, - minUsdcApePrice, - minWethApePrice - ); - } - - /// @inheritdoc IPoolApeStaking - function claimPairedApeAndCompound( - address nftAsset, - address[] calldata users, - ApeCoinStaking.PairNft[][] calldata _nftPairs, - uint256 minUsdcApePrice, - uint256 minWethApePrice - ) external nonReentrant { - require( - users.length == _nftPairs.length, - Errors.INCONSISTENT_PARAMS_LENGTH - ); - DataTypes.PoolStorage storage ps = poolStorage(); - ApeStakingLocalVars memory localVar = _compoundCache( - ps, - nftAsset, - users.length - ); - require(msg.sender == localVar.compoundBot, Errors.CALLER_NOT_OPERATOR); - - for (uint256 i = 0; i < _nftPairs.length; i++) { - localVar.transferredTokenOwners = new address[]( - _nftPairs[i].length - ); - for (uint256 j = 0; j < _nftPairs[i].length; j++) { - require( - users[i] == - INToken(localVar.xTokenAddress).ownerOf( - _nftPairs[i][j].mainTokenId - ), - Errors.NOT_THE_OWNER - ); - - localVar.transferredTokenOwners[ - j - ] = _validateBAKCOwnerAndTransfer( - localVar, - _nftPairs[i][j].bakcTokenId, - users[i] - ); - } - - INTokenApeStaking(localVar.xTokenAddress).claimBAKC( - _nftPairs[i], - address(this) - ); - - for (uint256 index = 0; index < _nftPairs[i].length; index++) { - localVar.bakcContract.safeTransferFrom( - localVar.xTokenAddress, - localVar.transferredTokenOwners[index], - _nftPairs[i][index].bakcTokenId - ); - } - - _addUserToCompoundCache(ps, localVar, i, users[i]); - } - - _compoundForUsers( - ps, - localVar, - users, - minUsdcApePrice, - minWethApePrice - ); - } - - function _generalCache(DataTypes.PoolStorage storage ps, address nftAsset) - internal - view - returns (ApeStakingLocalVars memory localVar) - { - localVar.xTokenAddress = ps._reserves[nftAsset].xTokenAddress; - localVar.bakcContract = INTokenApeStaking(localVar.xTokenAddress) - .getBAKC(); - localVar.bakcNToken = ps - ._reserves[address(localVar.bakcContract)] - .xTokenAddress; - } - - function _compoundCache( - DataTypes.PoolStorage storage ps, - address nftAsset, - uint256 numUsers - ) internal view returns (ApeStakingLocalVars memory localVar) { - localVar = _generalCache(ps, nftAsset); - localVar.balanceBefore = APE_COIN.balanceOf(address(this)); - localVar.amounts = new uint256[](numUsers); - localVar.swapAmounts = new uint256[](numUsers); - localVar.options = new DataTypes.ApeCompoundStrategy[](numUsers); - localVar.compoundFee = ps._apeCompoundFee; - localVar.compoundBot = ps._apeCompoundBot; - } - - function _addUserToCompoundCache( - DataTypes.PoolStorage storage ps, - ApeStakingLocalVars memory localVar, - uint256 i, - address user - ) internal view { - localVar.balanceAfter = APE_COIN.balanceOf(address(this)); - localVar.options[i] = ps._apeCompoundStrategies[user]; - unchecked { - localVar.amounts[i] = (localVar.balanceAfter - - localVar.balanceBefore).percentMul( - PercentageMath.PERCENTAGE_FACTOR - localVar.compoundFee - ); - localVar.balanceBefore = localVar.balanceAfter; - localVar.totalAmount += localVar.amounts[i]; - } - - if (localVar.options[i].swapPercent > 0) { - localVar.swapAmounts[i] = localVar.amounts[i].percentMul( - localVar.options[i].swapPercent - ); - if ( - localVar.options[i].swapTokenOut == - DataTypes.ApeCompoundTokenOut.USDC - ) { - localVar.totalUsdcSwapAmount += localVar.swapAmounts[i]; - } else { - localVar.totalWethSwapAmount += localVar.swapAmounts[i]; - } - } - } - - /// @inheritdoc IPoolApeStaking - function getApeCompoundFeeRate() external view returns (uint256) { - DataTypes.PoolStorage storage ps = poolStorage(); - return uint256(ps._apeCompoundFee); - } - - function _checkUserHf( - DataTypes.PoolStorage storage ps, - DataTypes.UserConfigurationMap memory userConfig, - address user, - bool checkAbove - ) private view { - uint256 healthFactor; - if (!userConfig.isBorrowingAny()) { - healthFactor = type(uint256).max; - } else { - (, , , , , , , healthFactor, , ) = GenericLogic - .calculateUserAccountData( - ps._reserves, - ps._reservesList, - DataTypes.CalculateUserAccountDataParams({ - userConfig: userConfig, - reservesCount: ps._reservesCount, - user: user, - oracle: ADDRESSES_PROVIDER.getPriceOracle() - }) - ); - } - - if (checkAbove) { - require( - healthFactor > DataTypes.HEALTH_FACTOR_LIQUIDATION_THRESHOLD, - Errors.HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD - ); - } else { - require( - healthFactor < DataTypes.HEALTH_FACTOR_LIQUIDATION_THRESHOLD, - Errors.HEALTH_FACTOR_NOT_BELOW_THRESHOLD - ); - } - } - - function _checkSApeIsNotPaused(DataTypes.PoolStorage storage ps) - internal - view - { - DataTypes.ReserveData storage reserve = ps._reserves[ - DataTypes.SApeAddress - ]; - - (bool isActive, , , bool isPaused, ) = reserve.configuration.getFlags(); - - require(isActive, Errors.RESERVE_INACTIVE); - require(!isPaused, Errors.RESERVE_PAUSED); - } - - function _compoundForUsers( - DataTypes.PoolStorage storage ps, - ApeStakingLocalVars memory localVar, - address[] calldata users, - uint256 minUsdcApePrice, - uint256 minWethApePrice - ) internal { - uint256 totalSwapAmount = localVar.totalUsdcSwapAmount + - localVar.totalWethSwapAmount; - if (localVar.totalAmount > totalSwapAmount) { - APE_COMPOUND.deposit( - address(this), - localVar.totalAmount - totalSwapAmount - ); - } - - uint256 compoundFee = localVar - .totalAmount - .percentDiv(PercentageMath.PERCENTAGE_FACTOR - localVar.compoundFee) - .percentMul(localVar.compoundFee); - if (compoundFee > 0) { - APE_COIN.safeTransfer(localVar.compoundBot, compoundFee); - } - - if (localVar.totalUsdcSwapAmount > 0) { - bytes memory usdcSwapPath = abi.encodePacked( - APE_COIN, - APE_WETH_FEE, - WETH, - WETH_USDC_FEE, - USDC - ); - localVar.pUSDCAddress = ps._reserves[address(USDC)].xTokenAddress; - localVar.usdcApePrice = _swapAndSupplyForUser( - ps, - address(USDC), - localVar.pUSDCAddress, - localVar.totalUsdcSwapAmount, - usdcSwapPath, - address(this), - minUsdcApePrice - ); - } - - if (localVar.totalWethSwapAmount > 0) { - bytes memory wethSwapPath = abi.encodePacked( - APE_COIN, - APE_WETH_FEE, - WETH - ); - localVar.pWETHAddress = ps._reserves[address(WETH)].xTokenAddress; - localVar.wethApePrice = _swapAndSupplyForUser( - ps, - address(WETH), - localVar.pWETHAddress, - localVar.totalWethSwapAmount, - wethSwapPath, - address(this), - minWethApePrice - ); - } - - for (uint256 i = 0; i < users.length; i++) { - if (localVar.swapAmounts[i] > 0) { - address swapTokenOut; - uint256 price; - if ( - localVar.options[i].swapTokenOut == - DataTypes.ApeCompoundTokenOut.USDC - ) { - swapTokenOut = localVar.pUSDCAddress; - price = localVar.usdcApePrice; - } else { - swapTokenOut = localVar.pWETHAddress; - price = localVar.wethApePrice; - } - IERC20(swapTokenOut).safeTransfer( - users[i], - (localVar.swapAmounts[i] * price) / 1e18 - ); - } - _repayAndSupplyForUser( - ps, - address(APE_COMPOUND), - address(this), - users[i], - localVar.amounts[i] - localVar.swapAmounts[i] - ); - } - } - - function _swapAndSupplyForUser( - DataTypes.PoolStorage storage ps, - address tokenOut, - address xTokenAddress, - uint256 amountIn, - bytes memory swapPath, - address user, - uint256 price - ) internal returns (uint256) { - if (amountIn == 0) { - return price; - } - uint256 amountOut = SWAP_ROUTER.exactInput( - ISwapRouter.ExactInputParams({ - path: swapPath, - recipient: address(this), - deadline: block.timestamp, - amountIn: amountIn, - amountOutMinimum: amountIn.wadMul(price) - }) - ); - uint256 beforeBalance = IERC20(xTokenAddress).balanceOf(address(this)); - _supplyForUser(ps, tokenOut, address(this), user, amountOut); - return - ((IERC20(xTokenAddress).balanceOf(address(this)) - beforeBalance) * - 1e18) / amountIn; - } - - function _repayAndSupplyForUser( - DataTypes.PoolStorage storage ps, - address asset, - address payer, - address onBehalfOf, - uint256 totalAmount - ) internal { - address variableDebtTokenAddress = ps - ._reserves[asset] - .variableDebtTokenAddress; - uint256 repayAmount = Math.min( - IERC20(variableDebtTokenAddress).balanceOf(onBehalfOf), - totalAmount - ); - _repayForUser(ps, asset, payer, onBehalfOf, repayAmount); - _supplyForUser(ps, asset, payer, onBehalfOf, totalAmount - repayAmount); - } - - function _supplyForUser( - DataTypes.PoolStorage storage ps, - address asset, - address payer, - address onBehalfOf, - uint256 amount - ) internal { - if (amount == 0) { - return; - } - DataTypes.UserConfigurationMap storage userConfig = ps._usersConfig[ - onBehalfOf - ]; - SupplyLogic.executeSupply( - ps._reserves, - userConfig, - DataTypes.ExecuteSupplyParams({ - asset: asset, - amount: amount, - onBehalfOf: onBehalfOf, - payer: payer, - referralCode: 0 - }) - ); - } - - function _repayForUser( - DataTypes.PoolStorage storage ps, - address asset, - address payer, - address onBehalfOf, - uint256 amount - ) internal returns (uint256) { - if (amount == 0) { - return 0; - } - return - BorrowLogic.executeRepay( - ps._reserves, - ps._usersConfig[onBehalfOf], - DataTypes.ExecuteRepayParams({ - asset: asset, - amount: amount, - onBehalfOf: onBehalfOf, - payer: payer, - usePTokens: false - }) - ); - } - - function _validateBAKCOwnerAndTransfer( - ApeStakingLocalVars memory localVar, - uint256 tokenId, - address userAddress - ) internal returns (address bakcOwner) { - bakcOwner = localVar.bakcContract.ownerOf(tokenId); - require( - (userAddress == bakcOwner) || - (bakcOwner == localVar.bakcNToken && - userAddress == - INToken(localVar.bakcNToken).ownerOf(tokenId)), - Errors.NOT_THE_BAKC_OWNER - ); - localVar.bakcContract.safeTransferFrom( - bakcOwner, - localVar.xTokenAddress, - tokenId - ); + uint256 balanceAfter = IERC20(asset).balanceOf(address(this)); + require(balanceAfter == balanceBefore, Errors.INVALID_PARAMETER); } } diff --git a/contracts/protocol/pool/PoolConfigurator.sol b/contracts/protocol/pool/PoolConfigurator.sol index 6d3f75b9c..407644ef6 100644 --- a/contracts/protocol/pool/PoolConfigurator.sol +++ b/contracts/protocol/pool/PoolConfigurator.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {VersionedInitializable} from "../libraries/paraspace-upgradeability/VersionedInitializable.sol"; import {ReserveConfiguration} from "../libraries/configuration/ReserveConfiguration.sol"; diff --git a/contracts/protocol/pool/PoolCore.sol b/contracts/protocol/pool/PoolCore.sol index 58dfd6f1d..1f8efdd92 100644 --- a/contracts/protocol/pool/PoolCore.sol +++ b/contracts/protocol/pool/PoolCore.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {ParaVersionedInitializable} from "../libraries/paraspace-upgradeability/ParaVersionedInitializable.sol"; import {Errors} from "../libraries/helpers/Errors.sol"; diff --git a/contracts/protocol/pool/PoolMarketplace.sol b/contracts/protocol/pool/PoolMarketplace.sol index 61951ede2..673a76d1b 100644 --- a/contracts/protocol/pool/PoolMarketplace.sol +++ b/contracts/protocol/pool/PoolMarketplace.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {ParaVersionedInitializable} from "../libraries/paraspace-upgradeability/ParaVersionedInitializable.sol"; import {Errors} from "../libraries/helpers/Errors.sol"; diff --git a/contracts/protocol/pool/PoolParameters.sol b/contracts/protocol/pool/PoolParameters.sol index 429ea3089..48c660c15 100644 --- a/contracts/protocol/pool/PoolParameters.sol +++ b/contracts/protocol/pool/PoolParameters.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {ParaVersionedInitializable} from "../libraries/paraspace-upgradeability/ParaVersionedInitializable.sol"; import {Errors} from "../libraries/helpers/Errors.sol"; @@ -242,52 +242,6 @@ contract PoolParameters is IERC20(token).approve(to, 0); } - /// @inheritdoc IPoolParameters - function setClaimApeForCompoundFee(uint256 fee) external onlyPoolAdmin { - require(fee < PercentageMath.HALF_PERCENTAGE_FACTOR, "Value Too High"); - DataTypes.PoolStorage storage ps = poolStorage(); - uint256 oldValue = ps._apeCompoundFee; - if (oldValue != fee) { - ps._apeCompoundFee = uint16(fee); - emit ClaimApeForYieldIncentiveUpdated(oldValue, fee); - } - } - - /// @inheritdoc IPoolParameters - function setClaimApeForCompoundBot(address bot) external onlyPoolAdmin { - DataTypes.PoolStorage storage ps = poolStorage(); - address oldValue = ps._apeCompoundBot; - if (oldValue != bot) { - ps._apeCompoundBot = bot; - emit ClaimApeForYieldIncentiveBotUpdated(oldValue, bot); - } - } - - /// @inheritdoc IPoolParameters - function setApeCompoundStrategy( - DataTypes.ApeCompoundStrategy calldata strategy - ) external { - require( - strategy.swapPercent == 0 || - (strategy.ty == DataTypes.ApeCompoundType.SwapAndSupply && - strategy.swapPercent > 0 && - strategy.swapPercent <= PercentageMath.PERCENTAGE_FACTOR), - "Invalid swap percent" - ); - DataTypes.PoolStorage storage ps = poolStorage(); - ps._apeCompoundStrategies[msg.sender] = strategy; - } - - /// @inheritdoc IPoolParameters - function getUserApeCompoundStrategy(address user) - external - view - returns (DataTypes.ApeCompoundStrategy memory strategy) - { - DataTypes.PoolStorage storage ps = poolStorage(); - strategy = ps._apeCompoundStrategies[user]; - } - /// @inheritdoc IPoolParameters function setAuctionRecoveryHealthFactor(uint64 value) external diff --git a/contracts/protocol/pool/PoolPositionMover.sol b/contracts/protocol/pool/PoolPositionMover.sol index 3b53132fe..461549124 100644 --- a/contracts/protocol/pool/PoolPositionMover.sol +++ b/contracts/protocol/pool/PoolPositionMover.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {ParaVersionedInitializable} from "../libraries/paraspace-upgradeability/ParaVersionedInitializable.sol"; import {DataTypes} from "../libraries/types/DataTypes.sol"; diff --git a/contracts/protocol/pool/PoolStorage.sol b/contracts/protocol/pool/PoolStorage.sol index 63c6e9085..35a758a23 100644 --- a/contracts/protocol/pool/PoolStorage.sol +++ b/contracts/protocol/pool/PoolStorage.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {UserConfiguration} from "../libraries/configuration/UserConfiguration.sol"; import {ReserveConfiguration} from "../libraries/configuration/ReserveConfiguration.sol"; diff --git a/contracts/protocol/tokenization/AStETHDebtToken.sol b/contracts/protocol/tokenization/AStETHDebtToken.sol index de12c7da6..1bcfe972e 100644 --- a/contracts/protocol/tokenization/AStETHDebtToken.sol +++ b/contracts/protocol/tokenization/AStETHDebtToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPool} from "../../interfaces/IPool.sol"; import {ILido} from "../../interfaces/ILido.sol"; diff --git a/contracts/protocol/tokenization/ATokenDebtToken.sol b/contracts/protocol/tokenization/ATokenDebtToken.sol index 62f0e687a..cf70ad941 100644 --- a/contracts/protocol/tokenization/ATokenDebtToken.sol +++ b/contracts/protocol/tokenization/ATokenDebtToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPool} from "../../interfaces/IPool.sol"; import {RebasingDebtToken} from "./RebasingDebtToken.sol"; diff --git a/contracts/protocol/tokenization/CApeDebtToken.sol b/contracts/protocol/tokenization/CApeDebtToken.sol index ee417a513..5aa177cff 100644 --- a/contracts/protocol/tokenization/CApeDebtToken.sol +++ b/contracts/protocol/tokenization/CApeDebtToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPool} from "../../interfaces/IPool.sol"; import {ICApe} from "../../interfaces/ICApe.sol"; diff --git a/contracts/protocol/tokenization/DelegationAwarePToken.sol b/contracts/protocol/tokenization/DelegationAwarePToken.sol index 34486a33c..44e05921f 100644 --- a/contracts/protocol/tokenization/DelegationAwarePToken.sol +++ b/contracts/protocol/tokenization/DelegationAwarePToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPool} from "../../interfaces/IPool.sol"; import {IDelegationToken} from "../../interfaces/IDelegationToken.sol"; diff --git a/contracts/protocol/tokenization/NToken.sol b/contracts/protocol/tokenization/NToken.sol index 1332e8ec8..361abfc91 100644 --- a/contracts/protocol/tokenization/NToken.sol +++ b/contracts/protocol/tokenization/NToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC20} from "../../dependencies/openzeppelin/contracts/IERC20.sol"; import {IERC721} from "../../dependencies/openzeppelin/contracts/IERC721.sol"; diff --git a/contracts/protocol/tokenization/NTokenApeStaking.sol b/contracts/protocol/tokenization/NTokenApeStaking.sol index 4c11c4edf..770b0c791 100644 --- a/contracts/protocol/tokenization/NTokenApeStaking.sol +++ b/contracts/protocol/tokenization/NTokenApeStaking.sol @@ -1,46 +1,41 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {NToken} from "./NToken.sol"; -import {ApeCoinStaking} from "../../dependencies/yoga-labs/ApeCoinStaking.sol"; import {IPool} from "../../interfaces/IPool.sol"; -import {IERC20} from "../../dependencies/openzeppelin/contracts/IERC20.sol"; import {IERC721} from "../../dependencies/openzeppelin/contracts/IERC721.sol"; import {IRewardController} from "../../interfaces/IRewardController.sol"; -import {ApeStakingLogic} from "./libraries/ApeStakingLogic.sol"; -import "../../interfaces/INTokenApeStaking.sol"; import {DataTypes} from "../libraries/types/DataTypes.sol"; +import {UserConfiguration} from "../libraries/configuration/UserConfiguration.sol"; +import "../../interfaces/IParaApeStaking.sol"; +import "../../dependencies/openzeppelin/contracts/SafeCast.sol"; +import "../libraries/helpers/Errors.sol"; /** * @title ApeCoinStaking NToken * * @notice Implementation of the NToken for the ParaSpace protocol */ -abstract contract NTokenApeStaking is NToken, INTokenApeStaking { - ApeCoinStaking immutable _apeCoinStaking; - - bytes32 constant APE_STAKING_DATA_STORAGE_POSITION = - bytes32( - uint256(keccak256("paraspace.proxy.ntoken.apestaking.storage")) - 1 - ); +abstract contract NTokenApeStaking is NToken { + using SafeCast for uint256; + using UserConfiguration for DataTypes.UserConfigurationMap; /** - * @dev Default percentage of borrower's ape position to be repaid as incentive in a unstaking transaction. - * @dev Percentage applied when the users ape position got unstaked by others. - * Expressed in bps, a value of 30 results in 0.3% + * @dev Minimum health factor to consider a user position healthy + * A value of 1e18 results in 1 */ - uint256 internal constant DEFAULT_UNSTAKE_INCENTIVE_PERCENTAGE = 30; + uint256 public constant HEALTH_FACTOR_LIQUIDATION_THRESHOLD = 1e18; + + IParaApeStaking immutable paraApeStaking; /** * @dev Constructor. * @param pool The address of the Pool contract */ - constructor( - IPool pool, - address apeCoinStaking, - address delegateRegistry - ) NToken(pool, false, delegateRegistry) { - _apeCoinStaking = ApeCoinStaking(apeCoinStaking); + constructor(IPool pool, address delegateRegistry) + NToken(pool, false, delegateRegistry) + { + paraApeStaking = IParaApeStaking(pool.paraApeStaking()); } function initialize( @@ -51,24 +46,10 @@ abstract contract NTokenApeStaking is NToken, INTokenApeStaking { string calldata nTokenSymbol, bytes calldata params ) public virtual override initializer { - IERC20 _apeCoin = _apeCoinStaking.apeCoin(); - //approve for apeCoinStaking - uint256 allowance = IERC20(_apeCoin).allowance( - address(this), - address(_apeCoinStaking) + IERC721(underlyingAsset).setApprovalForAll( + address(paraApeStaking), + true ); - if (allowance == 0) { - IERC20(_apeCoin).approve( - address(_apeCoinStaking), - type(uint256).max - ); - } - //approve for Pool contract - allowance = IERC20(_apeCoin).allowance(address(this), address(POOL)); - if (allowance == 0) { - IERC20(_apeCoin).approve(address(POOL), type(uint256).max); - } - getBAKC().setApprovalForAll(address(POOL), true); super.initialize( initializingPool, @@ -78,22 +59,11 @@ abstract contract NTokenApeStaking is NToken, INTokenApeStaking { nTokenSymbol, params ); - - initializeStakingData(); - } - - /** - * @notice Returns the address of BAKC contract address. - **/ - function getBAKC() public view returns (IERC721) { - return _apeCoinStaking.nftContracts(ApeStakingLogic.BAKC_POOL_ID); } - /** - * @notice Returns the address of ApeCoinStaking contract address. - **/ - function getApeStaking() external view returns (ApeCoinStaking) { - return _apeCoinStaking; + function isBayc() internal pure virtual returns (bool) { + // should be overridden + return true; } /** @@ -105,132 +75,42 @@ abstract contract NTokenApeStaking is NToken, INTokenApeStaking { uint256 tokenId, bool validate ) internal override { - ApeStakingLogic.executeUnstakePositionAndRepay( - _ERC721Data.owners, - apeStakingDataStorage(), - ApeStakingLogic.UnstakeAndRepayParams({ - POOL: POOL, - _apeCoinStaking: _apeCoinStaking, - _underlyingAsset: _ERC721Data.underlyingAsset, - poolId: POOL_ID(), - tokenId: tokenId, - incentiveReceiver: address(0), - bakcNToken: getBAKCNTokenAddress() - }) - ); - super._transfer(from, to, tokenId, validate); - } - - /** - * @notice Overrides the burn from NToken to withdraw all staked and pending rewards before burning the NToken on liquidation/withdraw - */ - function burn( - address from, - address receiverOfUnderlying, - uint256[] calldata tokenIds, - DataTypes.TimeLockParams calldata timeLockParams - ) external virtual override onlyPool nonReentrant returns (uint64, uint64) { - for (uint256 index = 0; index < tokenIds.length; index++) { - ApeStakingLogic.executeUnstakePositionAndRepay( - _ERC721Data.owners, - apeStakingDataStorage(), - ApeStakingLogic.UnstakeAndRepayParams({ - POOL: POOL, - _apeCoinStaking: _apeCoinStaking, - _underlyingAsset: _ERC721Data.underlyingAsset, - poolId: POOL_ID(), - tokenId: tokenIds[index], - incentiveReceiver: address(0), - bakcNToken: getBAKCNTokenAddress() - }) - ); - } - - return _burn(from, receiverOfUnderlying, tokenIds, timeLockParams); - } - - function POOL_ID() internal pure virtual returns (uint256) { - // should be overridden - return 0; - } - - function initializeStakingData() internal { - ApeStakingLogic.APEStakingParameter - storage dataStorage = apeStakingDataStorage(); - ApeStakingLogic.executeSetUnstakeApeIncentive( - dataStorage, - DEFAULT_UNSTAKE_INCENTIVE_PERCENTAGE - ); - } - - function setUnstakeApeIncentive(uint256 incentive) external onlyPoolAdmin { - ApeStakingLogic.executeSetUnstakeApeIncentive( - apeStakingDataStorage(), - incentive + address underlyingOwner = IERC721(_ERC721Data.underlyingAsset).ownerOf( + tokenId ); - } - - function apeStakingDataStorage() - internal - pure - returns (ApeStakingLogic.APEStakingParameter storage rgs) - { - bytes32 position = APE_STAKING_DATA_STORAGE_POSITION; - assembly { - rgs.slot := position + if (underlyingOwner == address(paraApeStaking)) { + uint32[] memory tokenIds = new uint32[](1); + tokenIds[0] = tokenId.toUint32(); + paraApeStaking.nApeOwnerChangeCallback(isBayc(), tokenIds); } + super._transfer(from, to, tokenId, validate); } - /** - * @notice Unstake Ape coin staking position and repay user debt - * @param tokenId Token id of the ape staking position on - * @param incentiveReceiver address to receive incentive - */ - function unstakePositionAndRepay(uint256 tokenId, address incentiveReceiver) + function unstakeApeStakingPosition(address user, uint32[] calldata tokenIds) external nonReentrant { - address bakcNToken = getBAKCNTokenAddress(); - require( - msg.sender == address(POOL) || msg.sender == bakcNToken, - "Invalid Caller" - ); - ApeStakingLogic.executeUnstakePositionAndRepay( - _ERC721Data.owners, - apeStakingDataStorage(), - ApeStakingLogic.UnstakeAndRepayParams({ - POOL: POOL, - _apeCoinStaking: _apeCoinStaking, - _underlyingAsset: _ERC721Data.underlyingAsset, - poolId: POOL_ID(), - tokenId: tokenId, - incentiveReceiver: incentiveReceiver, - bakcNToken: bakcNToken - }) - ); - } + uint256 arrayLength = tokenIds.length; + for (uint256 index = 0; index < arrayLength; index++) { + uint32 tokenId = tokenIds[index]; + require(user == ownerOf(tokenId), Errors.NOT_THE_OWNER); + } - /** - * @notice get user total ape staking position - * @param user user address - */ - function getUserApeStakingAmount(address user) - external - view - returns (uint256) - { - return - ApeStakingLogic.getUserTotalStakingAmount( - _ERC721Data.userState, - _ERC721Data.ownedTokens, - _ERC721Data.underlyingAsset, - user, - POOL_ID(), - _apeCoinStaking + DataTypes.UserConfigurationMap memory userConfig = POOL + .getUserConfiguration(user); + uint16 sApeReserveId = paraApeStaking.sApeReserveId(); + bool usageAsCollateralEnabled = userConfig.isUsingAsCollateral( + sApeReserveId + ); + if (usageAsCollateralEnabled && userConfig.isBorrowingAny()) { + (, , , , , uint256 healthFactor, ) = POOL.getUserAccountData(user); + //need to check user health factor + require( + healthFactor < HEALTH_FACTOR_LIQUIDATION_THRESHOLD, + Errors.HEALTH_FACTOR_NOT_BELOW_THRESHOLD ); - } + } - function getBAKCNTokenAddress() internal view returns (address) { - return POOL.getReserveData(address(getBAKC())).xTokenAddress; + paraApeStaking.nApeOwnerChangeCallback(isBayc(), tokenIds); } } diff --git a/contracts/protocol/tokenization/NTokenBAKC.sol b/contracts/protocol/tokenization/NTokenBAKC.sol index 3252e519f..394320b26 100644 --- a/contracts/protocol/tokenization/NTokenBAKC.sol +++ b/contracts/protocol/tokenization/NTokenBAKC.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {NToken} from "./NToken.sol"; import {IPool} from "../../interfaces/IPool.sol"; @@ -7,12 +7,11 @@ import {IERC20} from "../../dependencies/openzeppelin/contracts/IERC20.sol"; import {IERC721} from "../../dependencies/openzeppelin/contracts/IERC721.sol"; import {Errors} from "../libraries/helpers/Errors.sol"; import {XTokenType} from "../../interfaces/IXTokenType.sol"; -import {ApeStakingLogic} from "./libraries/ApeStakingLogic.sol"; -import {INTokenApeStaking} from "../../interfaces/INTokenApeStaking.sol"; -import {ApeCoinStaking} from "../../dependencies/yoga-labs/ApeCoinStaking.sol"; import {INToken} from "../../interfaces/INToken.sol"; import {IRewardController} from "../../interfaces/IRewardController.sol"; import {DataTypes} from "../libraries/types/DataTypes.sol"; +import "../../interfaces/IParaApeStaking.sol"; +import "../../dependencies/openzeppelin/contracts/SafeCast.sol"; /** * @title NTokenBAKC @@ -20,24 +19,18 @@ import {DataTypes} from "../libraries/types/DataTypes.sol"; * @notice Implementation of the NTokenBAKC for the ParaSpace protocol */ contract NTokenBAKC is NToken { - ApeCoinStaking immutable _apeCoinStaking; - address private immutable nBAYC; - address private immutable nMAYC; + using SafeCast for uint256; + + IParaApeStaking immutable paraApeStaking; /** * @dev Constructor. * @param pool The address of the Pool contract */ - constructor( - IPool pool, - address apeCoinStaking, - address _nBAYC, - address _nMAYC, - address delegateRegistry - ) NToken(pool, false, delegateRegistry) { - _apeCoinStaking = ApeCoinStaking(apeCoinStaking); - nBAYC = _nBAYC; - nMAYC = _nMAYC; + constructor(IPool pool, address delegateRegistry) + NToken(pool, false, delegateRegistry) + { + paraApeStaking = IParaApeStaking(pool.paraApeStaking()); } function initialize( @@ -57,18 +50,10 @@ contract NTokenBAKC is NToken { params ); - IERC20 ape = _apeCoinStaking.apeCoin(); - //approve for nBAYC - uint256 allowance = ape.allowance(address(this), nBAYC); - if (allowance == 0) { - ape.approve(nBAYC, type(uint256).max); - } - //approve for Pool nMAYC - allowance = ape.allowance(address(this), nMAYC); - if (allowance == 0) { - ape.approve(nMAYC, type(uint256).max); - } - IERC721(underlyingAsset).setApprovalForAll(address(POOL), true); + IERC721(underlyingAsset).setApprovalForAll( + address(paraApeStaking), + true + ); } function _transfer( @@ -77,67 +62,15 @@ contract NTokenBAKC is NToken { uint256 tokenId, bool validate ) internal override { - _unStakePairedApePosition(tokenId); - super._transfer(from, to, tokenId, validate); - } - - /** - * @notice Overrides the burn from NToken to withdraw all staked and pending rewards before burning the NToken on liquidation/withdraw - */ - function burn( - address from, - address receiverOfUnderlying, - uint256[] calldata tokenIds, - DataTypes.TimeLockParams calldata timeLockParams - ) external virtual override onlyPool nonReentrant returns (uint64, uint64) { - if (from != receiverOfUnderlying) { - for (uint256 index = 0; index < tokenIds.length; index++) { - _unStakePairedApePosition(tokenIds[index]); - } - } - return _burn(from, receiverOfUnderlying, tokenIds, timeLockParams); - } - - function _unStakePairedApePosition(uint256 tokenId) internal { - //check if have ape pair position - (uint256 bakcStakedAmount, ) = _apeCoinStaking.nftPosition( - ApeStakingLogic.BAKC_POOL_ID, + address underlyingOwner = IERC721(_ERC721Data.underlyingAsset).ownerOf( tokenId ); - if (bakcStakedAmount > 0) { - bool positionExisted = _tryUnstakeMainTokenPosition( - ApeStakingLogic.BAYC_POOL_ID, - nBAYC, - tokenId - ); - if (!positionExisted) { - _tryUnstakeMainTokenPosition( - ApeStakingLogic.MAYC_POOL_ID, - nMAYC, - tokenId - ); - } + if (underlyingOwner == address(paraApeStaking)) { + uint32[] memory tokenIds = new uint32[](1); + tokenIds[0] = tokenId.toUint32(); + paraApeStaking.nBakcOwnerChangeCallback(tokenIds); } - } - - function _tryUnstakeMainTokenPosition( - uint256 poolId, - address nToken, - uint256 tokenId - ) internal returns (bool) { - (uint256 mainTokenId, bool positionExisted) = _apeCoinStaking - .bakcToMain(tokenId, poolId); - if (positionExisted) { - bool sameOwner = INToken(nToken).ownerOf(mainTokenId) == - ownerOf(tokenId); - if (sameOwner) { - INTokenApeStaking(nToken).unstakePositionAndRepay( - mainTokenId, - address(0) - ); - } - } - return positionExisted; + super._transfer(from, to, tokenId, validate); } function getXTokenType() external pure override returns (XTokenType) { diff --git a/contracts/protocol/tokenization/NTokenBAYC.sol b/contracts/protocol/tokenization/NTokenBAYC.sol index 1c67db808..63326f7be 100644 --- a/contracts/protocol/tokenization/NTokenBAYC.sol +++ b/contracts/protocol/tokenization/NTokenBAYC.sol @@ -1,11 +1,9 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; -import {ApeCoinStaking} from "../../dependencies/yoga-labs/ApeCoinStaking.sol"; import {NTokenApeStaking} from "./NTokenApeStaking.sol"; import {IPool} from "../../interfaces/IPool.sol"; import {XTokenType} from "../../interfaces/IXTokenType.sol"; -import {ApeStakingLogic} from "./libraries/ApeStakingLogic.sol"; import {DataTypes} from "../libraries/types/DataTypes.sol"; /** @@ -14,114 +12,12 @@ import {DataTypes} from "../libraries/types/DataTypes.sol"; * @notice Implementation of the NToken for the ParaSpace protocol */ contract NTokenBAYC is NTokenApeStaking { - constructor( - IPool pool, - address apeCoinStaking, - address delegateRegistry - ) NTokenApeStaking(pool, apeCoinStaking, delegateRegistry) {} + constructor(IPool pool, address delegateRegistry) + NTokenApeStaking(pool, delegateRegistry) + {} - /** - * @notice Deposit ApeCoin to the BAYC Pool - * @param _nfts Array of SingleNft structs - * @dev Commits 1 or more BAYC NFTs, each with an ApeCoin amount to the BAYC pool.\ - * Each BAYC committed must attach an ApeCoin amount >= 1 ApeCoin and <= the BAYC pool cap amount. - */ - function depositApeCoin(ApeCoinStaking.SingleNft[] calldata _nfts) - external - onlyPool - nonReentrant - { - _apeCoinStaking.depositBAYC(_nfts); - } - - /** - * @notice Claim rewards for array of BAYC NFTs and send to recipient - * @param _nfts Array of NFTs owned and committed by the msg.sender - * @param _recipient Address to send claim reward to - */ - function claimApeCoin(uint256[] calldata _nfts, address _recipient) - external - onlyPool - nonReentrant - { - _apeCoinStaking.claimBAYC(_nfts, _recipient); - } - - /** - * @notice Withdraw staked ApeCoin from the BAYC pool. If withdraw is total staked amount, performs an automatic claim. - * @param _nfts Array of BAYC NFT's with staked amounts - * @param _recipient Address to send withdraw amount and claim to - */ - function withdrawApeCoin( - ApeCoinStaking.SingleNft[] calldata _nfts, - address _recipient, - DataTypes.TimeLockParams memory _timeLockParams - ) external onlyPool nonReentrant { - ApeStakingLogic.executeWithdrawBAYC( - POOL, - _ERC721Data.underlyingAsset, - _apeCoinStaking, - _nfts, - _recipient, - _timeLockParams - ); - } - - /** - * @notice Deposit ApeCoin to the Pair Pool, where Pair = (BAYC + BAKC) - * @param _nftPairs Array of PairNftWithAmount structs - * @dev Commits 1 or more Pairs, each with an ApeCoin amount to the Pair pool.\ - * Each BAKC committed must attach an ApeCoin amount >= 1 ApeCoin and <= the Pair pool cap amount.\ - * Example: BAYC + BAKC + 1 ApeCoin: [[0, 0, "1000000000000000000"]]\ - */ - function depositBAKC( - ApeCoinStaking.PairNftDepositWithAmount[] calldata _nftPairs - ) external onlyPool nonReentrant { - _apeCoinStaking.depositBAKC( - _nftPairs, - new ApeCoinStaking.PairNftDepositWithAmount[](0) - ); - } - - /** - * @notice Claim rewards for array of Paired NFTs and send to recipient - * @param _nftPairs Array of Paired BAYC/MAYC NFTs owned and committed by the msg.sender - * @param _recipient Address to send claim reward to - */ - function claimBAKC( - ApeCoinStaking.PairNft[] calldata _nftPairs, - address _recipient - ) external onlyPool nonReentrant { - _apeCoinStaking.claimBAKC( - _nftPairs, - new ApeCoinStaking.PairNft[](0), - _recipient - ); - } - - /** - * @notice Withdraw staked ApeCoin from the Pair pool. If withdraw is total staked amount, performs an automatic claim. - * @param _nftPairs Array of Paired BAYC NFT's with staked amounts - * @dev if pairs have split ownership and BAKC is attempting a withdraw, the withdraw must be for the total staked amount - */ - function withdrawBAKC( - ApeCoinStaking.PairNftWithdrawWithAmount[] calldata _nftPairs, - address _apeRecipient, - DataTypes.TimeLockParams memory _timeLockParams - ) external onlyPool nonReentrant { - ApeStakingLogic.withdrawBAKC( - POOL, - _ERC721Data.underlyingAsset, - _apeCoinStaking, - POOL_ID(), - _nftPairs, - _apeRecipient, - _timeLockParams - ); - } - - function POOL_ID() internal pure virtual override returns (uint256) { - return ApeStakingLogic.BAYC_POOL_ID; + function isBayc() internal pure virtual override returns (bool) { + return true; } function getXTokenType() external pure override returns (XTokenType) { diff --git a/contracts/protocol/tokenization/NTokenChromieSquiggle.sol b/contracts/protocol/tokenization/NTokenChromieSquiggle.sol index a0346af51..b6bd6da0f 100644 --- a/contracts/protocol/tokenization/NTokenChromieSquiggle.sol +++ b/contracts/protocol/tokenization/NTokenChromieSquiggle.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {NToken} from "./NToken.sol"; import {IPool} from "../../interfaces/IPool.sol"; @@ -7,9 +7,6 @@ import {IERC20} from "../../dependencies/openzeppelin/contracts/IERC20.sol"; import {IERC721} from "../../dependencies/openzeppelin/contracts/IERC721.sol"; import {Errors} from "../libraries/helpers/Errors.sol"; import {XTokenType} from "../../interfaces/IXTokenType.sol"; -import {ApeStakingLogic} from "./libraries/ApeStakingLogic.sol"; -import {INTokenApeStaking} from "../../interfaces/INTokenApeStaking.sol"; -import {ApeCoinStaking} from "../../dependencies/yoga-labs/ApeCoinStaking.sol"; import {INToken} from "../../interfaces/INToken.sol"; import {IRewardController} from "../../interfaces/IRewardController.sol"; import {DataTypes} from "../libraries/types/DataTypes.sol"; diff --git a/contracts/protocol/tokenization/NTokenMAYC.sol b/contracts/protocol/tokenization/NTokenMAYC.sol index e702430a0..aea242a95 100644 --- a/contracts/protocol/tokenization/NTokenMAYC.sol +++ b/contracts/protocol/tokenization/NTokenMAYC.sol @@ -1,11 +1,9 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; -import {ApeCoinStaking} from "../../dependencies/yoga-labs/ApeCoinStaking.sol"; import {NTokenApeStaking} from "./NTokenApeStaking.sol"; import {IPool} from "../../interfaces/IPool.sol"; import {XTokenType} from "../../interfaces/IXTokenType.sol"; -import {ApeStakingLogic} from "./libraries/ApeStakingLogic.sol"; import {DataTypes} from "../libraries/types/DataTypes.sol"; /** @@ -14,114 +12,12 @@ import {DataTypes} from "../libraries/types/DataTypes.sol"; * @notice Implementation of the NToken for the ParaSpace protocol */ contract NTokenMAYC is NTokenApeStaking { - constructor( - IPool pool, - address apeCoinStaking, - address delegateRegistry - ) NTokenApeStaking(pool, apeCoinStaking, delegateRegistry) {} + constructor(IPool pool, address delegateRegistry) + NTokenApeStaking(pool, delegateRegistry) + {} - /** - * @notice Deposit ApeCoin to the MAYC Pool - * @param _nfts Array of SingleNft structs - * @dev Commits 1 or more MAYC NFTs, each with an ApeCoin amount to the MAYC pool.\ - * Each MAYC committed must attach an ApeCoin amount >= 1 ApeCoin and <= the MAYC pool cap amount. - */ - function depositApeCoin(ApeCoinStaking.SingleNft[] calldata _nfts) - external - onlyPool - nonReentrant - { - _apeCoinStaking.depositMAYC(_nfts); - } - - /** - * @notice Claim rewards for array of MAYC NFTs and send to recipient - * @param _nfts Array of NFTs owned and committed by the msg.sender - * @param _recipient Address to send claim reward to - */ - function claimApeCoin(uint256[] calldata _nfts, address _recipient) - external - onlyPool - nonReentrant - { - _apeCoinStaking.claimMAYC(_nfts, _recipient); - } - - /** - * @notice Withdraw staked ApeCoin from the MAYC pool. If withdraw is total staked amount, performs an automatic claim. - * @param _nfts Array of MAYC NFT's with staked amounts - * @param _recipient Address to send withdraw amount and claim to - */ - function withdrawApeCoin( - ApeCoinStaking.SingleNft[] calldata _nfts, - address _recipient, - DataTypes.TimeLockParams memory _timeLockParams - ) external onlyPool nonReentrant { - ApeStakingLogic.executeWithdrawMAYC( - POOL, - _ERC721Data.underlyingAsset, - _apeCoinStaking, - _nfts, - _recipient, - _timeLockParams - ); - } - - /** - * @notice Deposit ApeCoin to the Pair Pool, where Pair = (MAYC + BAKC) - * @param _nftPairs Array of PairNftWithAmount structs - * @dev Commits 1 or more Pairs, each with an ApeCoin amount to the Pair pool.\ - * Each BAKC committed must attach an ApeCoin amount >= 1 ApeCoin and <= the Pair pool cap amount.\ - * Example: MAYC + BAKC + 1 ApeCoin: [[0, 0, "1000000000000000000"]]\ - */ - function depositBAKC( - ApeCoinStaking.PairNftDepositWithAmount[] calldata _nftPairs - ) external onlyPool nonReentrant { - _apeCoinStaking.depositBAKC( - new ApeCoinStaking.PairNftDepositWithAmount[](0), - _nftPairs - ); - } - - /** - * @notice Claim rewards for array of Paired NFTs and send to recipient - * @param _nftPairs Array of Paired MAYC NFTs owned and committed by the msg.sender - * @param _recipient Address to send claim reward to - */ - function claimBAKC( - ApeCoinStaking.PairNft[] calldata _nftPairs, - address _recipient - ) external onlyPool nonReentrant { - _apeCoinStaking.claimBAKC( - new ApeCoinStaking.PairNft[](0), - _nftPairs, - _recipient - ); - } - - /** - * @notice Withdraw staked ApeCoin from the Pair pool. If withdraw is total staked amount, performs an automatic claim. - * @param _nftPairs Array of Paired MAYC NFT's with staked amounts - * @dev if pairs have split ownership and BAKC is attempting a withdraw, the withdraw must be for the total staked amount - */ - function withdrawBAKC( - ApeCoinStaking.PairNftWithdrawWithAmount[] calldata _nftPairs, - address _apeRecipient, - DataTypes.TimeLockParams memory _timeLockParams - ) external onlyPool nonReentrant { - ApeStakingLogic.withdrawBAKC( - POOL, - _ERC721Data.underlyingAsset, - _apeCoinStaking, - POOL_ID(), - _nftPairs, - _apeRecipient, - _timeLockParams - ); - } - - function POOL_ID() internal pure virtual override returns (uint256) { - return ApeStakingLogic.MAYC_POOL_ID; + function isBayc() internal pure virtual override returns (bool) { + return false; } function getXTokenType() external pure override returns (XTokenType) { diff --git a/contracts/protocol/tokenization/NTokenMoonBirds.sol b/contracts/protocol/tokenization/NTokenMoonBirds.sol index 98fa21c6b..ad3c7ee23 100644 --- a/contracts/protocol/tokenization/NTokenMoonBirds.sol +++ b/contracts/protocol/tokenization/NTokenMoonBirds.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC20} from "../../dependencies/openzeppelin/contracts/IERC20.sol"; import {IERC721} from "../../dependencies/openzeppelin/contracts/IERC721.sol"; diff --git a/contracts/protocol/tokenization/NTokenOtherdeed.sol b/contracts/protocol/tokenization/NTokenOtherdeed.sol index 23c6964a1..ab6933c40 100644 --- a/contracts/protocol/tokenization/NTokenOtherdeed.sol +++ b/contracts/protocol/tokenization/NTokenOtherdeed.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IHotWalletProxy} from "../../interfaces/IHotWalletProxy.sol"; import {NToken} from "./NToken.sol"; diff --git a/contracts/protocol/tokenization/NTokenStakefish.sol b/contracts/protocol/tokenization/NTokenStakefish.sol index 284a8d75b..449354aad 100644 --- a/contracts/protocol/tokenization/NTokenStakefish.sol +++ b/contracts/protocol/tokenization/NTokenStakefish.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IStakefishNFTManager} from "../../interfaces/IStakefishNFTManager.sol"; import {IStakefishValidator} from "../../interfaces/IStakefishValidator.sol"; diff --git a/contracts/protocol/tokenization/NTokenUniswapV3.sol b/contracts/protocol/tokenization/NTokenUniswapV3.sol index 1c1dcce99..6bde82271 100644 --- a/contracts/protocol/tokenization/NTokenUniswapV3.sol +++ b/contracts/protocol/tokenization/NTokenUniswapV3.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC20} from "../../dependencies/openzeppelin/contracts/IERC20.sol"; import {IERC721} from "../../dependencies/openzeppelin/contracts/IERC721.sol"; @@ -13,7 +13,7 @@ import {WadRayMath} from "../libraries/math/WadRayMath.sol"; import {IPool} from "../../interfaces/IPool.sol"; import {NToken} from "./NToken.sol"; import {DataTypes} from "../libraries/types/DataTypes.sol"; -import {INonfungiblePositionManager} from "../../dependencies/uniswap/INonfungiblePositionManager.sol"; +import {INonfungiblePositionManager} from "../../dependencies/uniswapv3-periphery/interfaces/INonfungiblePositionManager.sol"; import {IWETH} from "../../misc/interfaces/IWETH.sol"; import {XTokenType} from "../../interfaces/IXTokenType.sol"; import {INTokenUniswapV3} from "../../interfaces/INTokenUniswapV3.sol"; diff --git a/contracts/protocol/tokenization/PToken.sol b/contracts/protocol/tokenization/PToken.sol index 2915bb9b7..7a708c54c 100644 --- a/contracts/protocol/tokenization/PToken.sol +++ b/contracts/protocol/tokenization/PToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC20} from "../../dependencies/openzeppelin/contracts/IERC20.sol"; import {GPv2SafeERC20} from "../../dependencies/gnosis/contracts/GPv2SafeERC20.sol"; diff --git a/contracts/protocol/tokenization/PTokenAStETH.sol b/contracts/protocol/tokenization/PTokenAStETH.sol index 53426bd86..0a729020f 100644 --- a/contracts/protocol/tokenization/PTokenAStETH.sol +++ b/contracts/protocol/tokenization/PTokenAStETH.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPool} from "../../interfaces/IPool.sol"; import {RebasingPToken} from "./RebasingPToken.sol"; diff --git a/contracts/protocol/tokenization/PTokenAToken.sol b/contracts/protocol/tokenization/PTokenAToken.sol index 95c20f2c8..de42b1247 100644 --- a/contracts/protocol/tokenization/PTokenAToken.sol +++ b/contracts/protocol/tokenization/PTokenAToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPool} from "../../interfaces/IPool.sol"; import {RebasingPToken} from "./RebasingPToken.sol"; diff --git a/contracts/protocol/tokenization/PTokenCApe.sol b/contracts/protocol/tokenization/PTokenCApe.sol index ef9ea1aef..bc2b5b989 100644 --- a/contracts/protocol/tokenization/PTokenCApe.sol +++ b/contracts/protocol/tokenization/PTokenCApe.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPool} from "../../interfaces/IPool.sol"; import {RebasingPToken} from "./RebasingPToken.sol"; diff --git a/contracts/protocol/tokenization/PTokenSApe.sol b/contracts/protocol/tokenization/PTokenSApe.sol index 700c5ffef..3c81d2bab 100644 --- a/contracts/protocol/tokenization/PTokenSApe.sol +++ b/contracts/protocol/tokenization/PTokenSApe.sol @@ -1,9 +1,8 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPool} from "../../interfaces/IPool.sol"; import {PToken} from "./PToken.sol"; -import {INTokenApeStaking} from "../../interfaces/INTokenApeStaking.sol"; import {WadRayMath} from "../libraries/math/WadRayMath.sol"; import {XTokenType} from "../../interfaces/IXTokenType.sol"; import {ApeCoinStaking} from "../../dependencies/yoga-labs/ApeCoinStaking.sol"; @@ -13,6 +12,8 @@ import {IERC20} from "../../dependencies/openzeppelin/contracts/IERC20.sol"; import {IScaledBalanceToken} from "../../interfaces/IScaledBalanceToken.sol"; import {IncentivizedERC20} from "./base/IncentivizedERC20.sol"; import {DataTypes} from "../libraries/types/DataTypes.sol"; +import {IParaApeStaking} from "../../interfaces/IParaApeStaking.sol"; +import {ScaledBalanceTokenBaseERC20} from "contracts/protocol/tokenization/base/ScaledBalanceTokenBaseERC20.sol"; /** * @title sApe PToken @@ -22,17 +23,10 @@ import {DataTypes} from "../libraries/types/DataTypes.sol"; contract PTokenSApe is PToken { using WadRayMath for uint256; - INTokenApeStaking immutable nBAYC; - INTokenApeStaking immutable nMAYC; + IParaApeStaking immutable paraApeStaking; - constructor( - IPool pool, - address _nBAYC, - address _nMAYC - ) PToken(pool) { - require(_nBAYC != address(0) && _nMAYC != address(0)); - nBAYC = INTokenApeStaking(_nBAYC); - nMAYC = INTokenApeStaking(_nMAYC); + constructor(IPool pool) PToken(pool) { + paraApeStaking = IParaApeStaking(pool.paraApeStaking()); } function mint( @@ -55,15 +49,13 @@ contract PTokenSApe is PToken { } function balanceOf(address user) public view override returns (uint256) { - uint256 totalStakedAPE = nBAYC.getUserApeStakingAmount(user) + - nMAYC.getUserApeStakingAmount(user); - return totalStakedAPE; + return paraApeStaking.totalSApeBalance(user); } function scaledBalanceOf(address user) public view - override + override(IScaledBalanceToken, ScaledBalanceTokenBaseERC20) returns (uint256) { return balanceOf(user); @@ -73,16 +65,16 @@ contract PTokenSApe is PToken { address, uint256, DataTypes.TimeLockParams calldata - ) external virtual override onlyPool { + ) public virtual override onlyPool { revert("not allowed"); } function transferOnLiquidation( - address, - address, - uint256 - ) external view override onlyPool { - revert("not allowed"); + address from, + address to, + uint256 value + ) external override onlyPool { + return paraApeStaking.transferFreeSApeBalance(from, to, value); } function _transfer( diff --git a/contracts/protocol/tokenization/PTokenStETH.sol b/contracts/protocol/tokenization/PTokenStETH.sol index 276069413..2c6535fc4 100644 --- a/contracts/protocol/tokenization/PTokenStETH.sol +++ b/contracts/protocol/tokenization/PTokenStETH.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPool} from "../../interfaces/IPool.sol"; import {ILido} from "../../interfaces/ILido.sol"; diff --git a/contracts/protocol/tokenization/PTokenStKSM.sol b/contracts/protocol/tokenization/PTokenStKSM.sol new file mode 100644 index 000000000..34dabce49 --- /dev/null +++ b/contracts/protocol/tokenization/PTokenStKSM.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.0; + +import {IPool} from "../../interfaces/IPool.sol"; +import {ILido} from "../../interfaces/ILido.sol"; +import {RebasingPToken} from "./RebasingPToken.sol"; +import {WadRayMath} from "../libraries/math/WadRayMath.sol"; +import {XTokenType} from "../../interfaces/IXTokenType.sol"; + +/** + * @title stKSM/stDOT Rebasing PToken + * + * @notice Implementation of the interest bearing token for the ParaSpace protocol + */ +contract PTokenStKSM is RebasingPToken { + constructor(IPool pool) RebasingPToken(pool) { + //intentionally empty + } + + /** + * @return Current rebasing index of stETH in RAY + **/ + function lastRebasingIndex() internal view override returns (uint256) { + // Returns amount of stETH corresponding to 10**27 stETH shares. + // The 10**27 is picked to provide the same precision as the ParaSpace + // liquidity index, which is in RAY (10**27). + return ILido(_underlyingAsset).getPooledKSMByShares(WadRayMath.RAY); + } + + function getXTokenType() external pure override returns (XTokenType) { + return XTokenType.PTokenStKSM; + } +} diff --git a/contracts/protocol/tokenization/PYieldToken.sol b/contracts/protocol/tokenization/PYieldToken.sol index 61259c0cd..df1c7228b 100644 --- a/contracts/protocol/tokenization/PYieldToken.sol +++ b/contracts/protocol/tokenization/PYieldToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPool} from "../../interfaces/IPool.sol"; import {PToken} from "./PToken.sol"; diff --git a/contracts/protocol/tokenization/RebasingDebtToken.sol b/contracts/protocol/tokenization/RebasingDebtToken.sol index c50702d62..309e68659 100644 --- a/contracts/protocol/tokenization/RebasingDebtToken.sol +++ b/contracts/protocol/tokenization/RebasingDebtToken.sol @@ -1,11 +1,13 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPool} from "../../interfaces/IPool.sol"; import {VariableDebtToken} from "./VariableDebtToken.sol"; import {WadRayMath} from "../libraries/math/WadRayMath.sol"; import {Errors} from "../libraries/helpers/Errors.sol"; import {SafeCast} from "../../dependencies/openzeppelin/contracts/SafeCast.sol"; +import {IScaledBalanceToken} from "../../interfaces/IScaledBalanceToken.sol"; +import {ScaledBalanceTokenBaseERC20} from "contracts/protocol/tokenization/base/ScaledBalanceTokenBaseERC20.sol"; /** * @title Rebasing Debt Token @@ -47,7 +49,7 @@ contract RebasingDebtToken is VariableDebtToken { function scaledBalanceOf(address user) public view - override + override(IScaledBalanceToken, ScaledBalanceTokenBaseERC20) returns (uint256) { return _scaledBalanceOf(user, lastRebasingIndex()); @@ -62,7 +64,7 @@ contract RebasingDebtToken is VariableDebtToken { function getScaledUserBalanceAndSupply(address user) external view - override + override(IScaledBalanceToken, ScaledBalanceTokenBaseERC20) returns (uint256, uint256) { uint256 rebasingIndex = lastRebasingIndex(); @@ -99,7 +101,7 @@ contract RebasingDebtToken is VariableDebtToken { public view virtual - override + override(IScaledBalanceToken, ScaledBalanceTokenBaseERC20) returns (uint256) { return _scaledTotalSupply(lastRebasingIndex()); diff --git a/contracts/protocol/tokenization/RebasingPToken.sol b/contracts/protocol/tokenization/RebasingPToken.sol index 990380d45..4cfa495f1 100644 --- a/contracts/protocol/tokenization/RebasingPToken.sol +++ b/contracts/protocol/tokenization/RebasingPToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPool} from "../../interfaces/IPool.sol"; import {PToken} from "./PToken.sol"; @@ -9,6 +9,8 @@ import {SafeCast} from "../../dependencies/openzeppelin/contracts/SafeCast.sol"; import {Errors} from "../libraries/helpers/Errors.sol"; import {IERC20} from "../../dependencies/openzeppelin/contracts/IERC20.sol"; import {GPv2SafeERC20} from "../../dependencies/gnosis/contracts/GPv2SafeERC20.sol"; +import {IScaledBalanceToken} from "../../interfaces/IScaledBalanceToken.sol"; +import {ScaledBalanceTokenBaseERC20} from "contracts/protocol/tokenization/base/ScaledBalanceTokenBaseERC20.sol"; /** * @title Rebasing PToken @@ -45,7 +47,7 @@ contract RebasingPToken is PToken { function scaledBalanceOf(address user) public view - override + override(IScaledBalanceToken, ScaledBalanceTokenBaseERC20) returns (uint256) { return _scaledBalanceOf(user, lastRebasingIndex()); @@ -60,7 +62,7 @@ contract RebasingPToken is PToken { function getScaledUserBalanceAndSupply(address user) external view - override + override(IScaledBalanceToken, ScaledBalanceTokenBaseERC20) returns (uint256, uint256) { uint256 rebasingIndex = lastRebasingIndex(); @@ -97,7 +99,7 @@ contract RebasingPToken is PToken { public view virtual - override + override(IScaledBalanceToken, ScaledBalanceTokenBaseERC20) returns (uint256) { return _scaledTotalSupply(lastRebasingIndex()); diff --git a/contracts/protocol/tokenization/StETHDebtToken.sol b/contracts/protocol/tokenization/StETHDebtToken.sol index 979a2a7ae..ce099a0d5 100644 --- a/contracts/protocol/tokenization/StETHDebtToken.sol +++ b/contracts/protocol/tokenization/StETHDebtToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPool} from "../../interfaces/IPool.sol"; import {ILido} from "../../interfaces/ILido.sol"; diff --git a/contracts/protocol/tokenization/StKSMDebtToken.sol b/contracts/protocol/tokenization/StKSMDebtToken.sol new file mode 100644 index 000000000..6c751fb63 --- /dev/null +++ b/contracts/protocol/tokenization/StKSMDebtToken.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.0; + +import {IPool} from "../../interfaces/IPool.sol"; +import {ILido} from "../../interfaces/ILido.sol"; +import {RebasingDebtToken} from "./RebasingDebtToken.sol"; +import {WadRayMath} from "../libraries/math/WadRayMath.sol"; + +/** + * @title stKSM/stDOT Rebasing Debt Token + * + * @notice Implementation of the interest bearing token for the ParaSpace protocol + */ +contract StKSMDebtToken is RebasingDebtToken { + constructor(IPool pool) RebasingDebtToken(pool) { + //intentionally empty + } + + /** + * @return Current rebasing index of stETH in RAY + **/ + function lastRebasingIndex() internal view override returns (uint256) { + // Returns amount of stETH corresponding to 10**27 stETH shares. + // The 10**27 is picked to provide the same precision as the ParaSpace + // liquidity index, which is in RAY (10**27). + return ILido(_underlyingAsset).getPooledKSMByShares(WadRayMath.RAY); + } +} diff --git a/contracts/protocol/tokenization/VariableDebtToken.sol b/contracts/protocol/tokenization/VariableDebtToken.sol index 4c5ad28a3..5075b6a53 100644 --- a/contracts/protocol/tokenization/VariableDebtToken.sol +++ b/contracts/protocol/tokenization/VariableDebtToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC20} from "../../dependencies/openzeppelin/contracts/IERC20.sol"; import {SafeCast} from "../../dependencies/openzeppelin/contracts/SafeCast.sol"; diff --git a/contracts/protocol/tokenization/base/DebtTokenBase.sol b/contracts/protocol/tokenization/base/DebtTokenBase.sol index a8f8cc314..f3b3a551e 100644 --- a/contracts/protocol/tokenization/base/DebtTokenBase.sol +++ b/contracts/protocol/tokenization/base/DebtTokenBase.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {Context} from "../../../dependencies/openzeppelin/contracts/Context.sol"; import {Errors} from "../../libraries/helpers/Errors.sol"; diff --git a/contracts/protocol/tokenization/base/EIP712Base.sol b/contracts/protocol/tokenization/base/EIP712Base.sol index 0e42cca01..f596ed89f 100644 --- a/contracts/protocol/tokenization/base/EIP712Base.sol +++ b/contracts/protocol/tokenization/base/EIP712Base.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title EIP712Base diff --git a/contracts/protocol/tokenization/base/IncentivizedERC20.sol b/contracts/protocol/tokenization/base/IncentivizedERC20.sol index ee5d6ae27..465befbb6 100644 --- a/contracts/protocol/tokenization/base/IncentivizedERC20.sol +++ b/contracts/protocol/tokenization/base/IncentivizedERC20.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {Context} from "../../../dependencies/openzeppelin/contracts/Context.sol"; import {IERC20} from "../../../dependencies/openzeppelin/contracts/IERC20.sol"; diff --git a/contracts/protocol/tokenization/base/MintableIncentivizedERC20.sol b/contracts/protocol/tokenization/base/MintableIncentivizedERC20.sol index de7fc9ba2..606df5f44 100644 --- a/contracts/protocol/tokenization/base/MintableIncentivizedERC20.sol +++ b/contracts/protocol/tokenization/base/MintableIncentivizedERC20.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IRewardController} from "../../../interfaces/IRewardController.sol"; import {IPool} from "../../../interfaces/IPool.sol"; diff --git a/contracts/protocol/tokenization/base/MintableIncentivizedERC721.sol b/contracts/protocol/tokenization/base/MintableIncentivizedERC721.sol index eb5b38c30..ab0b0431d 100644 --- a/contracts/protocol/tokenization/base/MintableIncentivizedERC721.sol +++ b/contracts/protocol/tokenization/base/MintableIncentivizedERC721.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {Context} from "../../../dependencies/openzeppelin/contracts/Context.sol"; import {Strings} from "../../../dependencies/openzeppelin/contracts/Strings.sol"; diff --git a/contracts/protocol/tokenization/base/ScaledBalanceTokenBaseERC20.sol b/contracts/protocol/tokenization/base/ScaledBalanceTokenBaseERC20.sol index 9c011d1b5..f1b460c15 100644 --- a/contracts/protocol/tokenization/base/ScaledBalanceTokenBaseERC20.sol +++ b/contracts/protocol/tokenization/base/ScaledBalanceTokenBaseERC20.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {SafeCast} from "../../../dependencies/openzeppelin/contracts/SafeCast.sol"; import {Errors} from "../../libraries/helpers/Errors.sol"; diff --git a/contracts/protocol/tokenization/libraries/ApeStakingLogic.sol b/contracts/protocol/tokenization/libraries/ApeStakingLogic.sol deleted file mode 100644 index 556a0c7a4..000000000 --- a/contracts/protocol/tokenization/libraries/ApeStakingLogic.sol +++ /dev/null @@ -1,387 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; -import {ApeCoinStaking} from "../../../dependencies/yoga-labs/ApeCoinStaking.sol"; -import {IERC721} from "../../../dependencies/openzeppelin/contracts/IERC721.sol"; -import {SafeERC20} from "../../../dependencies/openzeppelin/contracts/SafeERC20.sol"; -import {IERC20} from "../../../dependencies/openzeppelin/contracts/IERC20.sol"; -import {ITimeLock} from "../../../interfaces/ITimeLock.sol"; -import "../../../interfaces/IPool.sol"; -import {DataTypes} from "../../libraries/types/DataTypes.sol"; -import {PercentageMath} from "../../libraries/math/PercentageMath.sol"; -import "./MintableERC721Logic.sol"; -import "../../../dependencies/openzeppelin/contracts/SafeCast.sol"; -import "../../../interfaces/INToken.sol"; - -/** - * @title ApeStakingLogic library - * - * @notice Implements the base logic for ApeStaking - */ -library ApeStakingLogic { - using SafeERC20 for IERC20; - using PercentageMath for uint256; - using SafeCast for uint256; - - uint256 constant BAYC_POOL_ID = 1; - uint256 constant MAYC_POOL_ID = 2; - uint256 constant BAKC_POOL_ID = 3; - - struct APEStakingParameter { - uint256 unstakeIncentive; - } - event UnstakeApeIncentiveUpdated(uint256 oldValue, uint256 newValue); - - /** - * @notice Withdraw staked ApeCoin from the BAYC pool. If withdraw is total staked amount, performs an automatic claim. - * @param _nfts Array of BAYC NFT's with staked amounts - * @param _recipient Address to send withdraw amount and claim to - */ - function executeWithdrawBAYC( - IPool POOL, - address underlyingAsset, - ApeCoinStaking _apeCoinStaking, - ApeCoinStaking.SingleNft[] calldata _nfts, - address _recipient, - DataTypes.TimeLockParams memory _timeLockParams - ) external { - if (_timeLockParams.releaseTime != 0) { - IERC20 ApeCoin = _apeCoinStaking.apeCoin(); - uint256 beforeBalance = ApeCoin.balanceOf(address(this)); - _apeCoinStaking.withdrawBAYC(_nfts, address(this)); - uint256 afterBalance = ApeCoin.balanceOf(address(this)); - - uint256 totalAmount = afterBalance - beforeBalance; - createApeCoinAgreement( - POOL, - underlyingAsset, - ApeCoin, - totalAmount, - _recipient, - _timeLockParams - ); - } else { - _apeCoinStaking.withdrawBAYC(_nfts, _recipient); - } - } - - /** - * @notice Withdraw staked ApeCoin from the MAYC pool. If withdraw is total staked amount, performs an automatic claim. - * @param _nfts Array of MAYC NFT's with staked amounts - * @param _recipient Address to send withdraw amount and claim to - */ - function executeWithdrawMAYC( - IPool POOL, - address underlyingAsset, - ApeCoinStaking _apeCoinStaking, - ApeCoinStaking.SingleNft[] calldata _nfts, - address _recipient, - DataTypes.TimeLockParams memory _timeLockParams - ) external { - if (_timeLockParams.releaseTime != 0) { - IERC20 ApeCoin = _apeCoinStaking.apeCoin(); - uint256 beforeBalance = ApeCoin.balanceOf(address(this)); - _apeCoinStaking.withdrawMAYC(_nfts, address(this)); - uint256 afterBalance = ApeCoin.balanceOf(address(this)); - - uint256 totalAmount = afterBalance - beforeBalance; - createApeCoinAgreement( - POOL, - underlyingAsset, - ApeCoin, - totalAmount, - _recipient, - _timeLockParams - ); - } else { - _apeCoinStaking.withdrawMAYC(_nfts, _recipient); - } - } - - /** - * @notice withdraw Ape coin staking position from ApeCoinStaking - * @param _apeCoinStaking ApeCoinStaking contract address - * @param poolId identify whether BAYC or MAYC paired with BAKC - * @param _nftPairs Array of Paired BAYC/MAYC NFT's with staked amounts - * @param _apeRecipient the receiver of ape coin - */ - function withdrawBAKC( - IPool POOL, - address underlyingAsset, - ApeCoinStaking _apeCoinStaking, - uint256 poolId, - ApeCoinStaking.PairNftWithdrawWithAmount[] memory _nftPairs, - address _apeRecipient, - DataTypes.TimeLockParams memory _timeLockParams - ) external { - ApeCoinStaking.PairNftWithdrawWithAmount[] - memory _otherPairs = new ApeCoinStaking.PairNftWithdrawWithAmount[]( - 0 - ); - - IERC20 ApeCoin = _apeCoinStaking.apeCoin(); - uint256 beforeBalance = ApeCoin.balanceOf(address(this)); - if (poolId == BAYC_POOL_ID) { - _apeCoinStaking.withdrawBAKC(_nftPairs, _otherPairs); - } else { - _apeCoinStaking.withdrawBAKC(_otherPairs, _nftPairs); - } - uint256 afterBalance = ApeCoin.balanceOf(address(this)); - - uint256 totalAmount = afterBalance - beforeBalance; - if (_timeLockParams.releaseTime != 0) { - createApeCoinAgreement( - POOL, - underlyingAsset, - ApeCoin, - totalAmount, - _apeRecipient, - _timeLockParams - ); - } else { - ApeCoin.safeTransfer(_apeRecipient, totalAmount); - } - } - - function createApeCoinAgreement( - IPool POOL, - address underlyingAsset, - IERC20 ApeCoin, - uint256 amount, - address recipient, - DataTypes.TimeLockParams memory timeLockParams - ) internal { - ITimeLock timeLock = POOL.TIME_LOCK(); - uint256[] memory amounts = new uint256[](1); - amounts[0] = amount; - - timeLock.createAgreement( - DataTypes.AssetType.ERC20, - timeLockParams.actionType, - underlyingAsset, - address(ApeCoin), - amounts, - recipient, - timeLockParams.releaseTime - ); - ApeCoin.safeTransfer(address(timeLock), amount); - } - - /** - * @notice undate incentive percentage for unstakePositionAndRepay - * @param stakingParameter storage for Ape staking - * @param incentive new incentive percentage - */ - function executeSetUnstakeApeIncentive( - APEStakingParameter storage stakingParameter, - uint256 incentive - ) external { - require( - incentive < PercentageMath.HALF_PERCENTAGE_FACTOR, - "Value Too High" - ); - uint256 oldValue = stakingParameter.unstakeIncentive; - if (oldValue != incentive) { - stakingParameter.unstakeIncentive = incentive; - emit UnstakeApeIncentiveUpdated(oldValue, incentive); - } - } - - struct UnstakeAndRepayParams { - IPool POOL; - ApeCoinStaking _apeCoinStaking; - address _underlyingAsset; - uint256 poolId; - uint256 tokenId; - address incentiveReceiver; - address bakcNToken; - } - - /** - * @notice Unstake Ape coin staking position and repay user debt - * @param _owners The state of ownership for nToken - * @param stakingParameter storage for Ape staking - * @param params The additional parameters needed to execute this function - */ - function executeUnstakePositionAndRepay( - mapping(uint256 => address) storage _owners, - APEStakingParameter storage stakingParameter, - UnstakeAndRepayParams memory params - ) external { - if ( - IERC721(params._underlyingAsset).ownerOf(params.tokenId) != - address(this) - ) { - return; - } - address positionOwner = _owners[params.tokenId]; - IERC20 _apeCoin = params._apeCoinStaking.apeCoin(); - uint256 balanceBefore = _apeCoin.balanceOf(address(this)); - - //1 unstake all position - { - //1.1 unstake Main pool position - (uint256 stakedAmount, ) = params._apeCoinStaking.nftPosition( - params.poolId, - params.tokenId - ); - if (stakedAmount > 0) { - ApeCoinStaking.SingleNft[] - memory nfts = new ApeCoinStaking.SingleNft[](1); - nfts[0].tokenId = params.tokenId.toUint32(); - nfts[0].amount = stakedAmount.toUint224(); - if (params.poolId == BAYC_POOL_ID) { - params._apeCoinStaking.withdrawBAYC(nfts, address(this)); - } else { - params._apeCoinStaking.withdrawMAYC(nfts, address(this)); - } - } - //1.2 unstake bakc pool position - (uint256 bakcTokenId, bool isPaired) = params - ._apeCoinStaking - .mainToBakc(params.poolId, params.tokenId); - if (isPaired) { - (stakedAmount, ) = params._apeCoinStaking.nftPosition( - BAKC_POOL_ID, - bakcTokenId - ); - if (stakedAmount > 0) { - ApeCoinStaking.PairNftWithdrawWithAmount[] - memory _nftPairs = new ApeCoinStaking.PairNftWithdrawWithAmount[]( - 1 - ); - _nftPairs[0].mainTokenId = params.tokenId.toUint32(); - _nftPairs[0].bakcTokenId = bakcTokenId.toUint32(); - _nftPairs[0].amount = stakedAmount.toUint184(); - _nftPairs[0].isUncommit = true; - ApeCoinStaking.PairNftWithdrawWithAmount[] - memory _otherPairs = new ApeCoinStaking.PairNftWithdrawWithAmount[]( - 0 - ); - - uint256 bakcBeforeBalance = _apeCoin.balanceOf( - params.bakcNToken - ); - if (params.poolId == BAYC_POOL_ID) { - params._apeCoinStaking.withdrawBAKC( - _nftPairs, - _otherPairs - ); - } else { - params._apeCoinStaking.withdrawBAKC( - _otherPairs, - _nftPairs - ); - } - uint256 bakcAfterBalance = _apeCoin.balanceOf( - params.bakcNToken - ); - uint256 balanceDiff = bakcAfterBalance - bakcBeforeBalance; - if (balanceDiff > 0) { - address bakcOwner = INToken(params.bakcNToken).ownerOf( - bakcTokenId - ); - _apeCoin.safeTransferFrom( - params.bakcNToken, - bakcOwner, - balanceDiff - ); - } - } - } - } - - uint256 unstakedAmount = _apeCoin.balanceOf(address(this)) - - balanceBefore; - if (unstakedAmount == 0) { - return; - } - //2 send incentive to caller - if (params.incentiveReceiver != address(0)) { - uint256 unstakeIncentive = stakingParameter.unstakeIncentive; - if (unstakeIncentive > 0) { - uint256 incentiveAmount = unstakedAmount.percentMul( - unstakeIncentive - ); - _apeCoin.safeTransfer( - params.incentiveReceiver, - incentiveAmount - ); - unstakedAmount = unstakedAmount - incentiveAmount; - } - } - - //3 repay and supply - params.POOL.repayAndSupply( - params._underlyingAsset, - positionOwner, - unstakedAmount - ); - } - - /** - * @notice get user total ape staking position - * @param userState The user state of nToken - * @param ownedTokens The ownership mapping state of nNtoken - * @param user User address - * @param poolId identify whether BAYC pool or MAYC pool - * @param _apeCoinStaking ApeCoinStaking contract address - */ - function getUserTotalStakingAmount( - mapping(address => UserState) storage userState, - mapping(address => mapping(uint256 => uint256)) storage ownedTokens, - address _underlyingAsset, - address user, - uint256 poolId, - ApeCoinStaking _apeCoinStaking - ) external view returns (uint256) { - uint256 totalBalance = uint256(userState[user].balance); - uint256 totalAmount; - for (uint256 index = 0; index < totalBalance; index++) { - uint256 tokenId = ownedTokens[user][index]; - totalAmount += getTokenIdStakingAmount( - _underlyingAsset, - poolId, - _apeCoinStaking, - tokenId - ); - } - - return totalAmount; - } - - /** - * @notice get ape staking position for a tokenId - * @param poolId identify whether BAYC pool or MAYC pool - * @param _apeCoinStaking ApeCoinStaking contract address - * @param tokenId specified the tokenId for the position - */ - function getTokenIdStakingAmount( - address _underlyingAsset, - uint256 poolId, - ApeCoinStaking _apeCoinStaking, - uint256 tokenId - ) public view returns (uint256) { - if (IERC721(_underlyingAsset).ownerOf(tokenId) != address(this)) { - return 0; - } - (uint256 apeStakedAmount, ) = _apeCoinStaking.nftPosition( - poolId, - tokenId - ); - - (uint256 bakcTokenId, bool isPaired) = _apeCoinStaking.mainToBakc( - poolId, - tokenId - ); - - if (isPaired) { - (uint256 bakcStakedAmount, ) = _apeCoinStaking.nftPosition( - BAKC_POOL_ID, - bakcTokenId - ); - apeStakedAmount += bakcStakedAmount; - } - - return apeStakedAmount; - } -} diff --git a/contracts/protocol/tokenization/libraries/MintableERC721Logic.sol b/contracts/protocol/tokenization/libraries/MintableERC721Logic.sol index 8e5ad9d70..a0e1d93df 100644 --- a/contracts/protocol/tokenization/libraries/MintableERC721Logic.sol +++ b/contracts/protocol/tokenization/libraries/MintableERC721Logic.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {SafeCast} from "../../../dependencies/openzeppelin/contracts/SafeCast.sol"; import {WadRayMath} from "../../libraries/math/WadRayMath.sol"; diff --git a/contracts/ui/UiIncentiveDataProvider.sol b/contracts/ui/UiIncentiveDataProvider.sol index 55354b84c..cc3136a3a 100644 --- a/contracts/ui/UiIncentiveDataProvider.sol +++ b/contracts/ui/UiIncentiveDataProvider.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPoolAddressesProvider} from "../interfaces/IPoolAddressesProvider.sol"; import {IRewardsController} from "./interfaces/IRewardsController.sol"; diff --git a/contracts/ui/UiPoolDataProvider.sol b/contracts/ui/UiPoolDataProvider.sol index edec57fc1..c10a820ac 100644 --- a/contracts/ui/UiPoolDataProvider.sol +++ b/contracts/ui/UiPoolDataProvider.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC20Detailed} from "../dependencies/openzeppelin/contracts/IERC20Detailed.sol"; import {IERC721Metadata} from "../dependencies/openzeppelin/contracts/IERC721Metadata.sol"; diff --git a/contracts/ui/WETHGateway.sol b/contracts/ui/WETHGateway.sol index a7ff7fe35..1e2c2f1ca 100644 --- a/contracts/ui/WETHGateway.sol +++ b/contracts/ui/WETHGateway.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {OwnableUpgradeable} from "../dependencies/openzeppelin/upgradeability/OwnableUpgradeable.sol"; import {IERC20} from "../dependencies/openzeppelin/contracts/IERC20.sol"; diff --git a/contracts/ui/WPunkGateway.sol b/contracts/ui/WPunkGateway.sol index 55f97397b..3c6ad4dfd 100644 --- a/contracts/ui/WPunkGateway.sol +++ b/contracts/ui/WPunkGateway.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {OwnableUpgradeable} from "../dependencies/openzeppelin/upgradeability/OwnableUpgradeable.sol"; import {IPool} from "../interfaces/IPool.sol"; diff --git a/contracts/ui/WalletBalanceProvider.sol b/contracts/ui/WalletBalanceProvider.sol index 7ba486e22..79a330819 100644 --- a/contracts/ui/WalletBalanceProvider.sol +++ b/contracts/ui/WalletBalanceProvider.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {Address} from "../dependencies/openzeppelin/contracts/Address.sol"; import {IERC20} from "../dependencies/openzeppelin/contracts/IERC20.sol"; diff --git a/contracts/ui/interfaces/IEACAggregatorProxy.sol b/contracts/ui/interfaces/IEACAggregatorProxy.sol index 6cc9d84e6..5f8ef5638 100644 --- a/contracts/ui/interfaces/IEACAggregatorProxy.sol +++ b/contracts/ui/interfaces/IEACAggregatorProxy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; interface IEACAggregatorProxy { function decimals() external view returns (uint8); diff --git a/contracts/ui/interfaces/IERC20DetailedBytes.sol b/contracts/ui/interfaces/IERC20DetailedBytes.sol index bf2753ea9..6c14f19ff 100644 --- a/contracts/ui/interfaces/IERC20DetailedBytes.sol +++ b/contracts/ui/interfaces/IERC20DetailedBytes.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IERC20} from "../../dependencies/openzeppelin/contracts/IERC20.sol"; diff --git a/contracts/ui/interfaces/IRewardsController.sol b/contracts/ui/interfaces/IRewardsController.sol index acd43b930..c56ebef07 100644 --- a/contracts/ui/interfaces/IRewardsController.sol +++ b/contracts/ui/interfaces/IRewardsController.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IRewardsDistributor} from "./IRewardsDistributor.sol"; import {ITransferStrategyBase} from "./ITransferStrategyBase.sol"; diff --git a/contracts/ui/interfaces/IRewardsDistributor.sol b/contracts/ui/interfaces/IRewardsDistributor.sol index b147b2de8..ebe591447 100644 --- a/contracts/ui/interfaces/IRewardsDistributor.sol +++ b/contracts/ui/interfaces/IRewardsDistributor.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; /** * @title IRewardsDistributor diff --git a/contracts/ui/interfaces/ITransferStrategyBase.sol b/contracts/ui/interfaces/ITransferStrategyBase.sol index 3f89ba934..8a45361c8 100644 --- a/contracts/ui/interfaces/ITransferStrategyBase.sol +++ b/contracts/ui/interfaces/ITransferStrategyBase.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; interface ITransferStrategyBase { event EmergencyWithdrawal( diff --git a/contracts/ui/interfaces/IUiIncentiveDataProvider.sol b/contracts/ui/interfaces/IUiIncentiveDataProvider.sol index d5875934d..5cac0cf5e 100644 --- a/contracts/ui/interfaces/IUiIncentiveDataProvider.sol +++ b/contracts/ui/interfaces/IUiIncentiveDataProvider.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPoolAddressesProvider} from "../../interfaces/IPoolAddressesProvider.sol"; diff --git a/contracts/ui/interfaces/IUiPoolDataProvider.sol b/contracts/ui/interfaces/IUiPoolDataProvider.sol index 9cc00cea1..75368691c 100644 --- a/contracts/ui/interfaces/IUiPoolDataProvider.sol +++ b/contracts/ui/interfaces/IUiPoolDataProvider.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {IPoolAddressesProvider} from "../../interfaces/IPoolAddressesProvider.sol"; import {ITimeLockStrategy} from "../../interfaces/ITimeLockStrategy.sol"; diff --git a/contracts/ui/interfaces/IWETHGateway.sol b/contracts/ui/interfaces/IWETHGateway.sol index 0850dab5b..a519e85d0 100644 --- a/contracts/ui/interfaces/IWETHGateway.sol +++ b/contracts/ui/interfaces/IWETHGateway.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {DataTypes} from "../../protocol/libraries/types/DataTypes.sol"; diff --git a/contracts/ui/interfaces/IWPunkGateway.sol b/contracts/ui/interfaces/IWPunkGateway.sol index 7f44a5cc4..37eb6d935 100644 --- a/contracts/ui/interfaces/IWPunkGateway.sol +++ b/contracts/ui/interfaces/IWPunkGateway.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {DataTypes} from "../../protocol/libraries/types/DataTypes.sol"; diff --git a/contracts/ui/libraries/RewardsDataTypes.sol b/contracts/ui/libraries/RewardsDataTypes.sol index 5aa5b3e57..62e92e288 100644 --- a/contracts/ui/libraries/RewardsDataTypes.sol +++ b/contracts/ui/libraries/RewardsDataTypes.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: agpl-3.0 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import {ITransferStrategyBase} from "../interfaces/ITransferStrategyBase.sol"; import {IEACAggregatorProxy} from "../../ui/interfaces/IEACAggregatorProxy.sol"; diff --git a/docs/ETHERSCAN-VERIFICATION.md b/docs/ETHERSCAN-VERIFICATION.md index 1ce6c481d..9b9439a0b 100644 --- a/docs/ETHERSCAN-VERIFICATION.md +++ b/docs/ETHERSCAN-VERIFICATION.md @@ -23,7 +23,7 @@ proxychains forge verify-contract 0xC0fe2dbe75B8908073B14BF19Af71B1B181f8984 \ --num-of-optimizations 800 \ --watch \ contracts/protocol/libraries/logic/SupplyLogic.sol:SupplyLogic \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### BorrowLogic @@ -34,7 +34,7 @@ proxychains forge verify-contract 0x2Cdd46Ea306771DF11CDfc8be8daBC4fe4C42000 \ --num-of-optimizations 800 \ --watch \ contracts/protocol/libraries/logic/BorrowLogic.sol:BorrowLogic \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### LiquidationLogic @@ -46,7 +46,7 @@ proxychains forge verify-contract 0x9e3FF2c3C7B72493B37321D447e6BBE932Af054D \ --watch \ contracts/protocol/libraries/logic/LiquidationLogic.sol:LiquidationLogic \ --libraries contracts/protocol/libraries/logic/SupplyLogic.sol:SupplyLogic:0xC0fe2dbe75B8908073B14BF19Af71B1B181f8984 \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### FlashClaimlogic @@ -57,7 +57,7 @@ proxychains forge verify-contract 0x70a226448d9095F4c0ca6Fbe55bBd4da0C75a0A5 \ --num-of-optimizations 800 \ --watch \ contracts/protocol/libraries/logic/FlashClaimLogic.sol:FlashClaimLogic \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### ConfiguratorLogic @@ -68,7 +68,7 @@ proxychains forge verify-contract 0xe8bcFDd8E9d22653a2dA7FE881A12E56aF8983C7 \ --num-of-optimizations 800 \ --watch \ contracts/protocol/libraries/logic/ConfiguratorLogic.sol:ConfiguratorLogic \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### AuctionLogic @@ -79,7 +79,7 @@ proxychains forge verify-contract 0xCE05EFdC79cE8Fb6D0Ed5A4a223b45ab6a51754e \ --num-of-optimizations 800 \ --watch \ contracts/protocol/libraries/logic/AuctionLogic.sol:AuctionLogic \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### AuctionLogic @@ -92,7 +92,7 @@ proxychains forge verify-contract 0xCE05EFdC79cE8Fb6D0Ed5A4a223b45ab6a51754e \ contracts/protocol/libraries/logic/PositionMoverLogic.sol:PositionMoverLogic \ --libraries contracts/protocol/libraries/logic/SupplyLogic.sol:SupplyLogic:0x7dc12cCe38Fd20393d19d5E4d65b021B35093aAB \ --libraries contracts/protocol/libraries/logic/BorrowLogic.sol:BorrowLogic:0xBd25Aa1c423cD59662aD1C328f963ce90Afbd94B \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### PoolLogic @@ -103,7 +103,7 @@ proxychains forge verify-contract 0xDA4b9E3D30A59eCF5AD669ADC591Ddd176fD80e8 \ --num-of-optimizations 1000 \ --watch \ contracts/protocol/libraries/logic/PoolLogic.sol:PoolLogic \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### MarketplaceLogic @@ -116,7 +116,7 @@ proxychains forge verify-contract 0x90c3B619a9714394d45f7CA4D0509A58C991ad02 \ contracts/protocol/libraries/logic/MarketplaceLogic.sol:MarketplaceLogic \ --libraries contracts/protocol/libraries/logic/SupplyLogic.sol:SupplyLogic:0xC0fe2dbe75B8908073B14BF19Af71B1B181f8984 \ --libraries contracts/protocol/libraries/logic/BorrowLogic.sol:BorrowLogic:0x2Cdd46Ea306771DF11CDfc8be8daBC4fe4C42000 \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### ApeStakingLogic @@ -127,7 +127,7 @@ proxychains forge verify-contract 0x0147154e1Be2E17b6d32D9589A2D8EA78a5cf35a \ --num-of-optimizations 1000 \ --watch \ contracts/protocol/tokenization/libraries/ApeStakingLogic.sol:ApeStakingLogic \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### MintableERC721Logic @@ -138,7 +138,7 @@ proxychains forge verify-contract 0x03734D476Ed3e158c969780F58A7537Dc7cE7F13 \ --num-of-optimizations 1 \ --watch \ contracts/protocol/tokenization/libraries/MintableERC721Logic.sol:MintableERC721Logic \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### PToken @@ -151,7 +151,7 @@ proxychains forge verify-contract 0x0139538b3513782E179ac96c690Bc1e378B42F8F \ contracts/protocol/tokenization/PToken.sol:PToken \ --constructor-args \ $(cast abi-encode "constructor(address)" "0x638a98BBB92a7582d07C52ff407D49664DC8b3Ee") \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### PTokenAToken @@ -164,7 +164,7 @@ proxychains forge verify-contract 0x2f34DD450924Aa9bE59422B40933eCaaD644D7Df \ contracts/protocol/tokenization/PTokenAToken.sol:PTokenAToken \ --constructor-args \ $(cast abi-encode "constructor(address)" "0x638a98BBB92a7582d07C52ff407D49664DC8b3Ee") \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### PTokenSApe @@ -177,7 +177,7 @@ proxychains forge verify-contract 0x540d448a1F6E79CF91902e47E1aE030F4F371265 \ contracts/protocol/tokenization/PTokenSApe.sol:PTokenSApe \ --constructor-args \ $(cast abi-encode "constructor(address,address,address)" "0x638a98BBB92a7582d07C52ff407D49664DC8b3Ee" "0xdb5485C85Bd95f38f9def0cA85499eF67dC581c0" "0xFA51cdc70c512c13eF1e4A3dbf1e99082b242896") \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### PTokenCApe @@ -190,7 +190,7 @@ proxychains forge verify-contract 0x8c17beb69971E127e78C2e60F0408232F7d6340F \ contracts/protocol/tokenization/PTokenCApe.sol:PTokenCApe \ --constructor-args \ $(cast abi-encode "constructor(address)" "0x638a98BBB92a7582d07C52ff407D49664DC8b3Ee") \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ## NToken @@ -207,7 +207,7 @@ proxychains forge verify-contract 0x73A613Bf41284C9721A4dEDce77E85C3444DdEBC \ $(cast abi-encode "constructor(address,address,address)" "0x638a98BBB92a7582d07C52ff407D49664DC8b3Ee" "0x5954aB967Bc958940b7EB73ee84797Dc8a2AFbb9" "0x00000000000076A84feF008CDAbe6409d2FE638B") \ --libraries contracts/protocol/tokenization/libraries/ApeStakingLogic.sol:ApeStakingLogic:0x40266cFA6cD32485a24fE9913ed9dAa3E896b6D4 \ --libraries contracts/protocol/tokenization/libraries/MintableERC721Logic.sol:MintableERC721Logic:0x03734D476Ed3e158c969780F58A7537Dc7cE7F13 \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### NTokenMAYC @@ -222,7 +222,7 @@ proxychains forge verify-contract 0x6f56Fc05852e5918DAa3DCfa38524dA589DEAF32 \ $(cast abi-encode "constructor(address,address,address)" "0x638a98BBB92a7582d07C52ff407D49664DC8b3Ee" "0x5954aB967Bc958940b7EB73ee84797Dc8a2AFbb9" "0x00000000000076A84feF008CDAbe6409d2FE638B") \ --libraries contracts/protocol/tokenization/libraries/ApeStakingLogic.sol:ApeStakingLogic:0x40266cFA6cD32485a24fE9913ed9dAa3E896b6D4 \ --libraries contracts/protocol/tokenization/libraries/MintableERC721Logic.sol:MintableERC721Logic:0x03734D476Ed3e158c969780F58A7537Dc7cE7F13 \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### NTokenBAKC @@ -236,7 +236,7 @@ proxychains forge verify-contract 0x10e6B156bfB1Dac6E1891545c0905C7025E0CEe2 \ --constructor-args \ $(cast abi-encode "constructor(address,address,address,address,address)" "0x638a98BBB92a7582d07C52ff407D49664DC8b3Ee" "0x5954aB967Bc958940b7EB73ee84797Dc8a2AFbb9" "0xdb5485C85Bd95f38f9def0cA85499eF67dC581c0" "0xFA51cdc70c512c13eF1e4A3dbf1e99082b242896" "0x00000000000076A84feF008CDAbe6409d2FE638B") \ --libraries contracts/protocol/tokenization/libraries/MintableERC721Logic.sol:MintableERC721Logic:0x03734D476Ed3e158c969780F58A7537Dc7cE7F13 \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### NTokenOtherdeed @@ -250,7 +250,7 @@ proxychains forge verify-contract 0xF7452CbE6a2c87641D27fff5cf0Ae8f8547f9021 \ --constructor-args \ $(cast abi-encode "constructor(address,address,address)" "0x638a98BBB92a7582d07C52ff407D49664DC8b3Ee" "0xC3AA9bc72Bd623168860a1e5c6a4530d3D80456c" "0x00000000000076A84feF008CDAbe6409d2FE638B") \ --libraries contracts/protocol/tokenization/libraries/MintableERC721Logic.sol:MintableERC721Logic:0x03734D476Ed3e158c969780F58A7537Dc7cE7F13 \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### NTokenStakefish @@ -264,7 +264,7 @@ proxychains forge verify-contract 0x0719E8D6acBDCECD1B6A4F32Cc7367c8969Ae352 \ --constructor-args \ $(cast abi-encode "constructor(address,address)" "0x638a98BBB92a7582d07C52ff407D49664DC8b3Ee" "0x00000000000076A84feF008CDAbe6409d2FE638B") \ --libraries contracts/protocol/tokenization/libraries/MintableERC721Logic.sol:MintableERC721Logic:0x8F3527276f7dB90F1F68d166Df366fA46fD70054 \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### NTokenMoonbirds @@ -278,7 +278,7 @@ proxychains forge verify-contract 0xec1aD73B834677f40f4121b8081abC7c64fF1460 \ --constructor-args \ $(cast abi-encode "constructor(address,address)" "0x638a98BBB92a7582d07C52ff407D49664DC8b3Ee" "0x00000000000076A84feF008CDAbe6409d2FE638B") \ --libraries contracts/protocol/tokenization/libraries/MintableERC721Logic.sol:MintableERC721Logic:0x03734D476Ed3e158c969780F58A7537Dc7cE7F13 \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### NTokenUniswapV3 @@ -292,7 +292,7 @@ proxychains forge verify-contract 0x8D7429dBeB0532048310DcBF06064d188FF9a5f2 \ --constructor-args \ $(cast abi-encode "constructor(address,address)" "0x638a98BBB92a7582d07C52ff407D49664DC8b3Ee" "0x00000000000076A84feF008CDAbe6409d2FE638B") \ --libraries contracts/protocol/tokenization/libraries/MintableERC721Logic.sol:MintableERC721Logic:0x03734D476Ed3e158c969780F58A7537Dc7cE7F13 \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### NToken @@ -306,7 +306,7 @@ proxychains forge verify-contract 0x39E4c2Fc79D4C39749BaD41D09af4C8901066477 \ --constructor-args \ $(cast abi-encode "constructor(address,bool,address)" "0x638a98BBB92a7582d07C52ff407D49664DC8b3Ee" false "0x00000000000076A84feF008CDAbe6409d2FE638B") \ --libraries contracts/protocol/tokenization/libraries/MintableERC721Logic.sol:MintableERC721Logic:0x03734D476Ed3e158c969780F58A7537Dc7cE7F13 \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ## DebtToken @@ -321,7 +321,7 @@ proxychains forge verify-contract 0xA00D612d9b2719e05eaB67602F8A72E88582c6Cf \ contracts/protocol/tokenization/ATokenDebtToken.sol:ATokenDebtToken \ --constructor-args \ $(cast abi-encode "constructor(address)" "0x638a98BBB92a7582d07C52ff407D49664DC8b3Ee") \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### VariableDebtToken @@ -334,7 +334,7 @@ proxychains forge verify-contract 0x0f59196757B5BEDb94c149FB20E43D0323c52eA2 \ contracts/protocol/tokenization/VariableDebtToken.sol:VariableDebtToken \ --constructor-args \ $(cast abi-encode "constructor(address)" "0x638a98BBB92a7582d07C52ff407D49664DC8b3Ee") \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ## PoolConfigurator @@ -346,7 +346,7 @@ proxychains forge verify-contract 0x1a5191C39D354e52cB60ef060707568931233184 \ --watch \ contracts/protocol/pool/PoolConfigurator.sol:PoolConfigurator \ --libraries contracts/protocol/libraries/logic/ConfiguratorLogic.sol:ConfiguratorLogic:0xe8bcFDd8E9d22653a2dA7FE881A12E56aF8983C7 \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ## Pool @@ -366,7 +366,7 @@ proxychains forge verify-contract 0xE8932402560a13d9519649103d091c009e21778b \ --libraries contracts/protocol/libraries/logic/SupplyLogic.sol:SupplyLogic:0xC0fe2dbe75B8908073B14BF19Af71B1B181f8984 \ --libraries contracts/protocol/libraries/logic/BorrowLogic.sol:BorrowLogic:0x2Cdd46Ea306771DF11CDfc8be8daBC4fe4C42000 \ --libraries contracts/protocol/libraries/logic/FlashClaimLogic.sol:FlashClaimLogic:0x70a226448d9095F4c0ca6Fbe55bBd4da0C75a0A5 \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### PoolMarketplace @@ -380,7 +380,7 @@ proxychains forge verify-contract 0x6B58baa08a91f0F08900f43692a9796045454A17 \ $(cast abi-encode "constructor(address)" "0x6cD30e716ADbE47dADf7319f6F2FB83d507c857d") \ contracts/protocol/pool/PoolMarketplace.sol:PoolMarketplace \ --libraries contracts/protocol/libraries/logic/MarketplaceLogic.sol:MarketplaceLogic:0x1fE34BF51E802Adba9b1cBc0E216EFAeb1FE226B \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### PositionMover @@ -394,7 +394,7 @@ proxychains forge verify-contract 0x10D89AAc6f133DeE5eE65FEE6C862228eC256eB7 \ $(cast abi-encode "constructor(address,address,address)" "0x6cD30e716ADbE47dADf7319f6F2FB83d507c857d" "0x5f6ac80CdB9E87f3Cfa6a90E5140B9a16A361d5C" "0x70b97a0da65c15dfb0ffa02aee6fa36e507c2762") \ contracts/protocol/pool/PoolPositionMover.sol:PoolPositionMover \ --libraries contracts/protocol/libraries/logic/PositionMoverLogic.sol:PositionMoverLogic:0xa9b3f3EbD6aa58D541855cf8997Fb6ad839658a2 \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### cAPE @@ -407,7 +407,7 @@ proxychains forge verify-contract 0x1Ba6891D74b3B1f84b3EdFa6538D99eE979E8B63 \ --constructor-args \ $(cast abi-encode "constructor(address,address,address)" "0x4d224452801ACEd8B2F0aebE155379bb5D594381" "0x5954aB967Bc958940b7EB73ee84797Dc8a2AFbb9" "0x42b0C49130162F949e82ba855C4eFF0C3Fd4C5cC") \ contracts/misc/AutoCompoundApe.sol:AutoCompoundApe \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ## Oracle @@ -435,7 +435,7 @@ proxychains forge verify-contract 0x6D09f55aae5489D664203Fb8aD72A8d520A87470 \ --constructor-args \ $(cast abi-encode "constructor(uint256)" 10000000000000000) \ contracts/misc/CLFixedPriceSynchronicityPriceAdapter.sol:CLFixedPriceSynchronicityPriceAdapter \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### CLExchangeRateSynchronicityPriceAdapter @@ -448,7 +448,7 @@ proxychains forge verify-contract 0xFCbf6B66dED63D6a8231dB091c16a3481d2E8890 \ --constructor-args \ $(cast abi-encode "constructor(address)" "0xae78736cd615f374d3085123a210448e74fc6393") \ contracts/misc/CLExchangeRateSynchronicityPriceAdapter.sol:CLExchangeRateSynchronicityPriceAdapter \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### UniswapV3TwapOracleWrapper @@ -461,7 +461,7 @@ proxychains forge verify-contract 0x32A880E831814CfD55dC556645Ef06816fE9bE02 \ --constructor-args \ $(cast abi-encode "constructor(address,address,int32)" "0x824a30f2984f9013f2c8d0a29c0a3cc5fd5c0673" "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" "1800") \ contracts/misc/UniswapV3TwapOracleWrapper.sol:UniswapV3TwapOracleWrapper \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### UniswapV3OracleWrapper @@ -474,7 +474,7 @@ proxychains forge verify-contract 0xc0A1AACb2D3B98b5d1050A14de60725D46D4404f \ --constructor-args \ $(cast abi-encode "constructor(address,address,address)" "0x4893376342d5d7b3e31d4184c08b265e5ab2a3f6" "0x622e4726a167799826d1e1d150b076a7725f5d81" "0x5419C015B2D3f1e4600204eD7A67b8A97Fdf0429") \ contracts/misc/UniswapV3OracleWrapper.sol:UniswapV3OracleWrapper \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ## Proxy @@ -487,7 +487,7 @@ proxychains forge verify-contract 0xBAa0DaA4224d2eb4619FfDC8A50Ef50c754b55F3 \ --num-of-optimizations 200 \ --watch \ contracts/dependencies/openzeppelin/upgradeability/InitializableAdminUpgradeabilityProxy.sol:InitializableAdminUpgradeabilityProxy \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ## Interest Rate Strategy @@ -502,7 +502,7 @@ proxychains forge verify-contract 0x41BE4a63035025d79dEbecCE8df682e507fC0A2f \ --constructor-args \ $(cast abi-encode "constructor(address,uint256,uint256,uint256,uint256)" "0x6cD30e716ADbE47dADf7319f6F2FB83d507c857d" "450000000000000000000000000" "0" "70000000000000000000000000" "3000000000000000000000000000") \ contracts/protocol/pool/DefaultReserveInterestRateStrategy.sol:DefaultReserveInterestRateStrategy \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### DefaultReserveAuctionStrategy @@ -515,7 +515,7 @@ proxychains forge verify-contract 0xB1A4B17e33e164b826e213c8CeF448Bc82afdb5a \ --constructor-args \ $(cast abi-encode "constructor(uint256,uint256,uint256,uint256,uint256,uint256)" "10000000000000000000" "1100000000000000000" "800000000000000000" "6250000000000000" "45984894024785900" "900") \ contracts/protocol/pool/DefaultReserveAuctionStrategy.sol:DefaultReserveAuctionStrategy \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ### DefaultReserveTimeLockStrategy @@ -528,7 +528,7 @@ proxychains forge verify-contract 0x0bCc9C5F95833F37317C4F3Fb62bB4e9A7e8C8aa \ contracts/misc/DefaultTimeLockStrategy.sol:DefaultTimeLockStrategy \ --constructor-args \ $(cast abi-encode "constructor(address,uint256,uint256,uint48,uint48,uint48,uint256,uint48,uint256)" "0x638a98BBB92a7582d07C52ff407D49664DC8b3Ee" 4 12 12 7200 43200 10 600 86400) \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ## TimeLock @@ -541,7 +541,7 @@ proxychains forge verify-contract 0x3F736F58F3c51a7C92d8b6996B77Df19a0b5394F \ contracts/misc/TimeLock.sol:TimeLock \ --constructor-args \ $(cast abi-encode "constructor(address,address)" "0x45a35124749B061a29f91cc8ddf85606586dcf24" "0x0000000000000000000000000000000000000000") \ - --compiler-version v0.8.10+commit.fc410830 + --compiler-version v0.8.17+commit.8df45f5f ``` ## UI diff --git a/hardhat.config.ts b/hardhat.config.ts index aea474c7c..8a72fbfd8 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -14,6 +14,19 @@ import { VERBOSE, COMPILER_VERSION, COMPILER_OPTIMIZER_RUNS, + ZK_LIBRARIES, + ETHERSCAN_APIS, + BROWSER_URLS, + GOERLI_ETHERSCAN_KEY, + ARBITRUM_ETHERSCAN_KEY, + ARBITRUM_GOERLI_ETHERSCAN_KEY, + POLYGON_ETHERSCAN_KEY, + POLYGON_MUMBAI_ETHERSCAN_KEY, + POLYGON_ZKEVM_ETHERSCAN_KEY, + POLYGON_ZKEVM_GOERLI_ETHERSCAN_KEY, + MOONBASE_ETHERSCAN_KEY, + LINEA_ETHERSCAN_KEY, + LINEA_GOERLI_ETHERSCAN_KEY, } from "./helpers/hardhat-constants"; import {accounts} from "./wallets"; import {accounts as evmAccounts} from "./evm-wallets"; @@ -26,7 +39,7 @@ import fs from "fs"; dotenv.config(); -import "solidity-docgen-forked"; +import "solidity-docgen"; import "@typechain/hardhat"; import "@nomiclabs/hardhat-ethers"; import "@nomiclabs/hardhat-etherscan"; @@ -34,6 +47,9 @@ import "hardhat-gas-reporter"; import "@tenderly/hardhat-tenderly"; import "solidity-coverage"; import "hardhat-contract-sizer"; +import "@matterlabs/hardhat-zksync-deploy"; +import "@matterlabs/hardhat-zksync-solc"; +import "@matterlabs/hardhat-zksync-verify"; import {eEthereumNetwork} from "./helpers/types"; require(`${path.join(__dirname, "tasks/misc")}/set-bre.ts`); @@ -48,11 +64,22 @@ require(`${path.join(__dirname, "tasks/misc")}/set-bre.ts`); }); const hardhatConfig: HardhatUserConfig = { + zksolc: { + version: "latest", + settings: { + libraries: ZK_LIBRARIES, + }, + }, contractSizer: { alphaSort: true, runOnCompile: false, disambiguatePaths: false, - except: ["Mock*", "ApeCoinStaking"], + except: [ + "Mock*", + "ApeCoinStaking", + "SwapRouter", + "NonfungiblePositionManager", + ], strict: true, }, paths: { @@ -73,7 +100,7 @@ const hardhatConfig: HardhatUserConfig = { // Docs for the compiler https://docs.soliditylang.org/en/v0.8.7/using-the-compiler.html compilers: [ { - version: COMPILER_VERSION, + version: COMPILER_VERSION.split("+")[0], settings: { optimizer: { enabled: true, @@ -82,18 +109,6 @@ const hardhatConfig: HardhatUserConfig = { evmVersion: "london", }, }, - { - version: "0.7.6", - settings: { - optimizer: { - enabled: true, - runs: 800, - }, - metadata: { - bytecodeHash: "none", - }, - }, - }, ], }, typechain: { @@ -152,6 +167,11 @@ const hardhatConfig: HardhatUserConfig = { url: NETWORKS_RPC_URL[eEthereumNetwork.moonbeam], accounts: DEPLOYER, }, + moonbase: { + chainId: CHAINS_ID[eEthereumNetwork.moonbase], + url: NETWORKS_RPC_URL[eEthereumNetwork.moonbase], + accounts: DEPLOYER, + }, hardhat: { hardfork: HARDFORK, blockGasLimit: DEFAULT_BLOCK_GAS_LIMIT, @@ -180,6 +200,52 @@ const hardhatConfig: HardhatUserConfig = { url: NETWORKS_RPC_URL[eEthereumNetwork.arbitrumGoerli], accounts: DEPLOYER, }, + polygon: { + chainId: CHAINS_ID[eEthereumNetwork.polygon], + url: NETWORKS_RPC_URL[eEthereumNetwork.polygon], + accounts: DEPLOYER, + }, + polygonMumbai: { + chainId: CHAINS_ID[eEthereumNetwork.polygonMumbai], + url: NETWORKS_RPC_URL[eEthereumNetwork.polygonMumbai], + accounts: DEPLOYER, + }, + polygonZkevm: { + chainId: CHAINS_ID[eEthereumNetwork.polygonZkevm], + url: NETWORKS_RPC_URL[eEthereumNetwork.polygonZkevm], + accounts: DEPLOYER, + }, + polygonZkevmGoerli: { + chainId: CHAINS_ID[eEthereumNetwork.polygonZkevmGoerli], + url: NETWORKS_RPC_URL[eEthereumNetwork.polygonZkevmGoerli], + accounts: DEPLOYER, + }, + zksync: { + chainId: CHAINS_ID[eEthereumNetwork.zksync], + url: NETWORKS_RPC_URL[eEthereumNetwork.zksync], + accounts: DEPLOYER, + ethNetwork: NETWORKS_RPC_URL[eEthereumNetwork.mainnet], + zksync: true, + verifyURL: ETHERSCAN_APIS[eEthereumNetwork.zksync], + }, + zksyncGoerli: { + chainId: CHAINS_ID[eEthereumNetwork.zksyncGoerli], + url: NETWORKS_RPC_URL[eEthereumNetwork.zksyncGoerli], + accounts: DEPLOYER, + ethNetwork: NETWORKS_RPC_URL[eEthereumNetwork.goerli], + zksync: true, + verifyURL: ETHERSCAN_APIS[eEthereumNetwork.zksyncGoerli], + }, + linea: { + chainId: CHAINS_ID[eEthereumNetwork.linea], + url: NETWORKS_RPC_URL[eEthereumNetwork.linea], + accounts: DEPLOYER, + }, + lineaGoerli: { + chainId: CHAINS_ID[eEthereumNetwork.lineaGoerli], + url: NETWORKS_RPC_URL[eEthereumNetwork.lineaGoerli], + accounts: DEPLOYER, + }, mainnet: { chainId: CHAINS_ID[eEthereumNetwork.mainnet], url: NETWORKS_RPC_URL[eEthereumNetwork.mainnet], @@ -188,29 +254,43 @@ const hardhatConfig: HardhatUserConfig = { }, etherscan: { apiKey: { - mainnet: ETHERSCAN_KEY, - goerli: ETHERSCAN_KEY, localhost: ETHERSCAN_KEY, - arbitrumOne: ETHERSCAN_KEY, + mainnet: ETHERSCAN_KEY, + goerli: GOERLI_ETHERSCAN_KEY, + arbitrum: ARBITRUM_ETHERSCAN_KEY, + arbitrumGoerli: ARBITRUM_GOERLI_ETHERSCAN_KEY, + polygon: POLYGON_ETHERSCAN_KEY, + polygonMumbai: POLYGON_MUMBAI_ETHERSCAN_KEY, + polygonZkevm: POLYGON_ZKEVM_ETHERSCAN_KEY, + polygonZkevmGoerli: POLYGON_ZKEVM_GOERLI_ETHERSCAN_KEY, + moonbeam: MOONBASE_ETHERSCAN_KEY, + moonbase: MOONBASE_ETHERSCAN_KEY, + linea: LINEA_ETHERSCAN_KEY, + lineaGoerli: LINEA_GOERLI_ETHERSCAN_KEY, }, customChains: [ - { - network: eEthereumNetwork.localhost, - chainId: CHAINS_ID[eEthereumNetwork.hardhat]!, - urls: { - apiURL: "http://localhost:4000/api", - browserURL: "http://localhost:4000", - }, + eEthereumNetwork.localhost, + eEthereumNetwork.goerli, + eEthereumNetwork.arbitrum, + eEthereumNetwork.arbitrumGoerli, + eEthereumNetwork.polygon, + eEthereumNetwork.polygonZkevm, + eEthereumNetwork.polygonMumbai, + eEthereumNetwork.polygonZkevmGoerli, + eEthereumNetwork.zksync, + eEthereumNetwork.zksyncGoerli, + eEthereumNetwork.moonbeam, + eEthereumNetwork.moonbase, + eEthereumNetwork.linea, + eEthereumNetwork.lineaGoerli, + ].map((network) => ({ + network, + chainId: CHAINS_ID[network]!, + urls: { + apiURL: ETHERSCAN_APIS[network], + browserURL: BROWSER_URLS[network], }, - { - network: eEthereumNetwork.arbitrum, - chainId: CHAINS_ID[eEthereumNetwork.hardhat]!, - urls: { - apiURL: "https://api.arbiscan.io/api", - browserURL: "https://arbiscan.io", - }, - }, - ], + })), }, }; diff --git a/helper-hardhat-config.ts b/helper-hardhat-config.ts index e44ba52f2..50717531b 100644 --- a/helper-hardhat-config.ts +++ b/helper-hardhat-config.ts @@ -11,11 +11,22 @@ import { GOERLI_CHAINID, HARDHAT_CHAINID, INFURA_KEY, + L1_RPC_URL, + L2_RPC_URL, + LINEA_CHAINID, + LINEA_GOERLI_CHAINID, MAINNET_CHAINID, + MOONBASE_CHAINID, MOONBEAM_CHAINID, PARALLEL_CHAINID, + POLYGON_CHAINID, + POLYGON_MUMBAI_CHAINID, + POLYGON_ZKEVM_CHAINID, + POLYGON_ZKEVM_GOERLI_CHAINID, RPC_URL, TENDERLY_FORK_ID, + ZKSYNC_CHAINID, + ZKSYNC_GOERLI_CHAINID, } from "./helpers/hardhat-constants"; dotenv.config(); @@ -38,22 +49,18 @@ export const buildForkConfig = (): }; export const NETWORKS_RPC_URL: iParamsPerNetwork = { - [eEthereumNetwork.kovan]: - RPC_URL || ALCHEMY_KEY - ? `https://eth-kovan.alchemyapi.io/v2/${ALCHEMY_KEY}` - : `https://kovan.infura.io/v3/${INFURA_KEY}`, - [eEthereumNetwork.ropsten]: - RPC_URL || ALCHEMY_KEY - ? `https://eth-ropsten.alchemyapi.io/v2/${ALCHEMY_KEY}` - : `https://ropsten.infura.io/v3/${INFURA_KEY}`, [eEthereumNetwork.goerli]: - RPC_URL || ALCHEMY_KEY + L1_RPC_URL || + RPC_URL || + (ALCHEMY_KEY ? `https://eth-goerli.alchemyapi.io/v2/${ALCHEMY_KEY}` - : `https://goerli.infura.io/v3/${INFURA_KEY}`, + : `https://goerli.infura.io/v3/${INFURA_KEY}`), [eEthereumNetwork.mainnet]: - RPC_URL || ALCHEMY_KEY + L1_RPC_URL || + RPC_URL || + (ALCHEMY_KEY ? `https://eth-mainnet.alchemyapi.io/v2/${ALCHEMY_KEY}` - : `https://mainnet.infura.io/v3/${INFURA_KEY}`, + : `https://mainnet.infura.io/v3/${INFURA_KEY}`), [eEthereumNetwork.hardhat]: RPC_URL || "http://localhost:8545", [eEthereumNetwork.anvil]: RPC_URL || "http://localhost:8545", [eEthereumNetwork.ganache]: RPC_URL || "http://localhost:8545", @@ -61,16 +68,47 @@ export const NETWORKS_RPC_URL: iParamsPerNetwork = { RPC_URL || `https://rpc.tenderly.co/fork/${TENDERLY_FORK_ID}`, [eEthereumNetwork.parallel]: RPC_URL || "http://localhost:29933", [eEthereumNetwork.moonbeam]: "https://rpc.api.moonbeam.network", + [eEthereumNetwork.moonbase]: "https://rpc.testnet.moonbeam.network", [eEthereumNetwork.arbitrum]: - RPC_URL || `https://arb-mainnet.g.alchemy.com/v2/${ALCHEMY_KEY}`, + L2_RPC_URL || + RPC_URL || + `https://arb-mainnet.g.alchemy.com/v2/${ALCHEMY_KEY}`, [eEthereumNetwork.arbitrumGoerli]: - RPC_URL || `https://arb-goerli.g.alchemy.com/v2/${ALCHEMY_KEY}`, + L2_RPC_URL || + RPC_URL || + `https://arb-goerli.g.alchemy.com/v2/${ALCHEMY_KEY}`, + [eEthereumNetwork.polygon]: + RPC_URL || `https://polygon-mainnet.g.alchemy.com/v2/${ALCHEMY_KEY}`, + [eEthereumNetwork.polygonMumbai]: + RPC_URL || `https://polygon-mumbai.g.alchemy.com/v2/${ALCHEMY_KEY}`, + [eEthereumNetwork.polygonZkevm]: + L2_RPC_URL || + RPC_URL || + `https://polygonzkevm-mainnet.g.alchemy.com/v2/${ALCHEMY_KEY}`, + [eEthereumNetwork.polygonZkevmGoerli]: + L2_RPC_URL || + RPC_URL || + `https://polygonzkevm-testnet.g.alchemy.com/v2/${ALCHEMY_KEY}`, + [eEthereumNetwork.zksync]: + L2_RPC_URL || RPC_URL || `https://mainnet.era.zksync.io`, + [eEthereumNetwork.zksyncGoerli]: + L2_RPC_URL || RPC_URL || `https://testnet.era.zksync.dev`, + [eEthereumNetwork.linea]: + L2_RPC_URL || + RPC_URL || + (INFURA_KEY + ? `https://linea-mainnet.infura.io/v3/${INFURA_KEY}` + : "https://rpc.linea.build"), + [eEthereumNetwork.lineaGoerli]: + L2_RPC_URL || + RPC_URL || + (INFURA_KEY + ? `https://linea-goerli.infura.io/v3/${INFURA_KEY}` + : `https://rpc.goerli.linea.build`), }; export const CHAINS_ID: iParamsPerNetwork = { [eEthereumNetwork.mainnet]: MAINNET_CHAINID, - [eEthereumNetwork.kovan]: undefined, - [eEthereumNetwork.ropsten]: undefined, [eEthereumNetwork.goerli]: GOERLI_CHAINID, [eEthereumNetwork.hardhat]: FORK ? FORK_CHAINID : HARDHAT_CHAINID, [eEthereumNetwork.anvil]: HARDHAT_CHAINID, @@ -78,14 +116,21 @@ export const CHAINS_ID: iParamsPerNetwork = { [eEthereumNetwork.parallel]: PARALLEL_CHAINID, [eEthereumNetwork.tenderlyMain]: undefined, [eEthereumNetwork.moonbeam]: MOONBEAM_CHAINID, + [eEthereumNetwork.moonbase]: MOONBASE_CHAINID, [eEthereumNetwork.arbitrum]: ARBITRUM_ONE_CHAINID, [eEthereumNetwork.arbitrumGoerli]: ARBITRUM_GOERLI_CHAINID, + [eEthereumNetwork.polygon]: POLYGON_CHAINID, + [eEthereumNetwork.polygonMumbai]: POLYGON_MUMBAI_CHAINID, + [eEthereumNetwork.polygonZkevm]: POLYGON_ZKEVM_CHAINID, + [eEthereumNetwork.polygonZkevmGoerli]: POLYGON_ZKEVM_GOERLI_CHAINID, + [eEthereumNetwork.zksync]: ZKSYNC_CHAINID, + [eEthereumNetwork.zksyncGoerli]: ZKSYNC_GOERLI_CHAINID, + [eEthereumNetwork.linea]: LINEA_CHAINID, + [eEthereumNetwork.lineaGoerli]: LINEA_GOERLI_CHAINID, }; export const BLOCK_TO_FORK: iParamsPerNetwork = { [eEthereumNetwork.mainnet]: undefined, - [eEthereumNetwork.kovan]: undefined, - [eEthereumNetwork.ropsten]: undefined, [eEthereumNetwork.goerli]: undefined, [eEthereumNetwork.hardhat]: undefined, [eEthereumNetwork.anvil]: undefined, @@ -93,6 +138,15 @@ export const BLOCK_TO_FORK: iParamsPerNetwork = { [eEthereumNetwork.parallel]: undefined, [eEthereumNetwork.tenderlyMain]: undefined, [eEthereumNetwork.moonbeam]: undefined, + [eEthereumNetwork.moonbase]: undefined, [eEthereumNetwork.arbitrum]: undefined, [eEthereumNetwork.arbitrumGoerli]: undefined, + [eEthereumNetwork.polygon]: undefined, + [eEthereumNetwork.polygonMumbai]: undefined, + [eEthereumNetwork.polygonZkevm]: undefined, + [eEthereumNetwork.polygonZkevmGoerli]: undefined, + [eEthereumNetwork.zksync]: undefined, + [eEthereumNetwork.zksyncGoerli]: undefined, + [eEthereumNetwork.linea]: undefined, + [eEthereumNetwork.lineaGoerli]: undefined, }; diff --git a/helpers/contracts-deployments.ts b/helpers/contracts-deployments.ts index 871052af3..8e3bda043 100644 --- a/helpers/contracts-deployments.ts +++ b/helpers/contracts-deployments.ts @@ -1,314 +1,175 @@ -import {DRE, getDb, getParaSpaceConfig, waitForTx} from "./misc-utils"; -import { - eContractid, - ERC20TokenContractId, - ERC721TokenContractId, - tEthereumAddress, - tStringTokenSmallUnits, -} from "./types"; +import {MockContract} from "ethereum-waffle"; import { ACLManager, - ACLManager__factory, - ApeCoinStaking__factory, - ApeStakingLogic, - ApeStakingLogic__factory, + AirdropFlashClaimReceiver, + AStETHDebtToken, ATokenDebtToken, - ATokenDebtToken__factory, AuctionLogic, - AuctionLogic__factory, - AutoCompoundApe__factory, + AutoCompoundApe, + AutoYieldApe, Azuki, - Azuki__factory, + BAYCSewerPass, BlurAdapter, - BlurAdapter__factory, BlurExchange, - BlurExchange__factory, BoredApeYachtClub, - BoredApeYachtClub__factory, BorrowLogic, - BorrowLogic__factory, CApeDebtToken, - CApeDebtToken__factory, + CLCETHSynchronicityPriceAdapter, + CLExchangeRateSynchronicityPriceAdapter, + CLFixedPriceSynchronicityPriceAdapter, CloneX, - CloneX__factory, + CLwstETHSynchronicityPriceAdapter, ConduitController, - ConduitController__factory, ConfiguratorLogic, - ConfiguratorLogic__factory, CryptoPunksMarket, - CryptoPunksMarket__factory, CurrencyManager, - CurrencyManager__factory, DefaultReserveAuctionStrategy, - DefaultReserveAuctionStrategy__factory, DefaultReserveInterestRateStrategy, - DefaultReserveInterestRateStrategy__factory, + DefaultTimeLockStrategy, DelegationAwarePToken, - DelegationAwarePToken__factory, + DelegationRegistry, + DepositContract, Doodles, - Doodles__factory, ERC721Delegate, - ERC721Delegate__factory, ERC721OracleWrapper, - ERC721OracleWrapper__factory, + ERC20OracleWrapper, ExecutionDelegate, - ExecutionDelegate__factory, ExecutionManager, - ExecutionManager__factory, ExecutorWithTimelock, - ExecutorWithTimelock__factory, FlashClaimLogic, - FlashClaimLogic__factory, + HelperContract, + HotWalletProxy, + InitializableAdminUpgradeabilityProxy, InitializableImmutableAdminUpgradeabilityProxy, - InitializableImmutableAdminUpgradeabilityProxy__factory, Land, - Land__factory, LiquidationLogic, - LiquidationLogic__factory, LooksRareAdapter, - LooksRareAdapter__factory, LooksRareExchange, - LooksRareExchange__factory, MarketplaceLogic, - MarketplaceLogic__factory, Meebits, - Meebits__factory, MerkleVerifier, - MerkleVerifier__factory, MintableDelegationERC20, - MintableDelegationERC20__factory, MintableERC20, - MintableERC20__factory, MintableERC721, - MintableERC721__factory, MintableERC721Logic, - MintableERC721Logic__factory, MockAggregator, - MockAggregator__factory, MockAirdropProject, - MockAirdropProject__factory, - MockMultiAssetAirdropProject, - MockMultiAssetAirdropProject__factory, + MockAStETH, MockAToken, - MockAToken__factory, + MockCToken, + MockedDelegateRegistry, + MockFeePool, MockIncentivesController, - MockIncentivesController__factory, MockInitializableFromConstructorImple, - MockInitializableFromConstructorImple__factory, MockInitializableImple, - MockInitializableImple__factory, MockInitializableImpleV2, - MockInitializableImpleV2__factory, + MockMultiAssetAirdropProject, MockNToken, - MockNToken__factory, MockPToken, - MockPToken__factory, MockReentrantInitializableImple, - MockReentrantInitializableImple__factory, MockReserveAuctionStrategy, - MockReserveAuctionStrategy__factory, MockReserveConfiguration, - MockReserveConfiguration__factory, - MockTokenFaucet__factory, + MockRETH, MockVariableDebtToken, - MockVariableDebtToken__factory, Moonbirds, - Moonbirds__factory, MutantApeYachtClub, - MutantApeYachtClub__factory, NFTFloorOracle, - NFTFloorOracle__factory, NToken, - NToken__factory, + NTokenBAKC, NTokenBAYC, - NTokenBAYC__factory, NTokenMAYC, - NTokenMAYC__factory, NTokenMoonBirds, - NTokenMoonBirds__factory, + NTokenOtherdeed, + NTokenStakefish, NTokenUniswapV3, - NTokenUniswapV3__factory, + ParaProxyInterfaces, + ParaProxyInterfaces__factory, ParaProxy__factory, + ParaSpaceAirdrop, ParaSpaceOracle, - ParaSpaceOracle__factory, PausableZoneController, - PausableZoneController__factory, PolicyManager, - PolicyManager__factory, PoolAddressesProvider, - PoolAddressesProvider__factory, PoolAddressesProviderRegistry, - PoolAddressesProviderRegistry__factory, PoolApeStaking, PoolApeStaking__factory, PoolConfigurator, - PoolConfigurator__factory, PoolCore, PoolCore__factory, PoolLogic, - PoolLogic__factory, PoolMarketplace, PoolMarketplace__factory, PoolParameters, PoolParameters__factory, + PoolPositionMover, + PoolPositionMover__factory, + PositionMoverLogic, PriceOracle, - PriceOracle__factory, ProtocolDataProvider, - ProtocolDataProvider__factory, PToken, - PToken__factory, + PTokenAStETH, PTokenAToken, - PTokenAToken__factory, PTokenCApe, - PTokenCApe__factory, PTokenSApe, - PTokenSApe__factory, PTokenStETH, - PTokenStETH__factory, + PTokenStKSM, + PYieldToken, ReservesSetupHelper, - ReservesSetupHelper__factory, RoyaltyFeeManager, - RoyaltyFeeManager__factory, RoyaltyFeeRegistry, - RoyaltyFeeRegistry__factory, Seaport, - Seaport__factory, SeaportAdapter, - SeaportAdapter__factory, + StakefishNFTManager, + StakefishValidatorFactory, + StakefishValidatorV1, StandardPolicyERC721, - StandardPolicyERC721__factory, - StETHMocked, - StETHMocked__factory, StETHDebtToken, - StETHDebtToken__factory, + StETHMocked, + StKSMDebtToken, StrategyStandardSaleForFixedPrice, - StrategyStandardSaleForFixedPrice__factory, SupplyLogic, - SupplyLogic__factory, + TimeLock, TransferManagerERC1155, - TransferManagerERC1155__factory, TransferManagerERC721, - TransferManagerERC721__factory, TransferSelectorNFT, - TransferSelectorNFT__factory, UiIncentiveDataProvider, - UiIncentiveDataProvider__factory, UiPoolDataProvider, - UiPoolDataProvider__factory, UniswapV3Factory, - UniswapV3Factory__factory, UniswapV3OracleWrapper, - UniswapV3OracleWrapper__factory, + UniswapV3TwapOracleWrapper, UserFlashclaimRegistry, - UserFlashclaimRegistry__factory, VariableDebtToken, - VariableDebtToken__factory, WalletBalanceProvider, - WalletBalanceProvider__factory, WETH9Mocked, - WETH9Mocked__factory, WETHGateway, - WETHGateway__factory, WPunk, - WPunk__factory, WPunkGateway, - WPunkGateway__factory, + WstETHMocked, X2Y2Adapter, - X2Y2Adapter__factory, X2Y2R1, - X2Y2R1__factory, - AutoCompoundApe, - InitializableAdminUpgradeabilityProxy__factory, - InitializableAdminUpgradeabilityProxy, - ParaProxyInterfaces__factory, - ParaProxyInterfaces, - MockedDelegateRegistry, - MockedDelegateRegistry__factory, - NTokenBAKC, - NTokenBAKC__factory, - P2PPairStaking__factory, - P2PPairStaking, - AirdropFlashClaimReceiver__factory, - AirdropFlashClaimReceiver, - CLwstETHSynchronicityPriceAdapter__factory, - CLExchangeRateSynchronicityPriceAdapter__factory, - CLwstETHSynchronicityPriceAdapter, - WstETHMocked__factory, - WstETHMocked, - BAYCSewerPass__factory, - BAYCSewerPass, - BAYCSewerPassClaim__factory, - AutoYieldApe__factory, - AutoYieldApe, - PYieldToken__factory, - PYieldToken, - UniswapV3TwapOracleWrapper, - UniswapV3TwapOracleWrapper__factory, - HelperContract, - HelperContract__factory, - ParaSpaceAirdrop__factory, - ParaSpaceAirdrop, - CLExchangeRateSynchronicityPriceAdapter, - PTokenAStETH__factory, - PTokenAStETH, - AStETHDebtToken__factory, - AStETHDebtToken, - MockAStETH, - MockAStETH__factory, - MockRETH, - MockRETH__factory, - CLCETHSynchronicityPriceAdapter__factory, - CLCETHSynchronicityPriceAdapter, - MockCToken, - MockCToken__factory, - TimeLock__factory, - DefaultTimeLockStrategy__factory, - DefaultTimeLockStrategy, - NTokenOtherdeed__factory, - NTokenOtherdeed, - HotWalletProxy__factory, - HotWalletProxy, - NTokenStakefish__factory, - NTokenStakefish, - DelegationRegistry, - DelegationRegistry__factory, - StakefishNFTManager__factory, - StakefishNFTManager, - StakefishValidatorV1__factory, - StakefishValidatorV1, - DepositContract__factory, - DepositContract, - StakefishValidatorFactory__factory, - StakefishValidatorFactory, - MockFeePool, - MockFeePool__factory, - MockLendPool__factory, - PoolPositionMover__factory, - PoolPositionMover, - PositionMoverLogic, - PositionMoverLogic__factory, - TimeLock, - NTokenChromieSquiggle__factory, - CLFixedPriceSynchronicityPriceAdapter, - CLFixedPriceSynchronicityPriceAdapter__factory, + ApeStakingP2PLogic, + ApeStakingPairPoolLogic, + ApeStakingSinglePoolLogic, + ApeCoinPoolLogic, + ParaApeStaking, } from "../types"; -import {MockContract} from "ethereum-waffle"; import { + getACLManager, getAllTokens, + getAutoCompoundApe, + getAutoYieldApe, getBAYCSewerPass, + getContractFactory, getFirstSigner, - getProtocolDataProvider, + getHelperContract, + getInitializableAdminUpgradeabilityProxy, + getParaApeStaking, getPoolProxy, + getProtocolDataProvider, getPunks, + getTimeLockProxy, getUniswapV3SwapRouter, getWETH, - getACLManager, - getTimeLockProxy, - getInitializableAdminUpgradeabilityProxy, - getAutoCompoundApe, - getP2PPairStaking, - getAutoYieldApe, - getHelperContract, } from "./contracts-getters"; import { convertToCurrencyDecimals, @@ -319,24 +180,114 @@ import { insertContractAddressInDb, withSaveAndVerify, } from "./contracts-helpers"; +import {DRE, getDb, getParaSpaceConfig, waitForTx} from "./misc-utils"; +import { + eContractid, + ERC20TokenContractId, + ERC721TokenContractId, + tEthereumAddress, + tStringTokenSmallUnits, +} from "./types"; -import * as nonfungiblePositionManager from "@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json"; -import * as uniSwapRouter from "@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json"; import * as nFTDescriptor from "@uniswap/v3-periphery/artifacts/contracts/libraries/NFTDescriptor.sol/NFTDescriptor.json"; import * as nonfungibleTokenPositionDescriptor from "@uniswap/v3-periphery/artifacts/contracts/NonfungibleTokenPositionDescriptor.sol/NonfungibleTokenPositionDescriptor.json"; -import {Address} from "hardhat-deploy/dist/types"; import {Contract} from "ethers"; -import {LiquidationLogicLibraryAddresses} from "../types/factories/contracts/protocol/libraries/logic/LiquidationLogic__factory"; -import {MarketplaceLogicLibraryAddresses} from "../types/factories/contracts/protocol/libraries/logic/MarketplaceLogic__factory"; -import {PoolCoreLibraryAddresses} from "../types/factories/contracts/protocol/pool/PoolCore__factory"; -import {PoolMarketplaceLibraryAddresses} from "../types/factories/contracts/protocol/pool/PoolMarketplace__factory"; -import {PoolParametersLibraryAddresses} from "../types/factories/contracts/protocol/pool/PoolParameters__factory"; -import {PositionMoverLogicLibraryAddresses} from "../types/factories/contracts/protocol/libraries/logic/PositionMoverLogic__factory"; +import {Address, Libraries} from "hardhat-deploy/dist/types"; +import {parseEther} from "ethers/lib/utils"; import {pick, upperFirst} from "lodash"; import {ZERO_ADDRESS} from "./constants"; -import {GLOBAL_OVERRIDES} from "./hardhat-constants"; -import {parseEther} from "ethers/lib/utils"; +import {GLOBAL_OVERRIDES, ZK_LIBRARIES_PATH} from "./hardhat-constants"; +import fs from "fs"; +import shell from "shelljs"; + +export const deployAllLibraries = async (verify?: boolean) => { + const supplyLogic = await deploySupplyLogic(verify); + const borrowLogic = await deployBorrowLogic(verify); + const auctionLogic = await deployAuctionLogic(verify); + const flashClaimLogic = await deployFlashClaimLogic(verify); + const poolLogic = await deployPoolLogic(verify); + const configuratorLogic = await deployConfiguratorLogic(verify); + const mintableERC721Logic = await deployMintableERC721Logic(verify); + const merkleVerifier = await deployMerkleVerifier(verify); + + const libraries = { + ["contracts/protocol/libraries/logic/AuctionLogic.sol"]: { + AuctionLogic: auctionLogic.address, + }, + ["contracts/protocol/libraries/logic/SupplyLogic.sol"]: { + SupplyLogic: supplyLogic.address, + }, + ["contracts/protocol/libraries/logic/BorrowLogic.sol"]: { + BorrowLogic: borrowLogic.address, + }, + ["contracts/protocol/libraries/logic/FlashClaimLogic.sol"]: { + FlashClaimLogic: flashClaimLogic.address, + }, + "contracts/protocol/libraries/logic/PoolLogic.sol": { + PoolLogic: poolLogic.address, + }, + "contracts/protocol/tokenization/libraries/MintableERC721Logic.sol": { + MintableERC721Logic: mintableERC721Logic.address, + }, + "contracts/protocol/libraries/logic/ConfiguratorLogic.sol": { + ConfiguratorLogic: configuratorLogic.address, + }, + "contracts/dependencies/blur-exchange/MerkleVerifier.sol": { + MerkleVerifier: merkleVerifier.address, + }, + "contracts/protocol/libraries/logic/LiquidationLogic.sol": { + LiquidationLogic: ZERO_ADDRESS, + }, + "contracts/protocol/libraries/logic/PositionMoverLogic.sol": { + PositionMoverLogic: ZERO_ADDRESS, + }, + "contracts/protocol/libraries/logic/MarketplaceLogic.sol": { + MarketplaceLogic: ZERO_ADDRESS, + }, + }; + + fs.writeFileSync(ZK_LIBRARIES_PATH, JSON.stringify(libraries)); + shell.exec("make build"); + + const liquidationLogic = await deployLiquidationLogic( + { + ["contracts/protocol/libraries/logic/SupplyLogic.sol:SupplyLogic"]: + supplyLogic.address, + }, + verify + ); + const positionMoverLogic = await deployPositionMoverLogic( + { + "contracts/protocol/libraries/logic/SupplyLogic.sol:SupplyLogic": + supplyLogic.address, + "contracts/protocol/libraries/logic/BorrowLogic.sol:BorrowLogic": + borrowLogic.address, + }, + verify + ); + const marketplaceLogic = await deployMarketplaceLogic( + { + "contracts/protocol/libraries/logic/SupplyLogic.sol:SupplyLogic": + supplyLogic.address, + "contracts/protocol/libraries/logic/BorrowLogic.sol:BorrowLogic": + borrowLogic.address, + }, + verify + ); + libraries["contracts/protocol/libraries/logic/PositionMoverLogic.sol"] = { + PositionMoverLogic: positionMoverLogic.address, + }; + libraries["contracts/protocol/libraries/logic/LiquidationLogic.sol"] = { + LiquidationLogic: liquidationLogic.address, + }; + libraries["contracts/protocol/libraries/logic/MarketplaceLogic.sol"] = { + MarketplaceLogic: marketplaceLogic.address, + }; + + fs.writeFileSync(ZK_LIBRARIES_PATH, JSON.stringify(libraries)); + shell.exec("make build"); +}; export const deployPoolAddressesProvider = async ( marketId: string, @@ -344,7 +295,7 @@ export const deployPoolAddressesProvider = async ( verify?: boolean ) => withSaveAndVerify( - new PoolAddressesProvider__factory(await getFirstSigner()), + await getContractFactory("PoolAddressesProvider"), eContractid.PoolAddressesProvider, [marketId, owner], verify @@ -355,7 +306,7 @@ export const deployPoolAddressesProviderRegistry = async ( verify?: boolean ) => withSaveAndVerify( - new PoolAddressesProviderRegistry__factory(await getFirstSigner()), + await getContractFactory("PoolAddressesProviderRegistry"), eContractid.PoolAddressesProviderRegistry, [owner], verify @@ -366,28 +317,28 @@ export const deployACLManager = async ( verify?: boolean ) => withSaveAndVerify( - new ACLManager__factory(await getFirstSigner()), + await getContractFactory("ACLManager"), eContractid.ACLManager, [provider], verify ) as Promise; -export const deployConfiguratorLogicLibrary = async (verify?: boolean) => +export const deployConfiguratorLogic = async (verify?: boolean) => withSaveAndVerify( - new ConfiguratorLogic__factory(await getFirstSigner()), + await getContractFactory("ConfiguratorLogic"), eContractid.ConfiguratorLogic, [], verify ) as Promise; export const deployPoolConfigurator = async (verify?: boolean) => { - const configuratorLogic = await deployConfiguratorLogicLibrary(verify); + const configuratorLogic = await deployConfiguratorLogic(verify); const libraries = { ["contracts/protocol/libraries/logic/ConfiguratorLogic.sol:ConfiguratorLogic"]: configuratorLogic.address, }; return withSaveAndVerify( - new PoolConfigurator__factory(libraries, await getFirstSigner()), + await getContractFactory("PoolConfigurator", libraries), eContractid.PoolConfiguratorImpl, [], verify, @@ -398,7 +349,7 @@ export const deployPoolConfigurator = async (verify?: boolean) => { export const deploySupplyLogic = async (verify?: boolean) => withSaveAndVerify( - new SupplyLogic__factory(await getFirstSigner()), + await getContractFactory("SupplyLogic"), eContractid.SupplyLogic, [], verify @@ -406,7 +357,7 @@ export const deploySupplyLogic = async (verify?: boolean) => export const deployFlashClaimLogic = async (verify?: boolean) => withSaveAndVerify( - new FlashClaimLogic__factory(await getFirstSigner()), + await getContractFactory("FlashClaimLogic"), eContractid.FlashClaimLogic, [], verify @@ -414,18 +365,18 @@ export const deployFlashClaimLogic = async (verify?: boolean) => export const deployBorrowLogic = async (verify?: boolean) => withSaveAndVerify( - new BorrowLogic__factory(await getFirstSigner()), + await getContractFactory("BorrowLogic"), eContractid.BorrowLogic, [], verify ) as Promise; export const deployLiquidationLogic = async ( - libraries: LiquidationLogicLibraryAddresses, + libraries: Libraries, verify?: boolean ) => withSaveAndVerify( - new LiquidationLogic__factory(libraries, await getFirstSigner()), + await getContractFactory("LiquidationLogic", libraries), eContractid.LiquidationLogic, [], verify, @@ -435,7 +386,7 @@ export const deployLiquidationLogic = async ( export const deployAuctionLogic = async (verify?: boolean) => withSaveAndVerify( - new AuctionLogic__factory(await getFirstSigner()), + await getContractFactory("AuctionLogic"), eContractid.AuctionLogic, [], verify @@ -443,26 +394,28 @@ export const deployAuctionLogic = async (verify?: boolean) => export const deployPoolLogic = async (verify?: boolean) => withSaveAndVerify( - new PoolLogic__factory(await getFirstSigner()), + await getContractFactory("PoolLogic"), eContractid.PoolLogic, [], verify ) as Promise; export const deployPositionMoverLogic = async ( - libraries: PositionMoverLogicLibraryAddresses, + libraries: Libraries, verify?: boolean ) => withSaveAndVerify( - new PositionMoverLogic__factory(libraries, await getFirstSigner()), + await getContractFactory("PositionMoverLogic", libraries), eContractid.PositionMoverLogic, [], - verify + verify, + false, + libraries ) as Promise; export const deployPoolCoreLibraries = async ( verify?: boolean -): Promise => { +): Promise => { const supplyLogic = await deploySupplyLogic(verify); const borrowLogic = await deployBorrowLogic(verify); const auctionLogic = await deployAuctionLogic(verify); @@ -494,7 +447,7 @@ export const deployPoolCore = async (provider: string, verify?: boolean) => { const {poolCoreSelectors} = getPoolSignatures(); const poolCore = (await withSaveAndVerify( - new PoolCore__factory(coreLibraries, await getFirstSigner()), + await getContractFactory("PoolCore", coreLibraries), eContractid.PoolCoreImpl, [ provider, @@ -538,7 +491,7 @@ export const deployPoolMarketplace = async ( const {poolMarketplaceSelectors} = getPoolSignatures(); const poolMarketplace = (await withSaveAndVerify( - new PoolMarketplace__factory(marketplaceLibraries, await getFirstSigner()), + await getContractFactory("PoolMarketplace", marketplaceLibraries), eContractid.PoolMarketplaceImpl, [provider], verify, @@ -575,7 +528,7 @@ export const deployPoolApeStaking = async ( const allTokens = await getAllTokens(); const poolApeStaking = (await withSaveAndVerify( - new PoolApeStaking__factory(apeStakingLibraries, await getFirstSigner()), + await getContractFactory("PoolApeStaking", apeStakingLibraries), eContractid.PoolApeStakingImpl, [ provider, @@ -612,7 +565,7 @@ export const deployPoolParameters = async ( }; const poolParameters = (await withSaveAndVerify( - new PoolParameters__factory(parametersLibraries, await getFirstSigner()), + await getContractFactory("PoolParameters", parametersLibraries), eContractid.PoolParametersImpl, [provider], verify, @@ -630,7 +583,7 @@ export const deployPoolParameters = async ( export const deployPoolParaProxyInterfaces = async (verify?: boolean) => { const {poolParaProxyInterfacesSelectors} = await getPoolSignatures(); const poolParaProxyInterfaces = (await withSaveAndVerify( - new ParaProxyInterfaces__factory(await getFirstSigner()), + await getContractFactory("ParaProxyInterfaces"), eContractid.ParaProxyInterfacesImpl, [], verify, @@ -655,31 +608,29 @@ export const deployPoolPositionMover = async ( ) => { const supplyLogic = await deploySupplyLogic(verify); const borrowLogic = await deployBorrowLogic(verify); - const positionMoverLibraries = { + const positionMoverLogicLibraries = { "contracts/protocol/libraries/logic/SupplyLogic.sol:SupplyLogic": supplyLogic.address, "contracts/protocol/libraries/logic/BorrowLogic.sol:BorrowLogic": borrowLogic.address, }; const positionMoverLogic = await deployPositionMoverLogic( - positionMoverLibraries, + positionMoverLogicLibraries, verify ); + const positionMoverLibraries = { + ["contracts/protocol/libraries/logic/PositionMoverLogic.sol:PositionMoverLogic"]: + positionMoverLogic.address, + }; const {poolPositionMoverSelectors} = await getPoolSignatures(); const poolPositionMover = (await withSaveAndVerify( - new PoolPositionMover__factory( - { - ["contracts/protocol/libraries/logic/PositionMoverLogic.sol:PositionMoverLogic"]: - positionMoverLogic.address, - }, - await getFirstSigner() - ), + await getContractFactory("PoolPositionMover", positionMoverLibraries), eContractid.PoolPositionMoverImpl, [provider, bendDaoLendPoolLoan, bendDaoLendPool], verify, false, - undefined, + positionMoverLibraries, poolPositionMoverSelectors )) as PoolPositionMover; @@ -692,9 +643,9 @@ export const deployPoolPositionMover = async ( }; export const deployPoolMarketplaceLibraries = async ( - coreLibraries: PoolCoreLibraryAddresses, + coreLibraries: Libraries, verify?: boolean -): Promise => { +): Promise => { const marketplaceLogic = await deployMarketplaceLogic( pick(coreLibraries, [ "contracts/protocol/libraries/logic/SupplyLogic.sol:SupplyLogic", @@ -710,7 +661,7 @@ export const deployPoolMarketplaceLibraries = async ( export const deployPoolParametersLibraries = async ( verify?: boolean -): Promise => { +): Promise => { const poolLogic = await deployPoolLogic(verify); return { ["contracts/protocol/libraries/logic/PoolLogic.sol:PoolLogic"]: @@ -824,14 +775,10 @@ export const deployPoolComponents = async ( const apeStakingLibraries = pick(coreLibraries, [ "contracts/protocol/libraries/logic/BorrowLogic.sol:BorrowLogic", - "contracts/protocol/libraries/logic/SupplyLogic.sol:SupplyLogic", ]); const allTokens = await getAllTokens(); - const APE_WETH_FEE = 3000; - const WETH_USDC_FEE = 500; - const { poolCoreSelectors, poolParametersSelectors, @@ -840,7 +787,7 @@ export const deployPoolComponents = async ( } = getPoolSignatures(); const poolCore = (await withSaveAndVerify( - new PoolCore__factory(coreLibraries, await getFirstSigner()), + await getContractFactory("PoolCore", coreLibraries), eContractid.PoolCoreImpl, [ provider, @@ -856,7 +803,7 @@ export const deployPoolComponents = async ( )) as PoolCore; const poolParameters = (await withSaveAndVerify( - new PoolParameters__factory(parametersLibraries, await getFirstSigner()), + await getContractFactory("PoolParameters", parametersLibraries), eContractid.PoolParametersImpl, [provider], verify, @@ -866,7 +813,7 @@ export const deployPoolComponents = async ( )) as PoolParameters; const poolMarketplace = (await withSaveAndVerify( - new PoolMarketplace__factory(marketplaceLibraries, await getFirstSigner()), + await getContractFactory("PoolMarketplace", marketplaceLibraries), eContractid.PoolMarketplaceImpl, [provider], verify, @@ -877,20 +824,13 @@ export const deployPoolComponents = async ( const poolApeStaking = allTokens.APE ? ((await withSaveAndVerify( - new PoolApeStaking__factory( - apeStakingLibraries, - await getFirstSigner() - ), + await getContractFactory("PoolApeStaking", apeStakingLibraries), eContractid.PoolApeStakingImpl, [ provider, - (await getAutoCompoundApe()).address, allTokens.APE.address, - allTokens.USDC.address, - (await getUniswapV3SwapRouter()).address, - allTokens.WETH.address, - APE_WETH_FEE, - WETH_USDC_FEE, + (await getAutoCompoundApe()).address, + (await getParaApeStaking()).address, ], verify, false, @@ -913,7 +853,7 @@ export const deployPoolComponents = async ( export const deployPriceOracle = async (verify?: boolean) => withSaveAndVerify( - new PriceOracle__factory(await getFirstSigner()), + await getContractFactory("PriceOracle"), eContractid.PriceOracle, [], verify @@ -925,7 +865,7 @@ export const deployAggregator = async ( verify?: boolean ) => withSaveAndVerify( - new MockAggregator__factory(await getFirstSigner()), + await getContractFactory("MockAggregator"), eContractid.Aggregator.concat(upperFirst(symbol)), [price], verify @@ -943,7 +883,7 @@ export const deployParaSpaceOracle = async ( verify?: boolean ) => withSaveAndVerify( - new ParaSpaceOracle__factory(await getFirstSigner()), + await getContractFactory("ParaSpaceOracle"), eContractid.ParaSpaceOracle, [...args], verify @@ -951,7 +891,7 @@ export const deployParaSpaceOracle = async ( export const deployNFTFloorPriceOracle = async (verify?: boolean) => withSaveAndVerify( - new NFTFloorOracle__factory(await getFirstSigner()), + await getContractFactory("NFTFloorOracle"), eContractid.NFTFloorOracle, [], verify @@ -962,7 +902,7 @@ export const deployProtocolDataProvider = async ( verify?: boolean ) => withSaveAndVerify( - new ProtocolDataProvider__factory(await getFirstSigner()), + await getContractFactory("ProtocolDataProvider"), eContractid.ProtocolDataProvider, [addressesProvider], verify @@ -973,7 +913,7 @@ export const deployMintableERC20 = async ( verify?: boolean ): Promise => withSaveAndVerify( - new MintableERC20__factory(await getFirstSigner()), + await getContractFactory("MintableERC20"), args[1], [...args], verify @@ -984,7 +924,7 @@ export const deployMintableERC721 = async ( verify?: boolean ): Promise => withSaveAndVerify( - new MintableERC721__factory(await getFirstSigner()), + await getContractFactory("MintableERC721"), args[1], [...args], verify @@ -995,7 +935,7 @@ export const deployMintableDelegationERC20 = async ( verify?: boolean ): Promise => withSaveAndVerify( - new MintableDelegationERC20__factory(await getFirstSigner()), + await getContractFactory("MintableDelegationERC20"), eContractid.MintableDelegationERC20, [...args], verify @@ -1006,7 +946,7 @@ export const deployMockReserveAuctionStrategy = async ( verify?: boolean ) => withSaveAndVerify( - new MockReserveAuctionStrategy__factory(await getFirstSigner()), + await getContractFactory("MockReserveAuctionStrategy"), eContractid.MockReserveAuctionStrategy, [...args], verify @@ -1018,7 +958,7 @@ export const deployReserveAuctionStrategy = async ( verify?: boolean ) => withSaveAndVerify( - new DefaultReserveAuctionStrategy__factory(await getFirstSigner()), + await getContractFactory("DefaultReserveAuctionStrategy"), strategyName, [...args], verify @@ -1030,7 +970,7 @@ export const deployReserveInterestRateStrategy = async ( verify?: boolean ) => withSaveAndVerify( - new DefaultReserveInterestRateStrategy__factory(await getFirstSigner()), + await getContractFactory("DefaultReserveInterestRateStrategy"), strategyName, [...args], verify @@ -1041,7 +981,7 @@ export const deployGenericVariableDebtToken = async ( verify?: boolean ) => withSaveAndVerify( - new VariableDebtToken__factory(await getFirstSigner()), + await getContractFactory("VariableDebtToken"), eContractid.VariableDebtTokenImpl, [poolAddress], verify @@ -1052,7 +992,7 @@ export const deployGenericPTokenImpl = async ( verify?: boolean ) => withSaveAndVerify( - new PToken__factory(await getFirstSigner()), + await getContractFactory("PToken"), eContractid.PTokenImpl, [poolAddress], verify @@ -1073,7 +1013,7 @@ export const deployGenericNTokenImpl = async ( mintableERC721Logic, }; return withSaveAndVerify( - new NToken__factory(libraries, await getFirstSigner()), + await getContractFactory("NToken", libraries), eContractid.NTokenImpl, [poolAddress, atomicPricing, delegationRegistry], verify, @@ -1096,7 +1036,7 @@ export const deployUniswapV3NTokenImpl = async ( mintableERC721Logic, }; return withSaveAndVerify( - new NTokenUniswapV3__factory(libraries, await getFirstSigner()), + await getContractFactory("NTokenUniswapV3", libraries), eContractid.NTokenUniswapV3Impl, [poolAddress, delegationRegistry], verify, @@ -1119,7 +1059,7 @@ export const deployGenericMoonbirdNTokenImpl = async ( mintableERC721Logic, }; return withSaveAndVerify( - new NTokenMoonBirds__factory(libraries, await getFirstSigner()), + await getContractFactory("NTokenMoonBirds", libraries), eContractid.NTokenMoonBirdsImpl, [poolAddress, delegationRegistry], verify, @@ -1133,7 +1073,7 @@ export const deployDelegationAwarePTokenImpl = async ( verify?: boolean ) => withSaveAndVerify( - new DelegationAwarePToken__factory(await getFirstSigner()), + await getContractFactory("DelegationAwarePToken"), eContractid.DelegationAwarePTokenImpl, [poolAddress], verify @@ -1168,10 +1108,10 @@ export const deployAllERC20Tokens = async (verify?: boolean) => { // if contract address is already in db, then skip to next tokenSymbol if (contractAddress) { - console.log("contract address is already in db ", tokenSymbol); + console.log("contract address is already in db", tokenSymbol); continue; } else if (tokensConfig[tokenSymbol]) { - console.log("contract address is already in db ", tokenSymbol); + console.log("contract address is already in db", tokenSymbol); await insertContractAddressInDb( tokenSymbol, tokensConfig[tokenSymbol], @@ -1317,10 +1257,10 @@ export const deployAllERC721Tokens = async (verify?: boolean) => { // if contract address is already in db, then skip to next tokenSymbol if (contractAddress) { - console.log("contract address is already in db ", tokenSymbol); + console.log("contract address is already in db", tokenSymbol); continue; } else if (tokensConfig[tokenSymbol]) { - console.log("contract address is already in db ", tokenSymbol); + console.log("contract address is already in db", tokenSymbol); await insertContractAddressInDb( tokenSymbol, tokensConfig[tokenSymbol], @@ -1524,7 +1464,7 @@ export const deployMoonbirds = async ( verify?: boolean ) => withSaveAndVerify( - new Moonbirds__factory(await getFirstSigner()), + await getContractFactory("Moonbirds"), eContractid.MOONBIRD, [...args], verify @@ -1532,7 +1472,7 @@ export const deployMoonbirds = async ( export const deployReservesSetupHelper = async (verify?: boolean) => withSaveAndVerify( - new ReservesSetupHelper__factory(await getFirstSigner()), + await getContractFactory("ReservesSetupHelper"), eContractid.ReservesSetupHelper, [], verify @@ -1543,9 +1483,7 @@ export const deployInitializableImmutableAdminUpgradeabilityProxy = async ( verify?: boolean ) => withSaveAndVerify( - new InitializableImmutableAdminUpgradeabilityProxy__factory( - await getFirstSigner() - ), + await getContractFactory("InitializableImmutableAdminUpgradeabilityProxy"), eContractid.InitializableImmutableAdminUpgradeabilityProxy, [...args], verify @@ -1553,7 +1491,7 @@ export const deployInitializableImmutableAdminUpgradeabilityProxy = async ( export const deployWETH = async (verify?: boolean) => withSaveAndVerify( - new WETH9Mocked__factory(await getFirstSigner()), + await getContractFactory("WETH9Mocked"), eContractid.WETH, [], verify @@ -1565,7 +1503,7 @@ export const deployUiPoolDataProvider = async ( verify?: boolean ) => withSaveAndVerify( - new UiPoolDataProvider__factory(await getFirstSigner()), + await getContractFactory("UiPoolDataProvider"), eContractid.UiPoolDataProvider, [arg1, arg2], verify @@ -1573,7 +1511,7 @@ export const deployUiPoolDataProvider = async ( export const deployUiIncentiveDataProvider = async (verify?: boolean) => withSaveAndVerify( - new UiIncentiveDataProvider__factory(await getFirstSigner()), + await getContractFactory("UiIncentiveDataProvider"), eContractid.UiIncentiveDataProvider, [], verify @@ -1581,7 +1519,7 @@ export const deployUiIncentiveDataProvider = async (verify?: boolean) => export const deployWalletBalanceProvider = async (verify?: boolean) => withSaveAndVerify( - new WalletBalanceProvider__factory(await getFirstSigner()), + await getContractFactory("WalletBalanceProvider"), eContractid.WalletBalanceProvider, [], verify @@ -1593,7 +1531,7 @@ export const deployWETHGateway = async ( verify?: boolean ) => withSaveAndVerify( - new WETHGateway__factory(await getFirstSigner()), + await getContractFactory("WETHGateway"), eContractid.WETHGatewayImpl, [weth, pool], verify @@ -1604,26 +1542,21 @@ export const deployWETHGatewayProxy = async ( wethGateway: string, initData: string, verify?: boolean -) => { - const wethGatewayProxy = - new InitializableImmutableAdminUpgradeabilityProxy__factory( - await getFirstSigner() - ); - return withSaveAndVerify( - wethGatewayProxy, +) => + withSaveAndVerify( + await getContractFactory("InitializableImmutableAdminUpgradeabilityProxy"), eContractid.WETHGatewayProxy, [admin, wethGateway, initData], verify, true ) as Promise; -}; export const deployMeebits = async ( args: [tEthereumAddress, tEthereumAddress, tEthereumAddress], verify?: boolean ) => withSaveAndVerify( - new Meebits__factory(await getFirstSigner()), + await getContractFactory("Meebits"), eContractid.Meebits, [...args], verify @@ -1634,7 +1567,7 @@ export const deployAzuki = async ( verify?: boolean ) => withSaveAndVerify( - new Azuki__factory(await getFirstSigner()), + await getContractFactory("Azuki"), eContractid.Azuki, [...args], verify @@ -1646,7 +1579,7 @@ export const deployOTHR = async ( verify?: boolean ) => withSaveAndVerify( - new Land__factory(await getFirstSigner()), + await getContractFactory("Land"), eContractid.OTHR, [...args], verify @@ -1654,7 +1587,7 @@ export const deployOTHR = async ( export const deployCloneX = async (args: [], verify?: boolean) => withSaveAndVerify( - new CloneX__factory(await getFirstSigner()), + await getContractFactory("CloneX"), eContractid.CloneX, [...args], verify @@ -1665,7 +1598,7 @@ export const deploySewerPass = async ( verify?: boolean ) => withSaveAndVerify( - new BAYCSewerPass__factory(await getFirstSigner()), + await getContractFactory("BAYCSewerPass"), eContractid.SEWER, [...args], verify @@ -1673,7 +1606,7 @@ export const deploySewerPass = async ( export const deployDoodle = async (args: [], verify?: boolean) => withSaveAndVerify( - new Doodles__factory(await getFirstSigner()), + await getContractFactory("Doodles"), eContractid.Doodles, [...args], verify @@ -1684,7 +1617,7 @@ export const deployMAYC = async ( verify?: boolean ) => withSaveAndVerify( - new MutantApeYachtClub__factory(await getFirstSigner()), + await getContractFactory("MutantApeYachtClub"), eContractid.MutantApeYachtClub, [...args], verify @@ -1695,7 +1628,7 @@ export const deployBAYC = async ( verify?: boolean ) => withSaveAndVerify( - new BoredApeYachtClub__factory(await getFirstSigner()), + await getContractFactory("BoredApeYachtClub"), eContractid.BoredApeYachtClub, [...args], verify @@ -1709,15 +1642,30 @@ export const deployERC721OracleWrapper = async ( verify?: boolean ) => withSaveAndVerify( - new ERC721OracleWrapper__factory(await getFirstSigner()), + await getContractFactory("ERC721OracleWrapper"), eContractid.Aggregator.concat(upperFirst(symbol)), [addressesProvider, oracleAddress, asset], verify ) as Promise; +export const deployERC20OracleWrapper = async ( + pyth: string, + feedId: string, + expirationPeriod: string, + decimals: string, + symbol: string, + verify?: boolean +) => + withSaveAndVerify( + await getContractFactory("ERC20OracleWrapper"), + eContractid.Aggregator.concat(upperFirst(symbol)), + [pyth, feedId, expirationPeriod, decimals], + verify + ) as Promise; + export const deployPunks = async (args: [], verify?: boolean) => withSaveAndVerify( - new CryptoPunksMarket__factory(await getFirstSigner()), + await getContractFactory("CryptoPunksMarket"), eContractid.PUNKS, [...args], verify @@ -1728,7 +1676,7 @@ export const deployWPunks = async ( verify?: boolean ) => withSaveAndVerify( - new WPunk__factory(await getFirstSigner()), + await getContractFactory("WPunk"), eContractid.WPunk, [...args], verify @@ -1743,7 +1691,7 @@ export const deployPunkGateway = async ( ], verify?: boolean ) => { - const punkImpl = new WPunkGateway__factory(await getFirstSigner()); + const punkImpl = await getContractFactory("WPunkGateway"); return withSaveAndVerify( punkImpl, eContractid.WPunkGatewayImpl, @@ -1757,25 +1705,20 @@ export const deployPunkGatewayProxy = async ( punkGateway: string, initData: string, verify?: boolean -) => { - const punkGatewayProxy = - new InitializableImmutableAdminUpgradeabilityProxy__factory( - await getFirstSigner() - ); - return withSaveAndVerify( - punkGatewayProxy, +) => + withSaveAndVerify( + await getContractFactory("InitializableImmutableAdminUpgradeabilityProxy"), eContractid.WPunkGatewayProxy, [admin, punkGateway, initData], verify, true ) as Promise; -}; export const deploySeaportAdapter = async ( provider: tEthereumAddress, verify?: boolean ) => { - const seaportAdapter = new SeaportAdapter__factory(await getFirstSigner()); + const seaportAdapter = await getContractFactory("SeaportAdapter"); return withSaveAndVerify( seaportAdapter, @@ -1789,24 +1732,19 @@ export const deployLooksRareAdapter = async ( provider: tEthereumAddress, strategy: tEthereumAddress, verify?: boolean -) => { - const looksRareAdapter = new LooksRareAdapter__factory( - await getFirstSigner() - ); - - return withSaveAndVerify( - looksRareAdapter, +) => + withSaveAndVerify( + await getContractFactory("LooksRareAdapter"), eContractid.LooksRareAdapter, [provider, strategy], verify ) as Promise; -}; export const deployX2Y2Adapter = async ( provider: tEthereumAddress, verify?: boolean ) => { - const x2y2Adapter = new X2Y2Adapter__factory(await getFirstSigner()); + const x2y2Adapter = await getContractFactory("X2Y2Adapter"); return withSaveAndVerify( x2y2Adapter, @@ -1817,12 +1755,12 @@ export const deployX2Y2Adapter = async ( }; export const deployMarketplaceLogic = async ( - libraries: MarketplaceLogicLibraryAddresses, + libraries: Libraries, verify?: boolean ) => { - const marketplaceLogic = new MarketplaceLogic__factory( - libraries, - await getFirstSigner() + const marketplaceLogic = await getContractFactory( + "MarketplaceLogic", + libraries ); return withSaveAndVerify( @@ -1837,7 +1775,7 @@ export const deployMarketplaceLogic = async ( export const deployConduitController = async (verify?: boolean) => withSaveAndVerify( - new ConduitController__factory(await getFirstSigner()), + await getContractFactory("ConduitController"), eContractid.ConduitController, [], verify @@ -1848,7 +1786,7 @@ export const deployPausableZoneController = async ( verify?: boolean ) => withSaveAndVerify( - new PausableZoneController__factory(await getFirstSigner()), + await getContractFactory("PausableZoneController"), eContractid.PausableZoneController, [owner], verify @@ -1859,7 +1797,7 @@ export const deploySeaport = async ( verify?: boolean ) => withSaveAndVerify( - new Seaport__factory(await getFirstSigner()), + await getContractFactory("Seaport"), eContractid.Seaport, [conduitController], verify @@ -1867,7 +1805,7 @@ export const deploySeaport = async ( export const deployCurrencyManager = async (verify?: boolean) => withSaveAndVerify( - new CurrencyManager__factory(await getFirstSigner()), + await getContractFactory("CurrencyManager"), eContractid.CurrencyManager, [], verify @@ -1875,7 +1813,7 @@ export const deployCurrencyManager = async (verify?: boolean) => export const deployExecutionManager = async (verify?: boolean) => withSaveAndVerify( - new ExecutionManager__factory(await getFirstSigner()), + await getContractFactory("ExecutionManager"), eContractid.ExecutionManager, [], verify @@ -1890,7 +1828,7 @@ export const deployLooksRareExchange = async ( verify?: boolean ) => withSaveAndVerify( - new LooksRareExchange__factory(await getFirstSigner()), + await getContractFactory("LooksRareExchange"), eContractid.LooksRareExchange, [ currencyManager, @@ -1907,7 +1845,7 @@ export const deployRoyaltyFeeManager = async ( verify?: boolean ) => withSaveAndVerify( - new RoyaltyFeeManager__factory(await getFirstSigner()), + await getContractFactory("RoyaltyFeeManager"), eContractid.RoyaltyFeeManager, [royaltyFeeRegistry], verify @@ -1918,7 +1856,7 @@ export const deployRoyaltyFeeRegistry = async ( verify?: boolean ) => withSaveAndVerify( - new RoyaltyFeeRegistry__factory(await getFirstSigner()), + await getContractFactory("RoyaltyFeeRegistry"), eContractid.RoyaltyFeeRegistry, [royaltyFeeLimit], verify @@ -1930,7 +1868,7 @@ export const deployTransferSelectorNFT = async ( verify?: boolean ) => withSaveAndVerify( - new TransferSelectorNFT__factory(await getFirstSigner()), + await getContractFactory("TransferSelectorNFT"), eContractid.TransferSelectorNFT, [transferManagerERC721, transferManagerERC1155], verify @@ -1941,7 +1879,7 @@ export const deployTransferManagerERC721 = async ( verify?: boolean ) => withSaveAndVerify( - new TransferManagerERC721__factory(await getFirstSigner()), + await getContractFactory("TransferManagerERC721"), eContractid.TransferManagerERC721, [looksRareExchange], verify @@ -1952,7 +1890,7 @@ export const deployTransferManagerERC1155 = async ( verify?: boolean ) => withSaveAndVerify( - new TransferManagerERC1155__factory(await getFirstSigner()), + await getContractFactory("TransferManagerERC1155"), eContractid.TransferManagerERC1155, [looksRareExchange], verify @@ -1963,7 +1901,7 @@ export const deployStrategyStandardSaleForFixedPrice = async ( verify?: boolean ) => withSaveAndVerify( - new StrategyStandardSaleForFixedPrice__factory(await getFirstSigner()), + await getContractFactory("StrategyStandardSaleForFixedPrice"), eContractid.StrategyStandardSaleForFixedPrice, [protocolFee], verify @@ -1971,7 +1909,7 @@ export const deployStrategyStandardSaleForFixedPrice = async ( export const deployX2Y2R1 = async (verify?: boolean) => withSaveAndVerify( - new X2Y2R1__factory(await getFirstSigner()), + await getContractFactory("X2Y2R1"), eContractid.X2Y2R1, [], verify @@ -1979,34 +1917,32 @@ export const deployX2Y2R1 = async (verify?: boolean) => export const deployERC721Delegate = async (verify?: boolean) => withSaveAndVerify( - new ERC721Delegate__factory(await getFirstSigner()), + await getContractFactory("ERC721Delegate"), eContractid.ERC721Delegate, [], verify ) as Promise; -export const deployUniswapV3Factory = async (args: [], verify?: boolean) => { - const uniswapV3Factory = new UniswapV3Factory__factory( - await getFirstSigner() - ); - return withSaveAndVerify( - uniswapV3Factory, +export const deployUniswapV3Factory = async (args: [], verify?: boolean) => + withSaveAndVerify( + await getContractFactory("UniswapV3Factory"), eContractid.UniswapV3Factory, [...args], verify ) as Promise; -}; export const deployNonfungibleTokenPositionDescriptor = async ( args: [string, string], verify?: boolean ) => { - const nFTDescriptorFactory = ( - await DRE.ethers.getContractFactoryFromArtifact(nFTDescriptor) - ).connect(await getFirstSigner()); - const nftDescriptorLibraryContract = await withSaveAndVerify( - nFTDescriptorFactory, + { + artifact: nFTDescriptor, + factory: ( + await DRE.ethers.getContractFactoryFromArtifact(nFTDescriptor) + ).connect(await getFirstSigner()), + customData: undefined, + }, eContractid.NFTDescriptor, [], verify @@ -2014,17 +1950,20 @@ export const deployNonfungibleTokenPositionDescriptor = async ( const libraries = { NFTDescriptor: nftDescriptorLibraryContract.address, }; - const nonfungibleTokenPositionDescriptorFactory = ( - await DRE.ethers.getContractFactoryFromArtifact( - nonfungibleTokenPositionDescriptor, - { - libraries, - } - ) - ).connect(await getFirstSigner()); return withSaveAndVerify( - nonfungibleTokenPositionDescriptorFactory, + { + artifact: nonfungibleTokenPositionDescriptor, + factory: ( + await DRE.ethers.getContractFactoryFromArtifact( + nonfungibleTokenPositionDescriptor, + { + libraries, + } + ) + ).connect(await getFirstSigner()), + customData: undefined, + }, eContractid.NonfungibleTokenPositionDescriptor, [...args], verify, @@ -2040,7 +1979,7 @@ export const deployUniswapV3OracleWrapper = async ( verify?: boolean ) => withSaveAndVerify( - new UniswapV3OracleWrapper__factory(await getFirstSigner()), + await getContractFactory("UniswapV3OracleWrapper"), eContractid.Aggregator.concat(upperFirst(eContractid.UniswapV3)), [factory, manager, addressProvider], verify @@ -2054,7 +1993,7 @@ export const deployUniswapV3TwapOracleWrapper = async ( verify?: boolean ) => withSaveAndVerify( - new UniswapV3TwapOracleWrapper__factory(await getFirstSigner()), + await getContractFactory("UniswapV3TwapOracleWrapper"), eContractid.Aggregator.concat(upperFirst(symbol)), [pool, baseCurrency, twapWindow], verify @@ -2063,38 +2002,28 @@ export const deployUniswapV3TwapOracleWrapper = async ( export const deployNonfungiblePositionManager = async ( args: [string, string, string], verify?: boolean -) => { - const nonfungiblePositionManagerFactory = ( - await DRE.ethers.getContractFactoryFromArtifact(nonfungiblePositionManager) - ).connect(await getFirstSigner()); - - return withSaveAndVerify( - nonfungiblePositionManagerFactory, +) => + withSaveAndVerify( + await getContractFactory("NonfungiblePositionManager"), eContractid.UniswapV3, [...args], verify ); -}; export const deployUniswapSwapRouter = async ( args: [string, string], verify?: boolean -) => { - const swapRouter = ( - await DRE.ethers.getContractFactoryFromArtifact(uniSwapRouter) - ).connect(await getFirstSigner()); - - return withSaveAndVerify( - swapRouter, +) => + withSaveAndVerify( + await getContractFactory("SwapRouter"), eContractid.UniswapV3SwapRouter, [...args], verify ); -}; export const deployStETH = async (verify?: boolean): Promise => withSaveAndVerify( - new StETHMocked__factory(await getFirstSigner()), + await getContractFactory("StETHMocked"), eContractid.StETH, [], verify @@ -2105,7 +2034,7 @@ export const deployWStETH = async ( verify?: boolean ): Promise => withSaveAndVerify( - new WstETHMocked__factory(await getFirstSigner()), + await getContractFactory("WstETHMocked"), eContractid.WStETH, [stETHAddress], verify @@ -2116,7 +2045,7 @@ export const deployMockAToken = async ( verify?: boolean ): Promise => withSaveAndVerify( - new MockAToken__factory(await getFirstSigner()), + await getContractFactory("MockAToken"), args[1], [...args], verify @@ -2127,7 +2056,7 @@ export const deployMockCToken = async ( verify?: boolean ): Promise => withSaveAndVerify( - new MockCToken__factory(await getFirstSigner()), + await getContractFactory("MockCToken"), args[1], [...args], verify @@ -2138,7 +2067,7 @@ export const deployMockAStETH = async ( verify?: boolean ): Promise => withSaveAndVerify( - new MockAStETH__factory(await getFirstSigner()), + await getContractFactory("MockAStETH"), args[1], [...args], verify @@ -2149,7 +2078,7 @@ export const deployMockRETH = async ( verify?: boolean ): Promise => withSaveAndVerify( - new MockRETH__factory(await getFirstSigner()), + await getContractFactory("MockRETH"), args[1], [...args], verify @@ -2160,7 +2089,7 @@ export const deployPTokenAToken = async ( verify?: boolean ) => withSaveAndVerify( - new PTokenAToken__factory(await getFirstSigner()), + await getContractFactory("PTokenAToken"), eContractid.PTokenATokenImpl, [poolAddress], verify @@ -2171,18 +2100,29 @@ export const deployPTokenStETH = async ( verify?: boolean ) => withSaveAndVerify( - new PTokenStETH__factory(await getFirstSigner()), + await getContractFactory("PTokenStETH"), eContractid.PTokenStETHImpl, [poolAddress], verify ) as Promise; +export const deployPTokenStKSM = async ( + poolAddress: tEthereumAddress, + verify?: boolean +) => + withSaveAndVerify( + await getContractFactory("PTokenStKSM"), + eContractid.PTokenStKSMImpl, + [poolAddress], + verify + ) as Promise; + export const deployPTokenAStETH = async ( poolAddress: tEthereumAddress, verify?: boolean ) => withSaveAndVerify( - new PTokenAStETH__factory(await getFirstSigner()), + await getContractFactory("PTokenAStETH"), eContractid.PTokenAStETHImpl, [poolAddress], verify @@ -2190,26 +2130,23 @@ export const deployPTokenAStETH = async ( export const deployPTokenSApe = async ( poolAddress: tEthereumAddress, - nBAYC: tEthereumAddress, - nMAYC: tEthereumAddress, verify?: boolean ) => withSaveAndVerify( - new PTokenSApe__factory(await getFirstSigner()), + await getContractFactory("PTokenSApe"), eContractid.PTokenSApeImpl, - [poolAddress, nBAYC, nMAYC], + [poolAddress], verify ) as Promise; export const deployUserFlashClaimRegistry = async ( - poolAddress: tEthereumAddress, receiverImpl: tEthereumAddress, verify?: boolean ) => withSaveAndVerify( - new UserFlashclaimRegistry__factory(await getFirstSigner()), + await getContractFactory("UserFlashclaimRegistry"), eContractid.FlashClaimRegistry, - [poolAddress, receiverImpl], + [receiverImpl], verify ) as Promise; @@ -2219,18 +2156,14 @@ export const deployUserFlashClaimRegistryProxy = async ( // eslint-disable-next-line initData: any, verify?: boolean -) => { - const proxy = new InitializableImmutableAdminUpgradeabilityProxy__factory( - await getFirstSigner() - ); - return withSaveAndVerify( - proxy, +) => + withSaveAndVerify( + await getContractFactory("InitializableImmutableAdminUpgradeabilityProxy"), eContractid.UserFlashClaimRegistryProxy, [admin, registryImpl, initData], verify, true ) as Promise; -}; export const deployBAYCSewerPassClaim = async ( bayc: string, @@ -2242,7 +2175,7 @@ export const deployBAYCSewerPassClaim = async ( const deployer = await getFirstSigner(); const deployerAddress = await deployer.getAddress(); const baycSewerPassClaim = await withSaveAndVerify( - new BAYCSewerPassClaim__factory(await getFirstSigner()), + await getContractFactory("BAYCSewerPassClaim"), eContractid.BAYCSewerPassClaim, [bayc, mayc, bakc, sewerPass, deployerAddress], verify @@ -2268,7 +2201,7 @@ export const deployAirdropFlashClaimReceiver = async ( verify?: boolean ) => withSaveAndVerify( - new AirdropFlashClaimReceiver__factory(await getFirstSigner()), + await getContractFactory("AirdropFlashClaimReceiver"), eContractid.AirdropFlashClaimReceiver, [poolAddress], verify @@ -2279,7 +2212,7 @@ export const deployMockAirdropProject = async ( verify?: boolean ) => withSaveAndVerify( - new MockAirdropProject__factory(await getFirstSigner()), + await getContractFactory("MockAirdropProject"), eContractid.MockAirdropProject, [underlyingAddress], verify @@ -2291,7 +2224,7 @@ export const deployMockMultiAssetAirdropProject = async ( verify?: boolean ) => withSaveAndVerify( - new MockMultiAssetAirdropProject__factory(await getFirstSigner()), + await getContractFactory("MockMultiAssetAirdropProject"), eContractid.MockMultiAssetAirdropProject, [underlyingAddress1, underlyingAddress2], verify @@ -2307,7 +2240,7 @@ export const deployApeCoinStaking = async (verify?: boolean) => { ]; const apeCoinStaking = await withSaveAndVerify( - new ApeCoinStaking__factory(await getFirstSigner()), + await getContractFactory("ApeCoinStaking"), eContractid.ApeCoinStaking, [...args], verify @@ -2346,45 +2279,31 @@ export const deployApeCoinStaking = async (verify?: boolean) => { amount, "1666771200", "1761465600", - parseEther("100000"), + parseEther("50000"), GLOBAL_OVERRIDES ); return apeCoinStaking; }; -export const deployApeStakingLogic = async (verify?: boolean) => { - return withSaveAndVerify( - new ApeStakingLogic__factory(await getFirstSigner()), - eContractid.ApeStakingLogic, - [], - verify - ) as Promise; -}; - export const deployNTokenBAYCImpl = async ( apeCoinStaking: tEthereumAddress, poolAddress: tEthereumAddress, delegationRegistry: tEthereumAddress, verify?: boolean ) => { - const apeStakingLogic = - (await getContractAddressInDb(eContractid.ApeStakingLogic)) || - (await deployApeStakingLogic(verify)).address; const mintableERC721Logic = (await getContractAddressInDb(eContractid.MintableERC721Logic)) || (await deployMintableERC721Logic(verify)).address; const libraries = { - ["contracts/protocol/tokenization/libraries/ApeStakingLogic.sol:ApeStakingLogic"]: - apeStakingLogic, ["contracts/protocol/tokenization/libraries/MintableERC721Logic.sol:MintableERC721Logic"]: mintableERC721Logic, }; return withSaveAndVerify( - new NTokenBAYC__factory(libraries, await getFirstSigner()), + await getContractFactory("NTokenBAYC", libraries), eContractid.NTokenBAYCImpl, - [poolAddress, apeCoinStaking, delegationRegistry], + [poolAddress, delegationRegistry], verify, false, libraries @@ -2397,23 +2316,18 @@ export const deployNTokenMAYCImpl = async ( delegationRegistry: tEthereumAddress, verify?: boolean ) => { - const apeStakingLogic = - (await getContractAddressInDb(eContractid.ApeStakingLogic)) || - (await deployApeStakingLogic(verify)).address; const mintableERC721Logic = (await getContractAddressInDb(eContractid.MintableERC721Logic)) || (await deployMintableERC721Logic(verify)).address; const libraries = { - ["contracts/protocol/tokenization/libraries/ApeStakingLogic.sol:ApeStakingLogic"]: - apeStakingLogic, ["contracts/protocol/tokenization/libraries/MintableERC721Logic.sol:MintableERC721Logic"]: mintableERC721Logic, }; return withSaveAndVerify( - new NTokenMAYC__factory(libraries, await getFirstSigner()), + await getContractFactory("NTokenMAYC", libraries), eContractid.NTokenMAYCImpl, - [poolAddress, apeCoinStaking, delegationRegistry], + [poolAddress, delegationRegistry], verify, false, libraries @@ -2422,9 +2336,6 @@ export const deployNTokenMAYCImpl = async ( export const deployNTokenBAKCImpl = async ( poolAddress: tEthereumAddress, - apeCoinStaking: tEthereumAddress, - nBAYC: tEthereumAddress, - nMAYC: tEthereumAddress, delegationRegistry: tEthereumAddress, verify?: boolean ) => { @@ -2436,9 +2347,9 @@ export const deployNTokenBAKCImpl = async ( mintableERC721Logic, }; return withSaveAndVerify( - new NTokenBAKC__factory(libraries, await getFirstSigner()), + await getContractFactory("NTokenBAKC", libraries), eContractid.NTokenBAKCImpl, - [poolAddress, apeCoinStaking, nBAYC, nMAYC, delegationRegistry], + [poolAddress, delegationRegistry], verify, false, libraries @@ -2450,7 +2361,7 @@ export const deployATokenDebtToken = async ( verify?: boolean ) => withSaveAndVerify( - new ATokenDebtToken__factory(await getFirstSigner()), + await getContractFactory("ATokenDebtToken"), eContractid.ATokenDebtToken, [poolAddress], verify @@ -2461,18 +2372,29 @@ export const deployStETHDebtToken = async ( verify?: boolean ) => withSaveAndVerify( - new StETHDebtToken__factory(await getFirstSigner()), + await getContractFactory("StETHDebtToken"), eContractid.StETHDebtToken, [poolAddress], verify ) as Promise; +export const deployStKSMDebtToken = async ( + poolAddress: tEthereumAddress, + verify?: boolean +) => + withSaveAndVerify( + await getContractFactory("StKSMDebtToken"), + eContractid.StKSMDebtToken, + [poolAddress], + verify + ) as Promise; + export const deployAStETHDebtToken = async ( poolAddress: tEthereumAddress, verify?: boolean ) => withSaveAndVerify( - new AStETHDebtToken__factory(await getFirstSigner()), + await getContractFactory("AStETHDebtToken"), eContractid.AStETHDebtToken, [poolAddress], verify @@ -2480,7 +2402,7 @@ export const deployAStETHDebtToken = async ( export const deployMintableERC721Logic = async (verify?: boolean) => { return withSaveAndVerify( - new MintableERC721Logic__factory(await getFirstSigner()), + await getContractFactory("MintableERC721Logic"), eContractid.MintableERC721Logic, [], verify @@ -2489,7 +2411,7 @@ export const deployMintableERC721Logic = async (verify?: boolean) => { export const deployMerkleVerifier = async (verify?: boolean) => withSaveAndVerify( - new MerkleVerifier__factory(await getFirstSigner()), + await getContractFactory("MerkleVerifier"), eContractid.MerkleVerifier, [], verify @@ -2497,7 +2419,7 @@ export const deployMerkleVerifier = async (verify?: boolean) => export const deployExecutionDelegate = async (verify?: boolean) => withSaveAndVerify( - new ExecutionDelegate__factory(await getFirstSigner()), + await getContractFactory("ExecutionDelegate"), eContractid.ExecutionDelegate, [], verify @@ -2505,7 +2427,7 @@ export const deployExecutionDelegate = async (verify?: boolean) => export const deployPolicyManager = async (verify?: boolean) => withSaveAndVerify( - new PolicyManager__factory(await getFirstSigner()), + await getContractFactory("PolicyManager"), eContractid.PolicyManager, [], verify @@ -2513,7 +2435,7 @@ export const deployPolicyManager = async (verify?: boolean) => export const deployStandardPolicyERC721 = async (verify?: boolean) => withSaveAndVerify( - new StandardPolicyERC721__factory(await getFirstSigner()), + await getContractFactory("StandardPolicyERC721"), eContractid.StandardPolicyERC721, [], verify @@ -2525,9 +2447,9 @@ export const deployBlurExchangeImpl = async (verify?: boolean) => { ["contracts/dependencies/blur-exchange/MerkleVerifier.sol:MerkleVerifier"]: merkleVerifier.address, }; - const blurExchange = new BlurExchange__factory( - blurExchangeLibraries, - await getFirstSigner() + const blurExchange = await getContractFactory( + "BlurExchange", + blurExchangeLibraries ); return withSaveAndVerify( @@ -2546,12 +2468,8 @@ export const deployBlurExchangeProxy = async ( initData: string, verify?: boolean ) => { - const blurExchangeProxy = - new InitializableImmutableAdminUpgradeabilityProxy__factory( - await getFirstSigner() - ); return withSaveAndVerify( - blurExchangeProxy, + await getContractFactory("InitializableImmutableAdminUpgradeabilityProxy"), eContractid.BlurExchangeProxy, [admin, blurExchange, initData], verify, @@ -2565,7 +2483,7 @@ export const deployBlurAdapter = async ( verify?: boolean ) => { return withSaveAndVerify( - new BlurAdapter__factory(await getFirstSigner()), + await getContractFactory("BlurAdapter"), eContractid.BlurAdapter, [provider, policy], verify @@ -2577,7 +2495,7 @@ export const deployTimeLockExecutor = async ( verify?: boolean ) => { return withSaveAndVerify( - new ExecutorWithTimelock__factory(await getFirstSigner()), + await getContractFactory("ExecutorWithTimelock"), eContractid.TimeLockExecutor, [...args], verify @@ -2593,7 +2511,7 @@ export const deployAutoCompoundApeImpl = async (verify?: boolean) => { const args = [allTokens.APE.address, apeCoinStaking, aclManager.address]; return withSaveAndVerify( - new AutoCompoundApe__factory(await getFirstSigner()), + await getContractFactory("AutoCompoundApe"), eContractid.cAPEImpl, [...args], verify @@ -2602,7 +2520,7 @@ export const deployAutoCompoundApeImpl = async (verify?: boolean) => { export const deployAutoCompoundApeProxy = async (verify?: boolean) => { const proxyInstance = await withSaveAndVerify( - new InitializableAdminUpgradeabilityProxy__factory(await getFirstSigner()), + await getContractFactory("InitializableAdminUpgradeabilityProxy"), eContractid.cAPE, [], verify @@ -2638,10 +2556,60 @@ export const deployAutoCompoundApeImplAndAssignItToProxy = async ( ); }; -export const deployP2PPairStakingImpl = async ( - compoundFee: number, +export const deployApeStakingP2PLogic = async (verify?: boolean) => + withSaveAndVerify( + await getContractFactory("ApeStakingP2PLogic"), + eContractid.ApeStakingP2PLogic, + [], + verify + ) as Promise; + +export const deployApeStakingPairPoolLogic = async (verify?: boolean) => + withSaveAndVerify( + await getContractFactory("ApeStakingPairPoolLogic"), + eContractid.ApeStakingPairPoolLogic, + [], + verify + ) as Promise; + +export const deployApeStakingSinglePoolLogic = async (verify?: boolean) => + withSaveAndVerify( + await getContractFactory("ApeStakingSinglePoolLogic"), + eContractid.ApeStakingSinglePoolLogic, + [], + verify + ) as Promise; + +export const deployApeStakingApeCoinPoolLogic = async (verify?: boolean) => + withSaveAndVerify( + await getContractFactory("ApeCoinPoolLogic"), + eContractid.ApeStakingApeCoinPoolLogic, + [], + verify + ) as Promise; + +export const deployParaApeStakingLibraries = async ( verify?: boolean -) => { +): Promise => { + const p2pLogic = await deployApeStakingP2PLogic(verify); + const pairPoolLogic = await deployApeStakingPairPoolLogic(verify); + const singlePoolLogic = await deployApeStakingSinglePoolLogic(verify); + const apeCoinPoolLogic = await deployApeStakingApeCoinPoolLogic(verify); + + return { + ["contracts/apestaking/logic/ApeStakingP2PLogic.sol:ApeStakingP2PLogic"]: + p2pLogic.address, + ["contracts/apestaking/logic/ApeStakingPairPoolLogic.sol:ApeStakingPairPoolLogic"]: + pairPoolLogic.address, + ["contracts/apestaking/logic/ApeStakingSinglePoolLogic.sol:ApeStakingSinglePoolLogic"]: + singlePoolLogic.address, + ["contracts/apestaking/logic/ApeCoinPoolLogic.sol:ApeCoinPoolLogic"]: + apeCoinPoolLogic.address, + }; +}; + +export const deployParaApeStakingImpl = async (verify?: boolean) => { + const poolProxy = await getPoolProxy(); const allTokens = await getAllTokens(); const protocolDataProvider = await getProtocolDataProvider(); const nBAYC = ( @@ -2658,6 +2626,7 @@ export const deployP2PPairStakingImpl = async ( (await deployApeCoinStaking(verify)).address; const aclManager = await getACLManager(); const args = [ + poolProxy.address, allTokens.BAYC.address, allTokens.MAYC.address, allTokens.BAKC.address, @@ -2668,39 +2637,44 @@ export const deployP2PPairStakingImpl = async ( allTokens.cAPE.address, apeCoinStaking, aclManager.address, - compoundFee, ]; + const libraries = await deployParaApeStakingLibraries(verify); + return withSaveAndVerify( - new P2PPairStaking__factory(await getFirstSigner()), - eContractid.P2PPairStakingImpl, + await getContractFactory("ParaApeStaking", libraries), + eContractid.ParaApeStakingImpl, [...args], verify - ) as Promise; + ) as Promise; }; -export const deployP2PPairStaking = async (verify?: boolean) => { - const p2pImplementation = await deployP2PPairStakingImpl(0, verify); - - const deployer = await getFirstSigner(); - const deployerAddress = await deployer.getAddress(); - - const initData = p2pImplementation.interface.encodeFunctionData("initialize"); - +export const deployParaApeStaking = async ( + fakeImplementation: boolean, + verify?: boolean +) => { const proxyInstance = await withSaveAndVerify( - new InitializableAdminUpgradeabilityProxy__factory(await getFirstSigner()), - eContractid.P2PPairStaking, + await getContractFactory("InitializableAdminUpgradeabilityProxy"), + eContractid.ParaApeStaking, [], verify ); + if (!fakeImplementation) { + const paraApeStakingImpl = await deployParaApeStakingImpl(verify); + + const deployer = await getFirstSigner(); + const deployerAddress = await deployer.getAddress(); + const initData = + paraApeStakingImpl.interface.encodeFunctionData("initialize"); + + await waitForTx( + await (proxyInstance as InitializableAdminUpgradeabilityProxy)[ + "initialize(address,address,bytes)" + ](paraApeStakingImpl.address, deployerAddress, initData, GLOBAL_OVERRIDES) + ); + } - await waitForTx( - await (proxyInstance as InitializableAdminUpgradeabilityProxy)[ - "initialize(address,address,bytes)" - ](p2pImplementation.address, deployerAddress, initData, GLOBAL_OVERRIDES) - ); - - return await getP2PPairStaking(proxyInstance.address); + return await getParaApeStaking(proxyInstance.address); }; export const deployAutoYieldApeImpl = async (verify?: boolean) => { @@ -2721,7 +2695,7 @@ export const deployAutoYieldApeImpl = async (verify?: boolean) => { ]; return withSaveAndVerify( - new AutoYieldApe__factory(await getFirstSigner()), + await getContractFactory("AutoYieldApe"), eContractid.yAPEImpl, [...args], verify @@ -2730,7 +2704,7 @@ export const deployAutoYieldApeImpl = async (verify?: boolean) => { export const deployAutoYieldApeProxy = async (verify?: boolean) => { const proxyInstance = await withSaveAndVerify( - new InitializableAdminUpgradeabilityProxy__factory(await getFirstSigner()), + await getContractFactory("InitializableAdminUpgradeabilityProxy"), eContractid.yAPE, [], verify @@ -2781,7 +2755,7 @@ export const deployHelperContractImpl = async (verify?: boolean) => { ]; return withSaveAndVerify( - new HelperContract__factory(await getFirstSigner()), + await getContractFactory("HelperContract"), eContractid.HelperContractImpl, [...args], verify @@ -2798,7 +2772,7 @@ export const deployHelperContract = async (verify?: boolean) => { helperImplementation.interface.encodeFunctionData("initialize"); const proxyInstance = await withSaveAndVerify( - new InitializableAdminUpgradeabilityProxy__factory(await getFirstSigner()), + await getContractFactory("InitializableAdminUpgradeabilityProxy"), eContractid.HelperContract, [], verify @@ -2818,7 +2792,7 @@ export const deployPTokenCApe = async ( verify?: boolean ) => withSaveAndVerify( - new PTokenCApe__factory(await getFirstSigner()), + await getContractFactory("PTokenCApe"), eContractid.PTokenCApeImpl, [poolAddress], verify @@ -2829,7 +2803,7 @@ export const deployCApeDebtToken = async ( verify?: boolean ) => withSaveAndVerify( - new CApeDebtToken__factory(await getFirstSigner()), + await getContractFactory("CApeDebtToken"), eContractid.CApeDebtToken, [poolAddress], verify @@ -2840,7 +2814,7 @@ export const deployPYieldToken = async ( verify?: boolean ) => withSaveAndVerify( - new PYieldToken__factory(await getFirstSigner()), + await getContractFactory("PYieldToken"), eContractid.PYieldTokenImpl, [poolAddress], verify @@ -2853,7 +2827,7 @@ export const deployCLwstETHSynchronicityPriceAdapter = async ( verify?: boolean ) => withSaveAndVerify( - new CLwstETHSynchronicityPriceAdapter__factory(await getFirstSigner()), + await getContractFactory("CLwstETHSynchronicityPriceAdapter"), eContractid.Aggregator.concat(upperFirst(eContractid.WStETH)), [stETHAggregator, stETH, decimals], verify @@ -2865,9 +2839,7 @@ export const deployExchangeRateSynchronicityPriceAdapter = async ( verify?: boolean ) => withSaveAndVerify( - new CLExchangeRateSynchronicityPriceAdapter__factory( - await getFirstSigner() - ), + await getContractFactory("CLExchangeRateSynchronicityPriceAdapter"), eContractid.Aggregator.concat(upperFirst(symbol)), [asset], verify @@ -2879,7 +2851,7 @@ export const deployCTokenSynchronicityPriceAdapter = async ( verify?: boolean ) => withSaveAndVerify( - new CLCETHSynchronicityPriceAdapter__factory(await getFirstSigner()), + await getContractFactory("CLCETHSynchronicityPriceAdapter"), eContractid.Aggregator.concat(upperFirst(symbol)), [asset], verify @@ -2891,7 +2863,7 @@ export const deployFixedPriceSynchronicityPriceAdapter = async ( verify?: boolean ) => withSaveAndVerify( - new CLFixedPriceSynchronicityPriceAdapter__factory(await getFirstSigner()), + await getContractFactory("CLFixedPriceSynchronicityPriceAdapter"), eContractid.Aggregator.concat(upperFirst(symbol)), [fixedPrice], verify @@ -2903,7 +2875,7 @@ export const deployParaSpaceAirdrop = async ( verify?: boolean ) => withSaveAndVerify( - new ParaSpaceAirdrop__factory(await getFirstSigner()), + await getContractFactory("ParaSpaceAirdrop"), eContractid.ParaSpaceAirdrop, [token, deadline], verify @@ -2916,7 +2888,7 @@ export const deployTimeLockImpl = async ( const allTokens = await getAllTokens(); const wPunks = allTokens.WPUNKS?.address || ZERO_ADDRESS; const instance = await withSaveAndVerify( - new TimeLock__factory(await getFirstSigner()), + await getContractFactory("TimeLock"), eContractid.TimeLockImpl, [provider, wPunks], verify @@ -2926,7 +2898,7 @@ export const deployTimeLockImpl = async ( export const deployTimeLockProxy = async (verify?: boolean) => { const proxyInstance = await withSaveAndVerify( - new InitializableAdminUpgradeabilityProxy__factory(await getFirstSigner()), + await getContractFactory("InitializableAdminUpgradeabilityProxy"), eContractid.TimeLockProxy, [], verify @@ -2976,7 +2948,7 @@ export const deployReserveTimeLockStrategy = async ( verify?: boolean ) => withSaveAndVerify( - new DefaultTimeLockStrategy__factory(await getFirstSigner()), + await getContractFactory("DefaultTimeLockStrategy"), name, [ pool, @@ -3007,7 +2979,7 @@ export const deployOtherdeedNTokenImpl = async ( mintableERC721Logic, }; return withSaveAndVerify( - new NTokenOtherdeed__factory(libraries, await getFirstSigner()), + await getContractFactory("NTokenOtherdeed", libraries), eContractid.NTokenOtherdeedImpl, [poolAddress, warmWallet, delegationRegistryAddress], verify, @@ -3033,7 +3005,7 @@ export const deployChromieSquiggleNTokenImpl = async ( }; return withSaveAndVerify( - new NTokenChromieSquiggle__factory(libraries, await getFirstSigner()), + await getContractFactory("NTokenChromieSquiggle", libraries), eContractid.NTokenChromieSquiggleImpl, [poolAddress, delegationRegistryAddress, startTokenId, endTokenId], verify, @@ -3056,7 +3028,7 @@ export const deployStakefishNTokenImpl = async ( mintableERC721Logic, }; return withSaveAndVerify( - new NTokenStakefish__factory(libraries, await getFirstSigner()), + await getContractFactory("NTokenStakefish", libraries), eContractid.NTokenStakefishImpl, [poolAddress, delegationRegistryAddress], verify, @@ -3067,7 +3039,7 @@ export const deployStakefishNTokenImpl = async ( export const deployHotWalletProxy = async (verify?: boolean) => withSaveAndVerify( - new HotWalletProxy__factory(await getFirstSigner()), + await getContractFactory("HotWalletProxy"), eContractid.HotWalletProxy, [], verify @@ -3075,7 +3047,7 @@ export const deployHotWalletProxy = async (verify?: boolean) => export const deployDelegationRegistry = async (verify?: boolean) => withSaveAndVerify( - new DelegationRegistry__factory(await getFirstSigner()), + await getContractFactory("DelegationRegistry"), eContractid.DelegationRegistry, [], verify @@ -3087,7 +3059,7 @@ export const deployStakefishValidatorFactory = async ( verify?: boolean ) => withSaveAndVerify( - new StakefishValidatorFactory__factory(await getFirstSigner()), + await getContractFactory("StakefishValidatorFactory"), eContractid.StakefishValidatorFactory, [genesisImplementation, operator], verify @@ -3098,7 +3070,7 @@ export const deployStakefishNFTManager = async ( verify?: boolean ) => withSaveAndVerify( - new StakefishNFTManager__factory(await getFirstSigner()), + await getContractFactory("StakefishNFTManager"), eContractid.SFVLDR, [factory], verify @@ -3106,7 +3078,7 @@ export const deployStakefishNFTManager = async ( export const deployDepositContract = async (verify?: boolean) => withSaveAndVerify( - new DepositContract__factory(await getFirstSigner()), + await getContractFactory("DepositContract"), eContractid.DepositContract, [], verify @@ -3117,7 +3089,7 @@ export const deployStakefishValidator = async ( verify?: boolean ) => withSaveAndVerify( - new StakefishValidatorV1__factory(await getFirstSigner()), + await getContractFactory("StakefishValidatorV1"), eContractid.StakefishValidator, [depositContract], verify @@ -3145,7 +3117,7 @@ export const deployGenericPToken = async ( verify?: boolean ) => { const instance = await withSaveAndVerify( - new PToken__factory(await getFirstSigner()), + await getContractFactory("PToken"), eContractid.PTokenImpl, [poolAddress], verify @@ -3184,7 +3156,7 @@ export const deployDelegationAwarePToken = async ( verify?: boolean ) => { const instance = await withSaveAndVerify( - new DelegationAwarePToken__factory(await getFirstSigner()), + await getContractFactory("DelegationAwarePToken"), eContractid.DelegationAwarePTokenImpl, [poolAddress], verify @@ -3216,7 +3188,7 @@ export const deployMockVariableDebtToken = async ( verify?: boolean ) => { const instance = (await withSaveAndVerify( - new MockVariableDebtToken__factory(await getFirstSigner()), + await getContractFactory("MockVariableDebtToken"), eContractid.MockVariableDebtToken, [args[0]], verify @@ -3257,7 +3229,7 @@ export const deployMockNToken = async ( }; const instance = (await withSaveAndVerify( - new MockNToken__factory(libraries, await getFirstSigner()), + await getContractFactory("MockNToken", libraries), eContractid.MockNToken, [args[0], ZERO_ADDRESS, false], verify @@ -3289,7 +3261,7 @@ export const deployMockPToken = async ( verify?: boolean ) => { const instance = (await withSaveAndVerify( - new MockPToken__factory(await getFirstSigner()), + await getContractFactory("MockPToken"), eContractid.MockPToken, [args[0]], verify @@ -3312,7 +3284,7 @@ export const deployMockPToken = async ( export const deployMockIncentivesController = async (verify?: boolean) => withSaveAndVerify( - new MockIncentivesController__factory(await getFirstSigner()), + await getContractFactory("MockIncentivesController"), eContractid.MockIncentivesController, [], verify @@ -3320,7 +3292,7 @@ export const deployMockIncentivesController = async (verify?: boolean) => export const deployMockReserveConfiguration = async (verify?: boolean) => withSaveAndVerify( - new MockReserveConfiguration__factory(await getFirstSigner()), + await getContractFactory("MockReserveConfiguration"), eContractid.MockReserveConfiguration, [], verify @@ -3328,7 +3300,7 @@ export const deployMockReserveConfiguration = async (verify?: boolean) => export const deployMockInitializableImple = async (verify?: boolean) => withSaveAndVerify( - new MockInitializableImple__factory(await getFirstSigner()), + await getContractFactory("MockInitializableImple"), eContractid.MockInitializableImple, [], verify @@ -3336,7 +3308,7 @@ export const deployMockInitializableImple = async (verify?: boolean) => export const deployMockInitializableImpleV2 = async (verify?: boolean) => withSaveAndVerify( - new MockInitializableImpleV2__factory(await getFirstSigner()), + await getContractFactory("MockInitializableImpleV2"), eContractid.MockInitializableImpleV2, [], verify @@ -3347,7 +3319,7 @@ export const deployMockInitializableFromConstructorImple = async ( verify?: boolean ) => withSaveAndVerify( - new MockInitializableFromConstructorImple__factory(await getFirstSigner()), + await getContractFactory("MockInitializableFromConstructorImple"), eContractid.MockInitializableFromConstructorImple, [...args], verify @@ -3355,7 +3327,7 @@ export const deployMockInitializableFromConstructorImple = async ( export const deployMockReentrantInitializableImple = async (verify?: boolean) => withSaveAndVerify( - new MockReentrantInitializableImple__factory(await getFirstSigner()), + await getContractFactory("MockReentrantInitializableImple"), eContractid.MockReentrantInitializableImple, [], verify @@ -3368,7 +3340,7 @@ export const deployMockTokenFaucet = async ( verify?: boolean ) => withSaveAndVerify( - new MockTokenFaucet__factory(await getFirstSigner()), + await getContractFactory("MockTokenFaucet"), eContractid.MockTokenFaucet, [erc20configs, erc721configs, punkConfig], verify @@ -3376,7 +3348,7 @@ export const deployMockTokenFaucet = async ( export const deployMockedDelegateRegistry = async (verify?: boolean) => withSaveAndVerify( - new MockedDelegateRegistry__factory(await getFirstSigner()), + await getContractFactory("MockedDelegateRegistry"), eContractid.MockedDelegateRegistry, [], verify @@ -3384,7 +3356,7 @@ export const deployMockedDelegateRegistry = async (verify?: boolean) => export const deployMockFeePool = async (verify?: boolean) => withSaveAndVerify( - new MockFeePool__factory(await getFirstSigner()), + await getContractFactory("MockFeePool"), eContractid.MockFeePool, [], verify @@ -3392,7 +3364,7 @@ export const deployMockFeePool = async (verify?: boolean) => export const deployMockBendDaoLendPool = async (weth, verify?: boolean) => withSaveAndVerify( - new MockLendPool__factory(await getFirstSigner()), + await getContractFactory("MockLendPool"), eContractid.MockBendDaoLendPool, [weth], verify diff --git a/helpers/contracts-getters.ts b/helpers/contracts-getters.ts index 60d60be45..b767f96ac 100644 --- a/helpers/contracts-getters.ts +++ b/helpers/contracts-getters.ts @@ -74,10 +74,8 @@ import { AutoCompoundApe__factory, InitializableAdminUpgradeabilityProxy__factory, StETHDebtToken__factory, - ApeStakingLogic__factory, MintableERC721Logic__factory, NTokenBAKC__factory, - P2PPairStaking__factory, ExecutorWithTimelock__factory, MultiSendCallOnly__factory, WstETHMocked__factory, @@ -97,6 +95,11 @@ import { NTokenStakefish__factory, MockLendPool__factory, NTokenChromieSquiggle__factory, + ParaApeStaking__factory, + AuctionLogic__factory, + PoolCore__factory, + PoolParameters__factory, + PoolMarketplace__factory, } from "../types"; import { getEthersSigners, @@ -104,8 +107,15 @@ import { ERC721TokenMap, impersonateAddress, getParaSpaceAdmins, + normalizeLibraryAddresses, + linkLibraries, } from "./contracts-helpers"; -import {DRE, getDb, getParaSpaceConfig} from "./misc-utils"; +import { + DRE, + getDb, + getParaSpaceConfig, + safeTransactionServiceUrl, +} from "./misc-utils"; import { eContractid, ERC721TokenContractId, @@ -117,20 +127,117 @@ import { INonfungiblePositionManager__factory, ISwapRouter__factory, } from "../types"; -import {IMPERSONATE_ADDRESS, RPC_URL} from "./hardhat-constants"; +import { + GLOBAL_OVERRIDES, + IMPERSONATE_ADDRESS, + RPC_URL, +} from "./hardhat-constants"; +import {accounts} from "../wallets"; +import * as zk from "zksync-web3"; +import {Deployer} from "@matterlabs/hardhat-zksync-deploy"; +import {HttpNetworkConfig} from "hardhat/types"; +import {ContractFactory, ethers} from "ethers"; +import {Libraries} from "hardhat-deploy/dist/types"; +import {ZERO_ADDRESS} from "./constants"; +import EthersAdapter from "@safe-global/safe-ethers-lib"; +import Safe from "@safe-global/safe-core-sdk"; +import SafeServiceClient from "@safe-global/safe-service-client"; export const getFirstSigner = async () => { - if (!RPC_URL) { - return first(await getEthersSigners())!; + if (DRE.network.zksync) { + return new zk.Wallet( + last(accounts)!.privateKey, + new zk.Provider((DRE.network.config as HttpNetworkConfig).url), + new ethers.providers.JsonRpcProvider( + (DRE.network.config as HttpNetworkConfig).ethNetwork + ) + ); + } else { + if (!RPC_URL) { + return first(await getEthersSigners())!; + } + + const {paraSpaceAdminAddress} = await getParaSpaceAdmins(); + return ( + await impersonateAddress(IMPERSONATE_ADDRESS || paraSpaceAdminAddress) + ).signer; } +}; - const {paraSpaceAdminAddress} = await getParaSpaceAdmins(); - return ( - await impersonateAddress(IMPERSONATE_ADDRESS || paraSpaceAdminAddress) - ).signer; +export const getContractFactory = async ( + name: string, + libraries?: Libraries +) => { + const signer = await getFirstSigner(); + if (DRE.network.zksync) { + const deployer = new Deployer(DRE, signer as zk.Wallet); + const artifact = await deployer.loadArtifact(name); + const factoryDeps = await deployer.extractFactoryDeps(artifact); + return { + artifact, + factory: new zk.ContractFactory( + artifact.abi, + artifact.bytecode, + signer as zk.Signer + ), + customData: { + factoryDeps, + feeToken: zk.utils.ETH_ADDRESS, + }, + }; + } else { + const artifact = await DRE.artifacts.readArtifact(name); + if (libraries) { + artifact.bytecode = linkLibraries( + artifact, + normalizeLibraryAddresses(libraries) + ); + } + return { + artifact, + factory: new ContractFactory(artifact.abi, artifact.bytecode, signer), + customData: undefined, + }; + } }; -export const getLastSigner = async () => last(await getEthersSigners())!; +export const recordByteCodeOnL1 = async (name: string) => { + if (!DRE.network.zksync) { + return; + } + + const signer = await getFirstSigner(); + const deployer = new Deployer(DRE, signer as zk.Wallet); + const artifact = await deployer.loadArtifact(name); + await (signer as zk.Wallet).requestExecute({ + contractAddress: ZERO_ADDRESS, + calldata: "0x", + l2GasLimit: GLOBAL_OVERRIDES.gasLimit, + l2Value: "0", + factoryDeps: [artifact.bytecode], + }); +}; + +export const getSafeSdkAndService = async (safeAddress: string) => { + const signer = await getFirstSigner(); + const ethAdapter = new EthersAdapter({ + ethers, + signerOrProvider: signer, + }); + + const safeSdk: Safe = await Safe.create({ + ethAdapter, + safeAddress, + }); + const safeService = new SafeServiceClient({ + txServiceUrl: safeTransactionServiceUrl(), + ethAdapter, + }); + return { + safeSdk, + safeService, + }; +}; export const getPoolAddressesProvider = async (address?: tEthereumAddress) => { return await PoolAddressesProvider__factory.connect( @@ -190,6 +297,17 @@ export const getBorrowLogic = async (address?: tEthereumAddress) => await getFirstSigner() ); +export const getAuctionLogic = async (address?: tEthereumAddress) => + await AuctionLogic__factory.connect( + address || + ( + await getDb() + .get(`${eContractid.AuctionLogic}.${DRE.network.name}`) + .value() + ).address, + await getFirstSigner() + ); + export const getLiquidationLogic = async (address?: tEthereumAddress) => await LiquidationLogic__factory.connect( address || @@ -234,6 +352,39 @@ export const getPoolLogic = async (address?: tEthereumAddress) => await getFirstSigner() ); +export const getPoolCoreImpl = async (address?: tEthereumAddress) => + await PoolCore__factory.connect( + address || + ( + await getDb() + .get(`${eContractid.PoolCoreImpl}.${DRE.network.name}`) + .value() + ).address, + await getFirstSigner() + ); + +export const getPoolParametersImpl = async (address?: tEthereumAddress) => + await PoolParameters__factory.connect( + address || + ( + await getDb() + .get(`${eContractid.PoolParametersImpl}.${DRE.network.name}`) + .value() + ).address, + await getFirstSigner() + ); + +export const getPoolMarketplaceImpl = async (address?: tEthereumAddress) => + await PoolMarketplace__factory.connect( + address || + ( + await getDb() + .get(`${eContractid.PoolMarketplaceImpl}.${DRE.network.name}`) + .value() + ).address, + await getFirstSigner() + ); + export const getPoolProxy = async (address?: tEthereumAddress) => { return await IPool__factory.connect( address || @@ -911,17 +1062,6 @@ export const getApeCoinStaking = async (address?: tEthereumAddress) => await getFirstSigner() ); -export const getApeStakingLogic = async (address?: tEthereumAddress) => - await ApeStakingLogic__factory.connect( - address || - ( - await getDb() - .get(`${eContractid.ApeStakingLogic}.${DRE.network.name}`) - .value() - ).address, - await getFirstSigner() - ); - export const getMintableERC721Logic = async (address?: tEthereumAddress) => await MintableERC721Logic__factory.connect( address || @@ -984,12 +1124,25 @@ export const getAutoYieldApe = async (address?: tEthereumAddress) => await getFirstSigner() ); -export const getP2PPairStaking = async (address?: tEthereumAddress) => - await P2PPairStaking__factory.connect( +export const getParaApeStaking = async (address?: tEthereumAddress) => + await ParaApeStaking__factory.connect( + address || + ( + await getDb() + .get(`${eContractid.ParaApeStaking}.${DRE.network.name}`) + .value() + ).address, + await getFirstSigner() + ); + +export const getParaApeStakingImplementation = async ( + address?: tEthereumAddress +) => + await ParaApeStaking__factory.connect( address || ( await getDb() - .get(`${eContractid.P2PPairStaking}.${DRE.network.name}`) + .get(`${eContractid.ParaApeStakingImpl}.${DRE.network.name}`) .value() ).address, await getFirstSigner() diff --git a/helpers/contracts-helpers.ts b/helpers/contracts-helpers.ts index 489408dca..805abe2d2 100644 --- a/helpers/contracts-helpers.ts +++ b/helpers/contracts-helpers.ts @@ -24,6 +24,8 @@ import { getParaSpaceConfig, isFork, sleep, + DbEntry, + shouldVerifyContract, } from "./misc-utils"; import { iFunctionSignature, @@ -37,6 +39,7 @@ import { DryRunExecutor, TimeLockData, TimeLockOperation, + EtherscanVerificationProvider, } from "./types"; import { ConsiderationItem, @@ -78,11 +81,19 @@ import { Seaport__factory, NTokenOtherdeed__factory, TimeLock__factory, - P2PPairStaking__factory, ISafe__factory, + NFTFloorOracle__factory, } from "../types"; -import {HardhatRuntimeEnvironment, HttpNetworkConfig} from "hardhat/types"; -import {getFirstSigner, getTimeLockExecutor} from "./contracts-getters"; +import { + Artifact, + HardhatRuntimeEnvironment, + HttpNetworkConfig, +} from "hardhat/types"; +import { + getFirstSigner, + getSafeSdkAndService, + getTimeLockExecutor, +} from "./contracts-getters"; import {getDefenderRelaySigner, usingDefender} from "./defender-utils"; import {usingTenderly, verifyAtTenderly} from "./tenderly-utils"; import {SignerWithAddress} from "../test/helpers/make-suite"; @@ -91,7 +102,7 @@ import {InitializableImmutableAdminUpgradeabilityProxy} from "../types"; import {decodeEvents} from "./seaport-helpers/events"; import {Order, SignatureVersion} from "./blur-helpers/types"; import {expect} from "chai"; -import {ABI} from "hardhat-deploy/dist/types"; +import {ABI, Libraries} from "hardhat-deploy/dist/types"; import {ethers} from "ethers"; import { GLOBAL_OVERRIDES, @@ -107,16 +118,21 @@ import { MULTI_SIG_NONCE, MULTI_SEND_CHUNK_SIZE, PKG_DATA, + COMPILER_VERSION, + COMPILER_OPTIMIZER_RUNS, + DEPLOY_MAX_RETRIES, + ETHERSCAN_KEY, + ETHERSCAN_APIS, + ETHERSCAN_VERIFICATION_PROVIDER, + DEPLOY_RETRY_INTERVAL, + eContractidToContractName, } from "./hardhat-constants"; -import {chunk, pick} from "lodash"; +import {chunk, first, pick} from "lodash"; import InputDataDecoder from "ethereum-input-data-decoder"; import { OperationType, SafeTransactionDataPartial, } from "@safe-global/safe-core-sdk-types"; -import Safe from "@safe-global/safe-core-sdk"; -import EthersAdapter from "@safe-global/safe-ethers-lib"; -import SafeServiceClient from "@safe-global/safe-service-client"; import {encodeMulti, MetaTransaction} from "ethers-multisend"; import { FlashbotsBundleProvider, @@ -125,10 +141,40 @@ import { } from "@flashbots/ethers-provider-bundle"; import {configureReservesByHelper, initReservesByHelper} from "./init-helpers"; import shell from "shelljs"; +import walkdir from "walkdir"; +import fs from "fs"; +import * as zk from "zksync-web3"; +import {hexlify} from "ethers/lib/utils"; +import {Overrides} from "./hardhat-constants"; +import {mapLimit} from "async"; export type ERC20TokenMap = {[symbol: string]: ERC20}; export type ERC721TokenMap = {[symbol: string]: ERC721}; +export const getZkSyncBytecodeHashes = () => { + const obj = {}; + walkdir.sync("./artifacts-zk", (path, stat) => { + if ( + stat.isDirectory() || + !path.endsWith(".json") || + path.endsWith("dbg.json") + ) { + return; + } + try { + const artifact = JSON.parse(fs.readFileSync(path, "utf8")); + if (artifact.contractName && artifact.bytecode) { + const bytecodeHash = hexlify(zk.utils.hashBytecode(artifact.bytecode)); + obj[bytecodeHash] = artifact.contractName; + obj[artifact.contractName] = bytecodeHash; + } + } catch (e) { + // + } + }); + return obj; +}; + export const registerContractInDb = async ( id: string, instance: Contract, @@ -253,17 +299,94 @@ export const getEthersSignersAddresses = async (): Promise< (await getEthersSigners()).map((signer) => signer.getAddress()) ); +export const verifyContracts = async (limit = 1) => { + const db = getDb(); + const network = DRE.network.name; + const entries = Object.entries(db.getState()).filter( + ([key, value]) => { + // constructorArgs must be Array to make the contract verifiable + return ( + shouldVerifyContract(key) && + !!value[network] && + Array.isArray(value[network].constructorArgs) + ); + } + ); + + await mapLimit(entries, limit, async ([key, value]) => { + const {address, constructorArgs = [], libraries} = value[network]; + let artifact: Artifact | undefined = undefined; + try { + artifact = await DRE.artifacts.readArtifact( + eContractidToContractName[key] || key + ); + } catch (e) { + // + } + await verifyContract(key, address, artifact, constructorArgs, libraries); + }); +}; + export const verifyContract = async ( id: string, - instance: Contract, - args: ConstructorArgs, + address: tEthereumAddress, + artifact: Artifact | undefined, + constructorArgs: ConstructorArgs, libraries?: LibraryAddresses ) => { if (usingTenderly()) { - await verifyAtTenderly(id, instance); + await verifyAtTenderly(id, address); + } + + let contractFQN: string | undefined = undefined; + if (artifact) { + contractFQN = artifact.sourceName + ":" + artifact.contractName; + } + + if ( + ETHERSCAN_VERIFICATION_PROVIDER == EtherscanVerificationProvider.hardhat + ) { + await verifyEtherscanContract( + id, + address, + contractFQN, + constructorArgs, + libraries + ); + } else if ( + ETHERSCAN_VERIFICATION_PROVIDER == EtherscanVerificationProvider.foundry && + artifact + ) { + const forgeVerifyContractCmd = `ETHERSCAN_API_KEY=${ETHERSCAN_KEY} ETH_RPC_URL=${ + (DRE.network.config as HttpNetworkConfig).url + } VERIFIER_URL=${ + ETHERSCAN_APIS[DRE.network.name || FORK] + } forge verify-contract ${address} \ + --chain-id ${DRE.network.config.chainId} \ + --num-of-optimizations ${COMPILER_OPTIMIZER_RUNS} \ + --watch \ + ${contractFQN} \ +${ + constructorArgs.length + ? `--constructor-args \ + $(cast abi-encode "constructor(${first(artifact.abi) + .inputs.map((x) => x.type) + .join(",")})" ${constructorArgs + .map((x) => (Array.isArray(x) ? `"[${x}"]` : `"${x}"`)) + .join(" ")})` + : "" +} \ +${ + libraries + ? Object.entries(libraries) + .map(([k, v]) => `--libraries ${k}:${v}`) + .join(" ") + : "" +} \ + --compiler-version v${COMPILER_VERSION}`; + console.log(forgeVerifyContractCmd); + shell.exec(forgeVerifyContractCmd); } - await verifyEtherscanContract(id, instance.address, args, libraries); - return instance; }; export const normalizeLibraryAddresses = ( @@ -278,50 +401,84 @@ export const normalizeLibraryAddresses = ( } }; -export const withSaveAndVerify = async ( - factory: C, +export const retry = async (fn: any, retries = 0) => { + try { + return await fn(); + } catch (e: any) { + if (++retries < DEPLOY_MAX_RETRIES) { + console.log("retrying..., error code:", e?.code); + await sleep(DEPLOY_RETRY_INTERVAL); + return await retry(fn, retries); + } else { + throw e; + } + } +}; + +export const withSaveAndVerify = async ( + { + artifact, + factory, + customData, + }: { + artifact: Artifact; + factory: ContractFactory; + customData: any; + }, id: string, args: ConstructorArgs, verify = true, proxy = false, libraries?: ParaSpaceLibraryAddresses, signatures?: iFunctionSignature[] -) => { - const addressInDb = await getContractAddressInDb(id); - if (DEPLOY_INCREMENTAL && isNotFalsyOrZeroAddress(addressInDb)) { - console.log("contract address is already in db ", id); - return await factory.attach(addressInDb); - } - - const normalizedLibraries = normalizeLibraryAddresses(libraries); - const deployArgs = proxy ? args.slice(0, args.length - 2) : args; - const [impl, initData] = ( - proxy ? args.slice(args.length - 2) : [] - ) as string[]; - const instance = await factory.deploy(...deployArgs, GLOBAL_OVERRIDES); - await waitForTx(instance.deployTransaction); - await registerContractInDb( - id, - instance, - deployArgs, - normalizedLibraries, - signatures - ); +) => + retry(async () => { + const addressInDb = await getContractAddressInDb(id); + if (DEPLOY_INCREMENTAL && isNotFalsyOrZeroAddress(addressInDb)) { + console.log("contract address is already in db", id); + return await factory.attach(addressInDb); + } - if (verify) { - await verifyContract(id, instance, deployArgs, normalizedLibraries); - } + const normalizedLibraries = normalizeLibraryAddresses(libraries); + const deployArgs = proxy ? args.slice(0, args.length - 2) : args; + const [impl, initData] = ( + proxy ? args.slice(args.length - 2) : [] + ) as string[]; - if (proxy) { - await waitForTx( - await ( - instance as InitializableImmutableAdminUpgradeabilityProxy - ).initialize(impl, initData, GLOBAL_OVERRIDES) + if (customData) { + GLOBAL_OVERRIDES.customData = customData; + } + const instance = await factory.deploy(...deployArgs, GLOBAL_OVERRIDES); + delete GLOBAL_OVERRIDES.customData; + await waitForTx(instance.deployTransaction); + await registerContractInDb( + id, + instance, + deployArgs, + normalizedLibraries, + signatures ); - } - return instance; -}; + if (proxy) { + await waitForTx( + await ( + instance as InitializableImmutableAdminUpgradeabilityProxy + ).initialize(impl, initData, GLOBAL_OVERRIDES) + ); + } + + if (verify) { + await verifyContract( + id, + instance.address, + artifact, + deployArgs, + normalizedLibraries + ); + } + + return instance; + }); export const convertToCurrencyDecimals = async ( tokenAddress: tEthereumAddress, @@ -575,7 +732,8 @@ export const createZone = async ( export const createConduit = async ( conduitController: ConduitController, owner: Signer, - conduitKey?: string + conduitKey?: string, + overrides?: Overrides ) => { const ownerAddress = await owner.getAddress(); const assignedConduitKey = @@ -587,7 +745,7 @@ export const createConduit = async ( await conduitController .connect(owner) - .createConduit(assignedConduitKey, ownerAddress, GLOBAL_OVERRIDES); + .createConduit(assignedConduitKey, ownerAddress, overrides); return conduitAddress; }; @@ -657,7 +815,7 @@ export const getParaSpaceAdmins = async (): Promise<{ }; export const getFunctionSignatures = ( - abi: string | ReadonlyArray | ABI + abi: string | ReadonlyArray | Readonly ): Array => { const i = new utils.Interface(abi); return Object.keys(i.functions).map((f) => { @@ -829,9 +987,8 @@ export const dryRunEncodedData = async ( export const dryRunMultipleEncodedData = async ( target: tEthereumAddress[], data: string[], - executionTime?: string + executionTime: (string | undefined)[] ) => { - executionTime = executionTime || (await getExecutionTime()); if ( DRY_RUN == DryRunExecutor.TimeLock && (await getContractAddressInDb(eContractid.TimeLockExecutor)) @@ -840,7 +997,7 @@ export const dryRunMultipleEncodedData = async ( const timeLockData = await getTimeLockData( target[i], data[i], - executionTime + executionTime[i] || (await getExecutionTime()) ); await insertTimeLockDataInDb(timeLockData); } @@ -850,7 +1007,7 @@ export const dryRunMultipleEncodedData = async ( const {newTarget, newData} = await getTimeLockData( target[i], data[i], - executionTime + executionTime[i] || (await getExecutionTime()) ); metaTransactions.push({ to: newTarget, @@ -906,8 +1063,8 @@ export const decodeInputData = (data: string) => { ...ICurve__factory.abi, ...NTokenOtherdeed__factory.abi, ...TimeLock__factory.abi, - ...P2PPairStaking__factory.abi, ...ISafe__factory.abi, + ...NFTFloorOracle__factory.abi, ]; const decoder = new InputDataDecoder(ABI); @@ -927,22 +1084,8 @@ export const proposeSafeTransaction = async ( withTimeLock = false ) => { const signer = await getFirstSigner(); - const ethAdapter = new EthersAdapter({ - ethers, - signerOrProvider: signer, - }); const MULTI_SIG = getParaSpaceConfig().Governance.Multisig; - - const safeSdk: Safe = await Safe.create({ - ethAdapter, - safeAddress: MULTI_SIG, - }); - const safeService = new SafeServiceClient({ - txServiceUrl: `https://safe-transaction-${ - FORK || DRE.network.name - }.safe.global`, - ethAdapter, - }); + const {safeSdk, safeService} = await getSafeSdkAndService(MULTI_SIG); if (withTimeLock) { const {newTarget, newData} = await getTimeLockData(target, data); @@ -1092,6 +1235,84 @@ export const initAndConfigureReserves = async ( await configureReservesByHelper(reserves, allTokenAddresses); }; +export const linkRawLibrary = ( + bytecode: string, + libraryName: string, + libraryAddress: string +): string => { + const address = libraryAddress.replace("0x", ""); + let encodedLibraryName; + if (libraryName.startsWith("$") && libraryName.endsWith("$")) { + encodedLibraryName = libraryName.slice(1, libraryName.length - 1); + } else { + encodedLibraryName = solidityKeccak256(["string"], [libraryName]).slice( + 2, + 36 + ); + } + const pattern = new RegExp(`_+\\$${encodedLibraryName}\\$_+`, "g"); + if (!pattern.exec(bytecode)) { + throw new Error( + `Can't link '${libraryName}' (${encodedLibraryName}) in \n----\n ${bytecode}\n----\n` + ); + } + return bytecode.replace(pattern, address); +}; + +export const linkRawLibraries = ( + bytecode: string, + libraries: Libraries +): string => { + for (const libName of Object.keys(libraries)) { + const libAddress = libraries[libName]; + bytecode = linkRawLibrary(bytecode, libName, libAddress); + } + return bytecode; +}; + +export const linkLibraries = ( + artifact: { + bytecode: string; + linkReferences?: { + [libraryFileName: string]: { + [libraryName: string]: Array<{length: number; start: number}>; + }; + }; + }, + libraries?: Libraries +) => { + let bytecode = artifact.bytecode; + + if (libraries) { + if (artifact.linkReferences) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + for (const [, fileReferences] of Object.entries( + artifact.linkReferences + )) { + for (const [libName, fixups] of Object.entries(fileReferences)) { + const addr = libraries[libName]; + if (addr === undefined) { + continue; + } + + for (const fixup of fixups) { + bytecode = + bytecode.substr(0, 2 + fixup.start * 2) + + addr.substr(2) + + bytecode.substr(2 + (fixup.start + fixup.length) * 2); + } + } + } + } else { + bytecode = linkRawLibraries(bytecode, libraries); + } + } + + // TODO return libraries object with path name : for names + + return bytecode; +}; + export const exec = ( cmd: string, options: {fatal: boolean; silent: boolean} = {fatal: true, silent: true} diff --git a/helpers/etherscan.ts b/helpers/etherscan.ts index 85ababdc2..be4ec096b 100644 --- a/helpers/etherscan.ts +++ b/helpers/etherscan.ts @@ -1,10 +1,9 @@ -import {DRE, getDb, sleep} from "./misc-utils"; +import {DRE, getDb, shouldVerifyContract, sleep} from "./misc-utils"; import {ConstructorArgs, LibraryAddresses, tEthereumAddress} from "./types"; import axios from "axios"; -import minimatch from "minimatch"; import { + ETHERSCAN_APIS, ETHERSCAN_KEY, - ETHERSCAN_VERIFICATION_CONTRACTS, ETHERSCAN_VERIFICATION_MAX_RETRIES, } from "./hardhat-constants"; @@ -24,32 +23,12 @@ const unableVerifyError = "Fail - Unable to verify"; type VerificationArgs = { address: string; + contract?: string; constructorArguments: ConstructorArgs; relatedSources?: true; libraries?: LibraryAddresses; }; -export const ETHERSCAN_NETWORKS = [ - "mainnet", - "ropsten", - "kovan", - "matic", - "mumbai", - "rinkeby", - "goerli", - "localhost", - "arbitrum", -]; - -export const ETHERSCAN_APIS = { - mainnet: "api.etherscan.io", - ropsten: "api-ropsten.etherscan.io", - kovan: "api-kovan.etherscan.io", - rinkeby: "api-rinkeby.etherscan.io", - goerli: "api-goerli.etherscan.io", - arbitrum: "api.arbiscan.io", -}; - const getIsVerified = async (contractId: string, address: string) => { const value = await getDb().get(`${contractId}.${DRE.network.name}`).value(); const isVerified = @@ -82,31 +61,22 @@ const setIsVerified = async (contractId: string, address: string) => { }; export const verifyEtherscanContract = async ( - contractId: string, + id: string, address: string, - constructorArguments: ConstructorArgs = [], + contractFQN: string | undefined = undefined, + constructorArgs: ConstructorArgs = [], libraries?: LibraryAddresses ) => { - if (!ETHERSCAN_NETWORKS.includes(DRE.network.name)) { + if (!shouldVerifyContract(id)) { return; } - if ( - ETHERSCAN_VERIFICATION_CONTRACTS?.every((p) => !minimatch(contractId, p)) - ) { - return; - } - - if (!ETHERSCAN_KEY) { - throw Error("Missing ETHERSCAN_KEY."); - } - - let isVerified = await getIsVerified(contractId, address); + let isVerified = await getIsVerified(id, address); if (isVerified) { return; } - console.log(`- Verifying ${contractId}`); + console.log(`- Verifying ${id}`); console.log(` - address: ${address}`); try { @@ -116,7 +86,8 @@ export const verifyEtherscanContract = async ( const params: VerificationArgs = { address, - constructorArguments, + contract: contractFQN, + constructorArguments: constructorArgs, relatedSources: true, libraries, }; @@ -129,7 +100,7 @@ export const verifyEtherscanContract = async ( isVerified = errMsg.includes(ALREADY_VERIFIED); } - if (isVerified) await setIsVerified(contractId, address); + if (isVerified) await setIsVerified(id, address); }; export const runTaskWithRetry = async ( @@ -191,9 +162,9 @@ const hasVerifiedSourceCode = async ( ): Promise => { try { const {data} = await axios.get( - `https://${ + `${ ETHERSCAN_APIS[DRE.network.name] - }/api?module=contract&action=getsourcecode&address=${address}&apikey=${ETHERSCAN_KEY}` + }?module=contract&action=getsourcecode&address=${address}&apikey=${ETHERSCAN_KEY}` ); return ( data.status === "1" && @@ -214,9 +185,9 @@ const verifyProxyContract = async ( "Content-Type": "application/x-www-form-urlencoded", }; const {data} = await axios.post( - `https://${ + `${ ETHERSCAN_APIS[DRE.network.name] - }/api?module=contract&action=verifyproxycontract&apikey=${ETHERSCAN_KEY}`, + }?module=contract&action=verifyproxycontract&apikey=${ETHERSCAN_KEY}`, `address=${address}`, { headers, diff --git a/helpers/hardhat-constants.ts b/helpers/hardhat-constants.ts index 5cc50da06..d248788ae 100644 --- a/helpers/hardhat-constants.ts +++ b/helpers/hardhat-constants.ts @@ -1,11 +1,12 @@ -import {Overrides} from "@ethersproject/contracts"; import dotenv from "dotenv"; -import {ethers} from "ethers"; +import {BigNumberish, ethers} from "ethers"; import fs from "fs"; import {HttpNetworkAccountsUserConfig} from "hardhat/types"; import {input} from "./wallet-helpers"; import {version} from "../package.json"; import git from "git-rev-sync"; +import {AccessListish} from "ethers/lib/utils"; +import {ZERO_ADDRESS} from "./constants"; dotenv.config(); @@ -15,7 +16,7 @@ const getPrivateKeyfromEncryptedJson = ( keystorePath && fs.existsSync(keystorePath) ? ethers.Wallet.fromEncryptedJsonSync( fs.readFileSync(keystorePath, "utf8"), - input("password: ") + DEPLOYER_PASSWORD || input("password: ") ).privateKey : ""; @@ -25,8 +26,17 @@ export const FORK_CHAINID = 522; export const MAINNET_CHAINID = 1; export const PARALLEL_CHAINID = 1592; export const MOONBEAM_CHAINID = 1284; +export const MOONBASE_CHAINID = 1287; export const ARBITRUM_ONE_CHAINID = 42161; export const ARBITRUM_GOERLI_CHAINID = 421613; +export const POLYGON_CHAINID = 137; +export const POLYGON_ZKEVM_CHAINID = 1101; +export const POLYGON_ZKEVM_GOERLI_CHAINID = 1442; +export const POLYGON_MUMBAI_CHAINID = 80001; +export const ZKSYNC_CHAINID = 324; +export const ZKSYNC_GOERLI_CHAINID = 280; +export const LINEA_GOERLI_CHAINID = 59140; +export const LINEA_CHAINID = 59144; export const INFURA_KEY = process.env.INFURA_KEY || ""; export const ALCHEMY_KEY = process.env.ALCHEMY_KEY || ""; @@ -46,7 +56,7 @@ export const FORK_BLOCK_NUMBER = process.env.FORK_BLOCK_NUMBER ? parseInt(process.env.FORK_BLOCK_NUMBER) : 0; -export const DEFAULT_BLOCK_GAS_LIMIT = 30000000; +export const DEFAULT_BLOCK_GAS_LIMIT = 40000000; export const HARDFORK = "london"; export const MOCHA_JOBS = parseInt(process.env.MOCHA_JOBS || "4"); @@ -55,8 +65,32 @@ export const REPORT_GAS = process.env.REPORT_GAS == "true" ? true : false; export const DB_PATH = process.env.DB_PATH ?? ":memory:"; export const ETHERSCAN_KEY = process.env.ETHERSCAN_KEY || ""; +export const GOERLI_ETHERSCAN_KEY = + process.env.GOERLI_ETHERSCAN_KEY || ETHERSCAN_KEY; +export const ARBITRUM_ETHERSCAN_KEY = + process.env.ARBITRUM_ETHERSCAN_KEY || ETHERSCAN_KEY; +export const ARBITRUM_GOERLI_ETHERSCAN_KEY = + process.env.ARBITRUM_GOERLI_ETHERSCAN_KEY || ARBITRUM_ETHERSCAN_KEY; +export const POLYGON_ETHERSCAN_KEY = + process.env.POLYGON_ETHERSCAN_KEY || ETHERSCAN_KEY; +export const POLYGON_MUMBAI_ETHERSCAN_KEY = + process.env.POLYGON_MUMBAI_ETHERSCAN_KEY || POLYGON_ETHERSCAN_KEY; +export const POLYGON_ZKEVM_ETHERSCAN_KEY = + process.env.POLYGON_ZKEVM_ETHERSCAN_KEY || POLYGON_ETHERSCAN_KEY; +export const POLYGON_ZKEVM_GOERLI_ETHERSCAN_KEY = + process.env.POLYGON_ZKEVM_GOERLI_ETHERSCAN_KEY || POLYGON_ZKEVM_ETHERSCAN_KEY; +export const MOONBEAM_ETHERSCAN_KEY = + process.env.MOONBEAM_ETHERSCAN_KEY || ETHERSCAN_KEY; +export const MOONBASE_ETHERSCAN_KEY = + process.env.MOONBASE_ETHERSCAN_KEY || MOONBEAM_ETHERSCAN_KEY; +export const LINEA_ETHERSCAN_KEY = + process.env.LINEA_ETHERSCAN_KEY || ETHERSCAN_KEY; +export const LINEA_GOERLI_ETHERSCAN_KEY = + process.env.LINEA_GOERLI_ETHERSCAN_KEY || LINEA_ETHERSCAN_KEY; export const ETHERSCAN_VERIFICATION = process.env.ETHERSCAN_VERIFICATION === "true" ? true : false; +export const ETHERSCAN_VERIFICATION_PROVIDER = + process.env.ETHERSCAN_VERIFICATION_PROVIDER || "hardhat"; export const ETHERSCAN_VERIFICATION_CONTRACTS = process.env.ETHERSCAN_VERIFICATION_CONTRACTS?.trim().split(/\s?,\s?/); export const ETHERSCAN_VERIFICATION_JOBS = parseInt( @@ -65,6 +99,60 @@ export const ETHERSCAN_VERIFICATION_JOBS = parseInt( export const ETHERSCAN_VERIFICATION_MAX_RETRIES = parseInt( process.env.ETHERSCAN_VERIFICATION_MAX_RETRIES || "3" ); +export const ETHERSCAN_NETWORKS = [ + "localhost", + "mainnet", + "goerli", + "arbitrum", + "polygon", + "matic", + "polygonMumbai", + "polygonZkevm", + "polygonZkevmGoerli", + "zksync", + "zksyncGoerli", + "linea", + "lineaGoerli", + "moonbeam", + "moonbase", +]; +export const ETHERSCAN_APIS = { + localhost: "http://localhost:4000/api", + mainnet: "https://api.etherscan.io/api", + goerli: "https://api-goerli.etherscan.io/api", + arbitrum: "https://api.arbiscan.io/api", + arbitrumGoerli: "https://api-goerli.arbiscan.io/api", + polygon: "https://api.polygonscan.com/api", + matic: "https://api.polygonscan.com/api", + polygonMumbai: "https://api-mumbai.polygonscan.com/api", + polygonZkevm: "https://api-zkevm.polygonscan.com/api", + polygonZkevmGoerli: "https://api-testnet-zkevm.polygonscan.com/api", + zksync: "https://zksync2-mainnet-explorer.zksync.io/contract_verification", + zksyncGoerli: + "https://zksync2-testnet-explorer.zksync.dev/contract_verification", + moonbeam: "https://api-moonbeam.moonscan.io/api", + moonbase: "https://api-moonbase.moonscan.io/api", + linea: "http://explorer.linea.build/api", + lineaGoerli: "https://explorer.goerli.linea.build/api", +}; +export const BROWSER_URLS = { + localhost: "http://localhost:4000", + mainnet: "https://etherscan.io", + goerli: "https://goerli.etherscan.io", + arbitrum: "https://arbiscan.io", + arbitrumGoerli: "https://goerli.arbiscan.io", + polygonZkevm: "https://zkevm.polygonscan.com", + polygonZkevmGoerli: "https://testnet-zkevm.polygonscan.com", + polygon: "https://polygonscan.com", + matic: "https://polygonscan.com", + polygonMumbai: "https://mumbai.polygonscan.com", + zksync: "https://zksync2-mainnet-explorer.zksync.io", + zksyncGoerli: "https://zksync2-testnet-explorer.zksync.dev", + moonbeam: "https://moonscan.io", + moonbase: "https://moonbase.moonscan.io", + linea: "https://explorer.linea.build", + lineaGoerli: "https://explorer.goerli.linea.build", +}; export const DEPLOY_START = parseInt(process.env.DEPLOY_START || "0"); export const DEPLOY_END = parseInt(process.env.DEPLOY_END || "24"); @@ -80,6 +168,7 @@ export const DEPLOYER_MNEMONIC = ( process.env.DEPLOYER_MNEMONIC || "test test test test test test test test test test test junk" ).trim(); +export const DEPLOYER_PASSWORD = process.env.DEPLOYER_PASSWORD || ""; export const DEPLOYER: HttpNetworkAccountsUserConfig = DEPLOYER_PRIVATE_KEY ? [DEPLOYER_PRIVATE_KEY] : { @@ -89,6 +178,18 @@ export const DEPLOYER: HttpNetworkAccountsUserConfig = DEPLOYER_PRIVATE_KEY export const BLOCKSCOUT_DISABLE_INDEXER = process.env.BLOCKSCOUT_DISABLE_INDEXER == "false" ? false : true; +export interface Overrides { + gasLimit?: BigNumberish; + gasPrice?: BigNumberish; + maxFeePerGas?: BigNumberish; + maxPriorityFeePerGas?: BigNumberish; + nonce?: BigNumberish; + type?: number; + accessList?: AccessListish; + customData?: Record; + ccipReadEnabled?: boolean; +} + export const GLOBAL_OVERRIDES: Overrides = { // maxFeePerGas: ethers.utils.parseUnits("20", "gwei"), // maxPriorityFeePerGas: ethers.utils.parseUnits("1.5", "gwei"), @@ -96,7 +197,9 @@ export const GLOBAL_OVERRIDES: Overrides = { // gasLimit: 12_450_000, }; -export const RPC_URL = process.env.RPC_URL || ""; +export const L1_RPC_URL = process.env.L1_RPC_URL || ""; +export const L2_RPC_URL = process.env.L2_RPC_URL || ""; +export const RPC_URL = process.env.RPC_URL || L1_RPC_URL || L2_RPC_URL || ""; export const JSONRPC_VARIANT = process.env.JSONRPC_VARIANT || "hardhat"; export const VERBOSE = process.env.VERBOSE == "true" ? true : false; export const DRY_RUN = process.env.DRY_RUN || ""; @@ -119,15 +222,15 @@ export const MULTI_SEND_CHUNK_SIZE = parseInt( export const VERSION = version; export const COMMIT = git.short(); -export const COMPILER_OPTIMIZER_RUNS = 800; -export const COMPILER_VERSION = "0.8.10"; +export const COMPILER_OPTIMIZER_RUNS = 200; +export const COMPILER_VERSION = "0.8.17+commit.8df45f5f"; export const PKG_DATA = { version: VERSION, git: { commit: COMMIT, }, compiler: { - version: COMPILER_VERSION, + version: "v" + COMPILER_VERSION, optimizer: { runs: COMPILER_OPTIMIZER_RUNS, }, @@ -151,3 +254,237 @@ export const TIME_LOCK_SIGS = { "0xe177246e": "setDelay(uint256)", "0x4dd18bf5": "setPendingAdmin(address)", }; + +export const ZK_LIBRARIES_PATH = "zk-libraries.json"; +export const ZK_LIBRARIES = fs.existsSync(ZK_LIBRARIES_PATH) + ? JSON.parse(fs.readFileSync(ZK_LIBRARIES_PATH, "utf8")) + : { + "contracts/protocol/libraries/logic/BorrowLogic.sol": { + BorrowLogic: ZERO_ADDRESS, + }, + "contracts/protocol/libraries/logic/SupplyLogic.sol": { + SupplyLogic: ZERO_ADDRESS, + }, + "contracts/protocol/libraries/logic/LiquidationLogic.sol": { + LiquidationLogic: ZERO_ADDRESS, + }, + "contracts/protocol/libraries/logic/AuctionLogic.sol": { + AuctionLogic: ZERO_ADDRESS, + }, + "contracts/protocol/libraries/logic/PositionMoverLogic.sol": { + PositionMoverLogic: ZERO_ADDRESS, + }, + "contracts/protocol/libraries/logic/PoolLogic.sol": { + PoolLogic: ZERO_ADDRESS, + }, + "contracts/protocol/libraries/logic/MarketplaceLogic.sol": { + MarketplaceLogic: ZERO_ADDRESS, + }, + "contracts/protocol/libraries/logic/FlashClaimLogic.sol": { + FlashClaimLogic: ZERO_ADDRESS, + }, + "contracts/protocol/tokenization/libraries/ApeStakingLogic.sol": { + ApeStakingLogic: ZERO_ADDRESS, + }, + "contracts/protocol/tokenization/libraries/MintableERC721Logic.sol": { + MintableERC721Logic: ZERO_ADDRESS, + }, + "contracts/protocol/libraries/logic/ConfiguratorLogic.sol": { + ConfiguratorLogic: ZERO_ADDRESS, + }, + "contracts/dependencies/blur-exchange/MerkleVerifier.sol": { + MerkleVerifier: ZERO_ADDRESS, + }, + }; + +export const DEPLOY_MAX_RETRIES = parseInt( + process.env.DEPLOY_MAX_RETRIES || "6" +); +export const DEPLOY_RETRY_INTERVAL = parseInt( + process.env.DEPLOY_RETRY_INTERVAL || "1500" +); + +export const eContractidToContractName = { + PoolAddressesProvider: "PoolAddressesProvider", + MintableERC20: "MintableERC20", + MintableERC721: "MintableERC721", + MintableDelegationERC20: "MintableDelegationERC20", + PoolAddressesProviderRegistry: "PoolAddressesProviderRegistry", + ACLManager: "ACLManager", + PoolConfiguratorProxy: "PoolConfiguratorProxy", + ValidationLogic: "ValidationLogic", + ReserveLogic: "ReserveLogic", + GenericLogic: "GenericLogic", + SupplyLogic: "SupplyLogic", + BorrowLogic: "BorrowLogic", + LiquidationLogic: "LiquidationLogic", + AuctionLogic: "AuctionLogic", + PoolLogic: "PoolLogic", + ConfiguratorLogic: "ConfiguratorLogic", + PoolProxy: "ParaProxy", + PriceOracle: "PriceOracle", + Aggregator: "Aggregator", + ParaSpaceOracle: "ParaSpaceOracle", + DefaultReserveInterestRateStrategy: "DefaultReserveInterestRateStrategy", + DefaultReserveAuctionStrategy: "DefaultReserveAuctionStrategy", + MockReserveAuctionStrategy: "MockReserveAuctionStrategy", + InitializableImmutableAdminUpgradeabilityProxy: + "InitializableImmutableAdminUpgradeabilityProxy", + MockFlashLoanReceiver: "MockFlashLoanReceiver", + PTokenImpl: "PToken", + PTokenSApeImpl: "PTokenSApe", + PTokenATokenImpl: "PTokenAToken", + PTokenStETHImpl: "PTokenStETH", + PTokenStKSMImpl: "PTokenStKSM", + PTokenAStETHImpl: "PTokenAStETH", + PTokenCApeImpl: "PTokenCApe", + PYieldTokenImpl: "PYieldToken", + NTokenImpl: "NToken", + NTokenMoonBirdsImpl: "NTokenMoonBirds", + NTokenUniswapV3Impl: "NTokenUniswapV3", + NTokenBAYCImpl: "NTokenBAYC", + NTokenMAYCImpl: "NTokenMAYC", + NTokenBAKCImpl: "NTokenBAKC", + DelegationAwarePTokenImpl: "DelegationAwarePToken", + VariableDebtTokenImpl: "VariableDebtToken", + MockVariableDebtToken: "MockVariableDebtToken", + FlashClaimRegistry: "UserFlashclaimRegistry", + UserFlashClaimRegistryProxy: "InitializableImmutableAdminUpgradeabilityProxy", + BAYCSewerPassClaim: "BAYCSewerPassClaim", + AirdropFlashClaimReceiver: "AirdropFlashClaimReceiver", + ProtocolDataProvider: "ProtocolDataProvider", + MockPToken: "MockPToken", + MockNToken: "MockNToken", + FeeProvider: "FeeProvider", + TokenDistributor: "TokenDistributor", + ReservesSetupHelper: "ReservesSetupHelper", + WETH: "WETH9Mocked", + PoolConfiguratorImpl: "PoolConfigurator", + MockIncentivesController: "MockIncentivesController", + MockReserveConfiguration: "MockReserveConfiguration", + MockPool: "MockPool", + MockInitializableImple: "MockInitializableImple", + MockInitializableImpleV2: "MockInitializableImpleV2", + MockInitializableFromConstructorImple: + "MockInitializableFromConstructorImple", + MockReentrantInitializableImple: "MockReentrantInitializableImple", + MockPoolInherited: "MockPoolInherited", + UiPoolDataProvider: "UiPoolDataProvider", + UiIncentiveDataProvider: "UiIncentiveDataProvider", + WalletBalanceProvider: "WalletBalanceProvider", + WETHGatewayImpl: "WETHGateway", + WETHGatewayProxy: "InitializableAdminUpgradeabilityProxy", + ERC721OracleWrapper: "ERC721OracleWrapper", + PUNKS: "CryptoPunksMarket", + WPunk: "WPunk", + WPunkGatewayImpl: "WPunkGateway", + WPunkGatewayProxy: "InitializableAdminUpgradeabilityProxy", + FlashClaimLogic: "FlashClaimLogic", + NFTFloorOracle: "NFTFloorOracle", + ParaSpace: "ParaSpace", + sParaSpace: "sParaSpace", + RewardsController: "RewardsController", + PCV: "PCV", + MockTokenFaucet: "MockTokenFaucet", + BoredApeYachtClub: "BAYC", + MutantApeYachtClub: "MAYC", + Doodles: "Doodles", + MOONBIRD: "Moonbirds", + Meebits: "Meebits", + Azuki: "Azuki", + CloneX: "CloneX", + OTHR: "MintableERC721", + ConduitController: "ConduitController", + PausableZoneController: "PausableZoneController", + ConduitKey: "ConduitKey", + Conduit: "Conduit", + PausableZone: "PausableZone", + Seaport: "Seaport", + MarketplaceLogic: "MarketplaceLogic", + SeaportAdapter: "SeaportAdapter", + LooksRareAdapter: "LooksRareAdapter", + X2Y2Adapter: "X2Y2Adapter", + BlurAdapter: "BlurAdapter", + CurrencyManager: "CurrencyManager", + ExecutionManager: "ExecutionManager", + LooksRareExchange: "LooksRareExchange", + RoyaltyFeeManager: "RoyaltyFeeManager", + RoyaltyFeeRegistry: "RoyaltyFeeRegistry", + TransferSelectorNFT: "TransferSelectorNFT", + TransferManagerERC721: "TransferManagerERC721", + TransferManagerERC1155: "TransferManagerERC1155", + StrategyStandardSaleForFixedPrice: "StrategyStandardSaleForFixedPrice", + X2Y2R1: "X2Y2R1", + ERC721Delegate: "ERC721Delegate", + MoonBirdHelper: "MoonBirdHelper", + UniswapV3: "UniswapV3", + UniswapV3Factory: "UniswapV3Factory", + UniswapV3SwapRouter: "UniswapV3SwapRouter", + NFTDescriptor: "NFTDescriptor", + NonfungibleTokenPositionDescriptor: "NonfungibleTokenPositionDescriptor", + NonfungiblePositionManager: "NonfungiblePositionManager", + StETH: "StETHMocked", + WStETH: "WstETHMocked", + MockAToken: "MockAToken", + MockCToken: "MockCToken", + MockAirdropProject: "MockAirdropProject", + PoolCoreImpl: "PoolCore", + PoolMarketplaceImpl: "PoolMarketplace", + PoolParametersImpl: "PoolParameters", + PoolApeStakingImpl: "PoolApeStaking", + ApeCoinStaking: "ApeCoinStaking", + ATokenDebtToken: "ATokenDebtToken", + StETHDebtToken: "StETHDebtToken", + StKSMDebtToken: "StKSMDebtToken", + CApeDebtToken: "CApeDebtToken", + AStETHDebtToken: "AStETHDebtToken", + ApeStakingLogic: "ApeStakingLogic", + MintableERC721Logic: "MintableERC721Logic", + MerkleVerifier: "MerkleVerifier", + ExecutionDelegate: "ExecutionDelegate", + PolicyManager: "PolicyManager", + StandardPolicyERC721: "StandardPolicyERC721", + BlurExchangeImpl: "BlurExchange", + BlurExchangeProxy: "InitializableAdminUpgradeabilityProxy", + BAKC: "MintableERC721", + SEWER: "BAYCSewerPass", + TimeLockExecutor: "ExecutorWithTimelock", + MultiSendCallOnly: "MultiSendCallOnly", + cAPE: "InitializableAdminUpgradeabilityProxy", + cAPEImpl: "AutoCompoundApe", + P2PPairStaking: "P2PPairStaking", + HelperContractImpl: "HelperContract", + HelperContract: "InitializableAdminUpgradeabilityProxy", + P2PPairStakingImpl: "P2PPairStaking", + yAPE: "InitializableAdminUpgradeabilityProxy", + yAPEImpl: "AutoYieldApe", + ParaProxyInterfacesImpl: "ParaProxyInterfaces", + MockedDelegateRegistry: "MockedDelegateRegistry", + MockMultiAssetAirdropProject: "MockMultiAssetAirdropProject", + ParaSpaceAirdrop: "ParaSpaceAirdrop", + TimeLockProxy: "InitializableAdminUpgradeabilityProxy", + TimeLockImpl: "TimeLock", + DefaultTimeLockStrategy: "DefaultTimeLockStrategy", + NTokenOtherdeedImpl: "NTokenOtherdeed", + NTokenChromieSquiggleImpl: "NTokenChromieSquiggle", + NTokenStakefishImpl: "NTokenStakefish", + HotWalletProxy: "HotWalletProxy", + SFVLDR: "StakefishNFTManager", + DelegationRegistry: "DelegationRegistry", + StakefishValidator: "StakefishValidatorV1", + StakefishValidatorFactory: "StakefishValidatorFactory", + DepositContract: "DepositContract", + MockFeePool: "MockFeePool", + HVMTL: "MintableERC721", + BEANZ: "MintableERC721", + DEGODS: "MintableERC721", + EXP: "MintableERC721", + VSL: "MintableERC721", + KODA: "MintableERC721", + BLOCKS: "MintableERC721", + EXRP: "MintableERC721", + WGLMR: "MintableERC721", + MockBendDaoLendPool: "MockLendPool", + PositionMoverLogic: "PositionMoverLogic", + PoolPositionMoverImpl: "PoolPositionMover", +}; diff --git a/helpers/init-helpers.ts b/helpers/init-helpers.ts index 62e9346ca..9f8ee0b29 100644 --- a/helpers/init-helpers.ts +++ b/helpers/init-helpers.ts @@ -3,7 +3,6 @@ import { ERC20TokenContractId, ERC721TokenContractId, IReserveParams, - NTokenContractId, tEthereumAddress, } from "./types"; import {chunk, waitForTx} from "./misc-utils"; @@ -51,6 +50,8 @@ import { deployChromieSquiggleNTokenImpl, deployAutoYieldApeImplAndAssignItToProxy, deployAutoCompoundApeImplAndAssignItToProxy, + deployPTokenStKSM, + deployStKSMDebtToken, } from "./contracts-deployments"; import {ZERO_ADDRESS} from "./constants"; @@ -117,6 +118,7 @@ export const initReservesByHelper = async ( genericDelegationAwarePTokenImplAddress; let pTokenImplementationAddress = genericPTokenImplAddress; let pTokenStETHImplementationAddress = ""; + let pTokenStKSMImplementationAddress = ""; let pTokenATokenImplementationAddress = ""; let pTokenAStETHImplementationAddress = ""; let pTokenSApeImplementationAddress = ""; @@ -129,6 +131,7 @@ export const initReservesByHelper = async ( let nTokenMAYCImplementationAddress = ""; let variableDebtTokenImplementationAddress = genericVariableDebtTokenAddress; let stETHVariableDebtTokenImplementationAddress = ""; + let stKSMVariableDebtTokenImplementationAddress = ""; let astETHVariableDebtTokenImplementationAddress = ""; let aTokenVariableDebtTokenImplementationAddress = ""; let psApeVariableDebtTokenImplementationAddress = ""; @@ -324,6 +327,8 @@ export const initReservesByHelper = async ( eContractid.NTokenMAYCImpl, eContractid.NTokenBAKCImpl, eContractid.NTokenStakefishImpl, + eContractid.NTokenChromieSquiggleImpl, + eContractid.NTokenOtherdeedImpl, ].includes(xTokenImpl) ) { xTokenType[symbol] = "nft"; @@ -399,6 +404,19 @@ export const initReservesByHelper = async ( ).address; } variableDebtTokenToUse = stETHVariableDebtTokenImplementationAddress; + } else if (reserveSymbol === ERC20TokenContractId.stDOT) { + if (!pTokenStKSMImplementationAddress) { + pTokenStKSMImplementationAddress = ( + await deployPTokenStKSM(pool.address, verify) + ).address; + } + xTokenToUse = pTokenStKSMImplementationAddress; + if (!stKSMVariableDebtTokenImplementationAddress) { + stKSMVariableDebtTokenImplementationAddress = ( + await deployStKSMDebtToken(pool.address, verify) + ).address; + } + variableDebtTokenToUse = stKSMVariableDebtTokenImplementationAddress; } else if ( reserveSymbol === ERC20TokenContractId.aWETH || reserveSymbol === ERC20TokenContractId.awstETH @@ -430,20 +448,8 @@ export const initReservesByHelper = async ( variableDebtTokenToUse = astETHVariableDebtTokenImplementationAddress; } else if (reserveSymbol === ERC20TokenContractId.sAPE) { if (!pTokenSApeImplementationAddress) { - const protocolDataProvider = await getProtocolDataProvider(); - const allTokens = await protocolDataProvider.getAllXTokens(); - const nBAYC = - // eslint-disable-next-line - allTokens.find( - (x) => x.symbol == NTokenContractId.nBAYC - )!.tokenAddress; - const nMAYC = - // eslint-disable-next-line - allTokens.find( - (x) => x.symbol == NTokenContractId.nMAYC - )!.tokenAddress; pTokenSApeImplementationAddress = ( - await deployPTokenSApe(pool.address, nBAYC, nMAYC, verify) + await deployPTokenSApe(pool.address, verify) ).address; } xTokenToUse = pTokenSApeImplementationAddress; @@ -536,27 +542,9 @@ export const initReservesByHelper = async ( xTokenToUse = nTokenMAYCImplementationAddress; } else if (reserveSymbol === ERC721TokenContractId.BAKC) { if (!nTokenBAKCImplementationAddress) { - const apeCoinStaking = - (await getContractAddressInDb(eContractid.ApeCoinStaking)) || - (await deployApeCoinStaking(verify)).address; - const protocolDataProvider = await getProtocolDataProvider(); - const allTokens = await protocolDataProvider.getAllXTokens(); - const nBAYC = - // eslint-disable-next-line - allTokens.find( - (x) => x.symbol == NTokenContractId.nBAYC - )!.tokenAddress; - const nMAYC = - // eslint-disable-next-line - allTokens.find( - (x) => x.symbol == NTokenContractId.nMAYC - )!.tokenAddress; nTokenBAKCImplementationAddress = ( await deployNTokenBAKCImpl( pool.address, - apeCoinStaking, - nBAYC, - nMAYC, delegationRegistryAddress, verify ) diff --git a/helpers/misc-utils.ts b/helpers/misc-utils.ts index e2c42479f..d9a5695b6 100644 --- a/helpers/misc-utils.ts +++ b/helpers/misc-utils.ts @@ -1,11 +1,9 @@ -import mapLimit from "async/mapLimit"; import {isZeroAddress} from "ethereumjs-util"; import {BigNumber, ContractTransaction, Wallet} from "ethers"; import {isAddress} from "ethers/lib/utils"; import {HardhatRuntimeEnvironment} from "hardhat/types"; import low from "lowdb"; import {getAdapter} from "./db-adapter"; -import {verifyEtherscanContract} from "./etherscan"; import {eEthereumNetwork, IParaSpaceConfiguration} from "../helpers/types"; import {ParaSpaceConfigs} from "../market-config"; import { @@ -18,9 +16,22 @@ import { HARDHAT_CHAINID, MAINNET_CHAINID, MOONBEAM_CHAINID, + POLYGON_MUMBAI_CHAINID, + POLYGON_CHAINID, + POLYGON_ZKEVM_CHAINID, + POLYGON_ZKEVM_GOERLI_CHAINID, + ZKSYNC_CHAINID, + ZKSYNC_GOERLI_CHAINID, + ETHERSCAN_NETWORKS, + ETHERSCAN_VERIFICATION_CONTRACTS, + ETHERSCAN_KEY, + MOONBASE_CHAINID, + LINEA_CHAINID, + LINEA_GOERLI_CHAINID, } from "./hardhat-constants"; import {ConstructorArgs, eContractid, tEthereumAddress} from "./types"; import dotenv from "dotenv"; +import minimatch from "minimatch"; dotenv.config(); @@ -44,12 +55,24 @@ export const isLocalTestnet = (): boolean => { export const isPublicTestnet = (): boolean => { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion return ( - [GOERLI_CHAINID, ARBITRUM_GOERLI_CHAINID].includes( - DRE.network.config.chainId! - ) || - [eEthereumNetwork.goerli, eEthereumNetwork.arbitrumGoerli].includes( - FORK as eEthereumNetwork - ) + [ + GOERLI_CHAINID, + ARBITRUM_GOERLI_CHAINID, + ZKSYNC_GOERLI_CHAINID, + POLYGON_ZKEVM_GOERLI_CHAINID, + POLYGON_MUMBAI_CHAINID, + MOONBASE_CHAINID, + LINEA_GOERLI_CHAINID, + ].includes(DRE.network.config.chainId!) || + [ + eEthereumNetwork.goerli, + eEthereumNetwork.arbitrumGoerli, + eEthereumNetwork.zksyncGoerli, + eEthereumNetwork.polygonZkevmGoerli, + eEthereumNetwork.polygonMumbai, + eEthereumNetwork.moonbase, + eEthereumNetwork.lineaGoerli, + ].includes(FORK as eEthereumNetwork) ); }; @@ -66,7 +89,7 @@ export const isMoonbeam = (): boolean => { ); }; -export const isArbitrumOne = (): boolean => { +export const isArbitrum = (): boolean => { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion return ( [ARBITRUM_ONE_CHAINID].includes(DRE.network.config.chainId!) || @@ -82,6 +105,71 @@ export const isEthereum = (): boolean => { ); }; +export const isPolygon = (): boolean => { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return ( + [POLYGON_CHAINID].includes(DRE.network.config.chainId!) || + [eEthereumNetwork.polygon].includes(FORK as eEthereumNetwork) + ); +}; + +export const isPolygonZkEVM = (): boolean => { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return ( + [POLYGON_ZKEVM_CHAINID].includes(DRE.network.config.chainId!) || + [eEthereumNetwork.polygonZkevm].includes(FORK as eEthereumNetwork) + ); +}; + +export const isZkSync = (): boolean => { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return ( + [ZKSYNC_CHAINID].includes(DRE.network.config.chainId!) || + [eEthereumNetwork.zksync].includes(FORK as eEthereumNetwork) + ); +}; + +export const isLinea = (): boolean => { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return ( + [LINEA_CHAINID].includes(DRE.network.config.chainId!) || + [eEthereumNetwork.linea].includes(FORK as eEthereumNetwork) + ); +}; + +export const isMainnet = (): boolean => + isEthereum() || + isMoonbeam() || + isArbitrum() || + isZkSync() || + isPolygon() || + isPolygonZkEVM() || + isLinea(); + +export const safeTransactionServiceUrl = (): string => { + return isMoonbeam() + ? "https://transaction.multisig.moonbeam.network" + : `https://safe-transaction-${FORK || DRE.network.name}.safe.global`; +}; + +export const shouldVerifyContract = (contractId: string): boolean => { + if (!ETHERSCAN_NETWORKS.includes(DRE.network.name)) { + return false; + } + + if ( + ETHERSCAN_VERIFICATION_CONTRACTS?.every((p) => !minimatch(contractId, p)) + ) { + return false; + } + + if (!ETHERSCAN_KEY) { + throw Error("Missing ETHERSCAN_KEY."); + } + + return true; +}; + export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); @@ -186,20 +274,6 @@ export const printContracts = () => { console.log(contractsPrint.join("\n")); }; -export const verifyContracts = async (limit = 1) => { - const db = getDb(); - const network = DRE.network.name; - const entries = Object.entries(db.getState()).filter(([, value]) => { - // constructorArgs must be Array to make the contract verifiable - return !!value[network] && Array.isArray(value[network].constructorArgs); - }); - - await mapLimit(entries, limit, async ([key, value]) => { - const {address, constructorArgs = [], libraries} = value[network]; - await verifyEtherscanContract(key, address, constructorArgs, libraries); - }); -}; - export const notFalsyOrZeroAddress = ( address: tEthereumAddress | null | undefined ): boolean => { diff --git a/helpers/oracles-helpers.ts b/helpers/oracles-helpers.ts index 11c332516..89ca14cf8 100644 --- a/helpers/oracles-helpers.ts +++ b/helpers/oracles-helpers.ts @@ -45,6 +45,7 @@ export const setInitialAssetPricesInOracle = async ( priceOracleInstance: PriceOracle ) => { for (const [assetSymbol, price] of Object.entries(prices)) { + console.log(`set ${assetSymbol} price`); await waitForTx( await priceOracleInstance.setAssetPrice( assetsAddresses[assetSymbol], diff --git a/helpers/tenderly-utils.ts b/helpers/tenderly-utils.ts index 6de561129..ddd78c6fe 100644 --- a/helpers/tenderly-utils.ts +++ b/helpers/tenderly-utils.ts @@ -1,19 +1,22 @@ import {HardhatRuntimeEnvironment} from "hardhat/types"; import {DRE} from "./misc-utils"; -import {Contract} from "ethers"; import {TENDERLY} from "./hardhat-constants"; +import {tEthereumAddress} from "./types"; export const usingTenderly = () => DRE && ((DRE as HardhatRuntimeEnvironment).network.name.includes("tenderly") || TENDERLY); -export const verifyAtTenderly = async (id: string, instance: Contract) => { +export const verifyAtTenderly = async ( + id: string, + address: tEthereumAddress +) => { console.log("\n- Doing Tenderly contract verification of", id); // eslint-disable-next-line await (DRE as any).tenderlyNetwork.verify({ name: id, - address: instance.address, + address, }); console.log(` - Verified ${id} at Tenderly!`); }; diff --git a/helpers/types.ts b/helpers/types.ts index 20d97c1ae..e7f8fe65b 100644 --- a/helpers/types.ts +++ b/helpers/types.ts @@ -1,18 +1,5 @@ import {BigNumber, BigNumberish, BytesLike} from "ethers"; -import {PromiseOrValue} from "../types/common"; - -import {BlurExchangeLibraryAddresses} from "../types/factories/contracts/dependencies/blur-exchange/BlurExchange__factory"; -import {LiquidationLogicLibraryAddresses} from "../types/factories/contracts/protocol/libraries/logic/LiquidationLogic__factory"; -import {PoolConfiguratorLibraryAddresses} from "../types/factories/contracts/protocol/pool/PoolConfigurator__factory"; -import {PoolCoreLibraryAddresses} from "../types/factories/contracts/protocol/pool/PoolCore__factory"; -import {PoolMarketplaceLibraryAddresses} from "../types/factories/contracts/protocol/pool/PoolMarketplace__factory"; -import {PoolParametersLibraryAddresses} from "../types/factories/contracts/protocol/pool/PoolParameters__factory"; -import {NTokenBAYCLibraryAddresses} from "../types/factories/contracts/protocol/tokenization/NTokenBAYC__factory"; -import {NTokenMAYCLibraryAddresses} from "../types/factories/contracts/protocol/tokenization/NTokenMAYC__factory"; -import {NTokenMoonBirdsLibraryAddresses} from "../types/factories/contracts/protocol/tokenization/NTokenMoonBirds__factory"; -import {NTokenUniswapV3LibraryAddresses} from "../types/factories/contracts/protocol/tokenization/NTokenUniswapV3__factory"; -import {NTokenLibraryAddresses} from "../types/factories/contracts/protocol/tokenization/NToken__factory"; -import {PoolPositionMoverLibraryAddresses} from "../types/factories/contracts/protocol/pool/PoolPositionMover__factory"; +import {Libraries} from "hardhat/types"; export enum AssetType { ERC20 = 0, @@ -27,6 +14,11 @@ export enum DryRunExecutor { None = "", } +export enum EtherscanVerificationProvider { + hardhat = "hardhat", + foundry = "foundry", +} + export enum TimeLockOperation { Queue = "queue", Execute = "execute", @@ -63,6 +55,17 @@ export enum XTokenType { NTokenOtherdeed = 15, NTokenStakefish = 16, NTokenChromieSquiggle = 17, + PhantomData1 = 18, + PhantomData2 = 19, + PhantomData3 = 20, + PhantomData4 = 21, + PhantomData5 = 22, + PhantomData6 = 23, + PhantomData7 = 24, + PhantomData8 = 25, + PhantomData9 = 26, + PhantomData10 = 27, + PTokenStKSM = 28, } export type ConstructorArgs = ( @@ -74,25 +77,11 @@ export type ConstructorArgs = ( | boolean[] )[]; -export type LibraryAddresses = {[key: string]: string}; - -export type ParaSpaceLibraryAddresses = - | LiquidationLogicLibraryAddresses - | PoolCoreLibraryAddresses - | PoolMarketplaceLibraryAddresses - | PoolParametersLibraryAddresses - | PoolConfiguratorLibraryAddresses - | BlurExchangeLibraryAddresses - | NTokenBAYCLibraryAddresses - | NTokenMAYCLibraryAddresses - | NTokenLibraryAddresses - | NTokenUniswapV3LibraryAddresses - | NTokenMoonBirdsLibraryAddresses - | PoolPositionMoverLibraryAddresses - | {["NFTDescriptor"]: string}; +export type LibraryAddresses = Libraries; + +export type ParaSpaceLibraryAddresses = Libraries; export enum eEthereumNetwork { - kovan = "kovan", ropsten = "ropsten", goerli = "goerli", mainnet = "mainnet", @@ -103,8 +92,17 @@ export enum eEthereumNetwork { localhost = "localhost", anvil = "anvil", moonbeam = "moonbeam", + moonbase = "moonbase", arbitrum = "arbitrum", arbitrumGoerli = "arbitrumGoerli", + polygon = "polygon", + polygonMumbai = "polygonMumbai", + polygonZkevm = "polygonZkevm", + polygonZkevmGoerli = "polygonZkevmGoerli", + zksync = "zksync", + zksyncGoerli = "zksyncGoerli", + linea = "linea", + lineaGoerli = "lineaGoerli", } export enum eContractid { @@ -114,7 +112,6 @@ export enum eContractid { MintableDelegationERC20 = "MintableDelegationERC20", PoolAddressesProviderRegistry = "PoolAddressesProviderRegistry", ACLManager = "ACLManager", - PoolParametersProvider = "PoolParametersProvider", PoolConfiguratorProxy = "PoolConfiguratorProxy", ValidationLogic = "ValidationLogic", ReserveLogic = "ReserveLogic", @@ -138,6 +135,7 @@ export enum eContractid { PTokenSApeImpl = "PTokenSApeImpl", PTokenATokenImpl = "PTokenATokenImpl", PTokenStETHImpl = "PTokenStETHImpl", + PTokenStKSMImpl = "PTokenStKSMImpl", PTokenAStETHImpl = "PTokenAStETHImpl", PTokenCApeImpl = "PTokenCApeImpl", PYieldTokenImpl = "PYieldTokenImpl", @@ -149,7 +147,6 @@ export enum eContractid { NTokenBAKCImpl = "NTokenBAKCImpl", DelegationAwarePTokenImpl = "DelegationAwarePTokenImpl", VariableDebtTokenImpl = "VariableDebtTokenImpl", - PsAPeDebtTokenImpl = "PsAPeDebtTokenImpl", MockVariableDebtToken = "MockVariableDebtToken", FlashClaimRegistry = "FlashClaimRegistry", UserFlashClaimRegistryProxy = "UserFlashClaimRegistryProxy", @@ -240,9 +237,9 @@ export enum eContractid { ApeCoinStaking = "ApeCoinStaking", ATokenDebtToken = "ATokenDebtToken", StETHDebtToken = "StETHDebtToken", + StKSMDebtToken = "StKSMDebtToken", CApeDebtToken = "CApeDebtToken", AStETHDebtToken = "AStETHDebtToken", - ApeStakingLogic = "ApeStakingLogic", MintableERC721Logic = "MintableERC721Logic", MerkleVerifier = "MerkleVerifier", ExecutionDelegate = "ExecutionDelegate", @@ -260,6 +257,12 @@ export enum eContractid { HelperContractImpl = "HelperContractImpl", HelperContract = "HelperContract", P2PPairStakingImpl = "P2PPairStakingImpl", + ApeStakingP2PLogic = "ApeStakingP2PLogic", + ApeStakingPairPoolLogic = "ApeStakingPairPoolLogic", + ApeStakingSinglePoolLogic = "ApeStakingSinglePoolLogic", + ApeStakingApeCoinPoolLogic = "ApeStakingApeCoinPoolLogic", + ParaApeStakingImpl = "ParaApeStakingImpl", + ParaApeStaking = "ParaApeStaking", yAPE = "yAPE", yAPEImpl = "yAPEImpl", ParaProxyInterfacesImpl = "ParaProxyInterfacesImpl", @@ -286,6 +289,8 @@ export enum eContractid { VSL = "VSL", KODA = "KODA", BLOCKS = "BLOCKS", + EXRP = "EXRP", + WGLMR = "WGLMR", MockBendDaoLendPool = "MockBendDaoLendPool", PositionMoverLogic = "PositionMoverLogic", PoolPositionMoverImpl = "PoolPositionMoverImpl", @@ -411,6 +416,29 @@ export enum ProtocolErrors { INVALID_TOKEN_ID = "135", //invalid token id + CALLER_NOT_ALLOWED = "141", //The caller of the function is not allowed + + INVALID_PARAMETER = "170", //invalid parameter + APE_POSITION_EXISTED = "171", //ape staking position already existed + BAKC_POSITION_EXISTED = "172", //bakc staking position already existed + PAIR_POSITION_EXISTED = "173", //pair staking position already existed + NOT_PAIRED_APE_AND_BAKC = "174", //not paired ape and bakc + NOT_APE_STAKING_BOT = "175", //not ape staking bot + NOT_THE_SAME_OWNER = "176", //not the same owner + NFT_NOT_IN_POOL = "178", //nft not in single pool + SAPE_FREE_BALANCE_NOT_ENOUGH = "179", //sape free balance not enough + NOT_ORDER_OFFERER = "180", //not order offerer + ORDER_ALREADY_CANCELLED = "181", //order already cancelled + ORDER_NOT_STARTED = "182", //order not started + ORDER_EXPIRED = "183", //order expired + INVALID_TOKEN = "184", //invalid token + INVALID_ORDER_STATUS = "185", //invalid order status + INVALID_STAKING_TYPE = "186", //invalid stake type + ORDER_TYPE_MATCH_FAILED = "187", //orders type match failed + ORDER_SHARE_MATCH_FAILED = "188", //orders share match failed + NO_BREAK_UP_PERMISSION = "189", //no permission to break up + INVALID_CASH_AMOUNT = "190", //invalid cash amount + // SafeCast SAFECAST_UINT128_OVERFLOW = "SafeCast: value doesn't fit in 128 bits", @@ -466,6 +494,11 @@ export interface iAssetBase { cETH: T; PUNK: T; xcDOT: T; + xcUSDT: T; + stDOT: T; + USDCWH: T; + WETHWH: T; + WBTCWH: T; WGLMR: T; BLUR: T; ARB: T; @@ -475,6 +508,9 @@ export interface iAssetBase { BAL: T; AAVE: T; RDNT: T; + MATIC: T; + stMATIC: T; + CRV: T; BAYC: T; WPUNKS: T; PUNKS: T; @@ -493,6 +529,7 @@ export interface iAssetBase { VSL: T; KODA: T; BLOCKS: T; + EXRP: T; } export type iAssetsWithoutETH = Omit, "ETH">; @@ -522,6 +559,11 @@ export type iParaSpacePoolAssets = Pick< | "cETH" | "PUNK" | "xcDOT" + | "xcUSDT" + | "stDOT" + | "USDCWH" + | "WETHWH" + | "WBTCWH" | "WGLMR" | "BLUR" | "ARB" @@ -531,6 +573,9 @@ export type iParaSpacePoolAssets = Pick< | "BAL" | "AAVE" | "RDNT" + | "MATIC" + | "stMATIC" + | "CRV" | "BAYC" | "PUNKS" | "WPUNKS" @@ -549,6 +594,7 @@ export type iParaSpacePoolAssets = Pick< | "VSL" | "KODA" | "BLOCKS" + | "EXRP" >; export type iMultiPoolsAssets = iAssetCommon | iParaSpacePoolAssets; @@ -577,6 +623,11 @@ export enum ERC20TokenContractId { cETH = "cETH", PUNK = "PUNK", xcDOT = "xcDOT", + xcUSDT = "xcUSDT", + stDOT = "stDOT", + USDCWH = "USDCWH", + WETHWH = "WETHWH", + WBTCWH = "WBTCWH", WGLMR = "WGLMR", BLUR = "BLUR", ARB = "ARB", @@ -586,6 +637,10 @@ export enum ERC20TokenContractId { BAL = "BAL", AAVE = "AAVE", RDNT = "RDNT", + MATIC = "MATIC", + stMATIC = "stMATIC", + CRV = "CRV", + WMATIC = "WMATIC", } export enum ERC721TokenContractId { @@ -610,6 +665,7 @@ export enum ERC721TokenContractId { VSL = "VSL", KODA = "KODA", BLOCKS = "BLOCKS", + EXRP = "EXRP", } export enum NTokenContractId { @@ -625,6 +681,7 @@ export enum NTokenContractId { nOTHR = "nOTHR", nSFVLDR = "nSFVLDR", nBLOCKS = "nBLOCKS", + nEXRP = "nEXRP", } export enum PTokenContractId { @@ -702,8 +759,6 @@ export type iParamsPerNetwork = iEthereumParamsPerNetwork; export type iParamsPerNetworkAll = iEthereumParamsPerNetwork; export interface iEthereumParamsPerNetwork { - [eEthereumNetwork.kovan]: T; - [eEthereumNetwork.ropsten]: T; [eEthereumNetwork.goerli]: T; [eEthereumNetwork.mainnet]: T; [eEthereumNetwork.hardhat]: T; @@ -712,8 +767,17 @@ export interface iEthereumParamsPerNetwork { [eEthereumNetwork.parallel]: T; [eEthereumNetwork.tenderlyMain]: T; [eEthereumNetwork.moonbeam]: T; + [eEthereumNetwork.moonbase]: T; [eEthereumNetwork.arbitrum]: T; [eEthereumNetwork.arbitrumGoerli]: T; + [eEthereumNetwork.polygon]: T; + [eEthereumNetwork.polygonMumbai]: T; + [eEthereumNetwork.polygonZkevm]: T; + [eEthereumNetwork.polygonZkevmGoerli]: T; + [eEthereumNetwork.zksync]: T; + [eEthereumNetwork.zksyncGoerli]: T; + [eEthereumNetwork.linea]: T; + [eEthereumNetwork.lineaGoerli]: T; } export enum RateMode { @@ -759,6 +823,11 @@ export interface IChainlinkConfig { cAPE?: tEthereumAddress; yAPE?: tEthereumAddress; xcDOT?: tEthereumAddress; + xcUSDT?: tEthereumAddress; + stDOT?: tEthereumAddress; + USDCWH?: tEthereumAddress; + WETHWH?: tEthereumAddress; + WBTCWH?: tEthereumAddress; WGLMR?: tEthereumAddress; ARB?: tEthereumAddress; GMX?: tEthereumAddress; @@ -767,6 +836,9 @@ export interface IChainlinkConfig { AAVE?: tEthereumAddress; BAL?: tEthereumAddress; RDNT?: tEthereumAddress; + WMATIC?: tEthereumAddress; + stMATIC?: tEthereumAddress; + CRV?: tEthereumAddress; // ERC721 DOODLE?: tEthereumAddress; BAYC?: tEthereumAddress; @@ -784,6 +856,7 @@ export interface IChainlinkConfig { VSL?: tEthereumAddress; KODA?: tEthereumAddress; BLOCKS?: tEthereumAddress; + EXRP?: tEthereumAddress; } export interface IYogaLabs { @@ -878,10 +951,10 @@ export interface IParaSpaceConfiguration extends ICommonConfiguration { export type PoolConfiguration = ICommonConfiguration | IParaSpaceConfiguration; export type Action = [ - PromiseOrValue, // target - PromiseOrValue, // value - PromiseOrValue, // signature - PromiseOrValue, // data - PromiseOrValue, // executeTime - PromiseOrValue // withDelegatecall + string, // target + BigNumberish, // value + string, // signature + BytesLike, // data + BigNumberish, // executeTime + boolean // withDelegatecall ]; diff --git a/market-config/auctionStrategies.ts b/market-config/auctionStrategies.ts index e258af3aa..79df5d8dd 100644 --- a/market-config/auctionStrategies.ts +++ b/market-config/auctionStrategies.ts @@ -221,6 +221,16 @@ export const auctionStrategyExp: IAuctionStrategyParams = { tickLength: "900", }; +export const auctionStrategyEXRP: IAuctionStrategyParams = { + name: "auctionStrategyEXRP", + maxPriceMultiplier: utils.parseUnits("3", 18).toString(), + minExpPriceMultiplier: utils.parseUnits("1.2", 18).toString(), + minPriceMultiplier: utils.parseUnits("0.8", 18).toString(), + stepLinear: utils.parseUnits("0.06875", 18).toString(), + stepExp: utils.parseUnits("0.0285474001559822", 18).toString(), + tickLength: "900", +}; + export const auctionStrategyLinear: IAuctionStrategyParams = { name: "auctionStrategyLinear", maxPriceMultiplier: utils.parseUnits("3", 18).toString(), diff --git a/market-config/index.ts b/market-config/index.ts index 7f7114ea9..f831bd98e 100644 --- a/market-config/index.ts +++ b/market-config/index.ts @@ -7,10 +7,13 @@ import { } from "../helpers/types"; import {MocksConfig, MocksUSDConfig} from "./mocks"; import { - ArbitrumOneOracleConfig, + ArbitrumOracleConfig, + LineaOracleConfig, MainnetOracleConfig, MoonbeamOracleConfig, + PolygonOracleConfig, TestnetOracleConfig, + ZkSyncOracleConfig, } from "./oracle"; import { strategyDAI, @@ -64,6 +67,15 @@ import { strategyAAVE, strategyUNI, strategyRDNT, + strategySTMATIC, + strategyCRV, + strategyWMATIC, + strategyXCUSDT, + strategyUSDCWH, + strategyWETHWH, + strategyWBTCWH, + strategySTDOT, + strategyEXRP, } from "./reservesConfigs"; export const CommonConfig: Pick< @@ -121,7 +133,7 @@ export const CommonConfig: Pick< }, }; -export const HardhatParaSpaceConfig: IParaSpaceConfiguration = { +export const HardhatConfig: IParaSpaceConfiguration = { // BASIC INFO ...CommonConfig, ParaSpaceTeam: "0xc783df8a850f42e7F7e57013759C285caa701eB6", @@ -171,20 +183,32 @@ export const HardhatParaSpaceConfig: IParaSpaceConfiguration = { }, }; -export const MoonbeamParaSpaceConfig: IParaSpaceConfiguration = { +export const MoonbeamConfig: IParaSpaceConfiguration = { // BASIC INFO ...CommonConfig, WrappedNativeTokenId: ERC20TokenContractId.WGLMR, - ParaSpaceTeam: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", - Treasury: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", - ParaSpaceAdmin: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", - EmergencyAdmins: ["0x018281853eCC543Aa251732e8FDaa7323247eBeB"], - RiskAdmin: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", - GatewayAdmin: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + ParaSpaceAdmin: "0x4a84d250419697440FDCea4826E2421b84af69Fe", + EmergencyAdmins: [ + "0x17816E9A858b161c3E37016D139cf618056CaCD4", + "0x69FAD68De47D5666Ad668C7D682dDb8FD6322949", + "0x2f2d07d60ea7330DD2314f4413CCbB2dC25276EF", + "0x001e2bcC5c1BfC3131d33Ba074B12c2F1237FB04", + "0x4a84d250419697440FDCea4826E2421b84af69Fe", + "0x4AC3fD073786a971e1B8dE5a526959c9B3B2B407", + ], + RiskAdmin: "0x4a84d250419697440FDCea4826E2421b84af69Fe", + GatewayAdmin: "0x4a84d250419697440FDCea4826E2421b84af69Fe", + ParaSpaceTeam: "0x4a84d250419697440FDCea4826E2421b84af69Fe", + Treasury: "0x4a84d250419697440FDCea4826E2421b84af69Fe", Tokens: { WGLMR: "0xAcc15dC74880C9944775448304B263D191c6077F", xcDOT: "0xFfFFfFff1FcaCBd218EDc0EbA20Fc2308C778080", - USDC: "0x818ec0A7Fe18Ff94269904fCED6AE3DaE6d6dC0b", + xcUSDT: "0xFFFFFFfFea09FB06d082fd1275CD48b191cbCD1d", + stDOT: "0xFA36Fe1dA08C89eC72Ea1F0143a35bFd5DAea108", + USDC: "0x931715fee2d06333043d11f658c8ce934ac61d0c", + WETH: "0xab3f0245b83feb11d15aaffefd7ad465a59817ed", + WBTC: "0xe57ebd2d67b462e9926e04a8e33f01cd0d64346d", + EXRP: "0x515e20e6275CEeFe19221FC53e77E38cc32b80Fb", }, YogaLabs: {}, Uniswap: {}, @@ -194,18 +218,65 @@ export const MoonbeamParaSpaceConfig: IParaSpaceConfiguration = { Chainlink: { WGLMR: "0x4497B606be93e773bbA5eaCFCb2ac5E2214220Eb", xcDOT: "0x1466b4bD0C4B6B8e1164991909961e0EE6a66d8c", - USDC: "0xA122591F60115D63421f66F752EF9f6e0bc73abC", + xcUSDT: "0xd925c5bf88bd0ca09312625d429240f811b437c6", + stDOT: "0xd925c5bf88bd0ca09312625d429240f811b437c6", + USDC: "0xa122591f60115d63421f66f752ef9f6e0bc73abc", + WETH: "0x9ce2388a1696e22f870341c3fc1e89710c7569b5", + WBTC: "0x8211b991d713ddae32326fd69e1e2510f4a653b0", }, // RESERVE ASSETS - CONFIG, ASSETS, BORROW RATES, ReservesConfig: { xcDOT: strategyXCDOT, + xcUSDT: strategyXCUSDT, + stDOT: strategySTDOT, WGLMR: strategyWGLMR, - USDC: strategyUSDC, + USDC: strategyUSDCWH, + WETH: strategyWETHWH, + WBTC: strategyWBTCWH, + EXRP: strategyEXRP, }, + Mocks: undefined, Oracle: MoonbeamOracleConfig, + Governance: { + Multisend: MULTI_SEND || "0x40A2aCCbd92BCA938b02010E17A5b8929b49130D", + Multisig: MULTI_SIG || "0x4a84d250419697440FDCea4826E2421b84af69Fe", + }, }; -export const GoerliParaSpaceConfig: IParaSpaceConfiguration = { +export const MoonbaseConfig: IParaSpaceConfiguration = { + // BASIC INFO + ...CommonConfig, + WrappedNativeTokenId: ERC20TokenContractId.WGLMR, + ParaSpaceTeam: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + Treasury: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + ParaSpaceAdmin: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + EmergencyAdmins: ["0x018281853eCC543Aa251732e8FDaa7323247eBeB"], + RiskAdmin: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + GatewayAdmin: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + Tokens: { + WGLMR: "0xD909178CC99d318e4D46e7E66a972955859670E1", + }, + YogaLabs: {}, + Uniswap: {}, + Marketplace: {}, + BendDAO: {}, + Stakefish: {}, + Chainlink: {}, + // RESERVE ASSETS - CONFIG, ASSETS, BORROW RATES, + ReservesConfig: { + xcDOT: strategyXCDOT, + xcUSDT: strategyXCUSDT, + stDOT: strategySTDOT, + WGLMR: strategyWGLMR, + USDC: strategyUSDCWH, + WETH: strategyWETHWH, + WBTC: strategyWBTCWH, + EXRP: strategyEXRP, + }, + Mocks: MocksUSDConfig, + Oracle: MoonbeamOracleConfig, +}; +export const GoerliConfig: IParaSpaceConfiguration = { // BASIC INFO ...CommonConfig, ParaSpaceTeam: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", @@ -305,6 +376,197 @@ export const GoerliParaSpaceConfig: IParaSpaceConfiguration = { DelegationRegistry: "0x00000000000076A84feF008CDAbe6409d2FE638B", }; +export const PolygonConfig: IParaSpaceConfiguration = { + // BASIC INFO + ...CommonConfig, + WrappedNativeTokenId: ERC20TokenContractId.WMATIC, + ParaSpaceAdmin: "0xeeE8Fd9B887ee57CAf2905851175470c03DE64F6", + EmergencyAdmins: [ + "0x17816E9A858b161c3E37016D139cf618056CaCD4", + "0x69FAD68De47D5666Ad668C7D682dDb8FD6322949", + "0x2f2d07d60ea7330DD2314f4413CCbB2dC25276EF", + "0x001e2bcC5c1BfC3131d33Ba074B12c2F1237FB04", + "0xeeE8Fd9B887ee57CAf2905851175470c03DE64F6", + "0x4AC3fD073786a971e1B8dE5a526959c9B3B2B407", + ], + RiskAdmin: "0xeeE8Fd9B887ee57CAf2905851175470c03DE64F6", + GatewayAdmin: "0xeeE8Fd9B887ee57CAf2905851175470c03DE64F6", + ParaSpaceTeam: "0xeeE8Fd9B887ee57CAf2905851175470c03DE64F6", + Treasury: "0xeeE8Fd9B887ee57CAf2905851175470c03DE64F6", + Tokens: { + WMATIC: "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270", + stMATIC: "0x3a58a54c066fdc0f2d55fc9c89f0415c92ebf3c4", + WETH: "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619", + WBTC: "0x1BFD67037B42Cf73acF2047067bd4F2C47D9BfD6", + USDT: "0xc2132D05D31c914a87C6611C10748AEb04B58e8F", + USDC: "0x2791bca1f2de4661ed88a30c99a7a9449aa84174", + DAI: "0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063", + UNI: "0xb33EaAd8d922B1083446DC23f610c2567fB5180f", + LINK: "0x53E0bca35eC356BD5ddDFebbD1Fc0fD03FaBad39", + AAVE: "0xD6DF932A45C0f255f85145f286eA0b292B21C90B", + BAL: "0x9a71012B13CA4d3D0Cdc72A177DF3ef03b0E76A3", + CRV: "0x172370d5Cd63279eFa6d502DAB29171933a610AF", + UniswapV3: "0xc36442b4a4522e871399cd717abdd847ab11fe88", + }, + YogaLabs: {}, + Uniswap: { + V3Factory: "0x1F98431c8aD98523631AE4a59f267346ea31F984", + V3NFTPositionManager: "0xc36442b4a4522e871399cd717abdd847ab11fe88", + V3Router: "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45", + }, + Marketplace: { + Seaport: "0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC", + }, + BendDAO: {}, + Stakefish: {}, + Chainlink: { + DAI: "0x4746dec9e833a82ec7c2c1356372ccf2cfcd2f3d", + USDT: "0x0a6513e40db6eb1b165753ad52e80663aea50545", + USDC: "0xfe4a8cc5b5b2366c1b58bea3858e81843581b2f7", + WETH: "0xf9680d99d6c9589e2a93a78a04a279e509205945", + WBTC: "0xc907e116054ad103354f2d350fd2514433d57f6f", + WMATIC: "0xab594600376ec9fd91f8e885dadf0ce036862de0", + LINK: "0xd9ffdb71ebe7496cc440152d43986aae0ab76665", + UNI: "0xdf0fb4e4f928d2dcb76f438575fdd8682386e13c", + AAVE: "0x72484b12719e23115761d5da1646945632979bb6", + BAL: "0xd106b538f2a868c28ca1ec7e298c3325e0251d66", + CRV: "0x336584C8E6Dc19637A5b36206B1c79923111b405", + stMATIC: "0xEe96b77129cF54581B5a8FECCcC50A6A067034a1", + }, + ReservesConfig: { + DAI: strategyDAI, + USDT: strategyUSDT, + USDC: strategyUSDC, + WETH: strategyWETH, + WBTC: strategyWBTC, + WMATIC: strategyWMATIC, + stMATIC: strategySTMATIC, + AAVE: strategyAAVE, + LINK: strategyLINK, + BAL: strategyBAL, + UNI: strategyUNI, + CRV: strategyCRV, + UniswapV3: strategyUniswapV3, + }, + Mocks: undefined, + Oracle: PolygonOracleConfig, + Governance: { + Multisend: MULTI_SEND || "0x40A2aCCbd92BCA938b02010E17A5b8929b49130D", + Multisig: MULTI_SIG || "0xeeE8Fd9B887ee57CAf2905851175470c03DE64F6", + }, +}; + +export const PolygonZkevmConfig: IParaSpaceConfiguration = { + // BASIC INFO + ...CommonConfig, + ParaSpaceTeam: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + Treasury: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + ParaSpaceAdmin: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + EmergencyAdmins: ["0x018281853eCC543Aa251732e8FDaa7323247eBeB"], + RiskAdmin: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + GatewayAdmin: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + Tokens: {}, + YogaLabs: {}, + Uniswap: {}, + Marketplace: {}, + BendDAO: {}, + Stakefish: {}, + Chainlink: {}, + ReservesConfig: { + DAI: strategyDAI, + USDC: strategyUSDC, + USDT: strategyUSDT, + FRAX: strategyFRAX, + WETH: strategyWETH, + WBTC: strategyWBTC, + stETH: strategySTETH, + wstETH: strategyWSTETH, + WMATIC: strategyWMATIC, + stMATIC: strategySTMATIC, + CRV: strategyCRV, + UniswapV3: strategyUniswapV3, + }, + Mocks: MocksUSDConfig, + Oracle: PolygonOracleConfig, +}; + +export const PolygonMumbaiConfig: IParaSpaceConfiguration = { + // BASIC INFO + ...CommonConfig, + WrappedNativeTokenId: ERC20TokenContractId.WMATIC, + ParaSpaceTeam: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + Treasury: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + ParaSpaceAdmin: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + EmergencyAdmins: ["0x018281853eCC543Aa251732e8FDaa7323247eBeB"], + RiskAdmin: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + GatewayAdmin: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + Tokens: { + WETH: "0xA6FA4fB5f76172d178d61B04b0ecd319C5d1C0aa", + WMATIC: "0x9c3C9283D3e44854697Cd22D3Faa240Cfb032889", + UniswapV3: "0xc36442b4a4522e871399cd717abdd847ab11fe88", + }, + YogaLabs: {}, + Uniswap: { + V3Factory: "0x1F98431c8aD98523631AE4a59f267346ea31F984", + V3NFTPositionManager: "0xc36442b4a4522e871399cd717abdd847ab11fe88", + V3Router: "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45", + }, + Marketplace: {}, + BendDAO: {}, + Stakefish: {}, + Chainlink: {}, + ReservesConfig: { + DAI: strategyDAI, + USDC: strategyUSDC, + USDT: strategyUSDT, + FRAX: strategyFRAX, + WETH: strategyWETH, + WBTC: strategyWBTC, + stETH: strategySTETH, + wstETH: strategyWSTETH, + stMATIC: strategySTMATIC, + WMATIC: strategyWMATIC, + CRV: strategyCRV, + UniswapV3: strategyUniswapV3, + }, + Mocks: MocksUSDConfig, + Oracle: PolygonOracleConfig, +}; + +export const PolygonZkevmGoerliConfig: IParaSpaceConfiguration = { + // BASIC INFO + ...CommonConfig, + ParaSpaceTeam: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + Treasury: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + ParaSpaceAdmin: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + EmergencyAdmins: ["0x018281853eCC543Aa251732e8FDaa7323247eBeB"], + RiskAdmin: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + GatewayAdmin: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + Tokens: {}, + YogaLabs: {}, + Uniswap: {}, + Marketplace: {}, + BendDAO: {}, + Stakefish: {}, + Chainlink: {}, + ReservesConfig: { + DAI: strategyDAI, + USDC: strategyUSDC, + USDT: strategyUSDT, + FRAX: strategyFRAX, + WETH: strategyWETH, + WBTC: strategyWBTC, + stETH: strategySTETH, + wstETH: strategyWSTETH, + WMATIC: strategyWMATIC, + stMATIC: strategySTMATIC, + CRV: strategyCRV, + UniswapV3: strategyUniswapV3, + }, + Mocks: MocksUSDConfig, + Oracle: PolygonOracleConfig, +}; + export const ArbitrumGoerliConfig: IParaSpaceConfiguration = { // BASIC INFO ...CommonConfig, @@ -353,22 +615,74 @@ export const ArbitrumGoerliConfig: IParaSpaceConfiguration = { UniswapV3: strategyUniswapV3, }, Mocks: MocksUSDConfig, - Oracle: ArbitrumOneOracleConfig, + Oracle: ArbitrumOracleConfig, +}; + +export const ZkSyncGoerliConfig: IParaSpaceConfiguration = { + // BASIC INFO + ...CommonConfig, + ParaSpaceTeam: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + Treasury: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + ParaSpaceAdmin: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + EmergencyAdmins: ["0x018281853eCC543Aa251732e8FDaa7323247eBeB"], + RiskAdmin: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + GatewayAdmin: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + Tokens: {}, + YogaLabs: {}, + Uniswap: {}, + Marketplace: {}, + BendDAO: {}, + Stakefish: {}, + Chainlink: {}, + ReservesConfig: { + DAI: strategyDAI, + USDC: strategyUSDC, + USDT: strategyUSDT, + FRAX: strategyFRAX, + WETH: strategyWETH, + WBTC: strategyWBTC, + }, + Mocks: MocksUSDConfig, + Oracle: ZkSyncOracleConfig, }; -export const ArbitrumOneParaSpaceConfig: IParaSpaceConfiguration = { +export const LineaGoerliConfig: IParaSpaceConfiguration = { + // BASIC INFO + ...CommonConfig, + ParaSpaceTeam: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + Treasury: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + ParaSpaceAdmin: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + EmergencyAdmins: ["0x018281853eCC543Aa251732e8FDaa7323247eBeB"], + RiskAdmin: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + GatewayAdmin: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + Tokens: {}, + YogaLabs: {}, + Uniswap: {}, + Marketplace: {}, + BendDAO: {}, + Stakefish: {}, + Chainlink: {}, + ReservesConfig: { + DAI: strategyDAI, + USDC: strategyUSDC, + USDT: strategyUSDT, + FRAX: strategyFRAX, + WETH: strategyWETH, + WBTC: strategyWBTC, + }, + Mocks: MocksUSDConfig, + Oracle: LineaOracleConfig, +}; + +export const ArbitrumConfig: IParaSpaceConfiguration = { // BASIC INFO ...CommonConfig, ParaSpaceAdmin: "0x1aD5db7e9fcdc6052A8362633E7CEaf80f623741", EmergencyAdmins: [ "0x17816E9A858b161c3E37016D139cf618056CaCD4", "0x69FAD68De47D5666Ad668C7D682dDb8FD6322949", - "0xD65Fee206a4ea89eBBcF4694E745C597AB6F8325", - "0x755C1bd877788739dD002B98B093c4852AbfA6c4", - "0x3A6c796edffc057d789F7d4ffAd438B1D48f3075", "0x2f2d07d60ea7330DD2314f4413CCbB2dC25276EF", "0x001e2bcC5c1BfC3131d33Ba074B12c2F1237FB04", - "0xe965198731CDdB2f06e91DD0CDff74b71e4b3714", "0x4AC3fD073786a971e1B8dE5a526959c9B3B2B407", ], RiskAdmin: "0x1aD5db7e9fcdc6052A8362633E7CEaf80f623741", @@ -398,7 +712,9 @@ export const ArbitrumOneParaSpaceConfig: IParaSpaceConfiguration = { V3Router: "0x4c60051384bd2d3c01bfc845cf5f4b44bcbe9de5", V3NFTPositionManager: "0xC36442b4a4522E871399CD717aBDD847Ab11FE88", }, - Marketplace: {}, + Marketplace: { + Seaport: "0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC", + }, BendDAO: {}, Stakefish: {}, Chainlink: { @@ -435,23 +751,89 @@ export const ArbitrumOneParaSpaceConfig: IParaSpaceConfiguration = { UniswapV3: strategyUniswapV3, }, Mocks: undefined, - Oracle: ArbitrumOneOracleConfig, + Oracle: ArbitrumOracleConfig, Governance: { Multisend: MULTI_SEND || "0x40A2aCCbd92BCA938b02010E17A5b8929b49130D", Multisig: MULTI_SIG || "0x1aD5db7e9fcdc6052A8362633E7CEaf80f623741", }, }; -export const MainnetParaSpaceConfig: IParaSpaceConfiguration = { +export const ZkSyncConfig: IParaSpaceConfiguration = { + // BASIC INFO + ...CommonConfig, + ParaSpaceAdmin: "0x3BeD3C25415e4D980954Dc5FDe2e11D7fb22E582", + EmergencyAdmins: [ + "0x17816E9A858b161c3E37016D139cf618056CaCD4", + "0x69FAD68De47D5666Ad668C7D682dDb8FD6322949", + "0x2f2d07d60ea7330DD2314f4413CCbB2dC25276EF", + "0x001e2bcC5c1BfC3131d33Ba074B12c2F1237FB04", + "0x4AC3fD073786a971e1B8dE5a526959c9B3B2B407", + ], + RiskAdmin: "0x3BeD3C25415e4D980954Dc5FDe2e11D7fb22E582", + GatewayAdmin: "0x3BeD3C25415e4D980954Dc5FDe2e11D7fb22E582", + ParaSpaceTeam: "0x3BeD3C25415e4D980954Dc5FDe2e11D7fb22E582", + Treasury: "0x909e36B512Ed45250fdff513523119d825647695", + Tokens: { + WETH: "0x5bF39BdE21B95d77fb18F27bBCb07F3648720A2e", + USDC: "0x3355df6D4c9C3035724Fd0e3914dE96A5a83aaf4", + WBTC: "0xBBeB516fb02a01611cBBE0453Fe3c580D7281011", + }, + YogaLabs: {}, + Uniswap: {}, + Marketplace: {}, + BendDAO: {}, + Stakefish: {}, + Chainlink: { + WETH: "0x279dBcc7417DC8a73F9154fb640E2467209C8C34", + USDC: "0x9Dc7257a0a21Ec3EAf0CbFB02fb01A2825a1e14e", + WBTC: "0x1474A19D97A9e84A201d481c2F995513d3380412", + }, + ReservesConfig: { + USDC: strategyUSDC, + WETH: strategyWETH, + WBTC: strategyWBTC, + }, + Mocks: undefined, + Oracle: ZkSyncOracleConfig, +}; + +export const LineaConfig: IParaSpaceConfiguration = { + // BASIC INFO + ...CommonConfig, + ParaSpaceTeam: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + Treasury: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + ParaSpaceAdmin: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + EmergencyAdmins: ["0x018281853eCC543Aa251732e8FDaa7323247eBeB"], + RiskAdmin: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + GatewayAdmin: "0x018281853eCC543Aa251732e8FDaa7323247eBeB", + Tokens: {}, + YogaLabs: {}, + Uniswap: {}, + Marketplace: {}, + BendDAO: {}, + Stakefish: {}, + Chainlink: {}, + ReservesConfig: { + DAI: strategyDAI, + USDC: strategyUSDC, + USDT: strategyUSDT, + FRAX: strategyFRAX, + WETH: strategyWETH, + WBTC: strategyWBTC, + stETH: strategySTETH, + wstETH: strategyWSTETH, + }, + Mocks: MocksUSDConfig, + Oracle: LineaOracleConfig, +}; + +export const MainnetConfig: IParaSpaceConfiguration = { // BASIC INFO ...CommonConfig, ParaSpaceAdmin: "0xe965198731CDdB2f06e91DD0CDff74b71e4b3714", EmergencyAdmins: [ "0x17816E9A858b161c3E37016D139cf618056CaCD4", "0x69FAD68De47D5666Ad668C7D682dDb8FD6322949", - "0xD65Fee206a4ea89eBBcF4694E745C597AB6F8325", - "0x755C1bd877788739dD002B98B093c4852AbfA6c4", - "0x3A6c796edffc057d789F7d4ffAd438B1D48f3075", "0x2f2d07d60ea7330DD2314f4413CCbB2dC25276EF", "0x001e2bcC5c1BfC3131d33Ba074B12c2F1237FB04", "0xe965198731CDdB2f06e91DD0CDff74b71e4b3714", @@ -601,12 +983,21 @@ export const MainnetParaSpaceConfig: IParaSpaceConfiguration = { export const ParaSpaceConfigs: Partial< Record > = { - [eEthereumNetwork.hardhat]: HardhatParaSpaceConfig, - [eEthereumNetwork.anvil]: HardhatParaSpaceConfig, - [eEthereumNetwork.localhost]: HardhatParaSpaceConfig, - [eEthereumNetwork.moonbeam]: MoonbeamParaSpaceConfig, - [eEthereumNetwork.goerli]: GoerliParaSpaceConfig, - [eEthereumNetwork.mainnet]: MainnetParaSpaceConfig, + [eEthereumNetwork.hardhat]: HardhatConfig, + [eEthereumNetwork.anvil]: HardhatConfig, + [eEthereumNetwork.localhost]: HardhatConfig, + [eEthereumNetwork.moonbeam]: MoonbeamConfig, + [eEthereumNetwork.moonbase]: MoonbaseConfig, + [eEthereumNetwork.goerli]: GoerliConfig, + [eEthereumNetwork.mainnet]: MainnetConfig, [eEthereumNetwork.arbitrumGoerli]: ArbitrumGoerliConfig, - [eEthereumNetwork.arbitrum]: ArbitrumOneParaSpaceConfig, + [eEthereumNetwork.arbitrum]: ArbitrumConfig, + [eEthereumNetwork.polygon]: PolygonConfig, + [eEthereumNetwork.polygonMumbai]: PolygonMumbaiConfig, + [eEthereumNetwork.polygonZkevm]: PolygonZkevmConfig, + [eEthereumNetwork.polygonZkevmGoerli]: PolygonZkevmGoerliConfig, + [eEthereumNetwork.zksync]: ZkSyncConfig, + [eEthereumNetwork.zksyncGoerli]: ZkSyncGoerliConfig, + [eEthereumNetwork.linea]: LineaConfig, + [eEthereumNetwork.lineaGoerli]: LineaGoerliConfig, }; diff --git a/market-config/mocks.ts b/market-config/mocks.ts index 91b567fb8..6f937681f 100644 --- a/market-config/mocks.ts +++ b/market-config/mocks.ts @@ -25,7 +25,12 @@ export const MOCK_CHAINLINK_AGGREGATORS_PRICES = { awstETH: parseEther("1").toString(), PUNK: parseEther("140").toString(), xcDOT: parseEther("0.0038333333333").toString(), + xcUSDT: parseEther("0.000915952223931999").toString(), + stDOT: parseEther("0.0038333333333").toString(), WGLMR: parseEther("0.00027291666666").toString(), + USDCWH: parseEther("0.000915952223931999").toString(), + WETHWH: parseEther("1").toString(), + WBTCWH: parseEther("18.356369399062118").toString(), BLUR: parseEther("0.0005").toString(), ARB: parseEther("0.00082").toString(), GMX: parseEther("0.0435").toString(), @@ -34,6 +39,9 @@ export const MOCK_CHAINLINK_AGGREGATORS_PRICES = { BAL: parseEther("0.0028").toString(), AAVE: parseEther("0.032").toString(), RDNT: parseEther("0.00015").toString(), + MATIC: parseEther("0.00058").toString(), + stMATIC: parseEther("0.00058").toString(), + CRV: parseEther("0.00058").toString(), // ERC721 BAYC: parseEther("101").toString(), WPUNKS: parseEther("140").toString(), @@ -55,6 +63,7 @@ export const MOCK_CHAINLINK_AGGREGATORS_PRICES = { VSL: parseEther("0.373").toString(), KODA: parseEther("9.5").toString(), BLOCKS: parseEther("9.54").toString(), + EXRP: parseEther("0.2").toString(), }; export const MOCK_CHAINLINK_AGGREGATORS_USD_PRICES = { @@ -80,7 +89,12 @@ export const MOCK_CHAINLINK_AGGREGATORS_USD_PRICES = { awstETH: parseUnits("2116", 8).toString(), PUNK: parseUnits("140", 8).toString(), xcDOT: parseUnits("5.75", 8).toString(), + xcUSDT: parseUnits("1", 8).toString(), + stDOT: parseUnits("5.75", 8).toString(), WGLMR: parseUnits("0.33", 8).toString(), + USDCWH: parseUnits("1", 8).toString(), + WETHWH: parseUnits("1896", 8).toString(), + WBTCWH: parseUnits("29195", 8).toString(), BLUR: parseUnits("0.57", 8).toString(), ARB: parseUnits("1.32", 8).toString(), GMX: parseUnits("69.2", 8).toString(), @@ -89,6 +103,9 @@ export const MOCK_CHAINLINK_AGGREGATORS_USD_PRICES = { BAL: parseUnits("5.72", 8).toString(), AAVE: parseUnits("64", 8).toString(), RDNT: parseUnits("0.3", 8).toString(), + MATIC: parseUnits("6.4", 8).toString(), + stMATIC: parseUnits("6.4", 8).toString(), + CRV: parseUnits("6.4", 8).toString(), // ERC721 BAYC: parseUnits("96239", 8).toString(), WPUNKS: parseUnits("113896", 8).toString(), @@ -110,6 +127,7 @@ export const MOCK_CHAINLINK_AGGREGATORS_USD_PRICES = { VSL: parseUnits("568", 8).toString(), KODA: parseUnits("14154", 8).toString(), BLOCKS: parseUnits("10800", 8).toString(), + EXRP: parseUnits("170", 8).toString(), }; export const MOCK_TOKEN_MINT_VALUE = { diff --git a/market-config/oracle.ts b/market-config/oracle.ts index 4a0ca4928..7b599d6fd 100644 --- a/market-config/oracle.ts +++ b/market-config/oracle.ts @@ -6,26 +6,53 @@ export const MainnetOracleConfig: IOracleConfig = { BaseCurrency: ERC20TokenContractId.WETH, BaseCurrencyUnit: constants.WeiPerEther, BaseCurrencyDecimals: 18, - ExpirationPeriod: 1800, + ExpirationPeriod: 2400, DeviationRate: 300, Nodes: [], }; export const MoonbeamOracleConfig: IOracleConfig = { - BaseCurrency: ERC20TokenContractId.USDC, + BaseCurrency: ZERO_ADDRESS, BaseCurrencyUnit: BigNumber.from("100000000"), BaseCurrencyDecimals: 8, - ExpirationPeriod: 600, - DeviationRate: 1000, + ExpirationPeriod: 2400, + DeviationRate: 300, Nodes: [], }; -export const ArbitrumOneOracleConfig: IOracleConfig = { +export const ArbitrumOracleConfig: IOracleConfig = { BaseCurrency: ZERO_ADDRESS, BaseCurrencyUnit: BigNumber.from("100000000"), BaseCurrencyDecimals: 8, - ExpirationPeriod: 600, - DeviationRate: 1000, + ExpirationPeriod: 2400, + DeviationRate: 300, + Nodes: [], +}; + +export const PolygonOracleConfig: IOracleConfig = { + BaseCurrency: ZERO_ADDRESS, + BaseCurrencyUnit: BigNumber.from("100000000"), + BaseCurrencyDecimals: 8, + ExpirationPeriod: 2400, + DeviationRate: 300, + Nodes: [], +}; + +export const ZkSyncOracleConfig: IOracleConfig = { + BaseCurrency: ZERO_ADDRESS, + BaseCurrencyUnit: BigNumber.from("100000000"), + BaseCurrencyDecimals: 8, + ExpirationPeriod: 2400, + DeviationRate: 300, + Nodes: [], +}; + +export const LineaOracleConfig: IOracleConfig = { + BaseCurrency: ZERO_ADDRESS, + BaseCurrencyUnit: BigNumber.from("100000000"), + BaseCurrencyDecimals: 8, + ExpirationPeriod: 2400, + DeviationRate: 300, Nodes: [], }; diff --git a/market-config/rateStrategies.ts b/market-config/rateStrategies.ts index 7359ed8cb..3d3cc4b67 100644 --- a/market-config/rateStrategies.ts +++ b/market-config/rateStrategies.ts @@ -73,6 +73,46 @@ export const rateStrategyXCDOT: IInterestRateStrategyParams = { variableRateSlope2: utils.parseUnits("0.2", 27).toString(), }; +export const rateStrategySTDOT: IInterestRateStrategyParams = { + name: "rateStrategySTDOT", + optimalUsageRatio: utils.parseUnits("0.80", 27).toString(), + baseVariableBorrowRate: utils.parseUnits("0.02", 27).toString(), + variableRateSlope1: utils.parseUnits("0.25", 27).toString(), + variableRateSlope2: utils.parseUnits("0.2", 27).toString(), +}; + +export const rateStrategyXCUSDT: IInterestRateStrategyParams = { + name: "rateStrategyXCUSDT", + optimalUsageRatio: utils.parseUnits("0.80", 27).toString(), + baseVariableBorrowRate: utils.parseUnits("0.02", 27).toString(), + variableRateSlope1: utils.parseUnits("0.25", 27).toString(), + variableRateSlope2: utils.parseUnits("0.2", 27).toString(), +}; + +export const rateStrategyUSDCWH: IInterestRateStrategyParams = { + name: "rateStrategyUSDCWH", + optimalUsageRatio: utils.parseUnits("0.9", 27).toString(), + baseVariableBorrowRate: utils.parseUnits("0", 27).toString(), + variableRateSlope1: utils.parseUnits("0.04", 27).toString(), + variableRateSlope2: utils.parseUnits("0.60", 27).toString(), +}; + +export const rateStrategyWETHWH: IInterestRateStrategyParams = { + name: "rateStrategyWETHWH", + optimalUsageRatio: utils.parseUnits("0.7", 27).toString(), + baseVariableBorrowRate: utils.parseUnits("0.025", 27).toString(), + variableRateSlope1: utils.parseUnits("0.08", 27).toString(), + variableRateSlope2: utils.parseUnits("0.9", 27).toString(), +}; + +export const rateStrategyWBTCWH: IInterestRateStrategyParams = { + name: "rateStrategyWBTCWH", + optimalUsageRatio: utils.parseUnits("0.85", 27).toString(), + baseVariableBorrowRate: utils.parseUnits("0.18", 27).toString(), + variableRateSlope1: utils.parseUnits("0.08", 27).toString(), + variableRateSlope2: utils.parseUnits("0.6", 27).toString(), +}; + export const rateStrategyWGLMR: IInterestRateStrategyParams = { name: "rateStrategyWGLMR", optimalUsageRatio: utils.parseUnits("0.80", 27).toString(), @@ -145,6 +185,42 @@ export const rateStrategyRDNT: IInterestRateStrategyParams = { variableRateSlope2: utils.parseUnits("0.60", 27).toString(), }; +export const rateStrategyMATIC: IInterestRateStrategyParams = { + name: "rateStrategyMATIC", + optimalUsageRatio: utils.parseUnits("0.9", 27).toString(), + baseVariableBorrowRate: utils.parseUnits("0", 27).toString(), + variableRateSlope1: utils.parseUnits("0.04", 27).toString(), + variableRateSlope2: utils.parseUnits("0.60", 27).toString(), +}; + +export const rateStrategySTMATIC: IInterestRateStrategyParams = { + name: "rateStrategySTMATIC", + optimalUsageRatio: utils.parseUnits("0.9", 27).toString(), + baseVariableBorrowRate: utils.parseUnits("0", 27).toString(), + variableRateSlope1: utils.parseUnits("0.04", 27).toString(), + variableRateSlope2: utils.parseUnits("0.60", 27).toString(), +}; + +export const rateStrategyCRV: IInterestRateStrategyParams = { + name: "rateStrategyCRV", + optimalUsageRatio: utils.parseUnits("0.9", 27).toString(), + baseVariableBorrowRate: utils.parseUnits("0", 27).toString(), + variableRateSlope1: utils.parseUnits("0.04", 27).toString(), + variableRateSlope2: utils.parseUnits("0.60", 27).toString(), +}; + +export const rateStrategyWMATIC: IInterestRateStrategyParams = { + name: "rateStrategyWMATIC", + optimalUsageRatio: utils.parseUnits("0.7", 27).toString(), + baseVariableBorrowRate: utils.parseUnits("0.025", 27).toString(), + variableRateSlope1: utils.parseUnits("0.08", 27).toString(), + variableRateSlope2: utils.parseUnits("0.9", 27).toString(), +}; + +//////////////////////////////////////////////////////////////////////////////// +// ERC721 +//////////////////////////////////////////////////////////////////////////////// + export const rateStrategyNFT: IInterestRateStrategyParams = { name: "rateStrategyNFT", optimalUsageRatio: utils.parseUnits("0.45", 27).toString(), diff --git a/market-config/reservesConfigs.ts b/market-config/reservesConfigs.ts index 5d3aaa7af..d209291b3 100644 --- a/market-config/reservesConfigs.ts +++ b/market-config/reservesConfigs.ts @@ -21,6 +21,8 @@ import { auctionStrategyVSL, auctionStrategyWPunks, auctionStrategyZero, + auctionStrategyEXRP, + auctionStrategyUniswapV3, } from "./auctionStrategies"; import { rateStrategyAAVE, @@ -28,19 +30,27 @@ import { rateStrategyARB, rateStrategyBAL, rateStrategyBLUR, + rateStrategyCRV, rateStrategyDAI, rateStrategyFRAX, rateStrategyGMX, rateStrategyLINK, rateStrategyNFT, rateStrategyRDNT, + rateStrategySTDOT, + rateStrategySTMATIC, rateStrategyUNI, rateStrategyUSDC, + rateStrategyUSDCWH, rateStrategyUSDT, rateStrategyWBTC, + rateStrategyWBTCWH, rateStrategyWETH, + rateStrategyWETHWH, rateStrategyWGLMR, + rateStrategyWMATIC, rateStrategyXCDOT, + rateStrategyXCUSDT, rateStrategyXETH, } from "./rateStrategies"; import { @@ -93,6 +103,15 @@ import { timeLockStrategyAAVE, timeLockStrategyUNI, timeLockStrategyRDNT, + timeLockStrategySTMATIC, + timeLockStrategyCRV, + timeLockStrategyWMATIC, + timeLockStrategyXCUSDT, + timeLockStrategyUSDCWH, + timeLockStrategyWETHWH, + timeLockStrategyWBTCWH, + timeLockStrategySTDOT, + timeLockStrategyEXRP, } from "./timeLockStrategies"; export const strategyDAI: IReserveParams = { @@ -259,7 +278,7 @@ export const strategyXCDOT: IReserveParams = { strategy: rateStrategyXCDOT, auctionStrategy: auctionStrategyZero, timeLockStrategy: timeLockStrategyXCDOT, - baseLTVAsCollateral: "6000", + baseLTVAsCollateral: "6500", liquidationProtocolFeePercentage: "0", liquidationThreshold: "7000", liquidationBonus: "10500", @@ -271,459 +290,203 @@ export const strategyXCDOT: IReserveParams = { supplyCap: "0", }; -export const strategyWGLMR: IReserveParams = { - strategy: rateStrategyWGLMR, +export const strategySTDOT: IReserveParams = { + strategy: rateStrategySTDOT, auctionStrategy: auctionStrategyZero, - timeLockStrategy: timeLockStrategyWGLMR, - baseLTVAsCollateral: "3000", + timeLockStrategy: timeLockStrategySTDOT, + baseLTVAsCollateral: "6500", liquidationProtocolFeePercentage: "0", - liquidationThreshold: "4500", + liquidationThreshold: "7000", liquidationBonus: "10500", borrowingEnabled: true, - reserveDecimals: "18", - xTokenImpl: eContractid.PTokenImpl, + reserveDecimals: "10", + xTokenImpl: eContractid.PTokenStKSMImpl, reserveFactor: "1000", borrowCap: "0", supplyCap: "0", }; -export const strategyBAYC: IReserveParams = { - strategy: rateStrategyNFT, - auctionStrategy: auctionStrategyBAYC, - timeLockStrategy: timeLockStrategyBAYC, - baseLTVAsCollateral: "4000", +export const strategyXCUSDT: IReserveParams = { + strategy: rateStrategyXCUSDT, + auctionStrategy: auctionStrategyZero, + timeLockStrategy: timeLockStrategyXCUSDT, + baseLTVAsCollateral: "7500", liquidationProtocolFeePercentage: "0", liquidationThreshold: "8000", liquidationBonus: "10500", - borrowingEnabled: false, - reserveDecimals: "0", - xTokenImpl: eContractid.NTokenBAYCImpl, - reserveFactor: "0", + borrowingEnabled: true, + reserveDecimals: "10", + xTokenImpl: eContractid.PTokenImpl, + reserveFactor: "1000", borrowCap: "0", supplyCap: "0", }; -export const strategyMAYC: IReserveParams = { - strategy: rateStrategyNFT, - auctionStrategy: auctionStrategyMAYC, - timeLockStrategy: timeLockStrategyMAYC, - baseLTVAsCollateral: "3250", +export const strategyUSDCWH: IReserveParams = { + strategy: rateStrategyUSDCWH, + auctionStrategy: auctionStrategyZero, + timeLockStrategy: timeLockStrategyUSDCWH, + baseLTVAsCollateral: "8700", + liquidationThreshold: "8900", liquidationProtocolFeePercentage: "0", - liquidationThreshold: "7000", - liquidationBonus: "10500", - borrowingEnabled: false, - reserveDecimals: "0", - xTokenImpl: eContractid.NTokenMAYCImpl, - reserveFactor: "0", + liquidationBonus: "10450", + borrowingEnabled: true, + reserveDecimals: "6", + xTokenImpl: eContractid.PTokenImpl, + reserveFactor: "1000", borrowCap: "0", supplyCap: "0", }; -export const strategyBAKC: IReserveParams = { - strategy: rateStrategyNFT, - auctionStrategy: auctionStrategyBAKC, - timeLockStrategy: timeLockStrategyBAKC, - baseLTVAsCollateral: "4000", +export const strategyWETHWH: IReserveParams = { + strategy: rateStrategyWETHWH, + auctionStrategy: auctionStrategyZero, + timeLockStrategy: timeLockStrategyWETHWH, + baseLTVAsCollateral: "8250", + liquidationThreshold: "8600", liquidationProtocolFeePercentage: "0", - liquidationThreshold: "8000", - liquidationBonus: "10500", - borrowingEnabled: false, - reserveDecimals: "0", - xTokenImpl: eContractid.NTokenBAKCImpl, - reserveFactor: "0", + liquidationBonus: "10450", + borrowingEnabled: true, + reserveDecimals: "18", + xTokenImpl: eContractid.PTokenImpl, + reserveFactor: "1000", borrowCap: "0", - supplyCap: "1000", + supplyCap: "0", }; -export const strategyDoodles: IReserveParams = { - strategy: rateStrategyNFT, - auctionStrategy: auctionStrategyDoodles, - timeLockStrategy: timeLockStrategyDoodles, - baseLTVAsCollateral: "3000", +export const strategyWBTCWH: IReserveParams = { + strategy: rateStrategyWBTCWH, + auctionStrategy: auctionStrategyZero, + timeLockStrategy: timeLockStrategyWBTCWH, + baseLTVAsCollateral: "7200", liquidationProtocolFeePercentage: "0", - liquidationThreshold: "6500", + liquidationThreshold: "8200", liquidationBonus: "10500", - borrowingEnabled: false, - reserveDecimals: "0", - xTokenImpl: eContractid.NTokenImpl, - reserveFactor: "0", + borrowingEnabled: true, + reserveDecimals: "8", + xTokenImpl: eContractid.PTokenImpl, + reserveFactor: "1000", borrowCap: "0", supplyCap: "0", }; -export const strategyOthr: IReserveParams = { - strategy: rateStrategyNFT, - auctionStrategy: auctionStrategyOthr, - timeLockStrategy: timeLockStrategyOTHR, +export const strategyWGLMR: IReserveParams = { + strategy: rateStrategyWGLMR, + auctionStrategy: auctionStrategyZero, + timeLockStrategy: timeLockStrategyWGLMR, baseLTVAsCollateral: "3000", liquidationProtocolFeePercentage: "0", - liquidationThreshold: "6500", + liquidationThreshold: "4500", liquidationBonus: "10500", - borrowingEnabled: false, - reserveDecimals: "0", - xTokenImpl: eContractid.NTokenImpl, - reserveFactor: "0", + borrowingEnabled: true, + reserveDecimals: "18", + xTokenImpl: eContractid.PTokenImpl, + reserveFactor: "1000", borrowCap: "0", supplyCap: "0", }; -export const strategyClonex: IReserveParams = { - strategy: rateStrategyNFT, - auctionStrategy: auctionStrategyCloneX, - timeLockStrategy: timeLockStrategyCloneX, - baseLTVAsCollateral: "3000", +export const strategyCBETH: IReserveParams = { + strategy: rateStrategyXETH, + auctionStrategy: auctionStrategyZero, + timeLockStrategy: timeLockStrategyWETH, + baseLTVAsCollateral: "7200", liquidationProtocolFeePercentage: "0", - liquidationThreshold: "6500", - liquidationBonus: "10500", - borrowingEnabled: false, - reserveDecimals: "0", - xTokenImpl: eContractid.NTokenImpl, - reserveFactor: "0", - borrowCap: "0", - supplyCap: "0", + liquidationThreshold: "8300", + liquidationBonus: "10700", + borrowingEnabled: true, + reserveDecimals: "18", + xTokenImpl: eContractid.PTokenImpl, + reserveFactor: "1000", + borrowCap: "110000", + supplyCap: "110000", }; -export const strategyMoonbird: IReserveParams = { - strategy: rateStrategyNFT, - auctionStrategy: auctionStrategyMoonbird, - timeLockStrategy: timeLockStrategyMoonbird, - baseLTVAsCollateral: "3000", +export const strategySTETH: IReserveParams = { + strategy: rateStrategyXETH, + auctionStrategy: auctionStrategyZero, + timeLockStrategy: timeLockStrategyWETH, + baseLTVAsCollateral: "6900", liquidationProtocolFeePercentage: "0", - liquidationThreshold: "6500", - liquidationBonus: "10500", - borrowingEnabled: false, - reserveDecimals: "0", - xTokenImpl: eContractid.NTokenMoonBirdsImpl, - reserveFactor: "0", + liquidationThreshold: "8100", + liquidationBonus: "10750", + borrowingEnabled: true, + reserveDecimals: "18", + xTokenImpl: eContractid.PTokenStETHImpl, + reserveFactor: "1000", borrowCap: "0", supplyCap: "0", }; -export const strategyMeebits: IReserveParams = { - strategy: rateStrategyNFT, - auctionStrategy: auctionStrategyMeebits, - timeLockStrategy: timeLockStrategyMeebits, - baseLTVAsCollateral: "3000", +export const strategyASTETH: IReserveParams = { + strategy: rateStrategyXETH, + auctionStrategy: auctionStrategyZero, + timeLockStrategy: timeLockStrategyASTETH, + baseLTVAsCollateral: "6900", liquidationProtocolFeePercentage: "0", - liquidationThreshold: "6500", - liquidationBonus: "10500", - borrowingEnabled: false, - reserveDecimals: "0", - xTokenImpl: eContractid.NTokenImpl, - reserveFactor: "0", + liquidationThreshold: "8100", + liquidationBonus: "10750", + borrowingEnabled: true, + reserveDecimals: "18", + xTokenImpl: eContractid.PTokenAStETHImpl, + reserveFactor: "1000", borrowCap: "0", supplyCap: "0", }; -export const strategyAzuki: IReserveParams = { - strategy: rateStrategyNFT, - auctionStrategy: auctionStrategyAzuki, - timeLockStrategy: timeLockStrategyAzuki, - baseLTVAsCollateral: "3000", +export const strategyWSTETH: IReserveParams = { + strategy: rateStrategyXETH, + auctionStrategy: auctionStrategyZero, + timeLockStrategy: timeLockStrategyWSTETH, + baseLTVAsCollateral: "6900", liquidationProtocolFeePercentage: "0", - liquidationThreshold: "6500", - liquidationBonus: "10500", - borrowingEnabled: false, - reserveDecimals: "0", - xTokenImpl: eContractid.NTokenImpl, - reserveFactor: "0", + liquidationThreshold: "8100", + liquidationBonus: "10750", + borrowingEnabled: true, + reserveDecimals: "18", + xTokenImpl: eContractid.PTokenImpl, + reserveFactor: "1000", borrowCap: "0", supplyCap: "0", }; -export const strategyWPunks: IReserveParams = { - strategy: rateStrategyNFT, - auctionStrategy: auctionStrategyWPunks, - timeLockStrategy: timeLockStrategyWPunks, - baseLTVAsCollateral: "3500", +export const strategyAWSTETH: IReserveParams = { + strategy: rateStrategyXETH, + auctionStrategy: auctionStrategyZero, + timeLockStrategy: timeLockStrategyAWSTETH, + baseLTVAsCollateral: "6900", liquidationProtocolFeePercentage: "0", - liquidationThreshold: "7000", - liquidationBonus: "10500", - borrowingEnabled: false, - reserveDecimals: "0", - xTokenImpl: eContractid.NTokenImpl, - reserveFactor: "0", + liquidationThreshold: "8100", + liquidationBonus: "10750", + borrowingEnabled: true, + reserveDecimals: "18", + xTokenImpl: eContractid.PTokenATokenImpl, + reserveFactor: "1000", borrowCap: "0", supplyCap: "0", }; -export const strategyUniswapV3: IReserveParams = { - strategy: rateStrategyNFT, +export const strategyBENDETH: IReserveParams = { + strategy: rateStrategyXETH, auctionStrategy: auctionStrategyZero, - timeLockStrategy: timeLockStrategyUniswapV3, - baseLTVAsCollateral: "3000", + timeLockStrategy: timeLockStrategyBENDETH, + baseLTVAsCollateral: "6900", liquidationProtocolFeePercentage: "0", - liquidationThreshold: "7000", - liquidationBonus: "10500", - borrowingEnabled: false, - reserveDecimals: "0", - xTokenImpl: eContractid.NTokenUniswapV3Impl, - reserveFactor: "0", + liquidationThreshold: "8100", + liquidationBonus: "10750", + borrowingEnabled: true, + reserveDecimals: "18", + xTokenImpl: eContractid.PTokenATokenImpl, + reserveFactor: "1000", borrowCap: "0", supplyCap: "0", }; -export const strategySEWER: IReserveParams = { - strategy: rateStrategyNFT, - auctionStrategy: auctionStrategySEWER, // same as BAKC, it won't be used as collateral so it's ok - timeLockStrategy: timeLockStrategySEWER, - baseLTVAsCollateral: "0", - liquidationProtocolFeePercentage: "0", - liquidationThreshold: "0000", - liquidationBonus: "00000", - borrowingEnabled: false, - reserveDecimals: "0", - xTokenImpl: eContractid.NTokenImpl, - reserveFactor: "0", - borrowCap: "0", - supplyCap: "1000", -}; - -export const strategyPudgyPenguins: IReserveParams = { - strategy: rateStrategyNFT, - auctionStrategy: auctionStrategyPudgyPenguins, - timeLockStrategy: timeLockStrategyPenguins, - baseLTVAsCollateral: "3000", - liquidationProtocolFeePercentage: "0", - liquidationThreshold: "6500", - liquidationBonus: "10500", - borrowingEnabled: false, - reserveDecimals: "0", - xTokenImpl: eContractid.NTokenImpl, - reserveFactor: "0", - borrowCap: "0", - supplyCap: "0", -}; - -export const strategyStakefishValidator: IReserveParams = { - strategy: rateStrategyNFT, - auctionStrategy: auctionStrategyStakefishValidator, - timeLockStrategy: timeLockStrategyStakefishValidator, - baseLTVAsCollateral: "7425", - liquidationProtocolFeePercentage: "0", - liquidationThreshold: "7740", - liquidationBonus: "10450", - borrowingEnabled: false, - reserveDecimals: "0", - xTokenImpl: eContractid.NTokenStakefishImpl, - reserveFactor: "0", - borrowCap: "0", - supplyCap: "20", -}; - -export const strategyHVMTL: IReserveParams = { - strategy: rateStrategyNFT, - auctionStrategy: auctionStrategyHVMTL, - timeLockStrategy: timeLockStrategyHVMTL, - baseLTVAsCollateral: "3000", - liquidationProtocolFeePercentage: "0", - liquidationThreshold: "6500", - liquidationBonus: "10500", - borrowingEnabled: false, - reserveDecimals: "0", - xTokenImpl: eContractid.NTokenImpl, - reserveFactor: "0", - borrowCap: "0", - supplyCap: "0", -}; - -export const strategyBEANZ: IReserveParams = { - strategy: rateStrategyNFT, - auctionStrategy: auctionStrategyBEANZ, - timeLockStrategy: timeLockStrategyBEANZ, - baseLTVAsCollateral: "3000", - liquidationProtocolFeePercentage: "0", - liquidationThreshold: "6500", - liquidationBonus: "10500", - borrowingEnabled: false, - reserveDecimals: "0", - xTokenImpl: eContractid.NTokenImpl, - reserveFactor: "0", - borrowCap: "0", - supplyCap: "0", -}; - -export const strategyDEGODS: IReserveParams = { - strategy: rateStrategyNFT, - auctionStrategy: auctionStrategyDEGODS, - timeLockStrategy: timeLockStrategyDEGODS, - baseLTVAsCollateral: "3000", - liquidationProtocolFeePercentage: "0", - liquidationThreshold: "6500", - liquidationBonus: "10500", - borrowingEnabled: false, - reserveDecimals: "0", - xTokenImpl: eContractid.NTokenImpl, - reserveFactor: "0", - borrowCap: "0", - supplyCap: "1000", -}; - -export const strategyEXP: IReserveParams = { - strategy: rateStrategyNFT, - auctionStrategy: auctionStrategyEXP, - timeLockStrategy: timeLockStrategyEXP, - baseLTVAsCollateral: "3000", - liquidationProtocolFeePercentage: "0", - liquidationThreshold: "6500", - liquidationBonus: "10500", - borrowingEnabled: false, - reserveDecimals: "0", - xTokenImpl: eContractid.NTokenImpl, - reserveFactor: "0", - borrowCap: "0", - supplyCap: "1000", -}; - -export const strategyVSL: IReserveParams = { - strategy: rateStrategyNFT, - auctionStrategy: auctionStrategyVSL, - timeLockStrategy: timeLockStrategyVSL, - baseLTVAsCollateral: "3000", - liquidationProtocolFeePercentage: "0", - liquidationThreshold: "6500", - liquidationBonus: "10500", - borrowingEnabled: false, - reserveDecimals: "0", - xTokenImpl: eContractid.NTokenImpl, - reserveFactor: "0", - borrowCap: "0", - supplyCap: "1000", -}; - -export const strategyKODA: IReserveParams = { - strategy: rateStrategyNFT, - auctionStrategy: auctionStrategyKODA, - timeLockStrategy: timeLockStrategyKODA, - baseLTVAsCollateral: "3000", - liquidationProtocolFeePercentage: "0", - liquidationThreshold: "6500", - liquidationBonus: "10500", - borrowingEnabled: false, - reserveDecimals: "0", - xTokenImpl: eContractid.NTokenImpl, - reserveFactor: "0", - borrowCap: "0", - supplyCap: "1000", -}; - -export const strategyBLOCKS: IReserveParams = { - strategy: rateStrategyNFT, - auctionStrategy: auctionStrategyBLOCKS, - timeLockStrategy: timeLockStrategyBLOCKS, - baseLTVAsCollateral: "2000", - liquidationProtocolFeePercentage: "0", - liquidationThreshold: "6500", - liquidationBonus: "10500", - borrowingEnabled: false, - reserveDecimals: "0", - xTokenImpl: eContractid.NTokenImpl, - reserveFactor: "0", - borrowCap: "0", - supplyCap: "0", -}; - -export const strategyCBETH: IReserveParams = { - strategy: rateStrategyXETH, - auctionStrategy: auctionStrategyZero, - timeLockStrategy: timeLockStrategyWETH, - baseLTVAsCollateral: "7200", - liquidationProtocolFeePercentage: "0", - liquidationThreshold: "8300", - liquidationBonus: "10700", - borrowingEnabled: true, - reserveDecimals: "18", - xTokenImpl: eContractid.PTokenImpl, - reserveFactor: "1000", - borrowCap: "110000", - supplyCap: "110000", -}; - -export const strategySTETH: IReserveParams = { - strategy: rateStrategyXETH, - auctionStrategy: auctionStrategyZero, - timeLockStrategy: timeLockStrategyWETH, - baseLTVAsCollateral: "6900", - liquidationProtocolFeePercentage: "0", - liquidationThreshold: "8100", - liquidationBonus: "10750", - borrowingEnabled: true, - reserveDecimals: "18", - xTokenImpl: eContractid.PTokenStETHImpl, - reserveFactor: "1000", - borrowCap: "0", - supplyCap: "0", -}; - -export const strategyASTETH: IReserveParams = { - strategy: rateStrategyXETH, - auctionStrategy: auctionStrategyZero, - timeLockStrategy: timeLockStrategyASTETH, - baseLTVAsCollateral: "6900", - liquidationProtocolFeePercentage: "0", - liquidationThreshold: "8100", - liquidationBonus: "10750", - borrowingEnabled: true, - reserveDecimals: "18", - xTokenImpl: eContractid.PTokenAStETHImpl, - reserveFactor: "1000", - borrowCap: "0", - supplyCap: "0", -}; - -export const strategyWSTETH: IReserveParams = { - strategy: rateStrategyXETH, - auctionStrategy: auctionStrategyZero, - timeLockStrategy: timeLockStrategyWSTETH, - baseLTVAsCollateral: "6900", - liquidationProtocolFeePercentage: "0", - liquidationThreshold: "8100", - liquidationBonus: "10750", - borrowingEnabled: true, - reserveDecimals: "18", - xTokenImpl: eContractid.PTokenImpl, - reserveFactor: "1000", - borrowCap: "0", - supplyCap: "0", -}; - -export const strategyAWSTETH: IReserveParams = { - strategy: rateStrategyXETH, - auctionStrategy: auctionStrategyZero, - timeLockStrategy: timeLockStrategyAWSTETH, - baseLTVAsCollateral: "6900", - liquidationProtocolFeePercentage: "0", - liquidationThreshold: "8100", - liquidationBonus: "10750", - borrowingEnabled: true, - reserveDecimals: "18", - xTokenImpl: eContractid.PTokenATokenImpl, - reserveFactor: "1000", - borrowCap: "0", - supplyCap: "0", -}; - -export const strategyBENDETH: IReserveParams = { - strategy: rateStrategyXETH, - auctionStrategy: auctionStrategyZero, - timeLockStrategy: timeLockStrategyBENDETH, - baseLTVAsCollateral: "6900", - liquidationProtocolFeePercentage: "0", - liquidationThreshold: "8100", - liquidationBonus: "10750", - borrowingEnabled: true, - reserveDecimals: "18", - xTokenImpl: eContractid.PTokenATokenImpl, - reserveFactor: "1000", - borrowCap: "0", - supplyCap: "0", -}; - -export const strategyAWETH: IReserveParams = { - strategy: rateStrategyXETH, - auctionStrategy: auctionStrategyZero, - timeLockStrategy: timeLockStrategyAWETH, - baseLTVAsCollateral: "8250", +export const strategyAWETH: IReserveParams = { + strategy: rateStrategyXETH, + auctionStrategy: auctionStrategyZero, + timeLockStrategy: timeLockStrategyAWETH, + baseLTVAsCollateral: "8250", liquidationProtocolFeePercentage: "0", liquidationThreshold: "8600", liquidationBonus: "10450", @@ -910,3 +673,407 @@ export const strategyRDNT: IReserveParams = { borrowCap: "0", supplyCap: "0", }; + +export const strategySTMATIC: IReserveParams = { + strategy: rateStrategySTMATIC, + auctionStrategy: auctionStrategyZero, + timeLockStrategy: timeLockStrategySTMATIC, + baseLTVAsCollateral: "5000", + liquidationProtocolFeePercentage: "0", + liquidationThreshold: "6500", + liquidationBonus: "11000", + borrowingEnabled: true, + reserveDecimals: "18", + xTokenImpl: eContractid.PTokenImpl, + reserveFactor: "1000", + borrowCap: "0", + supplyCap: "0", +}; + +export const strategyCRV: IReserveParams = { + strategy: rateStrategyCRV, + auctionStrategy: auctionStrategyZero, + timeLockStrategy: timeLockStrategyCRV, + baseLTVAsCollateral: "2500", + liquidationProtocolFeePercentage: "0", + liquidationThreshold: "3500", + liquidationBonus: "11000", + borrowingEnabled: true, + reserveDecimals: "18", + xTokenImpl: eContractid.PTokenImpl, + reserveFactor: "1000", + borrowCap: "0", + supplyCap: "0", +}; + +export const strategyWMATIC: IReserveParams = { + strategy: rateStrategyWMATIC, + auctionStrategy: auctionStrategyZero, + timeLockStrategy: timeLockStrategyWMATIC, + baseLTVAsCollateral: "6800", + liquidationThreshold: "7300", + liquidationProtocolFeePercentage: "0", + liquidationBonus: "10700", + borrowingEnabled: true, + reserveDecimals: "18", + xTokenImpl: eContractid.PTokenImpl, + reserveFactor: "2000", + borrowCap: "0", + supplyCap: "0", +}; + +//////////////////////////////////////////////////////////////////////////////// +// ERC721 +//////////////////////////////////////////////////////////////////////////////// + +export const strategyBAYC: IReserveParams = { + strategy: rateStrategyNFT, + auctionStrategy: auctionStrategyBAYC, + timeLockStrategy: timeLockStrategyBAYC, + baseLTVAsCollateral: "4000", + liquidationProtocolFeePercentage: "0", + liquidationThreshold: "8000", + liquidationBonus: "10500", + borrowingEnabled: false, + reserveDecimals: "0", + xTokenImpl: eContractid.NTokenBAYCImpl, + reserveFactor: "0", + borrowCap: "0", + supplyCap: "0", +}; + +export const strategyMAYC: IReserveParams = { + strategy: rateStrategyNFT, + auctionStrategy: auctionStrategyMAYC, + timeLockStrategy: timeLockStrategyMAYC, + baseLTVAsCollateral: "3250", + liquidationProtocolFeePercentage: "0", + liquidationThreshold: "7000", + liquidationBonus: "10500", + borrowingEnabled: false, + reserveDecimals: "0", + xTokenImpl: eContractid.NTokenMAYCImpl, + reserveFactor: "0", + borrowCap: "0", + supplyCap: "0", +}; + +export const strategyBAKC: IReserveParams = { + strategy: rateStrategyNFT, + auctionStrategy: auctionStrategyBAKC, + timeLockStrategy: timeLockStrategyBAKC, + baseLTVAsCollateral: "4000", + liquidationProtocolFeePercentage: "0", + liquidationThreshold: "8000", + liquidationBonus: "10500", + borrowingEnabled: false, + reserveDecimals: "0", + xTokenImpl: eContractid.NTokenBAKCImpl, + reserveFactor: "0", + borrowCap: "0", + supplyCap: "1000", +}; + +export const strategyDoodles: IReserveParams = { + strategy: rateStrategyNFT, + auctionStrategy: auctionStrategyDoodles, + timeLockStrategy: timeLockStrategyDoodles, + baseLTVAsCollateral: "3000", + liquidationProtocolFeePercentage: "0", + liquidationThreshold: "6500", + liquidationBonus: "10500", + borrowingEnabled: false, + reserveDecimals: "0", + xTokenImpl: eContractid.NTokenImpl, + reserveFactor: "0", + borrowCap: "0", + supplyCap: "0", +}; + +export const strategyOthr: IReserveParams = { + strategy: rateStrategyNFT, + auctionStrategy: auctionStrategyOthr, + timeLockStrategy: timeLockStrategyOTHR, + baseLTVAsCollateral: "3000", + liquidationProtocolFeePercentage: "0", + liquidationThreshold: "6500", + liquidationBonus: "10500", + borrowingEnabled: false, + reserveDecimals: "0", + xTokenImpl: eContractid.NTokenImpl, + reserveFactor: "0", + borrowCap: "0", + supplyCap: "0", +}; + +export const strategyClonex: IReserveParams = { + strategy: rateStrategyNFT, + auctionStrategy: auctionStrategyCloneX, + timeLockStrategy: timeLockStrategyCloneX, + baseLTVAsCollateral: "3000", + liquidationProtocolFeePercentage: "0", + liquidationThreshold: "6500", + liquidationBonus: "10500", + borrowingEnabled: false, + reserveDecimals: "0", + xTokenImpl: eContractid.NTokenImpl, + reserveFactor: "0", + borrowCap: "0", + supplyCap: "0", +}; + +export const strategyMoonbird: IReserveParams = { + strategy: rateStrategyNFT, + auctionStrategy: auctionStrategyMoonbird, + timeLockStrategy: timeLockStrategyMoonbird, + baseLTVAsCollateral: "3000", + liquidationProtocolFeePercentage: "0", + liquidationThreshold: "6500", + liquidationBonus: "10500", + borrowingEnabled: false, + reserveDecimals: "0", + xTokenImpl: eContractid.NTokenMoonBirdsImpl, + reserveFactor: "0", + borrowCap: "0", + supplyCap: "0", +}; + +export const strategyMeebits: IReserveParams = { + strategy: rateStrategyNFT, + auctionStrategy: auctionStrategyMeebits, + timeLockStrategy: timeLockStrategyMeebits, + baseLTVAsCollateral: "3000", + liquidationProtocolFeePercentage: "0", + liquidationThreshold: "6500", + liquidationBonus: "10500", + borrowingEnabled: false, + reserveDecimals: "0", + xTokenImpl: eContractid.NTokenImpl, + reserveFactor: "0", + borrowCap: "0", + supplyCap: "0", +}; + +export const strategyAzuki: IReserveParams = { + strategy: rateStrategyNFT, + auctionStrategy: auctionStrategyAzuki, + timeLockStrategy: timeLockStrategyAzuki, + baseLTVAsCollateral: "3000", + liquidationProtocolFeePercentage: "0", + liquidationThreshold: "6500", + liquidationBonus: "10500", + borrowingEnabled: false, + reserveDecimals: "0", + xTokenImpl: eContractid.NTokenImpl, + reserveFactor: "0", + borrowCap: "0", + supplyCap: "0", +}; + +export const strategyWPunks: IReserveParams = { + strategy: rateStrategyNFT, + auctionStrategy: auctionStrategyWPunks, + timeLockStrategy: timeLockStrategyWPunks, + baseLTVAsCollateral: "3500", + liquidationProtocolFeePercentage: "0", + liquidationThreshold: "7000", + liquidationBonus: "10500", + borrowingEnabled: false, + reserveDecimals: "0", + xTokenImpl: eContractid.NTokenImpl, + reserveFactor: "0", + borrowCap: "0", + supplyCap: "0", +}; + +export const strategyUniswapV3: IReserveParams = { + strategy: rateStrategyNFT, + auctionStrategy: auctionStrategyUniswapV3, + timeLockStrategy: timeLockStrategyUniswapV3, + baseLTVAsCollateral: "3000", + liquidationProtocolFeePercentage: "0", + liquidationThreshold: "7000", + liquidationBonus: "10500", + borrowingEnabled: false, + reserveDecimals: "0", + xTokenImpl: eContractid.NTokenUniswapV3Impl, + reserveFactor: "0", + borrowCap: "0", + supplyCap: "0", +}; + +export const strategySEWER: IReserveParams = { + strategy: rateStrategyNFT, + auctionStrategy: auctionStrategySEWER, // same as BAKC, it won't be used as collateral so it's ok + timeLockStrategy: timeLockStrategySEWER, + baseLTVAsCollateral: "0", + liquidationProtocolFeePercentage: "0", + liquidationThreshold: "0000", + liquidationBonus: "00000", + borrowingEnabled: false, + reserveDecimals: "0", + xTokenImpl: eContractid.NTokenImpl, + reserveFactor: "0", + borrowCap: "0", + supplyCap: "1000", +}; + +export const strategyPudgyPenguins: IReserveParams = { + strategy: rateStrategyNFT, + auctionStrategy: auctionStrategyPudgyPenguins, + timeLockStrategy: timeLockStrategyPenguins, + baseLTVAsCollateral: "3000", + liquidationProtocolFeePercentage: "0", + liquidationThreshold: "6500", + liquidationBonus: "10500", + borrowingEnabled: false, + reserveDecimals: "0", + xTokenImpl: eContractid.NTokenImpl, + reserveFactor: "0", + borrowCap: "0", + supplyCap: "0", +}; + +export const strategyStakefishValidator: IReserveParams = { + strategy: rateStrategyNFT, + auctionStrategy: auctionStrategyStakefishValidator, + timeLockStrategy: timeLockStrategyStakefishValidator, + baseLTVAsCollateral: "7425", + liquidationProtocolFeePercentage: "0", + liquidationThreshold: "7740", + liquidationBonus: "10450", + borrowingEnabled: false, + reserveDecimals: "0", + xTokenImpl: eContractid.NTokenStakefishImpl, + reserveFactor: "0", + borrowCap: "0", + supplyCap: "20", +}; + +export const strategyHVMTL: IReserveParams = { + strategy: rateStrategyNFT, + auctionStrategy: auctionStrategyHVMTL, + timeLockStrategy: timeLockStrategyHVMTL, + baseLTVAsCollateral: "3000", + liquidationProtocolFeePercentage: "0", + liquidationThreshold: "6500", + liquidationBonus: "10500", + borrowingEnabled: false, + reserveDecimals: "0", + xTokenImpl: eContractid.NTokenImpl, + reserveFactor: "0", + borrowCap: "0", + supplyCap: "0", +}; + +export const strategyBEANZ: IReserveParams = { + strategy: rateStrategyNFT, + auctionStrategy: auctionStrategyBEANZ, + timeLockStrategy: timeLockStrategyBEANZ, + baseLTVAsCollateral: "3000", + liquidationProtocolFeePercentage: "0", + liquidationThreshold: "6500", + liquidationBonus: "10500", + borrowingEnabled: false, + reserveDecimals: "0", + xTokenImpl: eContractid.NTokenImpl, + reserveFactor: "0", + borrowCap: "0", + supplyCap: "0", +}; + +export const strategyDEGODS: IReserveParams = { + strategy: rateStrategyNFT, + auctionStrategy: auctionStrategyDEGODS, + timeLockStrategy: timeLockStrategyDEGODS, + baseLTVAsCollateral: "3000", + liquidationProtocolFeePercentage: "0", + liquidationThreshold: "6500", + liquidationBonus: "10500", + borrowingEnabled: false, + reserveDecimals: "0", + xTokenImpl: eContractid.NTokenImpl, + reserveFactor: "0", + borrowCap: "0", + supplyCap: "1000", +}; + +export const strategyEXP: IReserveParams = { + strategy: rateStrategyNFT, + auctionStrategy: auctionStrategyEXP, + timeLockStrategy: timeLockStrategyEXP, + baseLTVAsCollateral: "3000", + liquidationProtocolFeePercentage: "0", + liquidationThreshold: "6500", + liquidationBonus: "10500", + borrowingEnabled: false, + reserveDecimals: "0", + xTokenImpl: eContractid.NTokenImpl, + reserveFactor: "0", + borrowCap: "0", + supplyCap: "1000", +}; + +export const strategyVSL: IReserveParams = { + strategy: rateStrategyNFT, + auctionStrategy: auctionStrategyVSL, + timeLockStrategy: timeLockStrategyVSL, + baseLTVAsCollateral: "3000", + liquidationProtocolFeePercentage: "0", + liquidationThreshold: "6500", + liquidationBonus: "10500", + borrowingEnabled: false, + reserveDecimals: "0", + xTokenImpl: eContractid.NTokenImpl, + reserveFactor: "0", + borrowCap: "0", + supplyCap: "1000", +}; + +export const strategyKODA: IReserveParams = { + strategy: rateStrategyNFT, + auctionStrategy: auctionStrategyKODA, + timeLockStrategy: timeLockStrategyKODA, + baseLTVAsCollateral: "3000", + liquidationProtocolFeePercentage: "0", + liquidationThreshold: "6500", + liquidationBonus: "10500", + borrowingEnabled: false, + reserveDecimals: "0", + xTokenImpl: eContractid.NTokenImpl, + reserveFactor: "0", + borrowCap: "0", + supplyCap: "1000", +}; + +export const strategyBLOCKS: IReserveParams = { + strategy: rateStrategyNFT, + auctionStrategy: auctionStrategyBLOCKS, + timeLockStrategy: timeLockStrategyBLOCKS, + baseLTVAsCollateral: "2000", + liquidationProtocolFeePercentage: "0", + liquidationThreshold: "6500", + liquidationBonus: "10500", + borrowingEnabled: false, + reserveDecimals: "0", + xTokenImpl: eContractid.NTokenImpl, + reserveFactor: "0", + borrowCap: "0", + supplyCap: "0", +}; + +export const strategyEXRP: IReserveParams = { + strategy: rateStrategyNFT, + auctionStrategy: auctionStrategyEXRP, + timeLockStrategy: timeLockStrategyEXRP, + baseLTVAsCollateral: "2000", + liquidationProtocolFeePercentage: "0", + liquidationThreshold: "3500", + liquidationBonus: "10500", + borrowingEnabled: false, + reserveDecimals: "0", + xTokenImpl: eContractid.NTokenImpl, + reserveFactor: "0", + borrowCap: "0", + supplyCap: "1000", +}; diff --git a/market-config/timeLockStrategies.ts b/market-config/timeLockStrategies.ts index ba8b1843e..5fc4d246a 100644 --- a/market-config/timeLockStrategies.ts +++ b/market-config/timeLockStrategies.ts @@ -253,6 +253,66 @@ export const timeLockStrategyXCDOT: ITimeLockStrategyParams = { period: "86400", }; +export const timeLockStrategySTDOT: ITimeLockStrategyParams = { + name: "timeLockStrategySTDOT", + minThreshold: parseUnits("1000", 10).toString(), + midThreshold: parseUnits("5000", 10).toString(), + minWaitTime: "12", + midWaitTime: "7200", + maxWaitTime: "21600", + poolPeriodWaitTime: "600", + poolPeriodLimit: parseUnits("50000", 10).toString(), + period: "86400", +}; + +export const timeLockStrategyXCUSDT: ITimeLockStrategyParams = { + name: "timeLockStrategyXCUSDT", + minThreshold: parseUnits("105000", 6).toString(), + midThreshold: parseUnits("200500", 6).toString(), + minWaitTime: "12", + midWaitTime: "7200", + maxWaitTime: "21600", + poolPeriodWaitTime: "600", + poolPeriodLimit: parseUnits("400000", 6).toString(), + period: "86400", +}; + +export const timeLockStrategyUSDCWH: ITimeLockStrategyParams = { + name: "timeLockStrategyUSDCWH", + minThreshold: parseUnits("105000", 6).toString(), + midThreshold: parseUnits("400000", 6).toString(), + minWaitTime: "12", + midWaitTime: "7200", + maxWaitTime: "21600", + poolPeriodWaitTime: "600", + poolPeriodLimit: parseUnits("1875000", 6).toString(), + period: "86400", +}; + +export const timeLockStrategyWETHWH: ITimeLockStrategyParams = { + name: "timeLockStrategyWETHWH", + minThreshold: parseUnits("51.5", 18).toString(), + midThreshold: parseUnits("155", 18).toString(), + minWaitTime: "12", + midWaitTime: "7200", + maxWaitTime: "21600", + poolPeriodWaitTime: "600", + poolPeriodLimit: parseUnits("1900", 18).toString(), + period: "86400", +}; + +export const timeLockStrategyWBTCWH: ITimeLockStrategyParams = { + name: "timeLockStrategyWBTCWH", + minThreshold: parseUnits("2.5", 8).toString(), + midThreshold: parseUnits("2.8", 8).toString(), + minWaitTime: "12", + midWaitTime: "7200", + maxWaitTime: "21600", + poolPeriodWaitTime: "600", + poolPeriodLimit: parseUnits("3", 8).toString(), + period: "86400", +}; + export const timeLockStrategyWGLMR: ITimeLockStrategyParams = { name: "timeLockStrategyWGLMR", minThreshold: parseUnits("1000", 18).toString(), @@ -361,6 +421,58 @@ export const timeLockStrategyUNI: ITimeLockStrategyParams = { period: "86400", }; +export const timeLockStrategyMATIC: ITimeLockStrategyParams = { + name: "timeLockStrategyMATIC", + minThreshold: parseUnits("80000", 18).toString(), + midThreshold: parseUnits("120000", 18).toString(), + minWaitTime: "12", + midWaitTime: "7200", + maxWaitTime: "21600", + poolPeriodWaitTime: "600", + poolPeriodLimit: parseUnits("240000", 18).toString(), + period: "86400", +}; + +export const timeLockStrategySTMATIC: ITimeLockStrategyParams = { + name: "timeLockStrategySTMATIC", + minThreshold: parseUnits("80000", 18).toString(), + midThreshold: parseUnits("120000", 18).toString(), + minWaitTime: "12", + midWaitTime: "7200", + maxWaitTime: "21600", + poolPeriodWaitTime: "600", + poolPeriodLimit: parseUnits("240000", 18).toString(), + period: "86400", +}; + +export const timeLockStrategyCRV: ITimeLockStrategyParams = { + name: "timeLockStrategyCRV", + minThreshold: parseUnits("80000", 18).toString(), + midThreshold: parseUnits("120000", 18).toString(), + minWaitTime: "12", + midWaitTime: "7200", + maxWaitTime: "21600", + poolPeriodWaitTime: "600", + poolPeriodLimit: parseUnits("240000", 18).toString(), + period: "86400", +}; + +export const timeLockStrategyWMATIC: ITimeLockStrategyParams = { + name: "timeLockStrategyWMATIC", + minThreshold: parseUnits("80000", 18).toString(), + midThreshold: parseUnits("120000", 18).toString(), + minWaitTime: "12", + midWaitTime: "7200", + maxWaitTime: "21600", + poolPeriodWaitTime: "600", + poolPeriodLimit: parseUnits("240000", 18).toString(), + period: "86400", +}; + +//////////////////////////////////////////////////////////////////////////////// +// ERC721 +//////////////////////////////////////////////////////////////////////////////// + export const timeLockStrategyBAYC: ITimeLockStrategyParams = { name: "timeLockStrategyBAYC", minThreshold: "2", @@ -612,3 +724,15 @@ export const timeLockStrategyBLOCKS: ITimeLockStrategyParams = { poolPeriodLimit: "10", period: "86400", }; + +export const timeLockStrategyEXRP: ITimeLockStrategyParams = { + name: "timeLockStrategyEXRP", + minThreshold: "20", + midThreshold: "50", + minWaitTime: "12", + midWaitTime: "7200", + maxWaitTime: "21600", + poolPeriodWaitTime: "600", + poolPeriodLimit: "100", + period: "86400", +}; diff --git a/package.json b/package.json index d1ac692b9..0fba584a1 100644 --- a/package.json +++ b/package.json @@ -24,14 +24,21 @@ "test": "hardhat test ./test/*.ts", "clean": "hardhat clean" }, + "resolutions": { + "ethereumjs-abi": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz" + }, "devDependencies": { "@commitlint/cli": "^17.0.3", "@commitlint/config-conventional": "^17.0.3", "@flashbots/ethers-provider-bundle": "^0.6.1", "@looksrare/sdk": "^0.7.4", + "@matterlabs/hardhat-zksync-deploy": "^0.6.3", + "@matterlabs/hardhat-zksync-solc": "^0.4.0", + "@matterlabs/hardhat-zksync-verify": "^0.1.8", + "@matterlabs/zksync-contracts": "^0.6.1", "@nomicfoundation/hardhat-network-helpers": "^1.0.6", "@nomiclabs/hardhat-ethers": "^2.0.0", - "@nomiclabs/hardhat-etherscan": "^3.1.0", + "@nomiclabs/hardhat-etherscan": "^3.1.7", "@nomiclabs/hardhat-waffle": "2.0.3", "@openzeppelin/contracts": "4.2.0", "@openzeppelin/contracts-upgradeable": "4.2.0", @@ -42,7 +49,7 @@ "@safe-global/safe-ethers-lib": "^1.7.0", "@safe-global/safe-service-client": "^1.5.0", "@tenderly/hardhat-tenderly": "1.1.0-beta.5", - "@typechain/ethers-v5": "^10.1.0", + "@typechain/ethers-v5": "^11.0.0", "@typechain/hardhat": "^6.1.2", "@types/chai": "^4.2.11", "@types/lowdb": "1.0.9", @@ -70,9 +77,9 @@ "ethers-multisend": "^2.4.0", "evm-bn": "^1.1.2", "git-rev-sync": "^3.0.2", - "hardhat": "^2.12.2", + "hardhat": "^2.13.0", "hardhat-contract-sizer": "^2.0.3", - "hardhat-deploy": "^0.11.4", + "hardhat-deploy": "^0.11.30", "hardhat-gas-reporter": "^1.0.9", "hardhat-typechain": "^0.3.3", "husky": "^8.0.1", @@ -87,11 +94,13 @@ "shelljs": "^0.8.5", "solhint": "^3.3.6", "solidity-coverage": "^0.8.2", - "solidity-docgen-forked": "^0.6.0-beta.29", + "solidity-docgen": "^0.6.0-beta.35", "ts-generator": "^0.1.1", "ts-node": "^10.9.1", "typechain": "^8.1.0", - "typescript": "4.7.4" + "typescript": "4.7.4", + "walkdir": "^0.4.1", + "zksync-web3": "^0.14.3" }, "author": "ParaSpace-MM Team", "contributors": [], diff --git a/scripts/deployments/steps/06_pool.ts b/scripts/deployments/steps/06_pool.ts index efdff9ff1..0d103653f 100644 --- a/scripts/deployments/steps/06_pool.ts +++ b/scripts/deployments/steps/06_pool.ts @@ -1,6 +1,7 @@ import {ZERO_ADDRESS} from "../../../helpers/constants"; import { deployMockBendDaoLendPool, + deployParaApeStaking, deployPoolComponents, deployPoolParaProxyInterfaces, deployPoolPositionMover, @@ -30,6 +31,8 @@ export const step_06 = async (verify = false) => { const paraSpaceConfig = getParaSpaceConfig(); try { + await deployParaApeStaking(true); + const { poolCore, poolParameters, @@ -159,10 +162,13 @@ export const step_06 = async (verify = false) => { ); const poolProxy = await getPoolProxy(poolAddress); - const uniswapV3Router = await getUniswapV3SwapRouter(); const allTokens = await getAllTokens(); - if (allTokens[ERC20TokenContractId.APE]) { + if ( + allTokens[ERC20TokenContractId.APE] && + (await getContractAddressInDb(eContractid.UniswapV3SwapRouter)) + ) { + const uniswapV3Router = await getUniswapV3SwapRouter(); const cAPE = await getAutoCompoundApe(); await waitForTx( await poolProxy.unlimitedApproveTo( diff --git a/scripts/deployments/steps/09_fallbackOracle.ts b/scripts/deployments/steps/09_fallbackOracle.ts index 3cfec2f1d..075ace60d 100644 --- a/scripts/deployments/steps/09_fallbackOracle.ts +++ b/scripts/deployments/steps/09_fallbackOracle.ts @@ -10,10 +10,8 @@ import {GLOBAL_OVERRIDES} from "../../../helpers/hardhat-constants"; import { getParaSpaceConfig, isLocalTestnet, - isEthereum, - isMoonbeam, isPublicTestnet, - isArbitrumOne, + isMainnet, } from "../../../helpers/misc-utils"; import {waitForTx} from "../../../helpers/misc-utils"; import {setInitialAssetPricesInOracle} from "../../../helpers/oracles-helpers"; @@ -24,7 +22,7 @@ export const step_09 = async (verify = false) => { const allTokens = await getAllTokens(); const paraSpaceConfig = getParaSpaceConfig(); - if (isEthereum() || isMoonbeam() || isArbitrumOne()) { + if (isMainnet()) { insertContractAddressInDb(eContractid.PriceOracle, ZERO_ADDRESS, false); } diff --git a/scripts/deployments/steps/10_allAggregators.ts b/scripts/deployments/steps/10_allAggregators.ts index 8fbfaa149..39469b580 100644 --- a/scripts/deployments/steps/10_allAggregators.ts +++ b/scripts/deployments/steps/10_allAggregators.ts @@ -9,6 +9,7 @@ import { import { getAllERC721Tokens, getAllTokens, + getFirstSigner, getPoolAddressesProvider, getPriceOracle, } from "../../../helpers/contracts-getters"; @@ -31,8 +32,8 @@ export const deployNftOracle = async (verify = false) => { const chainlinkConfig = paraSpaceConfig.Chainlink; // UniswapV3 should use price from `UniswapV3OracleWrapper` instead of NFTFloorOracle delete erc721Tokens[ERC721TokenContractId.UniswapV3]; - const [deployer, oracle1, oracle2, oracle3] = - await getEthersSignersAddresses(); + const deployer = await getFirstSigner(); + const [, oracle1, oracle2, oracle3] = await getEthersSignersAddresses(); //at launch phase we will only use 3 feeders for nft oracle in mainnet const feeders = oracleConfig.Nodes.length > 0 @@ -43,20 +44,24 @@ export const deployNftOracle = async (verify = false) => { .map(([, nft]) => nft.address) .filter((x) => x); const nftFloorOracle = await deployNFTFloorPriceOracle(verify); - await waitForTx( - await nftFloorOracle.initialize( - deployer, - feeders, - projects, - GLOBAL_OVERRIDES - ) - ); - await waitForTx( - await nftFloorOracle.setConfig( - oracleConfig.ExpirationPeriod, - oracleConfig.DeviationRate - ) - ); + try { + await waitForTx( + await nftFloorOracle.initialize( + await deployer.getAddress(), + feeders, + projects, + GLOBAL_OVERRIDES + ) + ); + await waitForTx( + await nftFloorOracle.setConfig( + oracleConfig.ExpirationPeriod, + oracleConfig.DeviationRate + ) + ); + } catch (e) { + // + } return nftFloorOracle; }; @@ -112,13 +117,14 @@ export const step_10 = async (verify = false) => { GLOBAL_OVERRIDES ); + const networkPriceInUsdAggregator = (chainlinkConfig[ + oracleConfig.BaseCurrency + ] || + allAggregatorsAddresses[ERC20TokenContractId.USDC] || + allAggregatorsAddresses[ERC20TokenContractId.USDT])!; await deployUiPoolDataProvider( - (chainlinkConfig[oracleConfig.BaseCurrency] || - allAggregatorsAddresses[ERC20TokenContractId.USDC] || - allAggregatorsAddresses[ERC20TokenContractId.USDT])!, - (chainlinkConfig[oracleConfig.BaseCurrency] || - allAggregatorsAddresses[ERC20TokenContractId.USDC] || - allAggregatorsAddresses[ERC20TokenContractId.USDT])!, + networkPriceInUsdAggregator, + networkPriceInUsdAggregator, verify ); await deployWalletBalanceProvider(verify); diff --git a/scripts/deployments/steps/11_allReserves.ts b/scripts/deployments/steps/11_allReserves.ts index 8e3ac463f..ddc8d87cd 100644 --- a/scripts/deployments/steps/11_allReserves.ts +++ b/scripts/deployments/steps/11_allReserves.ts @@ -90,6 +90,7 @@ export const step_11 = async (verify = false) => { xTokenImpl === eContractid.NTokenMoonBirdsImpl || xTokenImpl === eContractid.NTokenUniswapV3Impl || xTokenImpl === eContractid.PTokenStETHImpl || + xTokenImpl === eContractid.PTokenStKSMImpl || xTokenImpl === eContractid.PTokenATokenImpl || xTokenImpl === eContractid.PTokenSApeImpl || xTokenImpl === eContractid.PTokenCApeImpl || diff --git a/scripts/deployments/steps/15_seaport.ts b/scripts/deployments/steps/15_seaport.ts index 9389f5ffb..63c62a553 100644 --- a/scripts/deployments/steps/15_seaport.ts +++ b/scripts/deployments/steps/15_seaport.ts @@ -14,7 +14,7 @@ import { OPENSEA_SEAPORT_ID, PARASPACE_SEAPORT_ID, } from "../../../helpers/constants"; -import {getParaSpaceConfig, waitForTx} from "../../../helpers/misc-utils"; +import {DRE, getParaSpaceConfig, waitForTx} from "../../../helpers/misc-utils"; import { createZone, insertContractAddressInDb, @@ -36,10 +36,12 @@ export const step_15 = async (verify = false) => { verify ); const conduitKey = `${deployerAddress}000000000000000000000000`; + GLOBAL_OVERRIDES.gasLimit = 35_000_000; const conduit = await createConduit( conduitController, deployer, - conduitKey + conduitKey, + GLOBAL_OVERRIDES ); const conduitInstance = await getConduit(conduit); await waitForTx( @@ -54,14 +56,18 @@ export const step_15 = async (verify = false) => { addressesProvider.address, verify ); - await waitForTx( - await conduitController.updateChannel( - conduit, - seaport.address, - true, - GLOBAL_OVERRIDES - ) - ); + if (!DRE.network.config.zksync) { + // TODO: fix updateChannel method for zksync + await waitForTx( + await conduitController.updateChannel( + conduit, + seaport.address, + true, + GLOBAL_OVERRIDES + ) + ); + } + delete GLOBAL_OVERRIDES.gasLimit; await waitForTx( await addressesProvider.setMarketplace( PARASPACE_SEAPORT_ID, diff --git a/scripts/deployments/steps/16_looksrare.ts b/scripts/deployments/steps/16_looksrare.ts index 6332a18e2..ecfa999fc 100644 --- a/scripts/deployments/steps/16_looksrare.ts +++ b/scripts/deployments/steps/16_looksrare.ts @@ -24,18 +24,23 @@ import { import {GLOBAL_OVERRIDES} from "../../../helpers/hardhat-constants"; export const step_16 = async (verify = false) => { + const allTokens = await getAllTokens(); try { - if (!isLocalTestnet() && !isPublicTestnet()) { + if ((!isLocalTestnet() && !isPublicTestnet()) || !allTokens.WETH) { return; } - const allTokens = await getAllTokens(); const currencyManager = await deployCurrencyManager(verify); const addressesProvider = await getPoolAddressesProvider(); - await waitForTx( - await currencyManager.addCurrency(allTokens.DAI.address, GLOBAL_OVERRIDES) - ); + if (allTokens.DAI) { + await waitForTx( + await currencyManager.addCurrency( + allTokens.DAI.address, + GLOBAL_OVERRIDES + ) + ); + } await waitForTx( await currencyManager.addCurrency( allTokens.WETH.address, diff --git a/scripts/deployments/steps/18_blur.ts b/scripts/deployments/steps/18_blur.ts index 8ea466b89..01e7dd6cb 100644 --- a/scripts/deployments/steps/18_blur.ts +++ b/scripts/deployments/steps/18_blur.ts @@ -20,14 +20,14 @@ import { import {GLOBAL_OVERRIDES} from "../../../helpers/hardhat-constants"; export const step_18 = async (verify = false) => { + const allERC20Tokens = await getAllERC20Tokens(); try { - if (!isLocalTestnet() && !isPublicTestnet()) { + if ((!isLocalTestnet() && !isPublicTestnet()) || !allERC20Tokens.WETH) { return; } const addressesProvider = await getPoolAddressesProvider(); - const allERC20Tokens = await getAllERC20Tokens(); const blurExchangeImpl = await deployBlurExchangeImpl(verify); const executionDelegate = await deployExecutionDelegate(verify); diff --git a/scripts/deployments/steps/19_flashClaimRegistry.ts b/scripts/deployments/steps/19_flashClaimRegistry.ts index 9b3d6080e..13191f8db 100644 --- a/scripts/deployments/steps/19_flashClaimRegistry.ts +++ b/scripts/deployments/steps/19_flashClaimRegistry.ts @@ -28,7 +28,6 @@ export const step_19 = async (verify = false) => { ); const registry = await deployUserFlashClaimRegistry( - poolAddress, receiverImpl.address, verify ); @@ -36,7 +35,8 @@ export const step_19 = async (verify = false) => { await deployUserFlashClaimRegistryProxy( deployerAddress, registry.address, - [] + [], + verify ); if (!isLocalTestnet() && !isPublicTestnet()) { diff --git a/scripts/deployments/steps/20_p2pPairStaking.ts b/scripts/deployments/steps/20_p2pPairStaking.ts deleted file mode 100644 index 00b140457..000000000 --- a/scripts/deployments/steps/20_p2pPairStaking.ts +++ /dev/null @@ -1,78 +0,0 @@ -import {deployP2PPairStaking} from "../../../helpers/contracts-deployments"; -import { - getAllTokens, - getNTokenBAKC, - getNTokenBAYC, - getNTokenMAYC, - getPoolProxy, -} from "../../../helpers/contracts-getters"; -import {getParaSpaceConfig, waitForTx} from "../../../helpers/misc-utils"; -import { - ERC20TokenContractId, - ERC721TokenContractId, -} from "../../../helpers/types"; - -export const step_20 = async (verify = false) => { - const paraSpaceConfig = getParaSpaceConfig(); - try { - if (!paraSpaceConfig.ReservesConfig[ERC20TokenContractId.APE]) { - return; - } - // deploy P2PPairStaking - const p2pPairStaking = await deployP2PPairStaking(verify); - const allTokens = await getAllTokens(); - const pool = await getPoolProxy(); - - const bayc = allTokens[ERC721TokenContractId.BAYC]; - const mayc = allTokens[ERC721TokenContractId.MAYC]; - const bakc = allTokens[ERC721TokenContractId.BAKC]; - - if (bayc) { - const nBAYC = await getNTokenBAYC( - ( - await pool.getReserveData(bayc.address) - ).xTokenAddress - ); - await waitForTx( - await nBAYC.setApprovalForAllTo( - bayc.address, - p2pPairStaking.address, - true - ) - ); - } - - if (mayc) { - const nMAYC = await getNTokenMAYC( - ( - await pool.getReserveData(mayc.address) - ).xTokenAddress - ); - await waitForTx( - await nMAYC.setApprovalForAllTo( - mayc.address, - p2pPairStaking.address, - true - ) - ); - } - - if (bakc) { - const nBAKC = await getNTokenBAKC( - ( - await pool.getReserveData(bakc.address) - ).xTokenAddress - ); - await waitForTx( - await nBAKC.setApprovalForAllTo( - bakc.address, - p2pPairStaking.address, - true - ) - ); - } - } catch (error) { - console.error(error); - process.exit(1); - } -}; diff --git a/scripts/deployments/steps/20_paraApeStaking.ts b/scripts/deployments/steps/20_paraApeStaking.ts new file mode 100644 index 000000000..5398da6cc --- /dev/null +++ b/scripts/deployments/steps/20_paraApeStaking.ts @@ -0,0 +1,51 @@ +import { + deployParaApeStaking, + deployParaApeStakingImpl, +} from "../../../helpers/contracts-deployments"; +import { + getFirstSigner, + getInitializableAdminUpgradeabilityProxy, + getParaApeStaking, +} from "../../../helpers/contracts-getters"; +import {getParaSpaceConfig, waitForTx} from "../../../helpers/misc-utils"; +import {ERC20TokenContractId} from "../../../helpers/types"; +import {GLOBAL_OVERRIDES} from "../../../helpers/hardhat-constants"; +import {InitializableAdminUpgradeabilityProxy} from "../../../types"; + +export const step_20 = async (verify = false) => { + const paraSpaceConfig = getParaSpaceConfig(); + try { + if (!paraSpaceConfig.ReservesConfig[ERC20TokenContractId.APE]) { + return; + } + + const paraApeStaking = await getParaApeStaking(); + //upgrade to non-fake implementation + if (paraApeStaking) { + const paraApeStakingImpl = await deployParaApeStakingImpl(verify); + const paraApeStakingProxy = + await getInitializableAdminUpgradeabilityProxy(paraApeStaking.address); + + const deployer = await getFirstSigner(); + const deployerAddress = await deployer.getAddress(); + const initData = + paraApeStakingImpl.interface.encodeFunctionData("initialize"); + + await waitForTx( + await (paraApeStakingProxy as InitializableAdminUpgradeabilityProxy)[ + "initialize(address,address,bytes)" + ]( + paraApeStakingImpl.address, + deployerAddress, + initData, + GLOBAL_OVERRIDES + ) + ); + } else { + await deployParaApeStaking(false, verify); + } + } catch (error) { + console.error(error); + process.exit(1); + } +}; diff --git a/scripts/deployments/steps/23_renounceOwnership.ts b/scripts/deployments/steps/23_renounceOwnership.ts index 5c5d7e937..3221fca4c 100644 --- a/scripts/deployments/steps/23_renounceOwnership.ts +++ b/scripts/deployments/steps/23_renounceOwnership.ts @@ -7,7 +7,7 @@ import { getHelperContract, getInitializableAdminUpgradeabilityProxy, getNFTFloorOracle, - getP2PPairStaking, + getParaApeStaking, getPausableZoneController, getPoolAddressesProvider, getPoolAddressesProviderRegistry, @@ -372,27 +372,27 @@ export const step_23 = async ( } //////////////////////////////////////////////////////////////////////////////// - // P2PPairStaking + // ParaApeStaking //////////////////////////////////////////////////////////////////////////////// - if (await getContractAddressInDb(eContractid.P2PPairStaking)) { - console.time("transferring P2PPairStaking ownership..."); - const p2pPairStaking = await getP2PPairStaking(); - const p2pPairStakingProxy = - await getInitializableAdminUpgradeabilityProxy(p2pPairStaking.address); + if (await getContractAddressInDb(eContractid.ParaApeStaking)) { + console.time("transferring ParaApeStaking ownership..."); + const paraApeStaking = await getParaApeStaking(); + const paraApeStakingProxy = + await getInitializableAdminUpgradeabilityProxy(paraApeStaking.address); const signers = await getEthersSigners(); - const adminAddress = signers[5].getAddress(); + const adminAddress = await signers[5].getAddress(); if (DRY_RUN) { - const encodedData1 = p2pPairStakingProxy.interface.encodeFunctionData( + const encodedData1 = paraApeStakingProxy.interface.encodeFunctionData( "changeAdmin", [adminAddress] ); - await dryRunEncodedData(p2pPairStakingProxy.address, encodedData1); + await dryRunEncodedData(paraApeStakingProxy.address, encodedData1); } else { await waitForTx( - await p2pPairStakingProxy.changeAdmin(adminAddress, GLOBAL_OVERRIDES) + await paraApeStakingProxy.changeAdmin(adminAddress, GLOBAL_OVERRIDES) ); } - console.timeEnd("transferring P2PPairStaking ownership..."); + console.timeEnd("transferring ParaApeStaking ownership..."); console.log(); } diff --git a/scripts/deployments/steps/after-all.ts b/scripts/deployments/steps/after-all.ts index e1505403e..cf71c02ea 100644 --- a/scripts/deployments/steps/after-all.ts +++ b/scripts/deployments/steps/after-all.ts @@ -35,7 +35,7 @@ export const afterAll = async () => { ); } - if (!isFork() && BLOCKSCOUT_DISABLE_INDEXER) { + if (!isFork() || BLOCKSCOUT_DISABLE_INDEXER) { return; } await DRE.network.provider.send("evm_setAutomine", [false]); diff --git a/scripts/deployments/steps/index.ts b/scripts/deployments/steps/index.ts index a75d3afec..187db9886 100644 --- a/scripts/deployments/steps/index.ts +++ b/scripts/deployments/steps/index.ts @@ -19,7 +19,7 @@ export const getAllSteps = async () => { const {step_17} = await import("./17_x2y2"); const {step_18} = await import("./18_blur"); const {step_19} = await import("./19_flashClaimRegistry"); - const {step_20} = await import("./20_p2pPairStaking"); + const {step_20} = await import("./20_paraApeStaking"); const {step_21} = await import("./21_helperContract"); const {step_22} = await import("./22_timelock"); const {step_23} = await import("./23_renounceOwnership"); diff --git a/scripts/dev/12.set-timelock-strategy.ts b/scripts/dev/12.set-timelock-strategy.ts index be96e7273..07a120b58 100644 --- a/scripts/dev/12.set-timelock-strategy.ts +++ b/scripts/dev/12.set-timelock-strategy.ts @@ -59,6 +59,14 @@ import { timeLockStrategyLINK, timeLockStrategyAAVE, timeLockStrategyUNI, + timeLockStrategyWMATIC, + timeLockStrategySTMATIC, + timeLockStrategyXCUSDT, + timeLockStrategyUSDCWH, + timeLockStrategyWETHWH, + timeLockStrategyWBTCWH, + timeLockStrategySTDOT, + timeLockStrategyEXRP, } from "../../market-config/timeLockStrategies"; const TIME_LOCK_STRATEGY = { @@ -89,6 +97,11 @@ const TIME_LOCK_STRATEGY = { cAPE: timeLockStrategyCAPE, yAPE: timeLockStrategyYAPE, xcDOT: timeLockStrategyXCDOT, + stDOT: timeLockStrategySTDOT, + xcUSDT: timeLockStrategyXCUSDT, + USDCWH: timeLockStrategyUSDCWH, + WETHWH: timeLockStrategyWETHWH, + WBTCWH: timeLockStrategyWBTCWH, WGLMR: timeLockStrategyWGLMR, BLUR: timeLockStrategyBLUR, ARB: timeLockStrategyARB, @@ -96,6 +109,8 @@ const TIME_LOCK_STRATEGY = { LINK: timeLockStrategyLINK, AAVE: timeLockStrategyAAVE, UNI: timeLockStrategyUNI, + WMATIC: timeLockStrategyWMATIC, + stMATIC: timeLockStrategySTMATIC, // ERC721 BAYC: timeLockStrategyBAYC, ATK: timeLockStrategyBAYC, @@ -128,6 +143,7 @@ const TIME_LOCK_STRATEGY = { VSL: timeLockStrategyVSL, KODA: timeLockStrategyKODA, BLOCKS: timeLockStrategyBLOCKS, + EXRP: timeLockStrategyEXRP, }; const setTimeLockStrategy = async () => { diff --git a/scripts/dev/14.zksync-bytecode-hashes.ts b/scripts/dev/14.zksync-bytecode-hashes.ts new file mode 100644 index 000000000..6227f2594 --- /dev/null +++ b/scripts/dev/14.zksync-bytecode-hashes.ts @@ -0,0 +1,20 @@ +import rawBRE from "hardhat"; +import {getZkSyncBytecodeHashes} from "../../helpers/contracts-helpers"; + +const zksyncBytecodeHashes = async () => { + console.time("zksync-bytecode-hashes"); + console.log(getZkSyncBytecodeHashes()); + console.timeEnd("zksync-bytecode-hashes"); +}; + +async function main() { + await rawBRE.run("set-DRE"); + await zksyncBytecodeHashes(); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/scripts/dev/15.redeploy-market.ts b/scripts/dev/15.redeploy-market.ts new file mode 100644 index 000000000..532dcc8ad --- /dev/null +++ b/scripts/dev/15.redeploy-market.ts @@ -0,0 +1,65 @@ +import rawBRE from "hardhat"; +import {deployAggregator} from "../../helpers/contracts-deployments"; +import { + getAllTokens, + getParaSpaceOracle, + getPoolAddressesProvider, + getPoolConfiguratorProxy, +} from "../../helpers/contracts-getters"; +import {initAndConfigureReserves} from "../../helpers/contracts-helpers"; +import {GLOBAL_OVERRIDES} from "../../helpers/hardhat-constants"; +import {getParaSpaceConfig, waitForTx} from "../../helpers/misc-utils"; +import {ERC20TokenContractId} from "../../helpers/types"; +import {step_13} from "../deployments/steps/13_wethGateway"; +import {upgradeTimeLock} from "../upgrade/timeLock"; + +const redeployMarket = async (verify = false) => { + console.time("redeploy-market"); + const allTokens = await getAllTokens(); + const configurator = await getPoolConfiguratorProxy(); + const symbol = ERC20TokenContractId.WETH; + await waitForTx(await configurator.dropReserve(allTokens[symbol].address)); + // deploy new Token + const provider = await getPoolAddressesProvider(); + const oracle = await getParaSpaceOracle(); + const config = getParaSpaceConfig(); + const token = (await getAllTokens())[symbol]; + const isWrappedNativeToken = symbol == config.WrappedNativeTokenId; + if (isWrappedNativeToken) { + await waitForTx(await provider.setWETH(token.address)); + await upgradeTimeLock(verify); + await step_13(verify); + } + const aggregator = await deployAggregator( + symbol, + config?.Mocks?.AllAssetsInitialPrices[symbol]!, + verify + ); + await waitForTx( + await oracle.setAssetSources( + [token.address], + [aggregator.address], + GLOBAL_OVERRIDES + ) + ); + await initAndConfigureReserves([ + { + symbol, + address: token.address, + aggregator: aggregator.address, + }, + ]); + console.timeEnd("redeploy-market"); +}; + +async function main() { + await rawBRE.run("set-DRE"); + await redeployMarket(); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/scripts/dev/2.transfer-tokens.ts b/scripts/dev/2.transfer-tokens.ts index fcbc8ae6e..37d119edf 100644 --- a/scripts/dev/2.transfer-tokens.ts +++ b/scripts/dev/2.transfer-tokens.ts @@ -6,6 +6,7 @@ import { isFork, isEthereum, sleep, + waitForTx, } from "../../helpers/misc-utils"; import {ERC20TokenContractId, ERC721TokenContractId} from "../../helpers/types"; import { @@ -143,13 +144,16 @@ const transferTokens = async () => { const whale = await impersonateAddress(whaleAddress); // send some gas fee to whale try { - await signer.sendTransaction({ - to: whaleAddress, - value: utils.parseEther("5"), - gasLimit: 50000, - }); + await waitForTx( + await signer.sendTransaction({ + to: whaleAddress, + value: utils.parseEther("1"), + gasLimit: 50000, + }) + ); } catch (e) { console.error(e); + process.exit(1); } if (type === AssetType.ERC20) { @@ -163,7 +167,9 @@ const transferTokens = async () => { console.log( `transfer ${amount} ${name} from ${whaleAddress} to ${receiver}` ); - await token.transfer(receiver, amountWithUnits.toString()); + await waitForTx( + await token.transfer(receiver, amountWithUnits.toString()) + ); } else { console.log(`insufficient ${name} balance on ${whaleAddress}`); } @@ -179,7 +185,9 @@ const transferTokens = async () => { console.log( `transfer ${name}#${tokenId} from ${whaleAddress} to ${receiver}` ); - await token.transferFrom(whaleAddress, receiver, tokenId); + await waitForTx( + await token.transferFrom(whaleAddress, receiver, tokenId) + ); } } else if (type === AssetType.ERC721_MOONBIRD) { const moonbirds = await Moonbirds__factory.connect( @@ -200,10 +208,12 @@ const transferTokens = async () => { console.log( `transfer ${name}#${tokenId} from ${whaleAddress} to ${receiver}` ); - await moonbirds.safeTransferWhileNesting( - whaleAddress, - receiver, - tokenId + await waitForTx( + await moonbirds.safeTransferWhileNesting( + whaleAddress, + receiver, + tokenId + ) ); transferred += 1; } diff --git a/scripts/dev/3.info.ts b/scripts/dev/3.info.ts index 9292e9c0a..b5a556d49 100644 --- a/scripts/dev/3.info.ts +++ b/scripts/dev/3.info.ts @@ -6,7 +6,9 @@ import { } from "../../helpers/contracts-helpers"; import {DRE} from "../../helpers/misc-utils"; import * as envs from "../../helpers/hardhat-constants"; -import {accounts} from "../../wallets"; +import {fromBn} from "evm-bn"; +import {HttpNetworkConfig} from "hardhat/types"; +import * as zk from "zksync-web3"; const info = async () => { console.time("info"); @@ -14,17 +16,34 @@ const info = async () => { const signer = await getFirstSigner(); const signerAddress = await signer.getAddress(); + console.log(DRE.network.name); console.log(await DRE.ethers.provider.getNetwork()); console.log(await DRE.ethers.provider.getFeeData()); console.log(envs); console.log(await getParaSpaceAdmins()); - console.log(accounts); console.log(signerAddress); console.log(await signer.getTransactionCount()); + console.log((DRE.network.config as HttpNetworkConfig).url); + console.log(fromBn(await DRE.ethers.provider.getBalance(signerAddress))); console.log( await Promise.all((await getEthersSigners()).map((x) => x.getAddress())) ); + if (DRE.network.config.zksync) { + console.log( + "MainContract", + (await (signer as zk.Wallet).getMainContract()).address + ); + console.log( + "L1ERC20 BridgeContracts", + (await (signer as zk.Wallet).getL1BridgeContracts()).erc20.address + ); + console.log( + "L2ERC20 BridgeContracts", + (await (signer as zk.Wallet).getL2BridgeContracts()).erc20.address + ); + } + console.timeEnd("info"); }; diff --git a/scripts/upgrade/P2PPairStaking.ts b/scripts/upgrade/P2PPairStaking.ts deleted file mode 100644 index 365705a43..000000000 --- a/scripts/upgrade/P2PPairStaking.ts +++ /dev/null @@ -1,41 +0,0 @@ -import {deployP2PPairStakingImpl} from "../../helpers/contracts-deployments"; -import { - getInitializableAdminUpgradeabilityProxy, - getP2PPairStaking, -} from "../../helpers/contracts-getters"; -import {dryRunEncodedData} from "../../helpers/contracts-helpers"; -import {DRY_RUN, GLOBAL_OVERRIDES} from "../../helpers/hardhat-constants"; -import {waitForTx} from "../../helpers/misc-utils"; - -export const upgradeP2PPairStaking = async ( - compoundFee: number, - verify = false -) => { - console.time("deploy P2PPairStaking"); - const p2pPairStakingImpl = await deployP2PPairStakingImpl( - compoundFee, - verify - ); - const p2pPairStaking = await getP2PPairStaking(); - const p2pPairStakingProxy = await getInitializableAdminUpgradeabilityProxy( - p2pPairStaking.address - ); - console.timeEnd("deploy P2PPairStaking"); - - console.time("upgrade P2PPairStaking"); - if (DRY_RUN) { - const encodedData = p2pPairStakingProxy.interface.encodeFunctionData( - "upgradeTo", - [p2pPairStakingImpl.address] - ); - await dryRunEncodedData(p2pPairStakingProxy.address, encodedData); - } else { - await waitForTx( - await p2pPairStakingProxy.upgradeTo( - p2pPairStakingImpl.address, - GLOBAL_OVERRIDES - ) - ); - } - console.timeEnd("upgrade P2PPairStaking"); -}; diff --git a/scripts/upgrade/ntoken.ts b/scripts/upgrade/ntoken.ts index ae76c097a..8f0d39b85 100644 --- a/scripts/upgrade/ntoken.ts +++ b/scripts/upgrade/ntoken.ts @@ -104,26 +104,8 @@ export const upgradeNToken = async (verify = false) => { } else if (xTokenType == XTokenType.NTokenBAKC) { if (!nTokenBAKCImplementationAddress) { console.log("deploy NTokenBAKC implementation"); - const apeCoinStaking = await getApeCoinStaking(); - const nBAYC = - // eslint-disable-next-line - allXTokens.find( - (x) => x.symbol == NTokenContractId.nBAYC - )!.tokenAddress; - const nMAYC = - // eslint-disable-next-line - allXTokens.find( - (x) => x.symbol == NTokenContractId.nMAYC - )!.tokenAddress; nTokenBAKCImplementationAddress = ( - await deployNTokenBAKCImpl( - pool.address, - apeCoinStaking.address, - nBAYC, - nMAYC, - delegationRegistry, - verify - ) + await deployNTokenBAKCImpl(pool.address, delegationRegistry, verify) ).address; } newImpl = nTokenBAKCImplementationAddress; @@ -240,7 +222,10 @@ export const upgradeNToken = async (verify = false) => { await (await getNToken(newImpl)).NTOKEN_REVISION() ).toNumber(); - if (oldRevision == newRevision) { + if (oldRevision >= newRevision) { + console.log( + `trying to upgrade ${token.symbol}'s version from v${oldRevision} to v${newRevision}, skip` + ); continue; } diff --git a/scripts/upgrade/para_ape_staking.ts b/scripts/upgrade/para_ape_staking.ts new file mode 100644 index 000000000..05a5ef7cf --- /dev/null +++ b/scripts/upgrade/para_ape_staking.ts @@ -0,0 +1,35 @@ +import {deployParaApeStakingImpl} from "../../helpers/contracts-deployments"; +import { + getInitializableAdminUpgradeabilityProxy, + getParaApeStaking, +} from "../../helpers/contracts-getters"; +import {dryRunEncodedData} from "../../helpers/contracts-helpers"; +import {DRY_RUN, GLOBAL_OVERRIDES} from "../../helpers/hardhat-constants"; +import {waitForTx} from "../../helpers/misc-utils"; + +export const upgradeParaApeStaking = async (verify = false) => { + console.time("deploy ParaApeStaking"); + const paraApeStakingImpl = await deployParaApeStakingImpl(verify); + const paraApeStaking = await getParaApeStaking(); + const paraApeStakingProxy = await getInitializableAdminUpgradeabilityProxy( + paraApeStaking.address + ); + console.timeEnd("deploy ParaApeStaking"); + + console.time("upgrade ParaApeStaking"); + if (DRY_RUN) { + const encodedData = paraApeStakingProxy.interface.encodeFunctionData( + "upgradeTo", + [paraApeStakingImpl.address] + ); + await dryRunEncodedData(paraApeStakingProxy.address, encodedData); + } else { + await waitForTx( + await paraApeStakingProxy.upgradeTo( + paraApeStakingImpl.address, + GLOBAL_OVERRIDES + ) + ); + } + console.timeEnd("upgrade ParaApeStaking"); +}; diff --git a/scripts/upgrade/ptoken.ts b/scripts/upgrade/ptoken.ts index bebe3a7a4..0600a7b90 100644 --- a/scripts/upgrade/ptoken.ts +++ b/scripts/upgrade/ptoken.ts @@ -6,6 +6,7 @@ import { deployPTokenCApe, deployPTokenSApe, deployPTokenStETH, + deployPTokenStKSM, } from "../../helpers/contracts-deployments"; import { getPoolAddressesProvider, @@ -13,11 +14,7 @@ import { getProtocolDataProvider, getPToken, } from "../../helpers/contracts-getters"; -import { - NTokenContractId, - PTokenContractId, - XTokenType, -} from "../../helpers/types"; +import {PTokenContractId, XTokenType} from "../../helpers/types"; import dotenv from "dotenv"; import {DRY_RUN, GLOBAL_OVERRIDES} from "../../helpers/hardhat-constants"; @@ -37,6 +34,7 @@ export const upgradePToken = async (verify = false) => { let pTokenImplementationAddress = ""; let pTokenDelegationAwareImplementationAddress = ""; let pTokenStETHImplementationAddress = ""; + let pTokenStKSMImplementationAddress = ""; let pTokenSApeImplementationAddress = ""; let pTokenCApeImplementationAddress = ""; let pTokenATokenImplementationAddress = ""; @@ -86,18 +84,8 @@ export const upgradePToken = async (verify = false) => { } else if (xTokenType == XTokenType.PTokenSApe) { if (!pTokenSApeImplementationAddress) { console.log("deploy PTokenSApe implementation"); - const nBAYC = - // eslint-disable-next-line - allXTokens.find( - (x) => x.symbol == NTokenContractId.nBAYC - )!.tokenAddress; - const nMAYC = - // eslint-disable-next-line - allXTokens.find( - (x) => x.symbol == NTokenContractId.nMAYC - )!.tokenAddress; pTokenSApeImplementationAddress = ( - await deployPTokenSApe(poolAddress, nBAYC, nMAYC, verify) + await deployPTokenSApe(poolAddress, verify) ).address; } newImpl = pTokenSApeImplementationAddress; @@ -117,6 +105,14 @@ export const upgradePToken = async (verify = false) => { ).address; } newImpl = pTokenStETHImplementationAddress; + } else if (xTokenType == XTokenType.PTokenStKSM) { + if (!pTokenStKSMImplementationAddress) { + console.log("deploy PTokenStKSM implementation"); + pTokenStKSMImplementationAddress = ( + await deployPTokenStKSM(poolAddress, verify) + ).address; + } + newImpl = pTokenStKSMImplementationAddress; } else if (xTokenType == XTokenType.DelegationAwarePToken) { if (!pTokenDelegationAwareImplementationAddress) { console.log("deploy PTokenDelegationAware implementation"); diff --git a/tasks/deployments/20_p2pPairStaking.ts b/tasks/deployments/20_paraApeStaking.ts similarity index 67% rename from tasks/deployments/20_p2pPairStaking.ts rename to tasks/deployments/20_paraApeStaking.ts index 2ab569c77..9a60b2421 100644 --- a/tasks/deployments/20_p2pPairStaking.ts +++ b/tasks/deployments/20_paraApeStaking.ts @@ -1,11 +1,11 @@ import {task} from "hardhat/config"; import {ETHERSCAN_VERIFICATION} from "../../helpers/hardhat-constants"; -task("deploy:P2PPairStaking", "Deploy P2PPairStaking").setAction( +task("deploy:ParaApeStaking", "Deploy ParaApeStaking").setAction( async (_, DRE) => { await DRE.run("set-DRE"); const {step_20} = await import( - "../../scripts/deployments/steps/20_p2pPairStaking" + "../../scripts/deployments/steps/20_paraApeStaking" ); await step_20(ETHERSCAN_VERIFICATION); } diff --git a/tasks/deployments/99_deployAllLibraries.ts b/tasks/deployments/99_deployAllLibraries.ts new file mode 100644 index 000000000..0559b0021 --- /dev/null +++ b/tasks/deployments/99_deployAllLibraries.ts @@ -0,0 +1,12 @@ +import {task} from "hardhat/config"; +import {ETHERSCAN_VERIFICATION} from "../../helpers/hardhat-constants"; + +task("deploy:all-libraries", "Deploy All Libraries").setAction( + async (_, DRE) => { + await DRE.run("set-DRE"); + const {deployAllLibraries} = await import( + "../../helpers/contracts-deployments" + ); + await deployAllLibraries(ETHERSCAN_VERIFICATION); + } +); diff --git a/tasks/dev/coder.ts b/tasks/dev/coder.ts index 23db04a51..9eb38a58c 100644 --- a/tasks/dev/coder.ts +++ b/tasks/dev/coder.ts @@ -1,6 +1,7 @@ import {decodeMulti} from "ethers-multisend"; import {task} from "hardhat/config"; import {TIME_LOCK_SIGS} from "../../helpers/hardhat-constants"; +import {eContractid} from "../../helpers/types"; task("decode", "Decode input data") .addPositionalParam("data", "hex encoded data") @@ -9,12 +10,16 @@ task("decode", "Decode input data") const {getTimeLockExecutor} = await import( "../../helpers/contracts-getters" ); - const timeLock = await getTimeLockExecutor(); - const {decodeInputData} = await import("../../helpers/contracts-helpers"); - const sig = TIME_LOCK_SIGS[data.slice(0, 10)]; - if (sig) { - [, , , data] = timeLock.interface.decodeFunctionData(sig, data); - return; + const {decodeInputData, getContractAddressInDb} = await import( + "../../helpers/contracts-helpers" + ); + if (await getContractAddressInDb(eContractid.TimeLockExecutor)) { + const timeLock = await getTimeLockExecutor(); + const sig = TIME_LOCK_SIGS[data.slice(0, 10)]; + if (sig) { + [, , , data] = timeLock.interface.decodeFunctionData(sig, data); + return; + } } console.log(JSON.stringify(decodeInputData(data), null, 4)); diff --git a/tasks/dev/marketInfo.ts b/tasks/dev/marketInfo.ts index fb5d79366..bc308a93a 100644 --- a/tasks/dev/marketInfo.ts +++ b/tasks/dev/marketInfo.ts @@ -3,7 +3,7 @@ import minimatch from "minimatch"; import {fromBn} from "evm-bn"; import {log10} from "@prb/math"; import {BigNumber} from "ethers"; -import {RAY, WAD} from "../../helpers/constants"; +import {RAY, SAPE_ADDRESS, WAD} from "../../helpers/constants"; task("market-info", "Print markets info") .addPositionalParam("market", "Market name/symbol pattern", "*") @@ -14,6 +14,7 @@ task("market-info", "Print markets info") getPoolAddressesProvider, getUiPoolDataProvider, getParaSpaceOracle, + getERC20, } = await import("../../helpers/contracts-getters"); const {getProxyImplementation} = await import( "../../helpers/contracts-helpers" @@ -47,6 +48,15 @@ task("market-info", "Print markets info") console.log(" reserveFactor:", x.reserveFactor.toString()); console.log(" supplyCap:", x.supplyCap.toString()); console.log(" borrowCap:", x.borrowCap.toString()); + if (x.assetType == 0 && x.underlyingAsset != SAPE_ADDRESS) { + console.log( + " availableLiquidity:", + ( + await (await getERC20(x.underlyingAsset)).balanceOf(x.xTokenAddress) + ).toString() + ); + } + console.log(" xTokenProxy:", x.xTokenAddress); console.log( " xTokenImpl:", diff --git a/tasks/dev/safe.ts b/tasks/dev/safe.ts index 979d6a0e5..145801cf5 100644 --- a/tasks/dev/safe.ts +++ b/tasks/dev/safe.ts @@ -1,32 +1,27 @@ import {task} from "hardhat/config"; -import {FORK, TIME_LOCK_SIGS} from "../../helpers/hardhat-constants"; -import {ethers} from "ethers"; +import {TIME_LOCK_SIGS} from "../../helpers/hardhat-constants"; import {decodeMulti, MetaTransaction} from "ethers-multisend"; -import EthersAdapter from "@safe-global/safe-ethers-lib"; -import SafeServiceClient from "@safe-global/safe-service-client"; import {findLastIndex} from "lodash"; +import {eContractid} from "../../helpers/types"; task("decode-safe-txs", "Decode safe txs").setAction(async (_, DRE) => { await DRE.run("set-DRE"); - const {getFirstSigner, getTimeLockExecutor} = await import( + const {getTimeLockExecutor, getSafeSdkAndService} = await import( "../../helpers/contracts-getters" ); + const {getContractAddressInDb} = await import( + "../../helpers/contracts-helpers" + ); const {getParaSpaceConfig} = await import("../../helpers/misc-utils"); const {decodeInputData} = await import("../../helpers/contracts-helpers"); - const timeLock = await getTimeLockExecutor(); - const signer = await getFirstSigner(); - const ethAdapter = new EthersAdapter({ - ethers, - signerOrProvider: signer, - }); + const timeLock = (await getContractAddressInDb(eContractid.TimeLockExecutor)) + ? await getTimeLockExecutor() + : undefined; const paraSpaceConfig = getParaSpaceConfig(); - const safeService = new SafeServiceClient({ - txServiceUrl: `https://safe-transaction-${ - FORK || DRE.network.name - }.safe.global`, - ethAdapter, - }); + const {safeService} = await getSafeSdkAndService( + paraSpaceConfig.Governance.Multisig + ); const res = ( await safeService.getPendingTransactions( paraSpaceConfig.Governance.Multisig @@ -53,7 +48,7 @@ task("decode-safe-txs", "Decode safe txs").setAction(async (_, DRE) => { ? decodeMulti(cur.data).map((x) => ({to: x.to, data: x.data})) : [{to: cur.to, data: cur.data}] ).map(({to, data}) => { - if (to != timeLock.address) { + if (to != timeLock?.address) { return {to, data}; } diff --git a/tasks/dev/verifyContracts.ts b/tasks/dev/verifyContracts.ts index 4cd2766e7..87d833050 100644 --- a/tasks/dev/verifyContracts.ts +++ b/tasks/dev/verifyContracts.ts @@ -4,7 +4,7 @@ import {ETHERSCAN_VERIFICATION_JOBS} from "../../helpers/hardhat-constants"; task("verify-contracts", "Verify deployed contracts on etherscan").setAction( async (_, DRE) => { await DRE.run("set-DRE"); - const {verifyContracts} = await import("../../helpers/misc-utils"); + const {verifyContracts} = await import("../../helpers/contracts-helpers"); await verifyContracts(ETHERSCAN_VERIFICATION_JOBS); } ); diff --git a/tasks/misc/set-bre.ts b/tasks/misc/set-bre.ts index 63805be83..46ce7ec4c 100644 --- a/tasks/misc/set-bre.ts +++ b/tasks/misc/set-bre.ts @@ -1,13 +1,12 @@ import {task} from "hardhat/config"; import { DRE, - isArbitrumOne, - isEthereum, - isMoonbeam, + isMainnet, + isPolygon, isPublicTestnet, setDRE, } from "../../helpers/misc-utils"; -import {HardhatRuntimeEnvironment} from "hardhat/types"; +import {HardhatRuntimeEnvironment, HttpNetworkConfig} from "hardhat/types"; import { FORK, GLOBAL_OVERRIDES, @@ -16,6 +15,7 @@ import { TENDERLY_HEAD_ID, } from "../../helpers/hardhat-constants"; import {utils} from "ethers"; +import {Provider} from "zksync-web3"; task( `set-DRE`, @@ -44,6 +44,10 @@ task( console.log("- Initialized Tenderly fork:"); console.log(" - Fork: ", net.getFork()); console.log(" - Head: ", net.getHead()); + } else if (_DRE.network.config.zksync) { + _DRE.ethers.provider = new Provider( + (_DRE.network.config as HttpNetworkConfig).url + ); } console.log("- Environment"); @@ -65,26 +69,34 @@ task( setDRE(_DRE); - if (isPublicTestnet() || isEthereum() || isMoonbeam() || isArbitrumOne()) { + if (isPublicTestnet() || isMainnet()) { const feeData = await _DRE.ethers.provider.getFeeData(); - if (feeData.maxFeePerGas) { - GLOBAL_OVERRIDES.maxFeePerGas = feeData.maxFeePerGas; + if (feeData.maxFeePerGas && feeData.maxPriorityFeePerGas) { + GLOBAL_OVERRIDES.type = 2; + GLOBAL_OVERRIDES.maxFeePerGas = isPolygon() + ? feeData.maxFeePerGas.mul(2) + : feeData.maxFeePerGas; + GLOBAL_OVERRIDES.maxPriorityFeePerGas = isPolygon() + ? feeData.maxFeePerGas.mul(2) + : feeData.maxPriorityFeePerGas; + console.log(" - Type:", GLOBAL_OVERRIDES.type); + console.log( + " - MaxPriorityFeePerGas:", + utils.formatUnits(GLOBAL_OVERRIDES.maxPriorityFeePerGas, "gwei") + ); console.log( " - MaxFeePerGas:", - utils.formatUnits(feeData.maxFeePerGas, "gwei") + utils.formatUnits(GLOBAL_OVERRIDES.maxFeePerGas, "gwei") ); - } - if (feeData.maxPriorityFeePerGas) { - GLOBAL_OVERRIDES.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas; + } else if (feeData.gasPrice) { + GLOBAL_OVERRIDES.gasPrice = feeData.gasPrice; + GLOBAL_OVERRIDES.type = 0; + console.log(" - Type:", GLOBAL_OVERRIDES.type); console.log( - " - MaxPriorityFeePerGas:", - utils.formatUnits(GLOBAL_OVERRIDES.maxPriorityFeePerGas, "gwei") + " - GasPrice:", + utils.formatUnits(GLOBAL_OVERRIDES.gasPrice, "gwei") ); } - - if (feeData.maxFeePerGas && feeData.maxPriorityFeePerGas) { - GLOBAL_OVERRIDES.type = 2; - } } return _DRE; diff --git a/tasks/upgrade/index.ts b/tasks/upgrade/index.ts index 025c336aa..cf49b2887 100644 --- a/tasks/upgrade/index.ts +++ b/tasks/upgrade/index.ts @@ -119,17 +119,17 @@ task("upgrade:timelock", "upgrade timelock").setAction(async (_, DRE) => { console.timeEnd("upgrade timelock"); }); -task("upgrade:p2p-pair-staking", "upgrade p2p pair staking") - .addPositionalParam("compoundFee", "new compound fee") - .setAction(async (compoundFee, DRE) => { - const {upgradeP2PPairStaking} = await import( - "../../scripts/upgrade/P2PPairStaking" +task("upgrade:para-ape-staking", "upgrade para ape staking").setAction( + async (_, DRE) => { + const {upgradeParaApeStaking} = await import( + "../../scripts/upgrade/para_ape_staking" ); await DRE.run("set-DRE"); - console.time("upgrade p2p pair staking"); - await upgradeP2PPairStaking(compoundFee, ETHERSCAN_VERIFICATION); - console.timeEnd("upgrade p2p pair staking"); - }); + console.time("upgrade para ape staking"); + await upgradeParaApeStaking(ETHERSCAN_VERIFICATION); + console.timeEnd("upgrade para ape staking"); + } +); task("upgrade:ptoken", "upgrade ptoken").setAction(async (_, DRE) => { const {upgradePToken} = await import("../../scripts/upgrade/ptoken"); diff --git a/test/_base_interest_rate_strategy.spec.ts b/test/_base_interest_rate_strategy.spec.ts index 299dc93fe..d31d8e90d 100644 --- a/test/_base_interest_rate_strategy.spec.ts +++ b/test/_base_interest_rate_strategy.spec.ts @@ -34,10 +34,10 @@ import {getFirstSigner, getAggregator} from "../helpers/contracts-getters"; import {auctionStrategyExp} from "../market-config/auctionStrategies"; import { convertToCurrencyDecimals, - impersonateAddress, + // impersonateAddress, } from "../helpers/contracts-helpers"; import {increaseTime} from "../helpers/misc-utils"; -import {topUpNonPayableWithEther} from "./helpers/utils/funds"; +// import {topUpNonPayableWithEther} from "./helpers/utils/funds"; import {ETHERSCAN_VERIFICATION} from "../helpers/hardhat-constants"; import {ConfiguratorInputTypes} from "../types/contracts/interfaces/IPoolConfigurator"; @@ -253,29 +253,29 @@ describe("Interest Rate Tests", () => { ).to.be.revertedWith(INVALID_OPTIMAL_USAGE_RATIO); }); - it("TC-interest-rate-strategy-07 PoolConfigurator updates the ReserveInterestRateStrategy address", async () => { - const {pool, deployer, dai, configurator} = await loadFixture( - testEnvFixture - ); - - // Impersonate PoolConfigurator - await topUpNonPayableWithEther( - deployer.signer, - [configurator.address], - utils.parseEther("1") - ); - const configSigner = (await impersonateAddress(configurator.address)) - .signer; - - expect( - await pool - .connect(configSigner) - .setReserveInterestRateStrategyAddress(dai.address, ZERO_ADDRESS) - ); - - const config = await pool.getReserveData(dai.address); - expect(config.interestRateStrategyAddress).to.be.eq(ZERO_ADDRESS); - }); + // it("TC-interest-rate-strategy-07 PoolConfigurator updates the ReserveInterestRateStrategy address", async () => { + // const {pool, deployer, dai, configurator} = await loadFixture( + // testEnvFixture + // ); + // + // // Impersonate PoolConfigurator + // await topUpNonPayableWithEther( + // deployer.signer, + // [configurator.address], + // utils.parseEther("1") + // ); + // const configSigner = (await impersonateAddress(configurator.address)) + // .signer; + // + // expect( + // await pool + // .connect(configSigner) + // .setReserveInterestRateStrategyAddress(dai.address, ZERO_ADDRESS) + // ); + // + // const config = await pool.getReserveData(dai.address); + // expect(config.interestRateStrategyAddress).to.be.eq(ZERO_ADDRESS); + // }); }); context("Interest Rate and Index Overflow", () => { diff --git a/test/_base_reserve_configuration.spec.ts b/test/_base_reserve_configuration.spec.ts index e0c7a9807..53ab390c7 100644 --- a/test/_base_reserve_configuration.spec.ts +++ b/test/_base_reserve_configuration.spec.ts @@ -12,20 +12,24 @@ import { MintableERC20__factory, MockReserveConfiguration, MockReserveInterestRateStrategy__factory, - PoolCore__factory, PToken__factory, VariableDebtToken__factory, } from "../types"; import {ProtocolErrors} from "../helpers/types"; import {testEnvFixture} from "./helpers/setup-env"; import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; -import {topUpNonPayableWithEther} from "./helpers/utils/funds"; import {ZERO_ADDRESS} from "../helpers/constants"; -import {getFirstSigner, getTimeLockProxy} from "../helpers/contracts-getters"; +import { + getContractFactory, + getFirstSigner, + getTimeLockProxy, +} from "../helpers/contracts-getters"; import {auctionStrategyExp} from "../market-config/auctionStrategies"; -import {BigNumberish, utils} from "ethers"; +import {BigNumberish} from "ethers"; +// import {topUpNonPayableWithEther} from "./helpers/utils/funds"; +// import {utils} from "ethers"; +// import {impersonateAddress} from "../helpers/contracts-helpers"; import {ETHERSCAN_VERIFICATION} from "../helpers/hardhat-constants"; -import {impersonateAddress} from "../helpers/contracts-helpers"; import {ConfiguratorInputTypes} from "../types/contracts/interfaces/IPoolConfigurator"; describe("ReserveConfiguration", async () => { @@ -410,88 +414,88 @@ describe("ReserveConfiguration", async () => { expect(await configMock.getLiquidationProtocolFee()).to.be.eq(ZERO); }); - it("TC-reserve-configuration-20 Initialize an already initialized reserve. ReserveLogic `init` where xTokenAddress != ZERO_ADDRESS (revert expected)", async () => { - const {pool, dai, deployer, configurator} = await loadFixture( - testEnvFixture - ); - - // Impersonate PoolConfigurator - await topUpNonPayableWithEther( - deployer.signer, - [configurator.address], - utils.parseEther("1") - ); - const configSigner = (await impersonateAddress(configurator.address)) - .signer; - - const config = await pool.getReserveData(dai.address); - - await expect( - pool.connect(configSigner).initReserve( - dai.address, - config.xTokenAddress, // just need a non-used reserve token - config.variableDebtTokenAddress, - ZERO_ADDRESS, - ZERO_ADDRESS, - ZERO_ADDRESS - ) - ).to.be.revertedWith(ProtocolErrors.RESERVE_ALREADY_INITIALIZED); - }); - - it("TC-reserve-configuration-21 Init reserve with ZERO_ADDRESS as xToken twice, to enter `_addReserveToList()` already added (revert expected)", async () => { - /** - * To get into this case, we need to init a reserve with `xTokenAddress = address(0)` twice. - * `_addReserveToList()` is called from `initReserve`. However, in `initReserve` we run `init` before the `_addReserveToList()`, - * and in `init` we are checking if `xTokenAddress == address(0)`, so to bypass that we need this odd init. - */ - const {pool, dai, deployer, configurator} = await loadFixture( - testEnvFixture - ); - - // Impersonate PoolConfigurator - await topUpNonPayableWithEther( - deployer.signer, - [configurator.address], - utils.parseEther("1") - ); - const configSigner = (await impersonateAddress(configurator.address)) - .signer; - - const config = await pool.getReserveData(dai.address); - - const poolListBefore = await pool.getReservesList(); - - expect( - await pool - .connect(configSigner) - .initReserve( - config.xTokenAddress, - ZERO_ADDRESS, - config.variableDebtTokenAddress, - ZERO_ADDRESS, - ZERO_ADDRESS, - ZERO_ADDRESS - ) - ); - const poolListMid = await pool.getReservesList(); - expect(poolListBefore.length + 1).to.be.eq(poolListMid.length); - - // Add it again. - await expect( - pool - .connect(configSigner) - .initReserve( - config.xTokenAddress, - ZERO_ADDRESS, - config.variableDebtTokenAddress, - ZERO_ADDRESS, - ZERO_ADDRESS, - ZERO_ADDRESS - ) - ).to.be.revertedWith(ProtocolErrors.RESERVE_ALREADY_ADDED); - const poolListAfter = await pool.getReservesList(); - expect(poolListAfter.length).to.be.eq(poolListMid.length); - }); + // it("TC-reserve-configuration-20 Initialize an already initialized reserve. ReserveLogic `init` where xTokenAddress != ZERO_ADDRESS (revert expected)", async () => { + // const {pool, dai, deployer, configurator} = await loadFixture( + // testEnvFixture + // ); + // + // // Impersonate PoolConfigurator + // await topUpNonPayableWithEther( + // deployer.signer, + // [configurator.address], + // utils.parseEther("1") + // ); + // const configSigner = (await impersonateAddress(configurator.address)) + // .signer; + // + // const config = await pool.getReserveData(dai.address); + // + // await expect( + // pool.connect(configSigner).initReserve( + // dai.address, + // config.xTokenAddress, // just need a non-used reserve token + // config.variableDebtTokenAddress, + // ZERO_ADDRESS, + // ZERO_ADDRESS, + // ZERO_ADDRESS + // ) + // ).to.be.revertedWith(ProtocolErrors.RESERVE_ALREADY_INITIALIZED); + // }); + + // it("TC-reserve-configuration-21 Init reserve with ZERO_ADDRESS as xToken twice, to enter `_addReserveToList()` already added (revert expected)", async () => { + // /** + // * To get into this case, we need to init a reserve with `xTokenAddress = address(0)` twice. + // * `_addReserveToList()` is called from `initReserve`. However, in `initReserve` we run `init` before the `_addReserveToList()`, + // * and in `init` we are checking if `xTokenAddress == address(0)`, so to bypass that we need this odd init. + // */ + // const {pool, dai, deployer, configurator} = await loadFixture( + // testEnvFixture + // ); + // + // // Impersonate PoolConfigurator + // await topUpNonPayableWithEther( + // deployer.signer, + // [configurator.address], + // utils.parseEther("1") + // ); + // const configSigner = (await impersonateAddress(configurator.address)) + // .signer; + // + // const config = await pool.getReserveData(dai.address); + // + // const poolListBefore = await pool.getReservesList(); + // + // expect( + // await pool + // .connect(configSigner) + // .initReserve( + // config.xTokenAddress, + // ZERO_ADDRESS, + // config.variableDebtTokenAddress, + // ZERO_ADDRESS, + // ZERO_ADDRESS, + // ZERO_ADDRESS + // ) + // ); + // const poolListMid = await pool.getReservesList(); + // expect(poolListBefore.length + 1).to.be.eq(poolListMid.length); + // + // // Add it again. + // await expect( + // pool + // .connect(configSigner) + // .initReserve( + // config.xTokenAddress, + // ZERO_ADDRESS, + // config.variableDebtTokenAddress, + // ZERO_ADDRESS, + // ZERO_ADDRESS, + // ZERO_ADDRESS + // ) + // ).to.be.revertedWith(ProtocolErrors.RESERVE_ALREADY_ADDED); + // const poolListAfter = await pool.getReservesList(); + // expect(poolListAfter.length).to.be.eq(poolListMid.length); + // }); it("TC-reserve-configuration-22 Initialize reserves until max, then add one more (revert expected)", async () => { const {addressesProvider, poolAdmin, pool, configurator} = @@ -667,10 +671,9 @@ describe("ReserveConfiguration", async () => { const coreLibraries = await deployPoolCoreLibraries(false); const timeLock = await getTimeLockProxy(); - const NEW_POOL_IMPL_ARTIFACT = await new PoolCore__factory( - coreLibraries, - await getFirstSigner() - ).deploy(addressesProvider.address, timeLock.address); + const NEW_POOL_IMPL_ARTIFACT = await ( + await getContractFactory("PoolCore", coreLibraries) + ).factory.deploy(addressesProvider.address, timeLock.address); const xTokenImp = await new PToken__factory(await getFirstSigner()).deploy( pool.address diff --git a/test/_base_upgradeability.spec.ts b/test/_base_upgradeability.spec.ts index 9158d8d32..2f30228a8 100644 --- a/test/_base_upgradeability.spec.ts +++ b/test/_base_upgradeability.spec.ts @@ -2,6 +2,7 @@ import {expect} from "chai"; import {TestEnv} from "./helpers/make-suite"; import {ONE_ADDRESS, ZERO_ADDRESS} from "../helpers/constants"; import { + getContractFactory, getFirstSigner, getMockInitializableImple, getMockInitializableImpleV2, @@ -733,10 +734,9 @@ describe("Upgradeability", () => { ); const timeLock = await getTimeLockProxy(); - const poolCoreV2 = await new PoolCoreV2__factory( - coreLibraries, - await getFirstSigner() - ).deploy(addressesProvider.address, timeLock.address); + const poolCoreV2 = await ( + await getContractFactory("PoolCoreV2", coreLibraries) + ).factory.deploy(addressesProvider.address, timeLock.address); await waitForTx( await addressesProvider.updatePoolImpl( diff --git a/test/_data_providers.spec.ts b/test/_data_providers.spec.ts index 94c4b6b19..e2df50677 100644 --- a/test/_data_providers.spec.ts +++ b/test/_data_providers.spec.ts @@ -1,34 +1,34 @@ +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {encodeSqrtRatioX96} from "@uniswap/v3-sdk"; import {expect} from "chai"; +import {ethers} from "ethers"; import {ZERO_ADDRESS} from "../helpers/constants"; import { - convertToCurrencyDecimals, - withSaveAndVerify, -} from "../helpers/contracts-helpers"; -import {WalletBalanceProvider, WalletBalanceProvider__factory} from "../types"; -import { - borrowAndValidate, - changePriceAndValidate, - mintAndValidate, - supplyAndValidate, -} from "./helpers/validated-steps"; -import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; -import {testEnvFixture} from "./helpers/setup-env"; -import { - getFirstSigner, + getContractFactory, getMockIncentivesController, getUiIncentiveDataProviderV3, getUniswapV3OracleWrapper, } from "../helpers/contracts-getters"; -import {ethers} from "ethers"; +import { + convertToCurrencyDecimals, + withSaveAndVerify, +} from "../helpers/contracts-helpers"; import {waitForTx} from "../helpers/misc-utils"; +import {ERC20TokenContractId} from "../helpers/types"; +import {WalletBalanceProvider} from "../types"; +import {testEnvFixture} from "./helpers/setup-env"; import { approveTo, createNewPool, fund, mintNewPosition, } from "./helpers/uniswapv3-helper"; -import {encodeSqrtRatioX96} from "@uniswap/v3-sdk"; -import {ERC20TokenContractId} from "../helpers/types"; +import { + borrowAndValidate, + changePriceAndValidate, + mintAndValidate, + supplyAndValidate, +} from "./helpers/validated-steps"; const ETH_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; @@ -40,7 +40,7 @@ describe("UI Contracts Tests", () => { const testEnv = await loadFixture(testEnvFixture); walletBalanceProvider = (await withSaveAndVerify( - new WalletBalanceProvider__factory(await getFirstSigner()), + await getContractFactory("WalletBalanceProvider"), "WalletBalanceProvider", [], false diff --git a/test/_oracle_nft_floor_price.spec.ts b/test/_oracle_nft_floor_price.spec.ts index 6fb4cc24b..de09cecc2 100644 --- a/test/_oracle_nft_floor_price.spec.ts +++ b/test/_oracle_nft_floor_price.spec.ts @@ -309,7 +309,7 @@ describe("NFT Oracle Tests", () => { // grant admin role to user3 await nftFloorOracle.grantRole( - aclManager.DEFAULT_ADMIN_ROLE(), + await aclManager.DEFAULT_ADMIN_ROLE(), user3.address ); diff --git a/test/_pool_ape_staking.spec.ts b/test/_pool_ape_staking.spec.ts deleted file mode 100644 index 0df9070b4..000000000 --- a/test/_pool_ape_staking.spec.ts +++ /dev/null @@ -1,3307 +0,0 @@ -import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; -import {expect} from "chai"; -import {MAX_UINT_AMOUNT, ZERO_ADDRESS, ONE_ADDRESS} from "../helpers/constants"; -import { - getAutoCompoundApe, - getPoolConfiguratorProxy, - getPToken, - getPTokenSApe, - getTimeLockProxy, - getVariableDebtToken, -} from "../helpers/contracts-getters"; -import { - convertToCurrencyDecimals, - isUsingAsCollateral, -} from "../helpers/contracts-helpers"; -import {advanceTimeAndBlock, waitForTx} from "../helpers/misc-utils"; -import {VariableDebtToken, PTokenSApe, PToken, AutoCompoundApe} from "../types"; -import {TestEnv} from "./helpers/make-suite"; -import {testEnvFixture} from "./helpers/setup-env"; - -import { - borrowAndValidate, - changePriceAndValidate, - changeSApePriceAndValidate, - mintAndValidate, - supplyAndValidate, -} from "./helpers/validated-steps"; -import {almostEqual} from "./helpers/uniswapv3-helper"; -import {eContractid, ProtocolErrors} from "../helpers/types"; -import {parseEther} from "ethers/lib/utils"; -import { - executeAcceptBidWithCredit, - executeSeaportBuyWithCredit, -} from "./helpers/marketplace-helper"; -import {BigNumber} from "ethers"; -import {deployReserveTimeLockStrategy} from "../helpers/contracts-deployments"; - -describe("APE Coin Staking Test", () => { - let testEnv: TestEnv; - let variableDebtApeCoin: VariableDebtToken; - let variableDebtCApeCoin: VariableDebtToken; - let pApeCoin: PToken; - let cApe: AutoCompoundApe; - let pcApeCoin: PToken; - let pSApeCoin: PTokenSApe; - const sApeAddress = ONE_ADDRESS; - const InitialNTokenApeBalance = parseEther("100"); - - const fixture = async () => { - testEnv = await loadFixture(testEnvFixture); - const { - ape, - mayc, - bayc, - users, - bakc, - protocolDataProvider, - pool, - apeCoinStaking, - nMAYC, - nBAYC, - } = testEnv; - const user1 = users[0]; - const depositor = users[1]; - const user4 = users[5]; - - const { - xTokenAddress: pApeCoinAddress, - variableDebtTokenAddress: variableDebtApeCoinAddress, - } = await protocolDataProvider.getReserveTokensAddresses(ape.address); - const {xTokenAddress: pSApeCoinAddress} = - await protocolDataProvider.getReserveTokensAddresses(sApeAddress); - - cApe = await getAutoCompoundApe(); - const { - xTokenAddress: pcApeCoinAddress, - variableDebtTokenAddress: variableDebtCApeCoinAddress, - } = await protocolDataProvider.getReserveTokensAddresses(cApe.address); - - variableDebtApeCoin = await getVariableDebtToken( - variableDebtApeCoinAddress - ); - variableDebtCApeCoin = await getVariableDebtToken( - variableDebtCApeCoinAddress - ); - pApeCoin = await getPToken(pApeCoinAddress); - pSApeCoin = await getPTokenSApe(pSApeCoinAddress); - pcApeCoin = await getPToken(pcApeCoinAddress); - - await supplyAndValidate(ape, "20000", depositor, true); - await changePriceAndValidate(ape, "0.001"); - await changePriceAndValidate(cApe, "0.001"); - await changeSApePriceAndValidate(sApeAddress, "0.001"); - - await changePriceAndValidate(mayc, "50"); - await changePriceAndValidate(bayc, "50"); - - await waitForTx(await bakc["mint(uint256,address)"]("2", user1.address)); - - await waitForTx( - await ape.connect(user1.signer).approve(pool.address, MAX_UINT_AMOUNT) - ); - await waitForTx( - await bakc.connect(user1.signer).setApprovalForAll(pool.address, true) - ); - - // send extra tokens to the apestaking contract for rewards - await waitForTx( - await ape - .connect(user1.signer) - ["mint(address,uint256)"]( - apeCoinStaking.address, - parseEther("100000000000") - ) - ); - - // send extra tokens to the nToken contract for testing ape balance check - await waitForTx( - await ape - .connect(user1.signer) - ["mint(address,uint256)"](nMAYC.address, InitialNTokenApeBalance) - ); - await waitForTx( - await ape - .connect(user1.signer) - ["mint(address,uint256)"](nBAYC.address, InitialNTokenApeBalance) - ); - - await mintAndValidate(ape, "1", user4); - await waitForTx( - await ape.connect(user4.signer).approve(cApe.address, MAX_UINT_AMOUNT) - ); - // user4 deposit MINIMUM_LIQUIDITY to make test case easy - const MINIMUM_LIQUIDITY = await cApe.MINIMUM_LIQUIDITY(); - await waitForTx( - await cApe.connect(user4.signer).deposit(user4.address, MINIMUM_LIQUIDITY) - ); - - return testEnv; - }; - - it("TC-pool-ape-staking-01 test borrowApeAndStake: failed when borrow + cash < staking amount (revert expected)", async () => { - const { - users: [user1], - ape, - mayc, - pool, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - await mintAndValidate(ape, "16000", user1); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "16000"); - await expect( - pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: amount, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ).to.be.revertedWith(ProtocolErrors.TOTAL_STAKING_AMOUNT_WRONG); - }); - - it("TC-pool-ape-staking-02 test borrowApeAndStake: failed when borrow + cash > staking amount (revert expected)", async () => { - const { - users: [user1], - ape, - mayc, - pool, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - await mintAndValidate(ape, "16000", user1); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "16000"); - await expect( - pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: amount, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ).to.be.revertedWith(ProtocolErrors.TOTAL_STAKING_AMOUNT_WRONG); - }); - - it("TC-pool-ape-staking-03 test borrowApeAndStake: use 100% cash", async () => { - const { - users: [user1], - ape, - mayc, - pool, - nMAYC, - weth, - bakc, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - await mintAndValidate(ape, "15000", user1); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: amount, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - const totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - expect(totalStake).equal(amount); - - const pSApeBalance = await pSApeCoin.balanceOf(user1.address); - expect(pSApeBalance).equal(amount); - - const apeDebt = await variableDebtApeCoin.balanceOf(user1.address); - expect(apeDebt).equal(0); - - const bakcBalance = await bakc.balanceOf(user1.address); - expect(bakcBalance).equal(2); - - const userAccount = await pool.getUserAccountData(user1.address); - //50 + 15000*0.001 = 65 - expect(userAccount.totalCollateralBase).equal( - await convertToCurrencyDecimals(weth.address, "65") - ); - expect(userAccount.totalDebtBase).equal(0); - //50 * 0.325 + 15 * 0.2 = 19.25 - almostEqual( - userAccount.availableBorrowsBase, - await convertToCurrencyDecimals(weth.address, "19.25") - ); - }); - - it("TC-pool-ape-staking-04 test borrowApeAndStake: part cash, part debt", async () => { - const { - users: [user1], - ape, - mayc, - pool, - nMAYC, - weth, - bakc, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - await mintAndValidate(ape, "7000", user1); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - // 50 * 0.3250 + 7000 * 0.001 * 0.2 = 17.65 - // 17.65 / 0.001 = 17650 - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount2, - cashAmount: amount1, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - const totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - expect(totalStake).equal(amount); - - const pSApeBalance = await pSApeCoin.balanceOf(user1.address); - expect(pSApeBalance).equal(amount); - - const apeDebt = await variableDebtApeCoin.balanceOf(user1.address); - expect(apeDebt).equal(amount2); - - const bakcBalance = await bakc.balanceOf(user1.address); - expect(bakcBalance).equal(2); - - const userAccount = await pool.getUserAccountData(user1.address); - //50 + 15000*0.001 = 65 - expect(userAccount.totalCollateralBase).equal( - await convertToCurrencyDecimals(weth.address, "65") - ); - //8000*0.001 = 8 - expect(userAccount.totalDebtBase).equal( - await convertToCurrencyDecimals(weth.address, "8") - ); - //50 * 0.325 + 15 * 0.2 - 8=11.25 - almostEqual( - userAccount.availableBorrowsBase, - await convertToCurrencyDecimals(weth.address, "11.25") - ); - }); - - it("TC-pool-ape-staking-05 test borrowApeAndStake: use 100% debt", async () => { - const { - users: [user1], - ape, - mayc, - pool, - nMAYC, - weth, - bakc, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - const totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - expect(totalStake).equal(amount); - - const pSApeBalance = await pSApeCoin.balanceOf(user1.address); - expect(pSApeBalance).equal(amount); - - const apeDebt = await variableDebtApeCoin.balanceOf(user1.address); - expect(apeDebt).equal(amount); - - const bakcBalance = await bakc.balanceOf(user1.address); - expect(bakcBalance).equal(2); - - const userAccount = await pool.getUserAccountData(user1.address); - //50 + 15000*0.001 = 65 - expect(userAccount.totalCollateralBase).equal( - await convertToCurrencyDecimals(weth.address, "65") - ); - //15000*0.001 = 15 - expect(userAccount.totalDebtBase).equal( - await convertToCurrencyDecimals(weth.address, "15") - ); - //50 * 0.325 + 15 * 0.2 - 15=4.25 - almostEqual( - userAccount.availableBorrowsBase, - await convertToCurrencyDecimals(weth.address, "4.25") - ); - }); - - it("TC-pool-ape-staking-06 test withdrawBAKC fails when hf < 1 (revert expected)", async () => { - const { - users: [user1], - ape, - mayc, - pool, - weth, - nMAYC, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - await changePriceAndValidate(mayc, "40"); - await changePriceAndValidate(ape, "0.002"); - await changeSApePriceAndValidate(sApeAddress, "0.002"); - const userAccount = await pool.getUserAccountData(user1.address); - //40 + 15000*0.002 = 70 - expect(userAccount.totalCollateralBase).equal( - await convertToCurrencyDecimals(weth.address, "70") - ); - //15000*0.002 = 30 - almostEqual( - userAccount.totalDebtBase, - await convertToCurrencyDecimals(weth.address, "30") - ); - //40 * 0.325 + 30 * 0.2 - 30=-11 - almostEqual(userAccount.availableBorrowsBase, 0); - - let withdrawAmount = await convertToCurrencyDecimals(ape.address, "3000"); - expect( - await pool - .connect(user1.signer) - .withdrawApeCoin(mayc.address, [{tokenId: 0, amount: withdrawAmount}]) - ); - withdrawAmount = await convertToCurrencyDecimals(ape.address, "4000"); - expect( - await pool - .connect(user1.signer) - .withdrawApeCoin(mayc.address, [{tokenId: 0, amount: withdrawAmount}]) - ); - - const totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - expect(totalStake).equal(amount2); - - await expect( - pool - .connect(user1.signer) - .withdrawBAKC(mayc.address, [ - {mainTokenId: 0, bakcTokenId: 0, amount: amount2, isUncommit: true}, - ]) - ).to.be.revertedWith( - ProtocolErrors.HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD - ); - }); - - it("TC-pool-ape-staking-07 test withdrawApeCoin fails when hf < 1 (revert expected)", async () => { - const { - users: [user1], - ape, - mayc, - pool, - weth, - nMAYC, - bakc, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - await changePriceAndValidate(mayc, "40"); - await changePriceAndValidate(ape, "0.002"); - await changeSApePriceAndValidate(sApeAddress, "0.002"); - const userAccount = await pool.getUserAccountData(user1.address); - //40 + 15000*0.002 = 70 - expect(userAccount.totalCollateralBase).equal( - await convertToCurrencyDecimals(weth.address, "70") - ); - //15000*0.002 = 30 - almostEqual( - userAccount.totalDebtBase, - await convertToCurrencyDecimals(weth.address, "30") - ); - //40 * 0.325 + 30 * 0.2 - 30=-11 - almostEqual(userAccount.availableBorrowsBase, 0); - - const withdrawAmount = await convertToCurrencyDecimals(ape.address, "4000"); - expect( - await pool.connect(user1.signer).withdrawBAKC(mayc.address, [ - { - mainTokenId: 0, - bakcTokenId: 0, - amount: withdrawAmount, - isUncommit: false, - }, - ]) - ); - expect( - await pool.connect(user1.signer).withdrawBAKC(mayc.address, [ - { - mainTokenId: 0, - bakcTokenId: 0, - amount: withdrawAmount, - isUncommit: true, - }, - ]) - ); - - const bakcBalance = await bakc.balanceOf(user1.address); - expect(bakcBalance).equal(2); - - const totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - expect(totalStake).equal(amount1); - - await expect( - pool - .connect(user1.signer) - .withdrawApeCoin(mayc.address, [{tokenId: 0, amount: amount1}]) - ).to.be.revertedWith( - ProtocolErrors.HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD - ); - - const apeBalanceForNToken = await ape.balanceOf(nMAYC.address); - expect(apeBalanceForNToken).equal(InitialNTokenApeBalance); - }); - - it("TC-pool-ape-staking-08 test withdrawBAKC fails when hf < 1 (revert expected)", async () => { - const { - users: [user1, user2], - ape, - mayc, - pool, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - await expect( - pool - .connect(user2.signer) - .withdrawBAKC(mayc.address, [ - {mainTokenId: 0, bakcTokenId: 0, amount: amount2, isUncommit: true}, - ]) - ).to.be.revertedWith(ProtocolErrors.NOT_THE_OWNER); - }); - - it("TC-pool-ape-staking-09 test withdrawApeCoin fails when user is not the owner (revert expected)", async () => { - const { - users: [user1, user2], - ape, - mayc, - pool, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - await expect( - pool - .connect(user2.signer) - .withdrawApeCoin(mayc.address, [{tokenId: 0, amount: amount1}]) - ).to.be.revertedWith(ProtocolErrors.NOT_THE_OWNER); - }); - - it("TC-pool-ape-staking-10 test claimBAKC success when hf > 1", async () => { - const { - users: [user1], - ape, - mayc, - pool, - weth, - nMAYC, - apeCoinStaking, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 1, amount: amount2}], - true - ) - ); - - await changePriceAndValidate(mayc, "40"); - await changePriceAndValidate(ape, "0.002"); - await changeSApePriceAndValidate(sApeAddress, "0.002"); - const userAccount = await pool.getUserAccountData(user1.address); - //40 + 15000*0.002 = 70 - expect(userAccount.totalCollateralBase).equal( - await convertToCurrencyDecimals(weth.address, "70") - ); - //15000*0.002 = 30 - almostEqual( - userAccount.totalDebtBase, - await convertToCurrencyDecimals(weth.address, "30") - ); - //40 * 0.325 + 30 * 0.2 - 30=-11 - almostEqual(userAccount.availableBorrowsBase, 0); - - // advance in time - await advanceTimeAndBlock(parseInt("86400")); - - const pendingRewardsPool2 = await apeCoinStaking.pendingRewards( - 2, - nMAYC.address, - "0" - ); - expect(pendingRewardsPool2).to.be.gt(0); - - const pendingRewardsPool3 = await apeCoinStaking.pendingRewards( - 3, - nMAYC.address, - "1" - ); - expect(pendingRewardsPool3).to.be.gt(0); - - const userBalance = await ape.balanceOf(user1.address); - - expect( - await pool - .connect(user1.signer) - .claimBAKC(mayc.address, [{mainTokenId: 0, bakcTokenId: 1}]) - ); - - const totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - //reward is not as collateral - expect(totalStake).equal(amount); - - expect(await ape.balanceOf(user1.address)).to.be.eq( - userBalance.add(pendingRewardsPool3) - ); - - const apeBalanceForNToken = await ape.balanceOf(nMAYC.address); - expect(apeBalanceForNToken).equal(InitialNTokenApeBalance); - }); - - it("TC-pool-ape-staking-11 test claimBAKC success when hf < 1 (ape reward for bakc pool is not used as collateral)", async () => { - const { - users: [user1], - ape, - mayc, - pool, - weth, - apeCoinStaking, - nMAYC, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 1, amount: amount2}], - true - ) - ); - - await changePriceAndValidate(mayc, "40"); - await changePriceAndValidate(ape, "0.002"); - await changeSApePriceAndValidate(sApeAddress, "0.002"); - const userAccount = await pool.getUserAccountData(user1.address); - //40 + 15000*0.002 = 70 - expect(userAccount.totalCollateralBase).equal( - await convertToCurrencyDecimals(weth.address, "70") - ); - //15000*0.002 = 30 - almostEqual( - userAccount.totalDebtBase, - await convertToCurrencyDecimals(weth.address, "30") - ); - //40 * 0.325 + 30 * 0.2 - 30=-11 - almostEqual(userAccount.availableBorrowsBase, 0); - // advance in time - await advanceTimeAndBlock(parseInt("86400")); - - const pendingRewardsPool2 = await apeCoinStaking.pendingRewards( - 2, - nMAYC.address, - "0" - ); - expect(pendingRewardsPool2).to.be.gt(0); - - const pendingRewardsPool3 = await apeCoinStaking.pendingRewards( - 3, - nMAYC.address, - "1" - ); - expect(pendingRewardsPool3).to.be.gt(0); - - const userBalance = await ape.balanceOf(user1.address); - - // drop HF to liquidation levels - await changePriceAndValidate(mayc, "3"); - - expect( - await pool - .connect(user1.signer) - .claimBAKC(mayc.address, [{mainTokenId: 0, bakcTokenId: 1}]) - ); - - const totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - //reward is not as collateral - expect(totalStake).equal(amount); - - expect(await ape.balanceOf(user1.address)).to.be.eq( - userBalance.add(pendingRewardsPool3) - ); - }); - - it("TC-pool-ape-staking-12 test claimApeCoin succeeds when hf > 1", async () => { - const { - users: [user1], - ape, - mayc, - pool, - weth, - nMAYC, - apeCoinStaking, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - await changePriceAndValidate(mayc, "40"); - await changePriceAndValidate(ape, "0.002"); - await changeSApePriceAndValidate(sApeAddress, "0.002"); - const userAccount = await pool.getUserAccountData(user1.address); - //40 + 15000*0.002 = 70 - expect(userAccount.totalCollateralBase).equal( - await convertToCurrencyDecimals(weth.address, "70") - ); - //15000*0.002 = 30 - almostEqual( - userAccount.totalDebtBase, - await convertToCurrencyDecimals(weth.address, "30") - ); - //40 * 0.325 + 30 * 0.2 - 30=-11 - almostEqual(userAccount.availableBorrowsBase, 0); - - // advance in time - await advanceTimeAndBlock(parseInt("86400")); - - const pendingRewardsPool2 = await apeCoinStaking.pendingRewards( - 2, - nMAYC.address, - "0" - ); - - const userBalance = await ape.balanceOf(user1.address); - - expect(await pool.connect(user1.signer).claimApeCoin(mayc.address, [0])); - - const totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - expect(totalStake).equal(amount); - - expect(await ape.balanceOf(user1.address)).to.be.eq( - userBalance.add(pendingRewardsPool2) - ); - }); - - it("TC-pool-ape-staking-13 test claimApeCoin should success when hf < 1", async () => { - const { - users: [user1], - ape, - mayc, - pool, - weth, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - await changePriceAndValidate(mayc, "40"); - await changePriceAndValidate(ape, "0.002"); - await changeSApePriceAndValidate(sApeAddress, "0.002"); - const userAccount = await pool.getUserAccountData(user1.address); - //40 + 15000*0.002 = 70 - expect(userAccount.totalCollateralBase).equal( - await convertToCurrencyDecimals(weth.address, "70") - ); - //15000*0.002 = 30 - almostEqual( - userAccount.totalDebtBase, - await convertToCurrencyDecimals(weth.address, "30") - ); - //40 * 0.325 + 30 * 0.2 - 30=-11 - almostEqual(userAccount.availableBorrowsBase, 0); - - // drop HF to liquidation levels - await changePriceAndValidate(mayc, "3"); - - //ape coin reward is not used as collateral - expect(await pool.connect(user1.signer).claimApeCoin(mayc.address, [0])); - }); - - it("TC-pool-ape-staking-14 test unstakeApePositionAndRepay repays cape debt - no excess", async () => { - const { - users: [user1, user2], - ape, - mayc, - pool, - nMAYC, - } = await loadFixture(fixture); - - await mintAndValidate(ape, "20000", user2); - await waitForTx( - await ape.connect(user2.signer).approve(cApe.address, MAX_UINT_AMOUNT) - ); - await waitForTx( - await cApe - .connect(user2.signer) - .deposit(user2.address, parseEther("20000")) - ); - await waitForTx( - await cApe.connect(user2.signer).approve(pool.address, MAX_UINT_AMOUNT) - ); - await waitForTx( - await pool - .connect(user2.signer) - .supply(cApe.address, parseEther("20000"), user2.address, 0) - ); - - await supplyAndValidate(mayc, "1", user1, true); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: cApe.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - expect( - await pool - .connect(user1.signer) - .unstakeApePositionAndRepay(mayc.address, 0) - ); - - const totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - expect(totalStake).equal(0); - - const pSApeBalance = await pSApeCoin.balanceOf(user1.address); - expect(pSApeBalance).equal(0); - - const pApeBalance = await pApeCoin.balanceOf(user1.address); - expect(pApeBalance).equal(0); - - const cApeDebt = await variableDebtCApeCoin.balanceOf(user1.address); - const limit = await convertToCurrencyDecimals(cApe.address, "0.1"); - expect(cApeDebt.lt(limit)).equal(true); - }); - - it("TC-pool-ape-staking-15 test unstakeApePositionAndRepay repays cape debt", async () => { - const { - users: [user1, user2], - ape, - mayc, - pool, - nMAYC, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - await mintAndValidate(ape, "10000", user2); - await waitForTx( - await ape.connect(user2.signer).approve(cApe.address, MAX_UINT_AMOUNT) - ); - await waitForTx( - await cApe - .connect(user2.signer) - .deposit(user2.address, parseEther("10000")) - ); - await waitForTx( - await cApe.connect(user2.signer).approve(pool.address, MAX_UINT_AMOUNT) - ); - await waitForTx( - await pool - .connect(user2.signer) - .supply(cApe.address, parseEther("10000"), user2.address, 0) - ); - - const amount1 = parseEther("7000"); - const amount2 = parseEther("8000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount1, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount1}], - [], - true - ) - ); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: cApe.address, - borrowAmount: amount2, - cashAmount: 0, - }, - [], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - const apeDebt = await variableDebtApeCoin.balanceOf(user1.address); - almostEqual(apeDebt, amount1); - - let capeDebt = await variableDebtCApeCoin.balanceOf(user1.address); - almostEqual(capeDebt, amount2); - - expect( - await pool - .connect(user1.signer) - .unstakeApePositionAndRepay(mayc.address, 0) - ); - - const totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - expect(totalStake).equal(0); - - const pSApeBalance = await pSApeCoin.balanceOf(user1.address); - expect(pSApeBalance).equal(0); - - const pCApeBalance = await pcApeCoin.balanceOf(user1.address); - almostEqual(pCApeBalance, amount1); - - capeDebt = await variableDebtCApeCoin.balanceOf(user1.address); - expect(capeDebt).equal(0); - }); - - it("TC-pool-ape-staking-16 test unstakeApePositionAndRepay bakc reward should transfer to user wallet", async () => { - const { - users: [user1], - ape, - mayc, - pool, - apeCoinStaking, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - await mintAndValidate(ape, "7000", user1); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount2, - cashAmount: amount1, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - // advance in time - await advanceTimeAndBlock(parseInt("86400")); - - const pendingRewardsMaycPool = await apeCoinStaking.pendingRewards( - 2, - ZERO_ADDRESS, - "0" - ); - expect(pendingRewardsMaycPool).to.be.gt(0); - const pendingRewardsBakcPool = await apeCoinStaking.pendingRewards( - 3, - ZERO_ADDRESS, - "0" - ); - expect(pendingRewardsBakcPool).to.be.gt(0); - - expect( - await pool - .connect(user1.signer) - .unstakeApePositionAndRepay(mayc.address, 0) - ); - - const userBalance = await ape.balanceOf(user1.address); - - expect(userBalance).to.be.eq(pendingRewardsBakcPool); - }); - - it("TC-pool-ape-staking-17 test unstakeApePositionAndRepay by others fails when hf > 1(revert expected)", async () => { - const { - users: [user1, unstaker], - ape, - mayc, - pool, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - await expect( - pool.connect(unstaker.signer).unstakeApePositionAndRepay(mayc.address, 0) - ).to.be.revertedWith(ProtocolErrors.HEALTH_FACTOR_NOT_BELOW_THRESHOLD); - }); - - it("TC-pool-ape-staking-18 test unstakeApePositionAndRepay by others succeeds when hf < 1", async () => { - const { - users: [user1, unstaker, , , user2], - ape, - mayc, - pool, - nMAYC, - } = await loadFixture(fixture); - - await mintAndValidate(ape, "20000", user2); - await waitForTx( - await ape.connect(user2.signer).approve(cApe.address, MAX_UINT_AMOUNT) - ); - await waitForTx( - await cApe - .connect(user2.signer) - .deposit(user2.address, parseEther("20000")) - ); - await waitForTx( - await cApe.connect(user2.signer).approve(pool.address, MAX_UINT_AMOUNT) - ); - await waitForTx( - await pool - .connect(user2.signer) - .supply(cApe.address, parseEther("20000"), user2.address, 0) - ); - - await supplyAndValidate(mayc, "1", user1, true); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: cApe.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - await changePriceAndValidate(mayc, "40"); - await changePriceAndValidate(cApe, "0.08"); - - expect( - await pool - .connect(unstaker.signer) - .unstakeApePositionAndRepay(mayc.address, 0) - ); - - const totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - expect(totalStake).equal(0); - - const pSApeBalance = await pSApeCoin.balanceOf(user1.address); - expect(pSApeBalance).equal(0); - - const pcApeBalance = await pcApeCoin.balanceOf(user1.address); - expect(pcApeBalance).equal(0); - - const cApeDebt = await variableDebtCApeCoin.balanceOf(user1.address); - const target = await convertToCurrencyDecimals(cApe.address, "45"); - almostEqual(cApeDebt, target); - }); - - it("TC-pool-ape-staking-19 test can stake multiple times and partially unstake afterwards", async () => { - const { - users: [user1, unstaker, , , user2], - ape, - mayc, - bayc, - pool, - nMAYC, - nBAYC, - weth, - bakc, - } = await loadFixture(fixture); - - await mintAndValidate(ape, "30000", user2); - await waitForTx( - await ape.connect(user2.signer).approve(cApe.address, MAX_UINT_AMOUNT) - ); - await waitForTx( - await cApe - .connect(user2.signer) - .deposit(user2.address, parseEther("30000")) - ); - await waitForTx( - await cApe.connect(user2.signer).approve(pool.address, MAX_UINT_AMOUNT) - ); - await waitForTx( - await pool - .connect(user2.signer) - .supply(cApe.address, parseEther("30000"), user2.address, 0) - ); - - await supplyAndValidate(mayc, "2", user1, true); - await supplyAndValidate(bayc, "2", user1, true); - - const amount = await convertToCurrencyDecimals(cApe.address, "3000"); - const halfAmount = await convertToCurrencyDecimals(cApe.address, "9000"); - const totalAmount = await convertToCurrencyDecimals(cApe.address, "18000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: cApe.address, - borrowAmount: halfAmount, - cashAmount: 0, - }, - [ - {tokenId: 0, amount: amount}, - {tokenId: 1, amount: amount}, - ], - [{mainTokenId: 1, bakcTokenId: 0, amount: amount}], - true - ) - ); - - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: bayc.address, - borrowAsset: cApe.address, - borrowAmount: halfAmount, - cashAmount: 0, - }, - [ - {tokenId: 0, amount: amount}, - {tokenId: 1, amount: amount}, - ], - [{mainTokenId: 1, bakcTokenId: 1, amount: amount}], - true - ) - ); - - let maycStake = await nMAYC.getUserApeStakingAmount(user1.address); - expect(maycStake).equal(halfAmount); - - let baycStake = await nBAYC.getUserApeStakingAmount(user1.address); - expect(baycStake).equal(halfAmount); - - let pSApeBalance = await pSApeCoin.balanceOf(user1.address); - expect(pSApeBalance).equal(totalAmount); - - let cApeDebt = await variableDebtCApeCoin.balanceOf(user1.address); - almostEqual(cApeDebt, totalAmount); - - let bakcBalance = await bakc.balanceOf(user1.address); - expect(bakcBalance).equal(2); - - let userAccount = await pool.getUserAccountData(user1.address); - //50 * 4 + 18000*0.001 = 218 - expect(userAccount.totalCollateralBase).equal( - await convertToCurrencyDecimals(weth.address, "218") - ); - //18000*0.001 = 18 - almostEqual( - userAccount.totalDebtBase, - await convertToCurrencyDecimals(weth.address, "18") - ); - //50 * 2 * 0.4 + 50 * 2 * 0.325 + 18 * 0.2 - 18 = 58.1 - almostEqual( - userAccount.availableBorrowsBase, - await convertToCurrencyDecimals(weth.address, "58.1") - ); - - await changePriceAndValidate(mayc, "10"); - await changePriceAndValidate(bayc, "10"); - await changePriceAndValidate(cApe, "0.01"); - await changeSApePriceAndValidate(sApeAddress, "0.01"); - - expect( - await pool - .connect(unstaker.signer) - .unstakeApePositionAndRepay(mayc.address, 1) - ); - - maycStake = await nMAYC.getUserApeStakingAmount(user1.address); - expect(maycStake).equal(amount); - - baycStake = await nBAYC.getUserApeStakingAmount(user1.address); - expect(baycStake).equal(halfAmount); - - pSApeBalance = await pSApeCoin.balanceOf(user1.address); - expect(pSApeBalance).equal(amount.add(halfAmount)); - - cApeDebt = await variableDebtCApeCoin.balanceOf(user1.address); - //12000 + 6000*3/1000 - almostEqual( - cApeDebt, - amount - .add(halfAmount) - .add(await convertToCurrencyDecimals(weth.address, "18")) - ); - - bakcBalance = await bakc.balanceOf(user1.address); - expect(bakcBalance).equal(2); - - userAccount = await pool.getUserAccountData(user1.address); - //10 * 4 + 12000*0.01 = 160 - expect(userAccount.totalCollateralBase).equal( - await convertToCurrencyDecimals(weth.address, "160") - ); - //12018*0.01 = 120.18 - almostEqual( - userAccount.totalDebtBase, - await convertToCurrencyDecimals(weth.address, "120.18") - ); - - let apeBalanceForNToken = await ape.balanceOf(nMAYC.address); - expect(apeBalanceForNToken).equal(InitialNTokenApeBalance); - apeBalanceForNToken = await ape.balanceOf(nBAYC.address); - expect(apeBalanceForNToken).equal(InitialNTokenApeBalance); - }); - - it("TC-pool-ape-staking-20 test can liquidate NFT with existing staking positions", async () => { - const { - users: [user1, liquidator], - ape, - mayc, - pool, - weth, - bakc, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8"); - const amount = await convertToCurrencyDecimals(ape.address, "7008"); - - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - const borrowAmount = await convertToCurrencyDecimals(ape.address, "8000"); - expect( - await pool - .connect(user1.signer) - .borrow(ape.address, borrowAmount, 0, user1.address) - ); - - await supplyAndValidate(weth, "91", liquidator, true, "200000"); - - // drop HF and ERC-721_HF below 1 - await changePriceAndValidate(mayc, "3"); - - // start auction - await waitForTx( - await pool - .connect(liquidator.signer) - .startAuction(user1.address, mayc.address, 0) - ); - - const apeDebtBefore = await variableDebtApeCoin.balanceOf(user1.address); - - // try to liquidate the NFT - expect( - await pool - .connect(liquidator.signer) - .liquidateERC721( - mayc.address, - user1.address, - 0, - await convertToCurrencyDecimals(weth.address, "13"), - false, - {gasLimit: 5000000} - ) - ); - - expect(await ape.balanceOf(user1.address)).to.be.eq(borrowAmount); - - const pSApeBalance = await pSApeCoin.balanceOf(user1.address); - expect(pSApeBalance).to.be.eq(0); // whole position unstaked - - const apeDebt = await variableDebtApeCoin.balanceOf(user1.address); - almostEqual(apeDebt, apeDebtBefore); // no debt repaid - - expect(await bakc.ownerOf("0")).to.be.eq(user1.address); - expect(await mayc.ownerOf("0")).to.be.eq(liquidator.address); - }); - - it("TC-pool-ape-staking-21 test cannot borrow and stake an amount over user's available to borrow (revert expected)", async () => { - const { - users: [user1, depositor], - ape, - mayc, - pool, - weth, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - await supplyAndValidate(weth, "5", depositor, true); - await changePriceAndValidate(mayc, "10"); - await borrowAndValidate(weth, "3", user1); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - - await expect( - pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ).to.be.revertedWith(ProtocolErrors.COLLATERAL_CANNOT_COVER_NEW_BORROW); - }); - - it("TC-pool-ape-staking-22 test can transfer NFT with existing staking positions", async () => { - const { - users: [user1, user2], - ape, - mayc, - pool, - nMAYC, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - await mintAndValidate(ape, "15000", user1); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: amount, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - expect(await nMAYC.balanceOf(user1.address)).to.be.equal(1); - expect(await nMAYC.balanceOf(user2.address)).to.be.equal(0); - expect(await pSApeCoin.balanceOf(user1.address)).equal(amount); - expect(await pSApeCoin.balanceOf(user2.address)).equal(0); - - expect( - await nMAYC - .connect(user1.signer) - ["safeTransferFrom(address,address,uint256)"]( - user1.address, - user2.address, - 0, - {gasLimit: 5000000} - ) - ); - - expect(await nMAYC.balanceOf(user1.address)).to.be.equal(0); - expect(await nMAYC.balanceOf(user2.address)).to.be.equal(1); - expect(await pSApeCoin.balanceOf(user1.address)).equal(0); - expect(await pSApeCoin.balanceOf(user2.address)).equal(0); - }); - - it("TC-pool-ape-staking-23 test market accept bid offer should success", async () => { - const { - bayc, - nBAYC, - usdc, - pool, - ape, - users: [taker, maker, middleman], - } = await loadFixture(fixture); - const makerInitialBalance = "800"; - const middlemanInitialBalance = "200"; - const payNowAmount = await convertToCurrencyDecimals(usdc.address, "800"); - const creditAmount = await convertToCurrencyDecimals(usdc.address, "200"); - - const startAmount = payNowAmount.add(creditAmount); - const endAmount = startAmount; // fixed price but offerer cannot afford this - const nftId = 0; - - // 1, mint USDC to maker - await mintAndValidate(usdc, makerInitialBalance, maker); - - // 2, middleman supplies USDC to pool to be borrowed by maker later - await supplyAndValidate(usdc, middlemanInitialBalance, middleman, true); - - // 3, mint ntoken for taker - await mintAndValidate(ape, "15000", taker); - await supplyAndValidate(bayc, "1", taker, true); - - // 4, ape staking for ntoken - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - expect( - await pool.connect(taker.signer).borrowApeAndStake( - { - nftAsset: bayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: amount, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - expect(await nBAYC.balanceOf(taker.address)).to.be.equal(1); - expect(await nBAYC.balanceOf(maker.address)).to.be.equal(0); - expect(await pSApeCoin.balanceOf(taker.address)).equal(amount); - expect(await pSApeCoin.balanceOf(maker.address)).equal(0); - - // 5, accept order - await executeAcceptBidWithCredit( - nBAYC, - usdc, - startAmount, - endAmount, - creditAmount, - nftId, - maker, - taker - ); - - // taker bayc should reduce - expect(await nBAYC.balanceOf(taker.address)).to.be.equal(0); - expect(await nBAYC.balanceOf(maker.address)).to.be.equal(1); - expect(await pSApeCoin.balanceOf(taker.address)).equal(0); - expect(await pSApeCoin.balanceOf(maker.address)).equal(0); - }); - - it("TC-pool-ape-staking-24 test market buy with credit should success", async () => { - const { - bayc, - nBAYC, - usdc, - pool, - ape, - users: [maker, taker, middleman], - } = await loadFixture(fixture); - const makerInitialBalance = "800"; - const middlemanInitialBalance = "200"; - const payNowAmount = await convertToCurrencyDecimals(usdc.address, "800"); - const creditAmount = await convertToCurrencyDecimals(usdc.address, "200"); - - const startAmount = payNowAmount.add(creditAmount); - const endAmount = startAmount; // fixed price but offerer cannot afford this - const nftId = 0; - - // 1, mint USDC to taker - await mintAndValidate(usdc, makerInitialBalance, taker); - - // 2, middleman supplies USDC to pool to be borrowed by taker later - await supplyAndValidate(usdc, middlemanInitialBalance, middleman, true); - - // 3, mint ntoken for maker - await mintAndValidate(ape, "15000", maker); - await supplyAndValidate(bayc, "1", maker, true); - - // 4, ape staking for ntoken - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - expect( - await pool.connect(maker.signer).borrowApeAndStake( - { - nftAsset: bayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: amount, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - expect(await nBAYC.balanceOf(maker.address)).to.be.equal(1); - expect(await nBAYC.balanceOf(taker.address)).to.be.equal(0); - expect(await pSApeCoin.balanceOf(maker.address)).equal(amount); - expect(await pSApeCoin.balanceOf(taker.address)).equal(0); - - // 5, buy with credit - await waitForTx( - await usdc.connect(taker.signer).approve(pool.address, startAmount) - ); - await executeSeaportBuyWithCredit( - nBAYC, - usdc, - startAmount, - endAmount, - creditAmount, - nftId, - maker, - taker - ); - - // taker bayc should reduce - expect(await nBAYC.balanceOf(maker.address)).to.be.equal(0); - expect(await nBAYC.balanceOf(taker.address)).to.be.equal(1); - expect(await pSApeCoin.balanceOf(maker.address)).equal(0); - expect(await pSApeCoin.balanceOf(taker.address)).equal(0); - }); - - it("TC-pool-ape-staking-25 unstakeApePositionAndRepay should set cApe as collateral", async () => { - const { - users: [user1], - ape, - mayc, - pool, - } = await loadFixture(fixture); - - const apeData = await pool.getReserveData(cApe.address); - await supplyAndValidate(ape, "1", user1, true); - await waitForTx( - await pool - .connect(user1.signer) - .setUserUseERC20AsCollateral(ape.address, false) - ); - let userConfig = BigNumber.from( - (await pool.getUserConfiguration(user1.address)).data - ); - expect(isUsingAsCollateral(userConfig, apeData.id)).to.be.false; - - await supplyAndValidate(mayc, "1", user1, true); - await mintAndValidate(ape, "7000", user1); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount2, - cashAmount: amount1, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - expect( - await pool - .connect(user1.signer) - .unstakeApePositionAndRepay(mayc.address, 0) - ); - - userConfig = BigNumber.from( - (await pool.getUserConfiguration(user1.address)).data - ); - expect(isUsingAsCollateral(userConfig, apeData.id)).to.be.true; - }); - - it("TC-pool-ape-staking-26 test borrowApeAndStake: User tries to staking on not Supplying (revert expected)", async () => { - const { - users: [user1], - ape, - bayc, - pool, - } = await loadFixture(fixture); - - await mintAndValidate(bayc, "1", user1); - await mintAndValidate(ape, "15000", user1); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - await expect( - pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: bayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: amount, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ).to.be.revertedWith(ProtocolErrors.NOT_THE_OWNER); - }); - - it("TC-pool-ape-staking-27 test borrowApeAndStake: User tries to staking 0 ape icon for BAYC (revert expected)", async () => { - const { - users: [user1], - ape, - bayc, - pool, - } = await loadFixture(fixture); - - await supplyAndValidate(bayc, "1", user1, true); - await mintAndValidate(ape, "15000", user1); - - const amount1 = await convertToCurrencyDecimals(ape.address, "0"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = amount1.add(amount2); - await expect( - pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: bayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: amount, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ).to.be.revertedWith("DepositMoreThanOneAPE()"); - }); - - it("TC-pool-ape-staking-28 test borrowApeAndStake: only staking BAKC", async () => { - const { - users: [user1], - ape, - bayc, - nBAYC, - pool, - weth, - bakc, - } = await loadFixture(fixture); - - await supplyAndValidate(bayc, "1", user1, true); - - await mintAndValidate(ape, "15000", user1); - - const amount1 = await convertToCurrencyDecimals(ape.address, "0"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = amount1.add(amount2); - await waitForTx( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: bayc.address, - borrowAsset: ape.address, - borrowAmount: amount2, - cashAmount: amount1, - }, - [], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount}], - true - ) - ); - - // User 1 - totalStake should increased in Stake amount - const totalStake = await nBAYC.getUserApeStakingAmount(user1.address); - expect(totalStake).equal(amount); - - // User 1 - pSape should increased in Stake amount - const pSApeBalance = await pSApeCoin.balanceOf(user1.address); - expect(pSApeBalance).equal(amount); - - // User 1 - Debt should increased in borrowAmount - const apeDebt = await variableDebtApeCoin.balanceOf(user1.address); - expect(apeDebt).equal(amount2); - - const bakcBalance = await bakc.balanceOf(user1.address); - expect(bakcBalance).equal(2); - - const userAccount = await pool.getUserAccountData(user1.address); - //50 + 8000*0.001 = 58 - expect(userAccount.totalCollateralBase).equal( - await convertToCurrencyDecimals(weth.address, "58") - ); - //8000*0.001 = 8 - expect(userAccount.totalDebtBase).equal( - await convertToCurrencyDecimals(weth.address, "8") - ); - - //50 * 0.4 + 8 * 0.2 - 8=13.6 - almostEqual( - userAccount.availableBorrowsBase, - await convertToCurrencyDecimals(weth.address, "13.6") - ); - }); - - it("TC-pool-ape-staking-29 test borrowApeAndStake: BAYC staked Add BAKC after first Pairing", async () => { - const { - users: [user1], - bayc, - ape, - pool, - weth, - nBAYC, - bakc, - } = await loadFixture(fixture); - await supplyAndValidate(bayc, "1", user1, true); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = amount1.add(amount2); - - await waitForTx( - await ape - .connect(user1.signer) - ["mint(address,uint256)"](user1.address, amount) - ); - - await waitForTx( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: bayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: amount1, - }, - [{tokenId: 0, amount: amount1}], - [], - true - ) - ); - - await waitForTx( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: bayc.address, - borrowAsset: ape.address, - borrowAmount: amount2, - cashAmount: 0, - }, - [], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - // User 1 - totalStake should increased in Stake amount - const totalStake = await nBAYC.getUserApeStakingAmount(user1.address); - expect(totalStake).equal(amount); - - // User 1 - pSape should increased in Stake amount - const pSApeBalance = await pSApeCoin.balanceOf(user1.address); - expect(pSApeBalance).equal(amount); - - // User 1 - Debt should increased in borrowAmount - const apeDebt = await variableDebtApeCoin.balanceOf(user1.address); - expect(apeDebt).equal(amount2); - - const bakcBalance = await bakc.balanceOf(user1.address); - expect(bakcBalance).equal(2); - - const userAccount = await pool.getUserAccountData(user1.address); - //50 + 15000*0.001 = 65 - expect(userAccount.totalCollateralBase).equal( - await convertToCurrencyDecimals(weth.address, "65") - ); - //8000*0.001 = 8 - expect(userAccount.totalDebtBase).equal( - await convertToCurrencyDecimals(weth.address, "8") - ); - //50 * 0.4 + 15 * 0.2 - 8=15 - almostEqual( - userAccount.availableBorrowsBase, - await convertToCurrencyDecimals(weth.address, "15") - ); - }); - - it("TC-pool-ape-staking-30 test borrowApeAndStake: MAYC staked Add BAKC after first Pairing", async () => { - const { - users: [user1], - mayc, - weth, - nMAYC, - ape, - pool, - bakc, - } = await loadFixture(fixture); - await supplyAndValidate(mayc, "1", user1, true); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = amount1.add(amount2); - - await waitForTx( - await ape - .connect(user1.signer) - ["mint(address,uint256)"](user1.address, amount) - ); - - await waitForTx( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: amount1, - }, - [{tokenId: 0, amount: amount1}], - [], - true - ) - ); - - await waitForTx( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount2, - cashAmount: 0, - }, - [], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - // User 1 - totalStake should increased in Stake amount - const totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - expect(totalStake).equal(amount); - - // User 1 - pSape should increased in Stake amount - const pSApeBalance = await pSApeCoin.balanceOf(user1.address); - expect(pSApeBalance).equal(amount); - - // User 1 - Debt should increased in borrowAmount - const apeDebt = await variableDebtApeCoin.balanceOf(user1.address); - expect(apeDebt).equal(amount2); - - const bakcBalance = await bakc.balanceOf(user1.address); - expect(bakcBalance).equal(2); - - const userAccount = await pool.getUserAccountData(user1.address); - //50 + 15000*0.001 = 65 - expect(userAccount.totalCollateralBase).equal( - await convertToCurrencyDecimals(weth.address, "65") - ); - //8000*0.001 = 8 - expect(userAccount.totalDebtBase).equal( - await convertToCurrencyDecimals(weth.address, "8") - ); - //50 * 0.325 + 15 * 0.2 - 8=11.25 - almostEqual( - userAccount.availableBorrowsBase, - await convertToCurrencyDecimals(weth.address, "11.25") - ); - }); - - it("TC-pool-ape-staking-31 test borrowApeAndStake: Insufficient liquidity of borrow ape (revert expected)", async () => { - const { - users: [user1], - bayc, - ape, - pool, - } = await loadFixture(fixture); - - await supplyAndValidate(bayc, "1", user1, true); - - // reduce pool liquidity - await borrowAndValidate(ape, "13000", user1); - const amount1 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount = amount1.add(amount2); - - await ape - .connect(user1.signer) - ["mint(address,uint256)"](user1.address, amount); - - await expect( - pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: bayc.address, - borrowAsset: ape.address, - borrowAmount: amount1, - cashAmount: amount2, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ).to.be.revertedWith("ERC20: transfer amount exceeds balance"); - }); - - it("TC-pool-ape-staking-32 test borrowApeAndStake: success use 100% cash when hf < 1", async () => { - const { - users: [user1, user2], - ape, - mayc, - pool, - usdt, - nMAYC, - weth, - bakc, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - await supplyAndValidate(usdt, "1000", user2, true); - await borrowAndValidate(ape, "5000", user1); - await borrowAndValidate(usdt, "800", user1); - await mintAndValidate(ape, "7000", user1); - - const amount = await convertToCurrencyDecimals(ape.address, "7000"); - - await changePriceAndValidate(mayc, "20"); - await changePriceAndValidate(usdt, "0.0009"); - await changePriceAndValidate(ape, "0.005"); - await changeSApePriceAndValidate(sApeAddress, "0.005"); - - const healthFactor = (await pool.getUserAccountData(user1.address)) - .healthFactor; - - expect(healthFactor).to.be.lt(parseEther("1")); - - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: amount, - }, - [], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount}], - true - ) - ); - const healthFactorAfter = (await pool.getUserAccountData(user1.address)) - .healthFactor; - - // health factor should improve greater than 1 - expect(healthFactorAfter).to.be.gt(parseEther("1")); - - // User 1 - totalStake should increased in Stake amount - const totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - expect(totalStake).equal(amount); - - // User 1 - pSape should increased in Stake amount - const pSApeBalance = await pSApeCoin.balanceOf(user1.address); - expect(pSApeBalance).equal(amount); - - const bakcBalance = await bakc.balanceOf(user1.address); - expect(bakcBalance).equal(2); - - const userAccount = await pool.getUserAccountData(user1.address); - - //20 + 7000*0.005 = 55 - expect(userAccount.totalCollateralBase).equal( - await convertToCurrencyDecimals(weth.address, "55") - ); - - //5000*0.005 + 800 * 0.0009 = 25.72 - almostEqual( - userAccount.totalDebtBase, - await convertToCurrencyDecimals(weth.address, "25.72") - ); - - //availableBorrowsInBaseCurrency < totalDebtInBaseCurrency = 0 - almostEqual( - userAccount.availableBorrowsBase, - await convertToCurrencyDecimals(weth.address, "0") - ); - }); - - it("TC-pool-ape-staking-33 test safeTransferFrom BAKC: original owner withdraws all", async () => { - const { - users: [user1, , user3], - ape, - mayc, - pool, - nMAYC, - bakc, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - await mintAndValidate(ape, "7000", user1); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount2, - cashAmount: amount1, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - const totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - const pSApeBalance = await pSApeCoin.balanceOf(user1.address); - const userBalance = await ape.balanceOf(user1.address); - const user3Balance = await ape.balanceOf(user3.address); - - await waitForTx( - await bakc - .connect(user1.signer) - ["safeTransferFrom(address,address,uint256)"]( - user1.address, - user3.address, - "0" - ) - ); - - const bakcBalance = await bakc.balanceOf(user1.address); - expect(bakcBalance).equal(1); - - const bakcBalanceUser3 = await bakc.balanceOf(user3.address); - expect(bakcBalanceUser3).equal(1); - - await waitForTx( - await pool - .connect(user1.signer) - .withdrawBAKC(mayc.address, [ - {mainTokenId: 0, bakcTokenId: 0, amount: amount2, isUncommit: true}, - ]) - ); - - // User 1 - totalStake should have decreased in BAKC amount - const totalStakeAfter = await nMAYC.getUserApeStakingAmount(user1.address); - expect(totalStakeAfter).equal(totalStake.sub(amount2)); - - // User 1 - totalStake should have increased in BAKC amount - const pSApeBalanceAfter = await pSApeCoin.balanceOf(user1.address); - expect(pSApeBalanceAfter).equal(pSApeBalance.sub(amount2)); - - // User 1 - Ape Balance should have increased in BAKC amount - const userBalanceAfter = await ape.balanceOf(user1.address); - expect(userBalanceAfter).equal(userBalance.add(amount2)); - - // User 3 - Ape Balance should remain the same - const user3BalanceAfter = await ape.balanceOf(user3.address); - expect(user3BalanceAfter).equal(user3Balance); - }); - - it("TC-pool-ape-staking-34 test safeTransferFrom BAKC: original owner withdraws part ape (revert expected)", async () => { - const { - users: [user1, , user3], - ape, - mayc, - pool, - bakc, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - await mintAndValidate(ape, "7000", user1); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount2, - cashAmount: amount1, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - await waitForTx( - await bakc - .connect(user1.signer) - ["safeTransferFrom(address,address,uint256)"]( - user1.address, - user3.address, - "0" - ) - ); - - const bakcBalance = await bakc.balanceOf(user1.address); - expect(bakcBalance).equal(1); - - const bakcBalanceUser3 = await bakc.balanceOf(user3.address); - expect(bakcBalanceUser3).equal(1); - - // Only withdraw all - await expect( - pool - .connect(user1.signer) - .withdrawBAKC(mayc.address, [ - {mainTokenId: 0, bakcTokenId: 0, amount: amount1, isUncommit: false}, - ]) - ).to.be.revertedWith(ProtocolErrors.NOT_THE_BAKC_OWNER); - }); - - it("TC-pool-ape-staking-35 test safeTransferFrom BAKC: original owner claim bakc reward (revert expected)", async () => { - const { - users: [user1, , user3], - ape, - mayc, - pool, - bakc, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - await mintAndValidate(ape, "7000", user1); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount2, - cashAmount: amount1, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - await waitForTx( - await bakc - .connect(user1.signer) - ["safeTransferFrom(address,address,uint256)"]( - user1.address, - user3.address, - "0" - ) - ); - - const bakcBalance = await bakc.balanceOf(user1.address); - expect(bakcBalance).equal(1); - - const bakcBalanceUser3 = await bakc.balanceOf(user3.address); - expect(bakcBalanceUser3).equal(1); - - // advance in time - await advanceTimeAndBlock(parseInt("86400")); - - await expect( - pool - .connect(user1.signer) - .claimBAKC(mayc.address, [{mainTokenId: 0, bakcTokenId: 0}]) - ).to.be.revertedWith(ProtocolErrors.NOT_THE_BAKC_OWNER); - }); - - it("TC-pool-ape-staking-36 test safeTransferFrom BAKC: new owner withdraw all (revert expected)", async () => { - const { - users: [user1, , user3], - ape, - mayc, - pool, - bakc, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - await mintAndValidate(ape, "7000", user1); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount2, - cashAmount: amount1, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - await waitForTx( - await bakc - .connect(user1.signer) - ["safeTransferFrom(address,address,uint256)"]( - user1.address, - user3.address, - "0" - ) - ); - - const bakcBalance = await bakc.balanceOf(user1.address); - expect(bakcBalance).equal(1); - - const bakcBalanceUser3 = await bakc.balanceOf(user3.address); - expect(bakcBalanceUser3).equal(1); - - // New owner - await expect( - pool - .connect(user3.signer) - .withdrawBAKC(mayc.address, [ - {mainTokenId: 0, bakcTokenId: 0, amount: amount2, isUncommit: true}, - ]) - ).to.be.revertedWith(ProtocolErrors.NOT_THE_OWNER); - }); - - it("TC-pool-ape-staking-37 test safeTransferFrom: transfer fails when hf < 1 (revert expected)", async () => { - const { - users: [user1, user2, user3], - ape, - mayc, - nMAYC, - pool, - usdt, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - await supplyAndValidate(usdt, "1000", user2, true); - await borrowAndValidate(ape, "5000", user1); - await borrowAndValidate(usdt, "800", user1); - await mintAndValidate(ape, "7000", user1); - - const amount1 = await convertToCurrencyDecimals(ape.address, "100"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount2, - cashAmount: amount1, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - await changePriceAndValidate(mayc, "0.001"); - await changePriceAndValidate(ape, "0.1"); - await changeSApePriceAndValidate(sApeAddress, "0.002"); - - await expect( - nMAYC - .connect(user1.signer) - ["safeTransferFrom(address,address,uint256)"]( - user1.address, - user3.address, - 0, - {gasLimit: 5000000} - ) - ).to.be.revertedWith( - ProtocolErrors.HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD - ); - }); - - it("TC-pool-ape-staking-38 test withdrawBAKC success when hf > 1 after withdrawBAKC", async () => { - const { - users: [user1], - ape, - mayc, - pool, - nMAYC, - bakc, - } = await loadFixture(fixture); - // 1. supply 1 mayc - await supplyAndValidate(mayc, "1", user1, true); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - // 2. stake one bakc and borrow 15000 ape - await waitForTx( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - const userAccount = await pool.getUserAccountData(user1.address); - const healthFactor = (await pool.getUserAccountData(user1.address)) - .healthFactor; - - expect(healthFactor.gt(parseEther("1"))).to.be.true; - // User1 - collateral amount should increased mayc amount * price + ape amount * ape price = 50 + 15000*0.001 = 65 - expect(userAccount.totalCollateralBase).equal( - await convertToCurrencyDecimals(ape.address, "65") - ); - // User1 - debt amount should increased ape amount * ape price = 15000*0.001 = 15 - almostEqual( - userAccount.totalDebtBase, - await convertToCurrencyDecimals(ape.address, "15") - ); - // User1 - available borrow should increased amount * baseLTVasCollateral - debt amount = 50 * 0.325 + 15 * 0.2 - 15=4.25 - almostEqual( - userAccount.availableBorrowsBase, - await convertToCurrencyDecimals(ape.address, "4.25") - ); - let totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - // User 1 - totalStake should increased in Stake amount - expect(totalStake).equal(amount); - // User 1 - pSape should increased in Stake amount - const pSApeBalance = await pSApeCoin.balanceOf(user1.address); - expect(pSApeBalance).equal(amount); - - const withdrawAmount = await convertToCurrencyDecimals(ape.address, "8000"); - await waitForTx( - await pool.connect(user1.signer).withdrawBAKC(mayc.address, [ - { - mainTokenId: 0, - bakcTokenId: 0, - amount: withdrawAmount, - isUncommit: true, - }, - ]) - ); - - const bakcBalance = await bakc.balanceOf(user1.address); - // User 1 - bakc balanace should increased 2 - expect(bakcBalance).equal(2); - // User1 - ape balance should increased amount2 - expect(await ape.balanceOf(user1.address)).eq(amount2); - totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - // User1 - total stake should increased amount1 - expect(totalStake).equal(amount1); - }); - - it("TC-pool-ape-staking-39 test withdrawApeCoin success when hf > 1 after withdrawApeCoin", async () => { - const { - users: [user1], - ape, - mayc, - pool, - nMAYC, - } = await loadFixture(fixture); - - // supply 1 mayc - await supplyAndValidate(mayc, "1", user1, true); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - // borrow and stake 15000 - await waitForTx( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - const userAccount = await pool.getUserAccountData(user1.address); - const healthFactor = (await pool.getUserAccountData(user1.address)) - .healthFactor; - - expect(healthFactor.gt(parseEther("1"))).to.be.true; - // User1 - collateral amount should increased mayc amount * price + ape amount * ape price = 50 + 15000*0.001 = 65 - expect(userAccount.totalCollateralBase).equal( - await convertToCurrencyDecimals(ape.address, "65") - ); - // User1 - debt amount should increased ape amount * ape price = 15000*0.001 = 15 - almostEqual( - userAccount.totalDebtBase, - await convertToCurrencyDecimals(ape.address, "15") - ); - // User1 - available borrow should increased amount * baseLTVasCollateral - debt amount = 50 * 0.325 + 15 * 0.2 - 15=4.25 - almostEqual( - userAccount.availableBorrowsBase, - await convertToCurrencyDecimals(ape.address, "4.25") - ); - let totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - // User 1 - totalStake should increased in Stake amount - expect(totalStake).equal(amount); - // User 1 - pSape should increased in Stake amount - const pSApeBalance = await pSApeCoin.balanceOf(user1.address); - expect(pSApeBalance).equal(amount); - - await waitForTx( - await pool - .connect(user1.signer) - .withdrawApeCoin(mayc.address, [{tokenId: 0, amount: amount1}]) - ); - const apeBalance = await ape.balanceOf(user1.address); - expect(apeBalance).equal(amount1); - totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - // User 1 - totalStake should increased in amount2 - expect(totalStake).equal(amount2); - }); - - it("TC-pool-ape-staking-40 test withdrawBAKC fails when sender is not NFT owner (revert expected)", async () => { - const { - users: [user1], - ape, - mayc, - pool, - nMAYC, - } = await loadFixture(fixture); - // 1. supply 1 mayc - await supplyAndValidate(mayc, "1", user1, true); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - // 2. stake one bakc and borrow 15000 ape - await waitForTx( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - const userAccount = await pool.getUserAccountData(user1.address); - // User1 - collateral amount should increased mayc amount * price + ape amount * ape price = 50 + 15000*0.001 = 65 - expect(userAccount.totalCollateralBase).equal( - await convertToCurrencyDecimals(ape.address, "65") - ); - // User1 - debt amount should increased ape amount * ape price = 15000*0.001 = 15 - almostEqual( - userAccount.totalDebtBase, - await convertToCurrencyDecimals(ape.address, "15") - ); - // User1 - available borrow should increased amount * baseLTVasCollateral - debt amount = 50 * 0.325 + 15 * 0.2 - 15=4.25 - almostEqual( - userAccount.availableBorrowsBase, - await convertToCurrencyDecimals(ape.address, "4.25") - ); - const totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - // User 1 - totalStake should increased in Stake amount - expect(totalStake).equal(amount); - // User 1 - pSape should increased in Stake amount - const pSApeBalance = await pSApeCoin.balanceOf(user1.address); - expect(pSApeBalance).equal(amount); - - await expect( - pool - .connect(user1.signer) - .withdrawBAKC(mayc.address, [ - {mainTokenId: 1, bakcTokenId: 0, amount: amount2, isUncommit: true}, - ]) - ).to.be.revertedWith(ProtocolErrors.NOT_THE_OWNER); - }); - - it("TC-pool-ape-staking-41 test withdrawBAKC fails when amount != total staking, the sender is the NFT owner, but the sender is not the BAKC owner(revert expected)", async () => { - const { - users: [user1, , user3], - ape, - mayc, - pool, - nMAYC, - bakc, - } = await loadFixture(fixture); - // 1. supply 1 mayc - await supplyAndValidate(mayc, "1", user1, true); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - // 2. stake one bakc and borrow 15000 ape - await waitForTx( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - const userAccount = await pool.getUserAccountData(user1.address); - // User1 - collateral amount should increased mayc amount * price + ape amount * ape price = 50 + 15000*0.001 = 65 - expect(userAccount.totalCollateralBase).equal( - await convertToCurrencyDecimals(ape.address, "65") - ); - // User1 - debt amount should increased ape amount * ape price = 15000*0.001 = 15 - almostEqual( - userAccount.totalDebtBase, - await convertToCurrencyDecimals(ape.address, "15") - ); - // User1 - available borrow should increased amount * baseLTVasCollateral - debt amount = 50 * 0.325 + 15 * 0.2 - 15=4.25 - almostEqual( - userAccount.availableBorrowsBase, - await convertToCurrencyDecimals(ape.address, "4.25") - ); - const totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - // User 1 - totalStake should increased in Stake amount - expect(totalStake).equal(amount); - // User 1 - pSape should increased in Stake amount - const pSApeBalance = await pSApeCoin.balanceOf(user1.address); - expect(pSApeBalance).equal(amount); - - await waitForTx( - await bakc - .connect(user1.signer) - .transferFrom(user1.address, user3.address, 0) - ); - // User 3 - The NFT owner with bakc id 0 should be changed to user3 - expect(await bakc.balanceOf(user3.address)).equal(1); - expect(await bakc.ownerOf(0)).eq(user3.address); - - const withdrawAmount = await convertToCurrencyDecimals(ape.address, "6000"); - - await expect( - pool.connect(user1.signer).withdrawBAKC(mayc.address, [ - { - mainTokenId: 0, - bakcTokenId: 0, - amount: withdrawAmount, - isUncommit: false, - }, - ]) - ).to.be.revertedWith(ProtocolErrors.NOT_THE_BAKC_OWNER); - }); - - it("TC-pool-ape-staking-42 test withdrawBAKC success when withdraw amount == bakc staking amount, it will automatically claim and transfer the reward to the BACK owner", async () => { - const { - users: [user1, , user3], - ape, - mayc, - pool, - nMAYC, - apeCoinStaking, - bakc, - } = await loadFixture(fixture); - // 1. supply 1 mayc - await supplyAndValidate(mayc, "1", user1, true); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - // 2. stake one bakc and borrow 15000 ape - await waitForTx( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - const userAccount = await pool.getUserAccountData(user1.address); - - // User1 - collateral amount should increased mayc amount * price + ape amount * ape price = 50 + 15000*0.001 = 65 - expect(userAccount.totalCollateralBase).equal( - await convertToCurrencyDecimals(ape.address, "65") - ); - // User1 - debt amount should increased ape amount * ape price = 15000*0.001 = 15 - almostEqual( - userAccount.totalDebtBase, - await convertToCurrencyDecimals(ape.address, "15") - ); - // User1 - available borrow should increased amount * baseLTVasCollateral - debt amount = 50 * 0.325 + 15 * 0.2 - 15=4.25 - almostEqual( - userAccount.availableBorrowsBase, - await convertToCurrencyDecimals(ape.address, "4.25") - ); - // User 1 - totalStake should increased in Stake amount - let totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - expect(totalStake).equal(amount); - // User 1 - pSape should increased in Stake amount - const pSApeBalance = await pSApeCoin.balanceOf(user1.address); - expect(pSApeBalance).equal(amount); - - await advanceTimeAndBlock(parseInt("86400")); - - // bayc rewards - // const pendingRewardsPool2 = await apeCoinStaking.pendingRewards( - // 2, - // nMAYC.address, - // "0" - // ); - // bakc rewards - const pendingRewardsPool3 = await apeCoinStaking.pendingRewards( - 3, - nMAYC.address, - "0" - ); - - await waitForTx( - await bakc - .connect(user1.signer) - ["safeTransferFrom(address,address,uint256)"]( - user1.address, - user3.address, - 0 - ) - ); - // User 3 - The NFT owner with bakc id 0 should be changed to user3 - expect(await bakc.ownerOf(0)).eq(user3.address); - - await waitForTx( - await pool - .connect(user1.signer) - .withdrawBAKC(mayc.address, [ - {mainTokenId: 0, bakcTokenId: 0, amount: amount2, isUncommit: true}, - ]) - ); - - // User1 - ape balance should increased amount2 - expect(await ape.balanceOf(user1.address)).eq(amount2); - // User 3 - ape balance should increased pendingRewardsPool3 - expect(await ape.balanceOf(user3.address)).eq(pendingRewardsPool3); - totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - // User1 - total stake should increased amount1 - expect(totalStake).equal(amount1); - }); - - it("TC-pool-ape-staking-43 test withdrawBAKC success when withdraw amount == bakc staking amount, and the sender is not the BAKC owner, it will automatically claim and transfer the reward to the BACK owner", async () => { - const { - users: [user1], - ape, - mayc, - pool, - nMAYC, - apeCoinStaking, - } = await loadFixture(fixture); - // 1. supply 1 mayc - await supplyAndValidate(mayc, "1", user1, true); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - // 2. stake one bakc and borrow 15000 ape - await waitForTx( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - const userAccount = await pool.getUserAccountData(user1.address); - - // User1 - collateral amount should increased mayc amount * price + ape amount * ape price = 50 + 15000*0.001 = 65 - expect(userAccount.totalCollateralBase).equal( - await convertToCurrencyDecimals(ape.address, "65") - ); - // User1 - debt amount should increased ape amount * ape price = 15000*0.001 = 15 - almostEqual( - userAccount.totalDebtBase, - await convertToCurrencyDecimals(ape.address, "15") - ); - // User1 - available borrow should increased amount * baseLTVasCollateral - debt amount = 50 * 0.325 + 15 * 0.2 - 15=4.25 - almostEqual( - userAccount.availableBorrowsBase, - await convertToCurrencyDecimals(ape.address, "4.25") - ); - // User 1 - totalStake should increased in Stake amount - let totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - expect(totalStake).equal(amount); - // User 1 - pSape should increased in Stake amount - const pSApeBalance = await pSApeCoin.balanceOf(user1.address); - expect(pSApeBalance).equal(amount); - - await advanceTimeAndBlock(parseInt("86400")); - - // bayc rewards - // const pendingRewardsPool2 = await apeCoinStaking.pendingRewards( - // 2, - // nMAYC.address, - // "0" - // ); - // bakc rewards - const pendingRewardsPool3 = await apeCoinStaking.pendingRewards( - 3, - nMAYC.address, - "0" - ); - - await waitForTx( - await pool - .connect(user1.signer) - .withdrawBAKC(mayc.address, [ - {mainTokenId: 0, bakcTokenId: 0, amount: amount2, isUncommit: true}, - ]) - ); - - // User1 - ape balance should increased amount2 + pendingRewardsPool3 - expect(await ape.balanceOf(user1.address)).eq( - amount2.add(pendingRewardsPool3) - ); - totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - // User1 - total stake should increased amount1 - expect(totalStake).equal(amount1); - }); - - it("TC-pool-ape-staking-44 test withdrawApeCoin fails when the sender is not the NFT owner(revert expected)", async () => { - const { - users: [user1, , user3], - ape, - mayc, - pool, - nMAYC, - } = await loadFixture(fixture); - - // supply 1 mayc - await supplyAndValidate(mayc, "1", user1, true); - await mintAndValidate(ape, "1000", user1); - - const amount = await convertToCurrencyDecimals(ape.address, "1000"); - // 2. stake one bakc and borrow 15000 ape - await waitForTx( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: amount, - }, - [{tokenId: 0, amount: amount}], - [], - true - ) - ); - - const userAccount = await pool.getUserAccountData(user1.address); - - // User1 - collateral amount should increased mayc amount * price + ape amount * ape price = 50 + 1000*0.001 = 51 - expect(userAccount.totalCollateralBase).equal( - await convertToCurrencyDecimals(ape.address, "51") - ); - // User1 - debt amount should increased 0 - almostEqual(userAccount.totalDebtBase, 0); - // User1 - available borrow should increased amount * baseLTVasCollateral = 50 * 0.325 + 1 * 0.2=16.45 - almostEqual( - userAccount.availableBorrowsBase, - await convertToCurrencyDecimals(ape.address, "16.45") - ); - // User 1 - totalStake should increased in Stake amount - const totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - expect(totalStake).equal(amount); - // User 1 - pSape should increased in Stake amount - const pSApeBalance = await pSApeCoin.balanceOf(user1.address); - expect(pSApeBalance).equal(amount); - - await waitForTx( - await nMAYC - .connect(user1.signer) - ["safeTransferFrom(address,address,uint256)"]( - user1.address, - user3.address, - 0 - ) - ); - expect(await nMAYC.balanceOf(user3.address)).eq(1); - expect(await nMAYC.ownerOf(0)).eq(user3.address); - - await expect( - pool - .connect(user1.signer) - .withdrawApeCoin(mayc.address, [{tokenId: 1, amount: amount}]) - ).to.be.revertedWith(ProtocolErrors.NOT_THE_OWNER); - }); - - it("TC-pool-ape-staking-45 test withdrawApeCoin success when withdraw amount == NFT staking amount, it will automatically claim and transfer the reward to the user account", async () => { - const { - users: [user1], - ape, - mayc, - pool, - nMAYC, - apeCoinStaking, - } = await loadFixture(fixture); - // 1. supply 1 mayc - await supplyAndValidate(mayc, "1", user1, true); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - // 2. stake one bakc and borrow 15000 ape - await waitForTx( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - const userAccount = await pool.getUserAccountData(user1.address); - - // User1 - collateral amount should increased mayc amount * price + ape amount * ape price = 50 + 15000*0.001 = 65 - expect(userAccount.totalCollateralBase).equal( - await convertToCurrencyDecimals(ape.address, "65") - ); - // User1 - debt amount should increased ape amount * ape price = 15000*0.001 = 15 - almostEqual( - userAccount.totalDebtBase, - await convertToCurrencyDecimals(ape.address, "15") - ); - // User1 - available borrow should increased amount * baseLTVasCollateral - debt amount = 50 * 0.325 + 15 * 0.2 - 15=4.25 - almostEqual( - userAccount.availableBorrowsBase, - await convertToCurrencyDecimals(ape.address, "4.25") - ); - // User 1 - totalStake should increased in Stake amount - let totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - expect(totalStake).equal(amount); - // User 1 - pSape should increased in Stake amount - const pSApeBalance = await pSApeCoin.balanceOf(user1.address); - expect(pSApeBalance).equal(amount); - - // advance in time - await advanceTimeAndBlock(parseInt("86400")); - - const pendingRewardsPool2 = await apeCoinStaking.pendingRewards( - 2, - nMAYC.address, - "0" - ); - await waitForTx( - await pool - .connect(user1.signer) - .withdrawApeCoin(mayc.address, [{tokenId: 0, amount: amount1}]) - ); - - // User1 - ape balance should increased amount1 + pendingRewardsPool2 - expect(await ape.balanceOf(user1.address)).to.be.eq( - amount1.add(pendingRewardsPool2) - ); - // User1 - total stake should increased amount2 - totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - expect(totalStake).equal(amount2); - }); - - it("TC-pool-ape-staking-46 test borrowApeAndStake will turn on the sAPE collateral", async () => { - const { - users: [user1, , user3], - ape, - mayc, - pool, - nMAYC, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user3, true); - // transfer mayc#0 to user1 who hasn't collateralized sAPE - await waitForTx( - await nMAYC - .connect(user3.signer) - ["safeTransferFrom(address,address,uint256)"]( - user3.address, - user1.address, - "0" - ) - ); - await mintAndValidate(ape, "15000", user1); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - const sApeReserveData = await pool.getReserveData(sApeAddress); - const configDataBefore = (await pool.getUserConfiguration(user1.address)) - .data; - expect(isUsingAsCollateral(configDataBefore, sApeReserveData.id)).false; - - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: amount, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - true - ) - ); - - const configDataAfter = (await pool.getUserConfiguration(user1.address)) - .data; - expect(isUsingAsCollateral(configDataAfter, sApeReserveData.id)).true; - }); - - it("TC-pool-ape-staking-47 test mayc withdrawApeCoin should transfer ape coin to timelock contract", async () => { - const { - users: [user1], - ape, - mayc, - pool, - poolAdmin, - } = await loadFixture(fixture); - - //setup timelock strategy - const minThreshold = await convertToCurrencyDecimals(ape.address, "100000"); - const midThreshold = await convertToCurrencyDecimals(ape.address, "200000"); - const minTime = 5; - const midTime = 300; - const maxTime = 3600; - - const timeLockProxy = await getTimeLockProxy(); - const defaultStrategy = await deployReserveTimeLockStrategy( - eContractid.DefaultTimeLockStrategy + "ERC20", - pool.address, - minThreshold.toString(), - midThreshold.toString(), - minTime.toString(), - midTime.toString(), - maxTime.toString(), - midThreshold.mul(10).toString(), - (12 * 3600).toString(), - (24 * 3600).toString() - ); - const poolConfigurator = await getPoolConfiguratorProxy(); - await waitForTx( - await poolConfigurator - .connect(poolAdmin.signer) - .setReserveTimeLockStrategyAddress(ape.address, defaultStrategy.address) - ); - - await supplyAndValidate(mayc, "1", user1, true); - const amount = parseEther("10000"); - const totalAmount = parseEther("20000"); - await mintAndValidate(ape, "20000", user1); - - await waitForTx( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: totalAmount, - }, - [{tokenId: 0, amount: amount}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount}], - true - ) - ); - - await waitForTx( - await pool - .connect(user1.signer) - .withdrawApeCoin(mayc.address, [{tokenId: 0, amount: amount}]) - ); - expect(await ape.balanceOf(timeLockProxy.address)).to.be.eq(amount); - - await waitForTx( - await pool - .connect(user1.signer) - .withdrawBAKC(mayc.address, [ - {mainTokenId: 0, bakcTokenId: 0, amount: amount, isUncommit: true}, - ]) - ); - expect(await ape.balanceOf(timeLockProxy.address)).to.be.eq(totalAmount); - - await advanceTimeAndBlock(10); - - await waitForTx(await timeLockProxy.connect(user1.signer).claim(["0"])); - expect(await ape.balanceOf(user1.address)).to.be.eq(amount); - - await waitForTx(await timeLockProxy.connect(user1.signer).claim(["1"])); - expect(await ape.balanceOf(user1.address)).to.be.eq(totalAmount); - expect(await ape.balanceOf(timeLockProxy.address)).to.be.eq(0); - }); - - it("TC-pool-ape-staking-48 test bayc withdrawApeCoin should transfer ape coin to timelock contract", async () => { - const { - users: [user1], - ape, - bayc, - pool, - poolAdmin, - } = await loadFixture(fixture); - - //setup timelock strategy - const minThreshold = await convertToCurrencyDecimals(ape.address, "100000"); - const midThreshold = await convertToCurrencyDecimals(ape.address, "200000"); - const minTime = 5; - const midTime = 300; - const maxTime = 3600; - - const timeLockProxy = await getTimeLockProxy(); - const defaultStrategy = await deployReserveTimeLockStrategy( - eContractid.DefaultTimeLockStrategy + "ERC20", - pool.address, - minThreshold.toString(), - midThreshold.toString(), - minTime.toString(), - midTime.toString(), - maxTime.toString(), - midThreshold.mul(10).toString(), - (12 * 3600).toString(), - (24 * 3600).toString() - ); - const poolConfigurator = await getPoolConfiguratorProxy(); - await waitForTx( - await poolConfigurator - .connect(poolAdmin.signer) - .setReserveTimeLockStrategyAddress(ape.address, defaultStrategy.address) - ); - - await supplyAndValidate(bayc, "1", user1, true); - const amount = parseEther("10000"); - const totalAmount = parseEther("20000"); - await mintAndValidate(ape, "20000", user1); - - await waitForTx( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: bayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: totalAmount, - }, - [{tokenId: 0, amount: amount}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount}], - true - ) - ); - - await waitForTx( - await pool - .connect(user1.signer) - .withdrawApeCoin(bayc.address, [{tokenId: 0, amount: amount}]) - ); - expect(await ape.balanceOf(timeLockProxy.address)).to.be.eq(amount); - - await waitForTx( - await pool - .connect(user1.signer) - .withdrawBAKC(bayc.address, [ - {mainTokenId: 0, bakcTokenId: 0, amount: amount, isUncommit: true}, - ]) - ); - expect(await ape.balanceOf(timeLockProxy.address)).to.be.eq(totalAmount); - - await advanceTimeAndBlock(10); - - await waitForTx(await timeLockProxy.connect(user1.signer).claim(["0"])); - expect(await ape.balanceOf(user1.address)).to.be.eq(amount); - - await waitForTx(await timeLockProxy.connect(user1.signer).claim(["1"])); - expect(await ape.balanceOf(user1.address)).to.be.eq(totalAmount); - expect(await ape.balanceOf(timeLockProxy.address)).to.be.eq(0); - }); - - it("TC-pool-ape-staking-49 test borrowApeAndStake with 100% debt failed if don't use sape as collateral", async () => { - const { - users: [user1], - ape, - mayc, - pool, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - - await changePriceAndValidate(ape, "0.003"); - - await expect( - pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - false - ) - ).to.be.revertedWith(ProtocolErrors.COLLATERAL_CANNOT_COVER_NEW_BORROW); - - await changePriceAndValidate(ape, "0.0001"); - - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - false - ) - ); - - const pSApeBalance = await pSApeCoin.balanceOf(user1.address); - expect(pSApeBalance).equal(amount); - - const userConfig = BigNumber.from( - (await pool.getUserConfiguration(user1.address)).data - ); - const apeData = await pool.getReserveData(ape.address); - expect(isUsingAsCollateral(userConfig, apeData.id)).to.be.false; - }); - - it("TC-pool-ape-staking-50 test withdrawApeCoin should success when hf < 1 and sApe is not used as collateral", async () => { - const { - users: [user1], - ape, - mayc, - pool, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - - const amount1 = await convertToCurrencyDecimals(ape.address, "7000"); - const amount2 = await convertToCurrencyDecimals(ape.address, "8000"); - const amount = await convertToCurrencyDecimals(ape.address, "15000"); - await changePriceAndValidate(mayc, "100"); - await changePriceAndValidate(ape, "0.001"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount1}], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount2}], - false - ) - ); - - await changePriceAndValidate(mayc, "40"); - await changePriceAndValidate(ape, "0.002"); - await changeSApePriceAndValidate(sApeAddress, "0.002"); - - const healthFactor = (await pool.getUserAccountData(user1.address)) - .healthFactor; - expect(healthFactor.lt(parseEther("1"))).to.be.true; - - expect( - await pool - .connect(user1.signer) - .withdrawApeCoin(mayc.address, [{tokenId: 0, amount: amount1}]) - ); - - expect( - await pool - .connect(user1.signer) - .withdrawBAKC(mayc.address, [ - {mainTokenId: 0, bakcTokenId: 0, amount: amount2, isUncommit: true}, - ]) - ); - }); -}); diff --git a/test/_pool_configurator.spec.ts b/test/_pool_configurator.spec.ts index 078931414..ae5975881 100644 --- a/test/_pool_configurator.spec.ts +++ b/test/_pool_configurator.spec.ts @@ -18,7 +18,7 @@ import {auctionStrategyExp} from "../market-config/auctionStrategies"; import {strategyWETH} from "../market-config/reservesConfigs"; import { convertToCurrencyDecimals, - impersonateAddress, + // impersonateAddress, } from "../helpers/contracts-helpers"; import { ERC20, @@ -36,7 +36,7 @@ import {waitForTx} from "../helpers/misc-utils"; import {BigNumberish} from "ethers"; import "./helpers/utils/wadraymath"; import {supplyAndValidate} from "./helpers/validated-steps"; -import {topUpNonPayableWithEther} from "./helpers/utils/funds"; +// import {topUpNonPayableWithEther} from "./helpers/utils/funds"; import {ETHERSCAN_VERIFICATION} from "../helpers/hardhat-constants"; describe("PoolConfigurator: Common", () => { @@ -727,45 +727,45 @@ describe("PoolConfigurator: Common", () => { expect(interestRateStrategyAddressAfter).to.be.eq(ONE_ADDRESS); }); - it("TC-poolConfigurator-setReserveInterestRateStrategyAddress-03 PoolConfigurator updates the ReserveInterestRateStrategy address for asset 0 (revert expected)", async () => { - const {pool, deployer, configurator} = await loadFixture(testEnvFixture); - - // Impersonate PoolConfigurator - await topUpNonPayableWithEther( - deployer.signer, - [configurator.address], - utils.parseEther("1") - ); - const configSigner = (await impersonateAddress(configurator.address)) - .signer; - - await expect( - pool - .connect(configSigner) - .setReserveInterestRateStrategyAddress(ZERO_ADDRESS, ZERO_ADDRESS) - ).to.be.revertedWith(ProtocolErrors.ZERO_ADDRESS_NOT_VALID); - }); - - it("TC-poolConfigurator-setReserveInterestRateStrategyAddress-04 PoolConfigurator updates the ReserveInterestRateStrategy address for an unlisted asset (revert expected)", async () => { - const {pool, deployer, configurator, users} = await loadFixture( - testEnvFixture - ); - - // Impersonate PoolConfigurator - await topUpNonPayableWithEther( - deployer.signer, - [configurator.address], - utils.parseEther("1") - ); - const configSigner = (await impersonateAddress(configurator.address)) - .signer; - - await expect( - pool - .connect(configSigner) - .setReserveInterestRateStrategyAddress(users[5].address, ZERO_ADDRESS) - ).to.be.revertedWith(ProtocolErrors.ASSET_NOT_LISTED); - }); + // it("TC-poolConfigurator-setReserveInterestRateStrategyAddress-03 PoolConfigurator updates the ReserveInterestRateStrategy address for asset 0 (revert expected)", async () => { + // const {pool, deployer, configurator} = await loadFixture(testEnvFixture); + // + // // Impersonate PoolConfigurator + // await topUpNonPayableWithEther( + // deployer.signer, + // [configurator.address], + // utils.parseEther("1") + // ); + // const configSigner = (await impersonateAddress(configurator.address)) + // .signer; + // + // await expect( + // pool + // .connect(configSigner) + // .setReserveInterestRateStrategyAddress(ZERO_ADDRESS, ZERO_ADDRESS) + // ).to.be.revertedWith(ProtocolErrors.ZERO_ADDRESS_NOT_VALID); + // }); + + // it("TC-poolConfigurator-setReserveInterestRateStrategyAddress-04 PoolConfigurator updates the ReserveInterestRateStrategy address for an unlisted asset (revert expected)", async () => { + // const {pool, deployer, configurator, users} = await loadFixture( + // testEnvFixture + // ); + // + // // Impersonate PoolConfigurator + // await topUpNonPayableWithEther( + // deployer.signer, + // [configurator.address], + // utils.parseEther("1") + // ); + // const configSigner = (await impersonateAddress(configurator.address)) + // .signer; + // + // await expect( + // pool + // .connect(configSigner) + // .setReserveInterestRateStrategyAddress(users[5].address, ZERO_ADDRESS) + // ).to.be.revertedWith(ProtocolErrors.ASSET_NOT_LISTED); + // }); it("TC-poolConfigurator-setReserveInterestRateStrategyAddress-05 Activates the zero address reserve for borrowing via pool admin (expect revert)", async () => { const {configurator} = await loadFixture(testEnvFixture); diff --git a/test/_pool_core_erc20_repay.spec.ts b/test/_pool_core_erc20_repay.spec.ts index db603f2d4..6173e442d 100644 --- a/test/_pool_core_erc20_repay.spec.ts +++ b/test/_pool_core_erc20_repay.spec.ts @@ -6,7 +6,6 @@ import {convertToCurrencyDecimals} from "../helpers/contracts-helpers"; import { advanceTimeAndBlock, setAutomine, - setAutomineEvm, waitForTx, } from "../helpers/misc-utils"; import {ProtocolErrors} from "../helpers/types"; @@ -22,7 +21,7 @@ import {almostEqual} from "./helpers/uniswapv3-helper"; import {utils} from "ethers"; import {getVariableDebtToken} from "../helpers/contracts-getters"; -const {RESERVE_INACTIVE, SAME_BLOCK_BORROW_REPAY} = ProtocolErrors; +const {RESERVE_INACTIVE} = ProtocolErrors; const fixture = async () => { const testEnv = await loadFixture(testEnvFixture); @@ -299,13 +298,13 @@ describe("pToken Repay Event Accounting", () => { .borrow(dai.address, utils.parseEther("500"), 0, user.address); // Turn on automining, but not mine a new block until next tx - await setAutomineEvm(true); + // await setAutomineEvm(true); - await expect( - pool - .connect(user.signer) - .repay(dai.address, utils.parseEther("500"), user.address) - ).to.be.revertedWith(SAME_BLOCK_BORROW_REPAY); + // await expect( + // pool + // .connect(user.signer) + // .repay(dai.address, utils.parseEther("500"), user.address) + // ).to.be.revertedWith(SAME_BLOCK_BORROW_REPAY); }); it("TC-erc20-repay-11 validateRepay() when variable borrowing and repaying in same block using credit delegation (revert expected)", async () => { @@ -367,13 +366,13 @@ describe("pToken Repay Event Accounting", () => { .borrow(dai.address, utils.parseEther("2"), 0, user1.address); // Turn on automining, but not mine a new block until next tx - await setAutomineEvm(true); - - await expect( - pool - .connect(user1.signer) - .repay(dai.address, utils.parseEther("2"), user1.address) - ).to.be.revertedWith(SAME_BLOCK_BORROW_REPAY); + // await setAutomineEvm(true); + // + // await expect( + // pool + // .connect(user1.signer) + // .repay(dai.address, utils.parseEther("2"), user1.address) + // ).to.be.revertedWith(SAME_BLOCK_BORROW_REPAY); }); }); }); diff --git a/test/_pool_core_erc20_supply.spec.ts b/test/_pool_core_erc20_supply.spec.ts index 9d2ffc08d..fe63c3b09 100644 --- a/test/_pool_core_erc20_supply.spec.ts +++ b/test/_pool_core_erc20_supply.spec.ts @@ -4,7 +4,7 @@ import {parseEther} from "ethers/lib/utils"; import {MAX_UINT_AMOUNT, ONE_YEAR, MAX_SUPPLY_CAP} from "../helpers/constants"; import { convertToCurrencyDecimals, - impersonateAddress, + // impersonateAddress, } from "../helpers/contracts-helpers"; import {advanceTimeAndBlock} from "../helpers/misc-utils"; import {testEnvFixture} from "./helpers/setup-env"; @@ -17,7 +17,7 @@ import { import {ProtocolErrors} from "../helpers/types"; import {TestEnv} from "./helpers/make-suite"; import {utils} from "ethers"; -import {topUpNonPayableWithEther} from "./helpers/utils/funds"; +// import {topUpNonPayableWithEther} from "./helpers/utils/funds"; describe("pToken Supply Event Accounting", () => { const {RESERVE_FROZEN, RESERVE_INACTIVE, UNDERLYING_BALANCE_ZERO} = @@ -227,57 +227,57 @@ describe("pToken Supply Event Accounting", () => { ).to.be.revertedWith(RESERVE_FROZEN); }); - it("TC-erc20-supply-12 validateSetUseERC20AsCollateral() when reserve is not active (revert expected)", async () => { - /** - * Since its not possible to deactivate a reserve with existing suppliers, making the user have - * xToken balance (pDAI) its not technically possible to end up in this situation. - * However, we impersonate the Pool to get some pDAI and make the test possible - */ - const { - pool, - configurator, - protocolDataProvider, - poolAdmin, - users, - dai, - pDai, - } = await loadFixture(testEnvFixture); - const user = users[0]; - - const configBefore = await protocolDataProvider.getReserveConfigurationData( - dai.address - ); - expect(configBefore.isActive).to.be.eq(true); - expect(configBefore.isFrozen).to.be.eq(false); - - await configurator - .connect(poolAdmin.signer) - .setReserveActive(dai.address, false); - - const configAfter = await protocolDataProvider.getReserveConfigurationData( - dai.address - ); - expect(configAfter.isActive).to.be.eq(false); - expect(configAfter.isFrozen).to.be.eq(false); - - const poolSigner = (await impersonateAddress(pool.address)).signer; - await topUpNonPayableWithEther( - user.signer, - [pool.address], - utils.parseEther("1") - ); - expect( - await pDai.connect(poolSigner).mint(user.address, user.address, 1, 1) - ); - - await expect( - pool.connect(user.signer).setUserUseERC20AsCollateral(dai.address, true) - ).to.be.revertedWith(RESERVE_INACTIVE); - - await expect( - pool.connect(user.signer).setUserUseERC20AsCollateral(dai.address, false) - ).to.be.revertedWith(RESERVE_INACTIVE); - }); + // it("TC-erc20-supply-12 validateSetUseERC20AsCollateral() when reserve is not active (revert expected)", async () => { + // /** + // * Since its not possible to deactivate a reserve with existing suppliers, making the user have + // * xToken balance (pDAI) its not technically possible to end up in this situation. + // * However, we impersonate the Pool to get some pDAI and make the test possible + // */ + // const { + // pool, + // configurator, + // protocolDataProvider, + // poolAdmin, + // users, + // dai, + // pDai, + // } = await loadFixture(testEnvFixture); + // const user = users[0]; + // + // const configBefore = await protocolDataProvider.getReserveConfigurationData( + // dai.address + // ); + // expect(configBefore.isActive).to.be.eq(true); + // expect(configBefore.isFrozen).to.be.eq(false); + // + // await configurator + // .connect(poolAdmin.signer) + // .setReserveActive(dai.address, false); + // + // const configAfter = await protocolDataProvider.getReserveConfigurationData( + // dai.address + // ); + // expect(configAfter.isActive).to.be.eq(false); + // expect(configAfter.isFrozen).to.be.eq(false); + // + // const poolSigner = (await impersonateAddress(pool.address)).signer; + // await topUpNonPayableWithEther( + // user.signer, + // [pool.address], + // utils.parseEther("1") + // ); + // expect( + // await pDai.connect(poolSigner).mint(user.address, user.address, 1, 1) + // ); + // + // await expect( + // pool.connect(user.signer).setUserUseERC20AsCollateral(dai.address, true) + // ).to.be.revertedWith(RESERVE_INACTIVE); + // + // await expect( + // pool.connect(user.signer).setUserUseERC20AsCollateral(dai.address, false) + // ).to.be.revertedWith(RESERVE_INACTIVE); + // }); it("TC-erc20-supply-13 validateSetUseERC20AsCollateral() with userBalance == 0 (revert expected)", async () => { const {pool, users, dai} = await loadFixture(testEnvFixture); diff --git a/test/_pool_initialization.spec.ts b/test/_pool_initialization.spec.ts index f04fe1102..539e8eb95 100644 --- a/test/_pool_initialization.spec.ts +++ b/test/_pool_initialization.spec.ts @@ -1,19 +1,21 @@ import {expect} from "chai"; -import {utils} from "ethers"; import {ZERO_ADDRESS} from "../helpers/constants"; import {deployPoolCoreLibraries} from "../helpers/contracts-deployments"; import {ProtocolErrors} from "../helpers/types"; -import {PoolCore__factory} from "../types"; -import {topUpNonPayableWithEther} from "./helpers/utils/funds"; -import {getFirstSigner, getTimeLockProxy} from "../helpers/contracts-getters"; +// import {topUpNonPayableWithEther} from "./helpers/utils/funds"; +// import {utils} from "ethers"; +// import {impersonateAddress} from "../helpers/contracts-helpers"; +import { + getContractFactory, + getTimeLockProxy, +} from "../helpers/contracts-getters"; import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; import {testEnvFixture} from "./helpers/setup-env"; -import {impersonateAddress} from "../helpers/contracts-helpers"; describe("Pool: Initialization", () => { const { CALLER_NOT_POOL_CONFIGURATOR, - NOT_CONTRACT, + // NOT_CONTRACT, INVALID_ADDRESSES_PROVIDER, } = ProtocolErrors; @@ -33,10 +35,9 @@ describe("Pool: Initialization", () => { const coreLibraries = await deployPoolCoreLibraries(false); const timeLock = await getTimeLockProxy(); - const poolCore = await new PoolCore__factory( - coreLibraries, - await getFirstSigner() - ).deploy(addressesProvider.address, timeLock.address); + const poolCore = await ( + await getContractFactory("PoolCore", coreLibraries) + ).factory.deploy(addressesProvider.address, timeLock.address); await expect(poolCore.initialize(deployer.address)).to.be.revertedWith( INVALID_ADDRESSES_PROVIDER @@ -66,31 +67,31 @@ describe("Pool: Initialization", () => { ).to.be.revertedWith(CALLER_NOT_POOL_CONFIGURATOR); }); - it("TC-pool_initialization-04 Tries to call `initReserve()` with an EOA as reserve (revert expected)", async () => { - const {pool, deployer, users, configurator} = await loadFixture( - testEnvFixture - ); - - // Impersonate PoolConfigurator - await topUpNonPayableWithEther( - deployer.signer, - [configurator.address], - utils.parseEther("1") - ); - const configSigner = (await impersonateAddress(configurator.address)) - .signer; - - await expect( - pool - .connect(configSigner) - .initReserve( - users[0].address, - ZERO_ADDRESS, - ZERO_ADDRESS, - ZERO_ADDRESS, - ZERO_ADDRESS, - ZERO_ADDRESS - ) - ).to.be.revertedWith(NOT_CONTRACT); - }); + // it("TC-pool_initialization-04 Tries to call `initReserve()` with an EOA as reserve (revert expected)", async () => { + // const {pool, deployer, users, configurator} = await loadFixture( + // testEnvFixture + // ); + // + // // Impersonate PoolConfigurator + // await topUpNonPayableWithEther( + // deployer.signer, + // [configurator.address], + // utils.parseEther("1") + // ); + // const configSigner = (await impersonateAddress(configurator.address)) + // .signer; + // + // await expect( + // pool + // .connect(configSigner) + // .initReserve( + // users[0].address, + // ZERO_ADDRESS, + // ZERO_ADDRESS, + // ZERO_ADDRESS, + // ZERO_ADDRESS, + // ZERO_ADDRESS + // ) + // ).to.be.revertedWith(NOT_CONTRACT); + // }); }); diff --git a/test/_sape_pool_operation.spec.ts b/test/_sape_pool_operation.spec.ts index e7e91fdb5..0fe7d4251 100644 --- a/test/_sape_pool_operation.spec.ts +++ b/test/_sape_pool_operation.spec.ts @@ -6,19 +6,16 @@ import {MAX_UINT_AMOUNT, ONE_ADDRESS} from "../helpers/constants"; import {ProtocolErrors} from "../helpers/types"; import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; import {testEnvFixture} from "./helpers/setup-env"; -import { - changePriceAndValidate, - mintAndValidate, - supplyAndValidate, -} from "./helpers/validated-steps"; -import {convertToCurrencyDecimals} from "../helpers/contracts-helpers"; -import {PTokenSApe} from "../types"; -import {getPTokenSApe} from "../helpers/contracts-getters"; +import {mintAndValidate, supplyAndValidate} from "./helpers/validated-steps"; +import {ParaApeStaking, PTokenSApe} from "../types"; +import {getParaApeStaking, getPTokenSApe} from "../helpers/contracts-getters"; +import {parseEther} from "ethers/lib/utils"; describe("SApe Pool Operation Test", () => { let testEnv: TestEnv; const sApeAddress = ONE_ADDRESS; let pSApeCoin: PTokenSApe; + let paraApeStaking: ParaApeStaking; const fixture = async () => { testEnv = await loadFixture(testEnvFixture); @@ -30,6 +27,8 @@ describe("SApe Pool Operation Test", () => { pool, } = testEnv; + paraApeStaking = await getParaApeStaking(); + const {xTokenAddress: pSApeCoinAddress} = await protocolDataProvider.getReserveTokensAddresses(sApeAddress); pSApeCoin = await getPTokenSApe(pSApeCoinAddress); @@ -65,21 +64,22 @@ describe("SApe Pool Operation Test", () => { } = await loadFixture(fixture); await supplyAndValidate(mayc, "1", user1, true); - await mintAndValidate(ape, "10000", user1); - - const amount = await convertToCurrencyDecimals(ape.address, "5000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount}], - [], - true - ) + await mintAndValidate(ape, "100000", user1); + + await waitForTx( + await ape + .connect(user1.signer) + .approve(paraApeStaking.address, MAX_UINT_AMOUNT) + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).depositApeCoinPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("100000"), + isBAYC: false, + tokenIds: [0], + }) ); const balance = await pSApeCoin.balanceOf(user1.address); @@ -105,93 +105,4 @@ describe("SApe Pool Operation Test", () => { }) ).to.be.revertedWith(ProtocolErrors.BORROWING_NOT_ENABLED); }); - - it("liquidate sApe is not allowed", async () => { - const { - users: [user1, liquidator], - ape, - mayc, - pool, - weth, - } = await loadFixture(fixture); - - await supplyAndValidate(mayc, "1", user1, true); - await mintAndValidate(ape, "10000", user1); - - const amount = await convertToCurrencyDecimals(ape.address, "5000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: amount}], - [], - true - ) - ); - - await supplyAndValidate(weth, "100", liquidator, true, "200000"); - - // BorrowLimit: (51 * 0.325 + 5000 * 0.0036906841286 * 0.2 - 5000 * 0.0036906841286) = 1.8122634856 - const borrowAmount = await convertToCurrencyDecimals(weth.address, "1"); - expect( - await pool - .connect(user1.signer) - .borrow(weth.address, borrowAmount, 0, user1.address) - ); - - // drop HF and ERC-721_HF below 1 - await changePriceAndValidate(mayc, "5"); - - await expect( - pool - .connect(liquidator.signer) - .liquidateERC20( - weth.address, - sApeAddress, - user1.address, - amount, - false, - {gasLimit: 5000000} - ) - ).to.be.revertedWith(ProtocolErrors.SAPE_NOT_ALLOWED); - }); - - // it("set sApe not as collateral is not allowed", async () => { - // const { - // users: [user1], - // ape, - // mayc, - // pool, - // } = await loadFixture(fixture); - // - // await supplyAndValidate(mayc, "1", user1, true); - // await mintAndValidate(ape, "10000", user1); - // - // const amount = await convertToCurrencyDecimals(ape.address, "5000"); - // expect( - // await pool.connect(user1.signer).borrowApeAndStake( - // { - // nftAsset: mayc.address, - // borrowAsset: ape.address, - // borrowAmount: amount, - // cashAmount: 0, - // }, - // [{tokenId: 0, amount: amount}], - // [], - // true - // ) - // ); - // - // await expect( - // pool - // .connect(user1.signer) - // .setUserUseERC20AsCollateral(sApeAddress, false, { - // gasLimit: 12_450_000, - // }) - // ).to.be.revertedWith(ProtocolErrors.SAPE_NOT_ALLOWED); - // }); }); diff --git a/test/_timelock.spec.ts b/test/_timelock.spec.ts index 2b306aecd..de08afd61 100644 --- a/test/_timelock.spec.ts +++ b/test/_timelock.spec.ts @@ -1,36 +1,46 @@ import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; import {expect} from "chai"; import {deployReserveTimeLockStrategy} from "../helpers/contracts-deployments"; -import {MAX_UINT_AMOUNT} from "../helpers/constants"; +import {MAX_UINT_AMOUNT, ONE_ADDRESS} from "../helpers/constants"; import { + getAutoCompoundApe, + getParaApeStaking, getPoolConfiguratorProxy, + getPTokenSApe, getTimeLockProxy, } from "../helpers/contracts-getters"; import {convertToCurrencyDecimals} from "../helpers/contracts-helpers"; import {advanceTimeAndBlock, waitForTx} from "../helpers/misc-utils"; import {eContractid} from "../helpers/types"; import {testEnvFixture} from "./helpers/setup-env"; -import {supplyAndValidate} from "./helpers/validated-steps"; +import {mintAndValidate, supplyAndValidate} from "./helpers/validated-steps"; import {parseEther} from "ethers/lib/utils"; import {almostEqual} from "./helpers/uniswapv3-helper"; +import {AutoCompoundApe, ParaApeStaking, PTokenSApe} from "../types"; describe("TimeLock functionality tests", () => { const minTime = 5; const midTime = 300; const maxTime = 3600; let timeLockProxy; + let cApe: AutoCompoundApe; + let paraApeStaking: ParaApeStaking; + let pSApeCoin: PTokenSApe; + const sApeAddress = ONE_ADDRESS; const fixture = async () => { const testEnv = await loadFixture(testEnvFixture); const { dai, + ape, usdc, pool, mayc, weth, wPunk, - users: [user1, user2], + users: [user1, user2, , , , user6], poolAdmin, + protocolDataProvider, } = testEnv; // User 1 - Deposit dai @@ -42,6 +52,22 @@ describe("TimeLock functionality tests", () => { await supplyAndValidate(weth, "1", user1, true); + cApe = await getAutoCompoundApe(); + const MINIMUM_LIQUIDITY = await cApe.MINIMUM_LIQUIDITY(); + paraApeStaking = await getParaApeStaking(); + const {xTokenAddress: pSApeCoinAddress} = + await protocolDataProvider.getReserveTokensAddresses(sApeAddress); + pSApeCoin = await getPTokenSApe(pSApeCoinAddress); + + // user6 deposit MINIMUM_LIQUIDITY to make test case easy + await mintAndValidate(ape, "1", user6); + await waitForTx( + await ape.connect(user6.signer).approve(cApe.address, MAX_UINT_AMOUNT) + ); + await waitForTx( + await cApe.connect(user6.signer).deposit(user6.address, MINIMUM_LIQUIDITY) + ); + const minThreshold = await convertToCurrencyDecimals(usdc.address, "1000"); const midThreshold = await convertToCurrencyDecimals(usdc.address, "2000"); const minThresholdNFT = 2; @@ -90,6 +116,19 @@ describe("TimeLock functionality tests", () => { defaultStrategy.address ) ); + await waitForTx( + await poolConfigurator + .connect(poolAdmin.signer) + .setReserveTimeLockStrategyAddress(ape.address, defaultStrategy.address) + ); + await waitForTx( + await poolConfigurator + .connect(poolAdmin.signer) + .setReserveTimeLockStrategyAddress( + cApe.address, + defaultStrategy.address + ) + ); await waitForTx( await poolConfigurator .connect(poolAdmin.signer) @@ -139,7 +178,7 @@ describe("TimeLock functionality tests", () => { }) ); - await expect(await usdc.balanceOf(pool.TIME_LOCK())).to.be.eq(amount); + await expect(await usdc.balanceOf(await pool.TIME_LOCK())).to.be.eq(amount); const balanceBefore = await usdc.balanceOf(user1.address); @@ -170,7 +209,7 @@ describe("TimeLock functionality tests", () => { }) ); - await expect(await usdc.balanceOf(pool.TIME_LOCK())).to.be.eq(amount); + await expect(await usdc.balanceOf(await pool.TIME_LOCK())).to.be.eq(amount); const balanceBefore = await usdc.balanceOf(user1.address); @@ -205,7 +244,7 @@ describe("TimeLock functionality tests", () => { }) ); - await expect(await usdc.balanceOf(pool.TIME_LOCK())).to.be.eq(amount); + await expect(await usdc.balanceOf(await pool.TIME_LOCK())).to.be.eq(amount); const balanceBefore = await usdc.balanceOf(user1.address); @@ -504,4 +543,112 @@ describe("TimeLock functionality tests", () => { await expect(balanceAfter).to.be.eq(balanceBefore.add(3)); }); + + it("sApe work as expected0", async () => { + const { + users: [user1], + ape, + bayc, + } = await loadFixture(fixture); + + await supplyAndValidate(bayc, "1", user1, true); + await mintAndValidate(ape, "200000", user1); + + await waitForTx( + await ape + .connect(user1.signer) + .approve(paraApeStaking.address, MAX_UINT_AMOUNT) + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).depositApeCoinPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("200000"), + isBAYC: true, + tokenIds: [0], + }) + ); + expect(await pSApeCoin.balanceOf(user1.address)).to.be.equal( + parseEther("200000") + ); + await waitForTx( + await paraApeStaking.connect(user1.signer).withdrawApeCoinPool({ + cashToken: ape.address, + cashAmount: parseEther("200000"), + isBAYC: true, + tokenIds: [0], + }) + ); + expect(await ape.balanceOf(user1.address)).to.be.equal("0"); + expect(await ape.balanceOf(timeLockProxy.address)).to.be.equal( + parseEther("200000") + ); + await advanceTimeAndBlock(13 * 3600); + await waitForTx(await timeLockProxy.connect(user1.signer).claim(["0"])); + expect(await ape.balanceOf(timeLockProxy.address)).to.be.equal("0"); + expect(await ape.balanceOf(user1.address)).to.be.equal( + parseEther("200000") + ); + }); + + it("sApe work as expected1", async () => { + const { + users: [user1], + ape, + bayc, + } = await loadFixture(fixture); + + await supplyAndValidate(bayc, "1", user1, true); + await mintAndValidate(ape, "200000", user1); + + await waitForTx( + await ape + .connect(user1.signer) + .approve(paraApeStaking.address, MAX_UINT_AMOUNT) + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).depositApeCoinPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("200000"), + isBAYC: true, + tokenIds: [0], + }) + ); + + expect(await pSApeCoin.balanceOf(user1.address)).to.be.equal( + parseEther("200000") + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).withdrawApeCoinPool({ + cashToken: ape.address, + cashAmount: "0", + isBAYC: true, + tokenIds: [0], + }) + ); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .withdrawFreeSApe(cApe.address, parseEther("200000")) + ); + + expect(await cApe.balanceOf(user1.address)).to.be.equal("0"); + expect(await cApe.balanceOf(timeLockProxy.address)).to.be.closeTo( + parseEther("200000"), + parseEther("1") + ); + + await advanceTimeAndBlock(13 * 3600); + await waitForTx(await timeLockProxy.connect(user1.signer).claim(["0"])); + + expect(await cApe.balanceOf(user1.address)).to.be.closeTo( + parseEther("200000"), + parseEther("1") + ); + }); }); diff --git a/test/_xtoken_ptoken.spec.ts b/test/_xtoken_ptoken.spec.ts index 12fa9aef6..116c09d70 100644 --- a/test/_xtoken_ptoken.spec.ts +++ b/test/_xtoken_ptoken.spec.ts @@ -23,7 +23,7 @@ import { impersonateAddress, } from "../helpers/contracts-helpers"; import {assertAlmostEqual, supplyAndValidate} from "./helpers/validated-steps"; -import {topUpNonPayableWithEther} from "./helpers/utils/funds"; +// import {topUpNonPayableWithEther} from "./helpers/utils/funds"; import {TestEnv} from "./helpers/make-suite"; import {almostEqual} from "./helpers/uniswapv3-helper"; @@ -992,23 +992,23 @@ describe("Ptoken edge cases", () => { .withArgs(ZERO_ADDRESS, ZERO_ADDRESS, amount); }); - it("TC-ptoken-edge-14: `mintToTreasury` should work when amount is zero", async () => { - const {deployer, pool, pDai} = await loadFixture(testEnvFixture); - - // Impersonate Pool - await topUpNonPayableWithEther( - deployer.signer, - [pool.address], - utils.parseEther("1") - ); - const poolSigner = (await impersonateAddress(pool.address)).signer; - - expect( - await pDai - .connect(poolSigner) - .mintToTreasury(0, utils.parseUnits("1", 27)) - ); - }); + // it("TC-ptoken-edge-14: `mintToTreasury` should work when amount is zero", async () => { + // const {deployer, pool, pDai} = await loadFixture(testEnvFixture); + // + // // Impersonate Pool + // await topUpNonPayableWithEther( + // deployer.signer, + // [pool.address], + // utils.parseEther("1") + // ); + // const poolSigner = (await impersonateAddress(pool.address)).signer; + // + // expect( + // await pDai + // .connect(poolSigner) + // .mintToTreasury(0, utils.parseUnits("1", 27)) + // ); + // }); it("TC-ptoken-edge-15: `setIncentivesController` should work", async () => { const {poolAdmin, pWETH, aclManager} = await loadFixture(testEnvFixture); diff --git a/test/_xtoken_variable_debt_token.spec.ts b/test/_xtoken_variable_debt_token.spec.ts index f10777606..7cb1f4185 100644 --- a/test/_xtoken_variable_debt_token.spec.ts +++ b/test/_xtoken_variable_debt_token.spec.ts @@ -4,12 +4,12 @@ import {increaseTime, timeLatest, waitForTx} from "../helpers/misc-utils"; import {MAX_UINT_AMOUNT, ZERO_ADDRESS} from "../helpers/constants"; import {ProtocolErrors} from "../helpers/types"; import {TestEnv} from "./helpers/make-suite"; -import {topUpNonPayableWithEther} from "./helpers/utils/funds"; +// import {topUpNonPayableWithEther} from "./helpers/utils/funds"; import { buildDelegationWithSigParams, convertToCurrencyDecimals, getSignatureFromTypedData, - impersonateAddress, + // impersonateAddress, } from "../helpers/contracts-helpers"; import {HardhatRuntimeEnvironment} from "hardhat/types"; import {VariableDebtToken__factory} from "../types"; @@ -29,8 +29,8 @@ describe("VariableDebtToken", () => { }); const { CALLER_MUST_BE_POOL, - INVALID_MINT_AMOUNT, - INVALID_BURN_AMOUNT, + // INVALID_MINT_AMOUNT, + // INVALID_BURN_AMOUNT, CALLER_NOT_POOL_ADMIN, } = ProtocolErrors; @@ -144,64 +144,64 @@ describe("VariableDebtToken", () => { ).to.be.revertedWith(CALLER_MUST_BE_POOL); }); - it("TC-variable-debt-token-04 Tries to mint with amountScaled == 0 (revert expected)", async () => { - const {deployer, pool, dai, protocolDataProvider, users} = testEnv; - - // Impersonate the Pool - await topUpNonPayableWithEther( - deployer.signer, - [pool.address], - utils.parseEther("1") - ); - const poolSigner = (await impersonateAddress(pool.address)).signer; - - const daiVariableDebtTokenAddress = ( - await protocolDataProvider.getReserveTokensAddresses(dai.address) - ).variableDebtTokenAddress; - - const variableDebtContract = VariableDebtToken__factory.connect( - daiVariableDebtTokenAddress, - deployer.signer - ); - - await expect( - variableDebtContract - .connect(poolSigner) - .mint( - users[0].address, - users[0].address, - 0, - utils.parseUnits("1", 27) - ) - ).to.be.revertedWith(INVALID_MINT_AMOUNT); - }); - - it("TC-variable-debt-token-05 Tries to burn with amountScaled == 0 (revert expected)", async () => { - const {deployer, pool, dai, protocolDataProvider, users} = testEnv; - - // Impersonate the Pool - await topUpNonPayableWithEther( - deployer.signer, - [pool.address], - utils.parseEther("1") - ); - const poolSigner = (await impersonateAddress(pool.address)).signer; - - const daiVariableDebtTokenAddress = ( - await protocolDataProvider.getReserveTokensAddresses(dai.address) - ).variableDebtTokenAddress; - - const variableDebtContract = VariableDebtToken__factory.connect( - daiVariableDebtTokenAddress, - deployer.signer - ); - - await expect( - variableDebtContract - .connect(poolSigner) - .burn(users[0].address, 0, utils.parseUnits("1", 27)) - ).to.be.revertedWith(INVALID_BURN_AMOUNT); - }); + // it("TC-variable-debt-token-04 Tries to mint with amountScaled == 0 (revert expected)", async () => { + // const {deployer, pool, dai, protocolDataProvider, users} = testEnv; + // + // // Impersonate the Pool + // await topUpNonPayableWithEther( + // deployer.signer, + // [pool.address], + // utils.parseEther("1") + // ); + // const poolSigner = (await impersonateAddress(pool.address)).signer; + // + // const daiVariableDebtTokenAddress = ( + // await protocolDataProvider.getReserveTokensAddresses(dai.address) + // ).variableDebtTokenAddress; + // + // const variableDebtContract = VariableDebtToken__factory.connect( + // daiVariableDebtTokenAddress, + // deployer.signer + // ); + // + // await expect( + // variableDebtContract + // .connect(poolSigner) + // .mint( + // users[0].address, + // users[0].address, + // 0, + // utils.parseUnits("1", 27) + // ) + // ).to.be.revertedWith(INVALID_MINT_AMOUNT); + // }); + + // it("TC-variable-debt-token-05 Tries to burn with amountScaled == 0 (revert expected)", async () => { + // const {deployer, pool, dai, protocolDataProvider, users} = testEnv; + // + // // Impersonate the Pool + // await topUpNonPayableWithEther( + // deployer.signer, + // [pool.address], + // utils.parseEther("1") + // ); + // const poolSigner = (await impersonateAddress(pool.address)).signer; + // + // const daiVariableDebtTokenAddress = ( + // await protocolDataProvider.getReserveTokensAddresses(dai.address) + // ).variableDebtTokenAddress; + // + // const variableDebtContract = VariableDebtToken__factory.connect( + // daiVariableDebtTokenAddress, + // deployer.signer + // ); + // + // await expect( + // variableDebtContract + // .connect(poolSigner) + // .burn(users[0].address, 0, utils.parseUnits("1", 27)) + // ).to.be.revertedWith(INVALID_BURN_AMOUNT); + // }); it("TC-variable-debt-token-06 Tries to transfer debt tokens (revert expected)", async () => { const {users, dai, protocolDataProvider} = testEnv; diff --git a/test/auto_compound_ape.spec.ts b/test/auto_compound_ape.spec.ts index fb1838d07..58607c80a 100644 --- a/test/auto_compound_ape.spec.ts +++ b/test/auto_compound_ape.spec.ts @@ -1,6 +1,6 @@ import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; import {expect} from "chai"; -import {AutoCompoundApe, PToken, PTokenSApe, VariableDebtToken} from "../types"; +import {AutoCompoundApe} from "../types"; import {TestEnv} from "./helpers/make-suite"; import {testEnvFixture} from "./helpers/setup-env"; import {mintAndValidate} from "./helpers/validated-steps"; @@ -12,13 +12,8 @@ import { fund, mintNewPosition, } from "./helpers/uniswapv3-helper"; -import { - getAutoCompoundApe, - getPToken, - getPTokenSApe, - getVariableDebtToken, -} from "../helpers/contracts-getters"; -import {MAX_UINT_AMOUNT, ONE_ADDRESS} from "../helpers/constants"; +import {getAutoCompoundApe} from "../helpers/contracts-getters"; +import {MAX_UINT_AMOUNT} from "../helpers/constants"; import {advanceTimeAndBlock, waitForTx} from "../helpers/misc-utils"; import {deployMockedDelegateRegistry} from "../helpers/contracts-deployments"; import {ETHERSCAN_VERIFICATION} from "../helpers/hardhat-constants"; @@ -29,10 +24,6 @@ import {ProtocolErrors} from "../helpers/types"; describe("Auto Compound Ape Test", () => { let testEnv: TestEnv; let cApe: AutoCompoundApe; - let pCApe: PToken; - let variableDebtCAPE: VariableDebtToken; - let pSApeCoin: PTokenSApe; - const sApeAddress = ONE_ADDRESS; let user1Amount; let user2Amount; let user3Amount; @@ -49,24 +40,12 @@ describe("Auto Compound Ape Test", () => { users: [user1, user2, , , user3, user4, user5], apeCoinStaking, pool, - protocolDataProvider, - poolAdmin, nftPositionManager, } = testEnv; cApe = await getAutoCompoundApe(); MINIMUM_LIQUIDITY = await cApe.MINIMUM_LIQUIDITY(); - const { - xTokenAddress: pCApeAddress, - variableDebtTokenAddress: variableDebtPsApeAddress, - } = await protocolDataProvider.getReserveTokensAddresses(cApe.address); - pCApe = await getPToken(pCApeAddress); - variableDebtCAPE = await getVariableDebtToken(variableDebtPsApeAddress); - const {xTokenAddress: pSApeCoinAddress} = - await protocolDataProvider.getReserveTokensAddresses(sApeAddress); - pSApeCoin = await getPTokenSApe(pSApeCoinAddress); - await mintAndValidate(ape, "1000", user1); await mintAndValidate(ape, "2000", user2); await mintAndValidate(ape, "4000", user3); @@ -104,16 +83,6 @@ describe("Auto Compound Ape Test", () => { await ape.connect(user4.signer).approve(cApe.address, MAX_UINT_AMOUNT) ); - await waitForTx( - await pool.connect(poolAdmin.signer).setClaimApeForCompoundFee(30) - ); - - await waitForTx( - await pool - .connect(poolAdmin.signer) - .setClaimApeForCompoundBot(user2.address) - ); - // send extra tokens to the apestaking contract for rewards await waitForTx( await ape @@ -411,597 +380,6 @@ describe("Auto Compound Ape Test", () => { almostEqual(user1ApeBalance, parseEther("5923.8")); }); - it("claimApeAndCompound function work as expected 1", async () => { - const { - pUsdc, - usdc, - users: [user1, user2, , , user3], - mayc, - pool, - ape, - } = await loadFixture(fixture); - - await waitForTx( - await mayc.connect(user1.signer)["mint(address)"](user1.address) - ); - await waitForTx( - await mayc.connect(user2.signer)["mint(address)"](user2.address) - ); - await waitForTx( - await mayc.connect(user3.signer)["mint(address)"](user3.address) - ); - await waitForTx( - await mayc.connect(user1.signer).setApprovalForAll(pool.address, true) - ); - await waitForTx( - await mayc.connect(user2.signer).setApprovalForAll(pool.address, true) - ); - await waitForTx( - await mayc.connect(user3.signer).setApprovalForAll(pool.address, true) - ); - await waitForTx( - await pool - .connect(user1.signer) - .supplyERC721( - mayc.address, - [{tokenId: 0, useAsCollateral: true}], - user1.address, - "0" - ) - ); - await waitForTx( - await pool - .connect(user2.signer) - .supplyERC721( - mayc.address, - [{tokenId: 1, useAsCollateral: true}], - user2.address, - "0" - ) - ); - await waitForTx( - await pool - .connect(user3.signer) - .supplyERC721( - mayc.address, - [{tokenId: 2, useAsCollateral: true}], - user3.address, - "0" - ) - ); - - await waitForTx( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: user1Amount, - }, - [{tokenId: 0, amount: user1Amount}], - [], - true - ) - ); - - await waitForTx( - await pool.connect(user2.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: user2Amount, - }, - [{tokenId: 1, amount: user2Amount}], - [], - true - ) - ); - - await waitForTx( - await pool.connect(user3.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: user3Amount, - }, - [{tokenId: 2, amount: user3Amount}], - [], - true - ) - ); - - await advanceTimeAndBlock(3600); - - // repay then supply - await waitForTx( - await pool.connect(user1.signer).setApeCompoundStrategy({ - ty: 0, - swapTokenOut: 0, - swapPercent: 0, - }) - ); - - // repay then supply - await waitForTx( - await pool.connect(user2.signer).setApeCompoundStrategy({ - ty: 0, - swapTokenOut: 0, - swapPercent: 0, - }) - ); - - // swap half then supply - await waitForTx( - await pool.connect(user3.signer).setApeCompoundStrategy({ - ty: 0, - swapTokenOut: 0, - swapPercent: 5000, - }) - ); - const beforeBalance = await ape.balanceOf(user2.address); - - await waitForTx( - await pool - .connect(user2.signer) - .claimApeAndCompound( - mayc.address, - [user1.address, user2.address, user3.address], - [[0], [1], [2]], - 3827874, - 3506149922170000, - {gasLimit: 5000000} - ) - ); - - // 3600 / 7 * 99.7% = 512.74 - const user1Balance = await pCApe.balanceOf(user1.address); - almostEqual(user1Balance, parseEther("512.7428")); - - // 3600 * 2 / 7 * 99.7% = 1025.48 - const user2Balance = await pCApe.balanceOf(user2.address); - almostEqual(user2Balance, parseEther("1025.48")); - - // 3600 * 4 / 7 * 99.7% * 50% = 1025.4857142857142858 - const user3Balance = await pCApe.balanceOf(user3.address); - almostEqual(user3Balance, parseEther("1025.48571")); - - almostEqual( - await pUsdc.balanceOf(user3.address), - await convertToCurrencyDecimals(usdc.address, "4059.235479") - ); - - // 3600 * 0.003 - almostEqual( - (await ape.balanceOf(user2.address)).sub(beforeBalance), - parseEther("10.8") - ); - - await advanceTimeAndBlock(3600); - - await waitForTx( - await pool - .connect(user2.signer) - .claimApeAndCompound( - mayc.address, - [user1.address, user2.address, user3.address], - [[0], [1], [2]], - 3827874, - 3506149922170000, - {gasLimit: 5000000} - ) - ); - }); - - it("claimApeAndCompound function work as expected 2", async () => { - const { - users: [user1, user2], - mayc, - pool, - ape, - } = await loadFixture(fixture); - - await waitForTx( - await mayc.connect(user1.signer)["mint(address)"](user1.address) - ); - await waitForTx( - await mayc.connect(user1.signer)["mint(address)"](user1.address) - ); - await waitForTx( - await mayc.connect(user1.signer)["mint(address)"](user1.address) - ); - await waitForTx( - await mayc.connect(user1.signer).setApprovalForAll(pool.address, true) - ); - await waitForTx( - await pool.connect(user1.signer).supplyERC721( - mayc.address, - [ - {tokenId: 0, useAsCollateral: true}, - {tokenId: 1, useAsCollateral: true}, - {tokenId: 2, useAsCollateral: true}, - ], - user1.address, - "0" - ) - ); - - const totalAmount = parseEther("900"); - const userAmount = parseEther("300"); - await waitForTx( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: totalAmount, - }, - [ - {tokenId: 0, amount: userAmount}, - {tokenId: 1, amount: userAmount}, - {tokenId: 2, amount: userAmount}, - ], - [], - true - ) - ); - - await advanceTimeAndBlock(3600); - - const beforeBalance = await ape.balanceOf(user2.address); - await waitForTx( - await pool - .connect(user2.signer) - .claimApeAndCompound( - mayc.address, - [user1.address], - [[0, 1, 2]], - 3827874, - 3506149922170000, - { - gasLimit: 5000000, - } - ) - ); - - //3600 * 0.997 = 3589.2 - const user1Balance = await pCApe.balanceOf(user1.address); - almostEqual(user1Balance, parseEther("3589.2")); - - // 3600 * 0.003 - almostEqual( - (await ape.balanceOf(user2.address)).sub(beforeBalance), - parseEther("10.8") - ); - - await advanceTimeAndBlock(3600); - - await waitForTx( - await pool - .connect(user2.signer) - .claimApeAndCompound( - mayc.address, - [user1.address], - [[0, 1, 2]], - 3827874, - 3506149922170000, - { - gasLimit: 5000000, - } - ) - ); - }); - - it("claimApeAndCompound function work as expected 3", async () => { - const { - pWETH, - weth, - users: [user1, user2, , , user3], - mayc, - pool, - ape, - } = await loadFixture(fixture); - - await waitForTx( - await mayc.connect(user1.signer)["mint(address)"](user1.address) - ); - await waitForTx( - await mayc.connect(user2.signer)["mint(address)"](user2.address) - ); - await waitForTx( - await mayc.connect(user3.signer)["mint(address)"](user3.address) - ); - await waitForTx( - await mayc.connect(user1.signer).setApprovalForAll(pool.address, true) - ); - await waitForTx( - await mayc.connect(user2.signer).setApprovalForAll(pool.address, true) - ); - await waitForTx( - await mayc.connect(user3.signer).setApprovalForAll(pool.address, true) - ); - await waitForTx( - await pool - .connect(user1.signer) - .supplyERC721( - mayc.address, - [{tokenId: 0, useAsCollateral: true}], - user1.address, - "0" - ) - ); - await waitForTx( - await pool - .connect(user2.signer) - .supplyERC721( - mayc.address, - [{tokenId: 1, useAsCollateral: true}], - user2.address, - "0" - ) - ); - await waitForTx( - await pool - .connect(user3.signer) - .supplyERC721( - mayc.address, - [{tokenId: 2, useAsCollateral: true}], - user3.address, - "0" - ) - ); - - await waitForTx( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: user1Amount, - }, - [{tokenId: 0, amount: user1Amount}], - [], - true - ) - ); - - await waitForTx( - await pool.connect(user2.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: user2Amount, - }, - [{tokenId: 1, amount: user2Amount}], - [], - true - ) - ); - - await waitForTx( - await pool.connect(user3.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: user3Amount, - }, - [{tokenId: 2, amount: user3Amount}], - [], - true - ) - ); - - await advanceTimeAndBlock(3600); - - // repay then supply - await waitForTx( - await pool.connect(user1.signer).setApeCompoundStrategy({ - ty: 0, - swapTokenOut: 0, - swapPercent: 0, - }) - ); - - // repay then supply - await waitForTx( - await pool.connect(user2.signer).setApeCompoundStrategy({ - ty: 0, - swapTokenOut: 0, - swapPercent: 0, - }) - ); - - // swap half then supply - await waitForTx( - await pool.connect(user3.signer).setApeCompoundStrategy({ - ty: 0, - swapTokenOut: 1, - swapPercent: 5000, - }) - ); - - const beforeBalance = await ape.balanceOf(user2.address); - await waitForTx( - await pool - .connect(user2.signer) - .claimApeAndCompound( - mayc.address, - [user1.address, user2.address, user3.address], - [[0], [1], [2]], - 3827874, - 3506149922170000, - {gasLimit: 5000000} - ) - ); - - // 3600 / 7 * 99.7% = 512.74 - const user1Balance = await pCApe.balanceOf(user1.address); - almostEqual(user1Balance, parseEther("512.7428")); - - // 3600 * 2 / 7 * 99.7% = 1025.48 - const user2Balance = await pCApe.balanceOf(user2.address); - almostEqual(user2Balance, parseEther("1025.48")); - - // 3600 * 4 / 7 * 99.7% * 50% = 1025.4857142857142858 - const user3Balance = await pCApe.balanceOf(user3.address); - almostEqual(user3Balance, parseEther("1025.48571")); - - almostEqual( - await pWETH.balanceOf(user3.address), - await convertToCurrencyDecimals(weth.address, "3.732876") - ); - - // 3600 * 0.003 - almostEqual( - (await ape.balanceOf(user2.address)).sub(beforeBalance), - parseEther("10.8") - ); - - await advanceTimeAndBlock(3600); - - await waitForTx( - await pool - .connect(user2.signer) - .claimApeAndCompound( - mayc.address, - [user1.address, user2.address, user3.address], - [[0], [1], [2]], - 3827874, - 3506149922170000, - {gasLimit: 5000000} - ) - ); - }); - - it("claimPairedApeRewardAndCompound function work as expected", async () => { - const { - users: [user1, user2], - mayc, - pool, - ape, - bakc, - } = await loadFixture(fixture); - - await waitForTx( - await mayc.connect(user1.signer)["mint(address)"](user1.address) - ); - await waitForTx( - await mayc.connect(user1.signer)["mint(address)"](user1.address) - ); - await waitForTx( - await mayc.connect(user1.signer)["mint(address)"](user1.address) - ); - await waitForTx( - await bakc.connect(user1.signer)["mint(address)"](user1.address) - ); - await waitForTx( - await bakc.connect(user1.signer)["mint(address)"](user1.address) - ); - await waitForTx( - await bakc.connect(user1.signer)["mint(address)"](user1.address) - ); - await waitForTx( - await mayc.connect(user1.signer).setApprovalForAll(pool.address, true) - ); - await waitForTx( - await bakc.connect(user1.signer).setApprovalForAll(pool.address, true) - ); - await waitForTx( - await pool.connect(user1.signer).supplyERC721( - mayc.address, - [ - {tokenId: 0, useAsCollateral: true}, - {tokenId: 1, useAsCollateral: true}, - {tokenId: 2, useAsCollateral: true}, - ], - user1.address, - "0" - ) - ); - await waitForTx( - await pool.connect(user1.signer).supplyERC721( - bakc.address, - [ - {tokenId: 0, useAsCollateral: true}, - {tokenId: 1, useAsCollateral: true}, - {tokenId: 2, useAsCollateral: true}, - ], - user1.address, - "0" - ) - ); - - const totalAmount = parseEther("900"); - const userAmount = parseEther("300"); - await waitForTx( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: totalAmount, - }, - [], - [ - {mainTokenId: 0, bakcTokenId: 0, amount: userAmount}, - {mainTokenId: 1, bakcTokenId: 1, amount: userAmount}, - {mainTokenId: 2, bakcTokenId: 2, amount: userAmount}, - ], - true - ) - ); - - await advanceTimeAndBlock(3600); - - const beforeBalance = await ape.balanceOf(user2.address); - await waitForTx( - await pool.connect(user2.signer).claimPairedApeAndCompound( - mayc.address, - [user1.address], - [ - [ - {mainTokenId: 0, bakcTokenId: 0}, - {mainTokenId: 1, bakcTokenId: 1}, - {mainTokenId: 2, bakcTokenId: 2}, - ], - ], - 0, - 0 - ) - ); - - //3600 * 0.997 = 3589.2 - const user1Balance = await pCApe.balanceOf(user1.address); - almostEqual(user1Balance, parseEther("3589.2")); - - // 3600 * 0.003 - almostEqual( - (await ape.balanceOf(user2.address)).sub(beforeBalance), - parseEther("10.8") - ); - - await advanceTimeAndBlock(3600); - - await waitForTx( - await pool.connect(user2.signer).claimPairedApeAndCompound( - mayc.address, - [user1.address], - [ - [ - {mainTokenId: 0, bakcTokenId: 0}, - {mainTokenId: 1, bakcTokenId: 1}, - {mainTokenId: 2, bakcTokenId: 2}, - ], - ], - 0, - 0 - ) - ); - }); - it("bufferBalance work as expected", async () => { const { users: [user1, user2], @@ -1077,109 +455,6 @@ describe("Auto Compound Ape Test", () => { almostEqual(await ape.balanceOf(user2.address), user2Amount); }); - it("borrow cape and stake function work as expected: use 100% debt", async () => { - const { - users: [user1, user2], - mayc, - pool, - ape, - } = await loadFixture(fixture); - - await waitForTx( - await cApe.connect(user2.signer).deposit(user2.address, user2Amount) - ); - - await waitForTx( - await cApe.connect(user2.signer).approve(pool.address, user2Amount) - ); - - await waitForTx( - await pool - .connect(user2.signer) - .supply(cApe.address, user2Amount, user2.address, 0) - ); - - almostEqual(await pCApe.balanceOf(user2.address), user2Amount); - - await waitForTx( - await mayc.connect(user1.signer)["mint(address)"](user1.address) - ); - - await waitForTx( - await mayc.connect(user1.signer).setApprovalForAll(pool.address, true) - ); - await waitForTx( - await pool - .connect(user1.signer) - .supplyERC721( - mayc.address, - [{tokenId: 0, useAsCollateral: true}], - user1.address, - "0" - ) - ); - - await waitForTx( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: cApe.address, - borrowAmount: user1Amount, - cashAmount: 0, - }, - [{tokenId: 0, amount: user1Amount}], - [], - true - ) - ); - - const user2pCApeBalance = await pCApe.balanceOf(user2.address); - almostEqual(user2pCApeBalance, user2Amount); - let user1CApeDebtBalance = await variableDebtCAPE.balanceOf(user1.address); - almostEqual(user1CApeDebtBalance, user1Amount); - almostEqual(await pSApeCoin.balanceOf(user1.address), user1Amount); - almostEqual(await pCApe.balanceOf(user2.address), user2Amount); - almostEqual(await cApe.totalSupply(), user2Amount.sub(user1Amount)); - - const hourRewardAmount = parseEther("3600"); - await advanceTimeAndBlock(3600); - await waitForTx(await cApe.connect(user2.signer).harvestAndCompound()); - //this is a edge case here, because Ape single pool only got deposited by user2 - almostEqual( - await pCApe.balanceOf(user2.address), - user2Amount.add(hourRewardAmount.mul(2)) - ); - - user1CApeDebtBalance = await variableDebtCAPE.balanceOf(user1.address); - almostEqual(user1CApeDebtBalance, user1Amount.add(hourRewardAmount)); - - await waitForTx( - await pool - .connect(user1.signer) - .withdrawApeCoin(mayc.address, [{tokenId: 0, amount: user1Amount}]) - ); - const apeBalance = await ape.balanceOf(user1.address); - //user1Amount + borrow user1Amount + hourRewardAmount - almostEqual(apeBalance, user1Amount.mul(2).add(hourRewardAmount)); - - await waitForTx( - await cApe.connect(user1.signer).deposit(user1.address, apeBalance) - ); - - await waitForTx( - await cApe.connect(user1.signer).approve(pool.address, MAX_UINT_AMOUNT) - ); - await waitForTx( - await pool - .connect(user1.signer) - .repay(cApe.address, apeBalance, user1.address) - ); - user1CApeDebtBalance = await variableDebtCAPE.balanceOf(user1.address); - expect(user1CApeDebtBalance).to.be.equal(0); - - almostEqual(await cApe.balanceOf(user1.address), user1Amount); - }); - it("test vote delegation", async () => { const { users: [user1], diff --git a/test/contracts/NFTFloorOracle.t.sol b/test/contracts/NFTFloorOracle.t.sol index f76835337..c2ac7eee5 100644 --- a/test/contracts/NFTFloorOracle.t.sol +++ b/test/contracts/NFTFloorOracle.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.10; +pragma solidity ^0.8.0; import "../../contracts/misc/NFTFloorOracle.sol"; import "ds-test/test.sol"; diff --git a/test/helpers/p2ppairstaking-helper.ts b/test/helpers/p2ppairstaking-helper.ts index 41bb169cf..1784378d0 100644 --- a/test/helpers/p2ppairstaking-helper.ts +++ b/test/helpers/p2ppairstaking-helper.ts @@ -1,10 +1,5 @@ import {DRE} from "../../helpers/misc-utils"; -import { - AutoCompoundApe, - MintableERC20, - MintableERC721, - P2PPairStaking, -} from "../../types"; +import {ParaApeStaking} from "../../types"; import {SignerWithAddress} from "./make-suite"; import {convertSignatureToEIP2098} from "../../helpers/seaport-helpers/encoding"; import {BigNumberish, BytesLike} from "ethers"; @@ -23,9 +18,9 @@ export type ListingOrder = { }; export async function getSignedListingOrder( - p2pPairStaking: P2PPairStaking, + p2pPairStaking: ParaApeStaking, stakingType: number, - listingToken: MintableERC721 | MintableERC20 | AutoCompoundApe, + listingToken: string, tokenId: number, share: number, signer: SignerWithAddress @@ -54,7 +49,7 @@ export async function getSignedListingOrder( const order = { stakingType: stakingType, offerer: signer.address, - token: listingToken.address, + token: listingToken, tokenId: tokenId, share: share, startTime: now - 3600, diff --git a/test/helpers/utils/funds.ts b/test/helpers/utils/funds.ts index 4f1e31193..6a5c0b724 100644 --- a/test/helpers/utils/funds.ts +++ b/test/helpers/utils/funds.ts @@ -1,21 +1,21 @@ -import {BigNumber, Signer} from "ethers"; -import {SelfdestructTransfer__factory} from "../../../types"; +// import {BigNumber, Signer} from "ethers"; +// import {SelfdestructTransfer__factory} from "../../../types"; -export const topUpNonPayableWithEther = async ( - holder: Signer, - accounts: string[], - amount: BigNumber -) => { - let selfdestructContract; - const factory = new SelfdestructTransfer__factory(holder); - for (const account of accounts) { - selfdestructContract = await factory.deploy(); - await selfdestructContract.deployed(); - await selfdestructContract.destroyAndTransfer(account, { - value: amount, - }); - } -}; +// export const topUpNonPayableWithEther = async ( +// holder: Signer, +// accounts: string[], +// amount: BigNumber +// ) => { +// let selfdestructContract; +// const factory = new SelfdestructTransfer__factory(holder); +// for (const account of accounts) { +// selfdestructContract = await factory.deploy(); +// await selfdestructContract.deployed(); +// await selfdestructContract.destroyAndTransfer(account, { +// value: amount, +// }); +// } +// }; // const topUpWalletsWithEther = async ( // holder: JsonRpcSigner, diff --git a/test/p2p_pair_staking.spec.ts b/test/p2p_pair_staking.spec.ts index 846727781..748ee7484 100644 --- a/test/p2p_pair_staking.spec.ts +++ b/test/p2p_pair_staking.spec.ts @@ -1,38 +1,47 @@ import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; import {expect} from "chai"; -import {AutoCompoundApe, P2PPairStaking} from "../types"; +import {AutoCompoundApe, ParaApeStaking} from "../types"; import {TestEnv} from "./helpers/make-suite"; import {testEnvFixture} from "./helpers/setup-env"; -import {mintAndValidate, supplyAndValidate} from "./helpers/validated-steps"; +import { + changePriceAndValidate, + changeSApePriceAndValidate, + mintAndValidate, + supplyAndValidate, +} from "./helpers/validated-steps"; import { getAutoCompoundApe, - getInitializableAdminUpgradeabilityProxy, - getP2PPairStaking, + getParaApeStaking, } from "../helpers/contracts-getters"; -import {MAX_UINT_AMOUNT} from "../helpers/constants"; +import {MAX_UINT_AMOUNT, ONE_ADDRESS} from "../helpers/constants"; import {advanceTimeAndBlock, waitForTx} from "../helpers/misc-utils"; import {getSignedListingOrder} from "./helpers/p2ppairstaking-helper"; import {parseEther} from "ethers/lib/utils"; import {almostEqual} from "./helpers/uniswapv3-helper"; -import {deployP2PPairStakingImpl} from "../helpers/contracts-deployments"; -import {GLOBAL_OVERRIDES} from "../helpers/hardhat-constants"; import {ProtocolErrors} from "../helpers/types"; describe("P2P Pair Staking Test", () => { let testEnv: TestEnv; - let p2pPairStaking: P2PPairStaking; + let paraApeStaking: ParaApeStaking; let cApe: AutoCompoundApe; let MINIMUM_LIQUIDITY; const fixture = async () => { testEnv = await loadFixture(testEnvFixture); - const {ape, users, apeCoinStaking, poolAdmin} = testEnv; + const { + ape, + users: [user1, user2, , user4, , user6], + apeCoinStaking, + poolAdmin, + } = testEnv; - const user1 = users[0]; - const user2 = users[1]; - const user4 = users[5]; + paraApeStaking = await getParaApeStaking(); - p2pPairStaking = await getP2PPairStaking(); + await waitForTx( + await paraApeStaking + .connect(poolAdmin.signer) + .setApeStakingBot(user4.address) + ); cApe = await getAutoCompoundApe(); MINIMUM_LIQUIDITY = await cApe.MINIMUM_LIQUIDITY(); @@ -48,27 +57,21 @@ describe("P2P Pair Staking Test", () => { ); // user4 deposit MINIMUM_LIQUIDITY to make test case easy - await mintAndValidate(ape, "1", user4); + await mintAndValidate(ape, "1", user6); await waitForTx( - await ape.connect(user4.signer).approve(cApe.address, MAX_UINT_AMOUNT) + await ape.connect(user6.signer).approve(cApe.address, MAX_UINT_AMOUNT) ); await waitForTx( - await cApe.connect(user4.signer).deposit(user4.address, MINIMUM_LIQUIDITY) + await cApe.connect(user6.signer).deposit(user6.address, MINIMUM_LIQUIDITY) ); + //user2 deposit free sApe await waitForTx( - await ape.connect(user2.signer).approve(cApe.address, MAX_UINT_AMOUNT) - ); - await waitForTx( - await cApe + await ape .connect(user2.signer) - .approve(p2pPairStaking.address, MAX_UINT_AMOUNT) - ); - await waitForTx( - await p2pPairStaking - .connect(poolAdmin.signer) - .setCompoundBot(user1.address) + .approve(paraApeStaking.address, MAX_UINT_AMOUNT) ); + await mintAndValidate(ape, "1000000", user2); return testEnv; }; @@ -82,59 +85,68 @@ describe("P2P Pair Staking Test", () => { } = await loadFixture(fixture); await supplyAndValidate(bayc, "1", user1, true); - await mintAndValidate(ape, "1000000", user2); - const apeAmount = await p2pPairStaking.getApeCoinStakingCap(0); + const apeAmount = await paraApeStaking.getApeCoinStakingCap(0); await waitForTx( - await cApe.connect(user2.signer).deposit(user2.address, apeAmount) + await paraApeStaking + .connect(user2.signer) + .depositFreeSApe(ape.address, apeAmount) ); const user1SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 0, - bayc, + bayc.address, 0, 2000, user1 ); const user2SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 0, - cApe, + ONE_ADDRESS, 0, 8000, user2 ); const txReceipt = await waitForTx( - await p2pPairStaking + await paraApeStaking .connect(user1.signer) .matchPairStakingList(user1SignedOrder, user2SignedOrder) ); const logLength = txReceipt.logs.length; const orderHash = txReceipt.logs[logLength - 1].data; + expect(await paraApeStaking.freeSApeBalance(user2.address)).to.be.closeTo( + "0", + parseEther("1") + ); + expect(await paraApeStaking.stakedSApeBalance(user2.address)).to.be.equal( + apeAmount + ); + await advanceTimeAndBlock(parseInt("3600")); await waitForTx( - await p2pPairStaking + await paraApeStaking .connect(user1.signer) .claimForMatchedOrderAndCompound([orderHash]) ); almostEqual( - await p2pPairStaking.pendingCApeReward(user1.address), + await paraApeStaking.pendingCApeReward(user1.address), parseEther("720") ); almostEqual( - await p2pPairStaking.pendingCApeReward(user2.address), + await paraApeStaking.pendingCApeReward(user2.address), parseEther("2880") ); await waitForTx( - await p2pPairStaking.connect(user1.signer).claimCApeReward(user1.address) + await paraApeStaking.connect(user1.signer).claimCApeReward(user1.address) ); await waitForTx( - await p2pPairStaking.connect(user2.signer).claimCApeReward(user2.address) + await paraApeStaking.connect(user2.signer).claimCApeReward(user2.address) ); almostEqual(await cApe.balanceOf(user1.address), parseEther("720")); @@ -148,17 +160,24 @@ describe("P2P Pair Staking Test", () => { await advanceTimeAndBlock(parseInt("3600")); await waitForTx( - await p2pPairStaking.connect(user1.signer).breakUpMatchedOrder(orderHash) + await paraApeStaking.connect(user1.signer).breakUpMatchedOrder(orderHash) ); expect(await bayc.balanceOf(nBAYC.address)).to.be.equal(1); - almostEqual(await cApe.balanceOf(user2.address), apeAmount); + expect(await paraApeStaking.freeSApeBalance(user2.address)).to.be.closeTo( + apeAmount, + parseEther("1") + ); + expect(await paraApeStaking.stakedSApeBalance(user2.address)).to.be.equal( + "0" + ); + almostEqual( - await p2pPairStaking.pendingCApeReward(user1.address), + await paraApeStaking.pendingCApeReward(user1.address), parseEther("720") ); almostEqual( - await p2pPairStaking.pendingCApeReward(user2.address), + await paraApeStaking.pendingCApeReward(user2.address), parseEther("2880") ); }); @@ -172,65 +191,68 @@ describe("P2P Pair Staking Test", () => { } = await loadFixture(fixture); await supplyAndValidate(mayc, "1", user1, true); - await mintAndValidate(ape, "1000000", user2); - - await waitForTx( - await mayc - .connect(user1.signer) - .setApprovalForAll(p2pPairStaking.address, true) - ); - const apeAmount = await p2pPairStaking.getApeCoinStakingCap(1); + const apeAmount = await paraApeStaking.getApeCoinStakingCap(1); await waitForTx( - await cApe.connect(user2.signer).deposit(user2.address, apeAmount) + await paraApeStaking + .connect(user2.signer) + .depositFreeSApe(ape.address, apeAmount) ); const user1SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 1, - mayc, + mayc.address, 0, 2000, user1 ); const user2SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 1, - cApe, + ONE_ADDRESS, 0, 8000, user2 ); const txReceipt = await waitForTx( - await p2pPairStaking + await paraApeStaking .connect(user1.signer) .matchPairStakingList(user1SignedOrder, user2SignedOrder) ); const logLength = txReceipt.logs.length; const orderHash = txReceipt.logs[logLength - 1].data; + expect(await paraApeStaking.freeSApeBalance(user2.address)).to.be.closeTo( + "0", + parseEther("1") + ); + expect(await paraApeStaking.stakedSApeBalance(user2.address)).to.be.equal( + apeAmount + ); + await advanceTimeAndBlock(parseInt("3600")); await waitForTx( - await p2pPairStaking + await paraApeStaking .connect(user1.signer) .claimForMatchedOrderAndCompound([orderHash]) ); almostEqual( - await p2pPairStaking.pendingCApeReward(user1.address), + await paraApeStaking.pendingCApeReward(user1.address), parseEther("720") ); almostEqual( - await p2pPairStaking.pendingCApeReward(user2.address), + await paraApeStaking.pendingCApeReward(user2.address), parseEther("2880") ); await waitForTx( - await p2pPairStaking.connect(user1.signer).claimCApeReward(user1.address) + await paraApeStaking.connect(user1.signer).claimCApeReward(user1.address) ); await waitForTx( - await p2pPairStaking.connect(user2.signer).claimCApeReward(user2.address) + await paraApeStaking.connect(user2.signer).claimCApeReward(user2.address) ); almostEqual(await cApe.balanceOf(user1.address), parseEther("720")); @@ -244,17 +266,24 @@ describe("P2P Pair Staking Test", () => { await advanceTimeAndBlock(parseInt("3600")); await waitForTx( - await p2pPairStaking.connect(user1.signer).breakUpMatchedOrder(orderHash) + await paraApeStaking.connect(user1.signer).breakUpMatchedOrder(orderHash) ); expect(await mayc.balanceOf(nMAYC.address)).to.be.equal(1); - almostEqual(await cApe.balanceOf(user2.address), apeAmount); + expect(await paraApeStaking.freeSApeBalance(user2.address)).to.be.closeTo( + apeAmount, + parseEther("1") + ); + expect(await paraApeStaking.stakedSApeBalance(user2.address)).to.be.equal( + "0" + ); + almostEqual( - await p2pPairStaking.pendingCApeReward(user1.address), + await paraApeStaking.pendingCApeReward(user1.address), parseEther("720") ); almostEqual( - await p2pPairStaking.pendingCApeReward(user2.address), + await paraApeStaking.pendingCApeReward(user2.address), parseEther("2880") ); }); @@ -271,51 +300,41 @@ describe("P2P Pair Staking Test", () => { await supplyAndValidate(bayc, "1", user1, true); await supplyAndValidate(bakc, "1", user3, true); - await mintAndValidate(ape, "1000000", user2); - - await waitForTx( - await bayc - .connect(user1.signer) - .setApprovalForAll(p2pPairStaking.address, true) - ); - await waitForTx( - await bakc - .connect(user3.signer) - .setApprovalForAll(p2pPairStaking.address, true) - ); - const apeAmount = await p2pPairStaking.getApeCoinStakingCap(2); + const apeAmount = await paraApeStaking.getApeCoinStakingCap(2); await waitForTx( - await cApe.connect(user2.signer).deposit(user2.address, apeAmount) + await paraApeStaking + .connect(user2.signer) + .depositFreeSApe(ape.address, apeAmount) ); const user1SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 2, - bayc, + bayc.address, 0, 2000, user1 ); const user3SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 2, - bakc, + bakc.address, 0, 2000, user3 ); const user2SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 2, - cApe, + ONE_ADDRESS, 0, 6000, user2 ); const txReceipt = await waitForTx( - await p2pPairStaking + await paraApeStaking .connect(user1.signer) .matchBAKCPairStakingList( user1SignedOrder, @@ -327,34 +346,42 @@ describe("P2P Pair Staking Test", () => { const logLength = txReceipt.logs.length; const orderHash = txReceipt.logs[logLength - 1].data; + expect(await paraApeStaking.freeSApeBalance(user2.address)).to.be.closeTo( + "0", + parseEther("1") + ); + expect(await paraApeStaking.stakedSApeBalance(user2.address)).to.be.equal( + apeAmount + ); + await advanceTimeAndBlock(parseInt("3600")); await waitForTx( - await p2pPairStaking + await paraApeStaking .connect(user1.signer) .claimForMatchedOrderAndCompound([orderHash]) ); almostEqual( - await p2pPairStaking.pendingCApeReward(user1.address), + await paraApeStaking.pendingCApeReward(user1.address), parseEther("720") ); almostEqual( - await p2pPairStaking.pendingCApeReward(user3.address), + await paraApeStaking.pendingCApeReward(user3.address), parseEther("720") ); almostEqual( - await p2pPairStaking.pendingCApeReward(user2.address), + await paraApeStaking.pendingCApeReward(user2.address), parseEther("2160") ); await waitForTx( - await p2pPairStaking.connect(user1.signer).claimCApeReward(user1.address) + await paraApeStaking.connect(user1.signer).claimCApeReward(user1.address) ); await waitForTx( - await p2pPairStaking.connect(user2.signer).claimCApeReward(user2.address) + await paraApeStaking.connect(user2.signer).claimCApeReward(user2.address) ); await waitForTx( - await p2pPairStaking.connect(user3.signer).claimCApeReward(user3.address) + await paraApeStaking.connect(user3.signer).claimCApeReward(user3.address) ); almostEqual(await cApe.balanceOf(user1.address), parseEther("720")); @@ -369,23 +396,29 @@ describe("P2P Pair Staking Test", () => { await advanceTimeAndBlock(parseInt("3600")); await waitForTx( - await p2pPairStaking.connect(user1.signer).breakUpMatchedOrder(orderHash) + await paraApeStaking.connect(user1.signer).breakUpMatchedOrder(orderHash) ); expect(await bayc.balanceOf(nBAYC.address)).to.be.equal(1); expect(await bakc.balanceOf(nBAKC.address)).to.be.equal(1); - almostEqual(await cApe.balanceOf(user2.address), apeAmount); + expect(await paraApeStaking.freeSApeBalance(user2.address)).to.be.closeTo( + apeAmount, + parseEther("1") + ); + expect(await paraApeStaking.stakedSApeBalance(user2.address)).to.be.equal( + "0" + ); almostEqual( - await p2pPairStaking.pendingCApeReward(user1.address), + await paraApeStaking.pendingCApeReward(user1.address), parseEther("720") ); almostEqual( - await p2pPairStaking.pendingCApeReward(user3.address), + await paraApeStaking.pendingCApeReward(user3.address), parseEther("720") ); almostEqual( - await p2pPairStaking.pendingCApeReward(user2.address), + await paraApeStaking.pendingCApeReward(user2.address), parseEther("2160") ); }); @@ -402,40 +435,41 @@ describe("P2P Pair Staking Test", () => { await supplyAndValidate(mayc, "1", user1, true); await supplyAndValidate(bakc, "1", user3, true); - await mintAndValidate(ape, "1000000", user2); - const apeAmount = await p2pPairStaking.getApeCoinStakingCap(2); + const apeAmount = await paraApeStaking.getApeCoinStakingCap(2); await waitForTx( - await cApe.connect(user2.signer).deposit(user2.address, apeAmount) + await paraApeStaking + .connect(user2.signer) + .depositFreeSApe(ape.address, apeAmount) ); const user1SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 2, - mayc, + mayc.address, 0, 2000, user1 ); const user3SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 2, - bakc, + bakc.address, 0, 2000, user3 ); const user2SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 2, - cApe, + ONE_ADDRESS, 0, 6000, user2 ); const txReceipt = await waitForTx( - await p2pPairStaking + await paraApeStaking .connect(user1.signer) .matchBAKCPairStakingList( user1SignedOrder, @@ -447,34 +481,42 @@ describe("P2P Pair Staking Test", () => { const logLength = txReceipt.logs.length; const orderHash = txReceipt.logs[logLength - 1].data; + expect(await paraApeStaking.freeSApeBalance(user2.address)).to.be.closeTo( + "0", + parseEther("1") + ); + expect(await paraApeStaking.stakedSApeBalance(user2.address)).to.be.equal( + apeAmount + ); + await advanceTimeAndBlock(parseInt("3600")); await waitForTx( - await p2pPairStaking + await paraApeStaking .connect(user1.signer) .claimForMatchedOrderAndCompound([orderHash]) ); almostEqual( - await p2pPairStaking.pendingCApeReward(user1.address), + await paraApeStaking.pendingCApeReward(user1.address), parseEther("720") ); almostEqual( - await p2pPairStaking.pendingCApeReward(user3.address), + await paraApeStaking.pendingCApeReward(user3.address), parseEther("720") ); almostEqual( - await p2pPairStaking.pendingCApeReward(user2.address), + await paraApeStaking.pendingCApeReward(user2.address), parseEther("2160") ); await waitForTx( - await p2pPairStaking.connect(user1.signer).claimCApeReward(user1.address) + await paraApeStaking.connect(user1.signer).claimCApeReward(user1.address) ); await waitForTx( - await p2pPairStaking.connect(user2.signer).claimCApeReward(user2.address) + await paraApeStaking.connect(user2.signer).claimCApeReward(user2.address) ); await waitForTx( - await p2pPairStaking.connect(user3.signer).claimCApeReward(user3.address) + await paraApeStaking.connect(user3.signer).claimCApeReward(user3.address) ); almostEqual(await cApe.balanceOf(user1.address), parseEther("720")); @@ -489,22 +531,29 @@ describe("P2P Pair Staking Test", () => { await advanceTimeAndBlock(parseInt("3600")); await waitForTx( - await p2pPairStaking.connect(user1.signer).breakUpMatchedOrder(orderHash) + await paraApeStaking.connect(user1.signer).breakUpMatchedOrder(orderHash) ); expect(await mayc.balanceOf(nMAYC.address)).to.be.equal(1); expect(await bakc.balanceOf(nBAKC.address)).to.be.equal(1); - almostEqual(await cApe.balanceOf(user2.address), apeAmount); + expect(await paraApeStaking.freeSApeBalance(user2.address)).to.be.closeTo( + apeAmount, + parseEther("1") + ); + expect(await paraApeStaking.stakedSApeBalance(user2.address)).to.be.equal( + "0" + ); + almostEqual( - await p2pPairStaking.pendingCApeReward(user1.address), + await paraApeStaking.pendingCApeReward(user1.address), parseEther("720") ); almostEqual( - await p2pPairStaking.pendingCApeReward(user3.address), + await paraApeStaking.pendingCApeReward(user3.address), parseEther("720") ); almostEqual( - await p2pPairStaking.pendingCApeReward(user2.address), + await paraApeStaking.pendingCApeReward(user2.address), parseEther("2160") ); }); @@ -519,53 +568,41 @@ describe("P2P Pair Staking Test", () => { await supplyAndValidate(bayc, "10", user1, true); await supplyAndValidate(bakc, "10", user3, true); - await mintAndValidate(ape, "10000000", user2); - - await waitForTx( - await bayc - .connect(user1.signer) - .setApprovalForAll(p2pPairStaking.address, true) - ); - await waitForTx( - await bakc - .connect(user3.signer) - .setApprovalForAll(p2pPairStaking.address, true) - ); await waitForTx( - await cApe + await paraApeStaking .connect(user2.signer) - .deposit(user2.address, parseEther("1000000")) + .depositFreeSApe(ape.address, parseEther("1000000")) ); const txArray: string[] = []; for (let i = 0; i < 10; i++) { const user1SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 2, - bayc, + bayc.address, i, 2000, user1 ); const user3SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 2, - bakc, + bakc.address, i, 2000, user3 ); const user2SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 2, - cApe, + ONE_ADDRESS, 0, 6000, user2 ); const txReceipt = await waitForTx( - await p2pPairStaking + await paraApeStaking .connect(user1.signer) .matchBAKCPairStakingList( user1SignedOrder, @@ -583,7 +620,7 @@ describe("P2P Pair Staking Test", () => { await advanceTimeAndBlock(parseInt("3600")); await waitForTx( - await p2pPairStaking + await paraApeStaking .connect(user1.signer) .claimForMatchedOrderAndCompound(txArray) ); @@ -598,45 +635,39 @@ describe("P2P Pair Staking Test", () => { } = await loadFixture(fixture); await supplyAndValidate(bayc, "1", user1, true); - await mintAndValidate(ape, "1000000", user2); - - await waitForTx( - await bayc - .connect(user1.signer) - .setApprovalForAll(p2pPairStaking.address, true) - ); + const apeAmount = await paraApeStaking.getApeCoinStakingCap(0); await waitForTx( - await ape + await paraApeStaking .connect(user2.signer) - .approve(p2pPairStaking.address, MAX_UINT_AMOUNT) + .depositFreeSApe(ape.address, apeAmount) ); const user1SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 0, - bayc, + bayc.address, 0, 2000, user1 ); const user2SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 0, - ape, + ONE_ADDRESS, 0, 8000, user2 ); await waitForTx( - await p2pPairStaking.connect(user2.signer).cancelListing(user2SignedOrder) + await paraApeStaking.connect(user2.signer).cancelListing(user2SignedOrder) ); await expect( - p2pPairStaking + paraApeStaking .connect(user1.signer) .matchPairStakingList(user1SignedOrder, user2SignedOrder) - ).to.be.revertedWith("order already cancelled"); + ).to.be.revertedWith(ProtocolErrors.INVALID_ORDER_STATUS); }); it("match failed when order was canceled 1", async () => { @@ -649,62 +680,51 @@ describe("P2P Pair Staking Test", () => { await supplyAndValidate(bayc, "1", user1, true); await supplyAndValidate(bakc, "1", user2, true); - await mintAndValidate(ape, "1000000", user3); - - await waitForTx( - await bayc - .connect(user1.signer) - .setApprovalForAll(p2pPairStaking.address, true) - ); + const apeAmount = await paraApeStaking.getApeCoinStakingCap(2); await waitForTx( - await bakc + await paraApeStaking .connect(user2.signer) - .setApprovalForAll(p2pPairStaking.address, true) - ); - await waitForTx( - await ape - .connect(user3.signer) - .approve(p2pPairStaking.address, MAX_UINT_AMOUNT) + .depositFreeSApe(ape.address, apeAmount) ); const user1SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 2, - bayc, + bayc.address, 0, 2000, user1 ); const user2SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 2, - bakc, + bakc.address, 0, 2000, user2 ); const user3SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 2, - ape, + ONE_ADDRESS, 0, 6000, user3 ); await waitForTx( - await p2pPairStaking.connect(user3.signer).cancelListing(user3SignedOrder) + await paraApeStaking.connect(user3.signer).cancelListing(user3SignedOrder) ); await expect( - p2pPairStaking + paraApeStaking .connect(user1.signer) .matchBAKCPairStakingList( user1SignedOrder, user2SignedOrder, user3SignedOrder ) - ).to.be.revertedWith("order already cancelled"); + ).to.be.revertedWith(ProtocolErrors.INVALID_ORDER_STATUS); }); it("match failed when orders type match failed 0", async () => { @@ -715,40 +735,35 @@ describe("P2P Pair Staking Test", () => { } = await loadFixture(fixture); await supplyAndValidate(bayc, "1", user1, true); - await mintAndValidate(ape, "1000000", user2); - - await waitForTx( - await bayc - .connect(user1.signer) - .setApprovalForAll(p2pPairStaking.address, true) - ); - const apeAmount = await p2pPairStaking.getApeCoinStakingCap(0); + const apeAmount = await paraApeStaking.getApeCoinStakingCap(0); await waitForTx( - await cApe.connect(user2.signer).deposit(user2.address, apeAmount) + await paraApeStaking + .connect(user2.signer) + .depositFreeSApe(ape.address, apeAmount) ); const user1SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 0, - bayc, + bayc.address, 0, 2000, user1 ); const user2SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 1, - cApe, + ONE_ADDRESS, 0, 8000, user2 ); await expect( - p2pPairStaking + paraApeStaking .connect(user1.signer) .matchPairStakingList(user1SignedOrder, user2SignedOrder) - ).to.be.revertedWith("orders type match failed"); + ).to.be.revertedWith(ProtocolErrors.ORDER_TYPE_MATCH_FAILED); }); it("match failed when orders type match failed 1", async () => { @@ -761,58 +776,47 @@ describe("P2P Pair Staking Test", () => { await supplyAndValidate(bayc, "1", user1, true); await supplyAndValidate(bakc, "1", user3, true); - await mintAndValidate(ape, "1000000", user2); - + const apeAmount = await paraApeStaking.getApeCoinStakingCap(2); await waitForTx( - await bayc - .connect(user1.signer) - .setApprovalForAll(p2pPairStaking.address, true) - ); - await waitForTx( - await bakc - .connect(user3.signer) - .setApprovalForAll(p2pPairStaking.address, true) - ); - - const apeAmount = await p2pPairStaking.getApeCoinStakingCap(2); - await waitForTx( - await cApe.connect(user2.signer).deposit(user2.address, apeAmount) + await paraApeStaking + .connect(user2.signer) + .depositFreeSApe(ape.address, apeAmount) ); const user1SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 2, - bayc, + bayc.address, 0, 2000, user1 ); const user3SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 1, - bakc, + bakc.address, 0, 2000, user3 ); const user2SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 2, - cApe, + ONE_ADDRESS, 0, 6000, user2 ); await expect( - p2pPairStaking + paraApeStaking .connect(user1.signer) .matchBAKCPairStakingList( user1SignedOrder, user3SignedOrder, user2SignedOrder ) - ).to.be.revertedWith("orders type match failed"); + ).to.be.revertedWith(ProtocolErrors.ORDER_TYPE_MATCH_FAILED); }); it("match failed when share match failed 0", async () => { @@ -823,40 +827,35 @@ describe("P2P Pair Staking Test", () => { } = await loadFixture(fixture); await supplyAndValidate(bayc, "1", user1, true); - await mintAndValidate(ape, "1000000", user2); - - await waitForTx( - await bayc - .connect(user1.signer) - .setApprovalForAll(p2pPairStaking.address, true) - ); - const apeAmount = await p2pPairStaking.getApeCoinStakingCap(0); + const apeAmount = await paraApeStaking.getApeCoinStakingCap(0); await waitForTx( - await cApe.connect(user2.signer).deposit(user2.address, apeAmount) + await paraApeStaking + .connect(user2.signer) + .depositFreeSApe(ape.address, apeAmount) ); const user1SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 0, - bayc, + bayc.address, 0, 2000, user1 ); const user2SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 0, - cApe, + ONE_ADDRESS, 0, 7000, user2 ); await expect( - p2pPairStaking + paraApeStaking .connect(user1.signer) .matchPairStakingList(user1SignedOrder, user2SignedOrder) - ).to.be.revertedWith("share match failed"); + ).to.be.revertedWith(ProtocolErrors.ORDER_SHARE_MATCH_FAILED); }); it("match failed when share match failed 1", async () => { @@ -869,58 +868,47 @@ describe("P2P Pair Staking Test", () => { await supplyAndValidate(bayc, "1", user1, true); await supplyAndValidate(bakc, "1", user3, true); - await mintAndValidate(ape, "1000000", user2); - - await waitForTx( - await bayc - .connect(user1.signer) - .setApprovalForAll(p2pPairStaking.address, true) - ); - await waitForTx( - await bakc - .connect(user3.signer) - .setApprovalForAll(p2pPairStaking.address, true) - ); - - const apeAmount = await p2pPairStaking.getApeCoinStakingCap(2); + const apeAmount = await paraApeStaking.getApeCoinStakingCap(2); await waitForTx( - await cApe.connect(user2.signer).deposit(user2.address, apeAmount) + await paraApeStaking + .connect(user2.signer) + .depositFreeSApe(ape.address, apeAmount) ); const user1SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 2, - bayc, + bayc.address, 0, 2000, user1 ); const user3SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 2, - bakc, + bakc.address, 0, 2000, user3 ); const user2SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 2, - cApe, + ONE_ADDRESS, 0, 7000, user2 ); await expect( - p2pPairStaking + paraApeStaking .connect(user1.signer) .matchBAKCPairStakingList( user1SignedOrder, user3SignedOrder, user2SignedOrder ) - ).to.be.revertedWith("share match failed"); + ).to.be.revertedWith(ProtocolErrors.ORDER_SHARE_MATCH_FAILED); }); it("listing order can only be canceled by offerer", async () => { @@ -930,84 +918,62 @@ describe("P2P Pair Staking Test", () => { } = await loadFixture(fixture); const user1SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 0, - bayc, + bayc.address, 0, 2000, user1 ); await expect( - p2pPairStaking.connect(user2.signer).cancelListing(user1SignedOrder) - ).to.be.revertedWith("not order offerer"); + paraApeStaking.connect(user2.signer).cancelListing(user1SignedOrder) + ).to.be.revertedWith(ProtocolErrors.NOT_ORDER_OFFERER); await waitForTx( - await p2pPairStaking.connect(user1.signer).cancelListing(user1SignedOrder) + await paraApeStaking.connect(user1.signer).cancelListing(user1SignedOrder) ); }); it("compound fee work as expected", async () => { const { - users: [user1, user2, user3, , user5], - poolAdmin, + users: [user1, user2], bayc, ape, + poolAdmin, } = await loadFixture(fixture); - const p2pPairStakingImpl = await deployP2PPairStakingImpl(50); - const p2pPairStaking = await getP2PPairStaking(); - const p2pPairStakingProxy = await getInitializableAdminUpgradeabilityProxy( - p2pPairStaking.address - ); await waitForTx( - await p2pPairStakingProxy - .connect(user5.signer) - .upgradeTo(p2pPairStakingImpl.address, GLOBAL_OVERRIDES) + await paraApeStaking.connect(poolAdmin.signer).setCompoundFee(50) ); - await supplyAndValidate(bayc, "1", user3, true); - await mintAndValidate(ape, "1000000", user2); - - //deposit cApe for user3 to let exchangeRate > 1 - await waitForTx( - await ape.connect(user2.signer).approve(cApe.address, MAX_UINT_AMOUNT) - ); + await supplyAndValidate(bayc, "1", user1, true); + const apeAmount = await paraApeStaking.getApeCoinStakingCap(0); await waitForTx( - await cApe + await paraApeStaking .connect(user2.signer) - .deposit(user2.address, parseEther("1000")) - ); - - await waitForTx( - await bayc - .connect(user3.signer) - .setApprovalForAll(p2pPairStaking.address, true) - ); - const apeAmount = await p2pPairStaking.getApeCoinStakingCap(0); - await waitForTx( - await cApe.connect(user2.signer).deposit(user2.address, apeAmount) + .depositFreeSApe(ape.address, apeAmount) ); const user1SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 0, - bayc, + bayc.address, 0, 2000, - user3 + user1 ); const user2SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 0, - cApe, + ONE_ADDRESS, 0, 8000, user2 ); const txReceipt = await waitForTx( - await p2pPairStaking + await paraApeStaking .connect(user1.signer) .matchPairStakingList(user1SignedOrder, user2SignedOrder) ); @@ -1017,22 +983,24 @@ describe("P2P Pair Staking Test", () => { await advanceTimeAndBlock(parseInt("3600")); await waitForTx( - await p2pPairStaking + await paraApeStaking .connect(user1.signer) .claimForMatchedOrderAndCompound([orderHash]) ); - almostEqual(await ape.balanceOf(user1.address), parseEther("18")); almostEqual( - await p2pPairStaking.pendingCApeReward(user3.address), + await paraApeStaking.pendingCApeReward(user1.address), parseEther("716.4") ); almostEqual( - await p2pPairStaking.pendingCApeReward(user2.address), + await paraApeStaking.pendingCApeReward(user2.address), parseEther("2865.6") ); - almostEqual(await ape.balanceOf(user1.address), parseEther("18")); + almostEqual( + await paraApeStaking.pendingCApeReward(paraApeStaking.address), + parseEther("18") + ); }); it("check ape token can be matched twice", async () => { @@ -1045,44 +1013,33 @@ describe("P2P Pair Staking Test", () => { await supplyAndValidate(bayc, "1", user1, true); await supplyAndValidate(bakc, "1", user3, true); - await mintAndValidate(ape, "1000000", user2); await waitForTx( - await bayc - .connect(user1.signer) - .setApprovalForAll(p2pPairStaking.address, true) - ); - await waitForTx( - await bakc - .connect(user3.signer) - .setApprovalForAll(p2pPairStaking.address, true) - ); - await waitForTx( - await cApe + await paraApeStaking .connect(user2.signer) - .deposit(user2.address, parseEther("500000")) + .depositFreeSApe(ape.address, parseEther("1000000")) ); //match bayc + ApeCoin let user1SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 0, - bayc, + bayc.address, 0, 2000, user1 ); let user2SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 0, - cApe, + ONE_ADDRESS, 0, 8000, user2 ); let txReceipt = await waitForTx( - await p2pPairStaking + await paraApeStaking .connect(user1.signer) .matchPairStakingList(user1SignedOrder, user2SignedOrder) ); @@ -1091,32 +1048,32 @@ describe("P2P Pair Staking Test", () => { //match bayc + bakc + ApeCoin user1SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 2, - bayc, + bayc.address, 0, 2000, user1 ); const user3SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 2, - bakc, + bakc.address, 0, 2000, user3 ); user2SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 2, - cApe, + ONE_ADDRESS, 0, 6000, user2 ); txReceipt = await waitForTx( - await p2pPairStaking + await paraApeStaking .connect(user1.signer) .matchBAKCPairStakingList( user1SignedOrder, @@ -1128,11 +1085,11 @@ describe("P2P Pair Staking Test", () => { const orderHash1 = txReceipt.logs[logLength - 1].data; await waitForTx( - await p2pPairStaking.connect(user1.signer).breakUpMatchedOrder(orderHash0) + await paraApeStaking.connect(user1.signer).breakUpMatchedOrder(orderHash0) ); await waitForTx( - await p2pPairStaking.connect(user1.signer).breakUpMatchedOrder(orderHash1) + await paraApeStaking.connect(user1.signer).breakUpMatchedOrder(orderHash1) ); }); @@ -1144,46 +1101,40 @@ describe("P2P Pair Staking Test", () => { } = await loadFixture(fixture); await supplyAndValidate(bayc, "2", user1, true); - await mintAndValidate(ape, "1000000", user2); - + const apeAmount = await paraApeStaking.getApeCoinStakingCap(0); await waitForTx( - await bayc - .connect(user1.signer) - .setApprovalForAll(p2pPairStaking.address, true) - ); - await waitForTx( - await cApe + await paraApeStaking .connect(user2.signer) - .deposit(user2.address, parseEther("500000")) + .depositFreeSApe(ape.address, apeAmount) ); const user1SignedOrder0 = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 0, - bayc, + bayc.address, 0, 2000, user1 ); const user1SignedOrder1 = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 0, - bayc, + bayc.address, 1, 2000, user1 ); const user2SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 0, - cApe, + ONE_ADDRESS, 0, 8000, user2 ); const txReceipt = await waitForTx( - await p2pPairStaking + await paraApeStaking .connect(user1.signer) .matchPairStakingList(user1SignedOrder0, user2SignedOrder) ); @@ -1191,17 +1142,17 @@ describe("P2P Pair Staking Test", () => { const orderHash0 = txReceipt.logs[logLength - 1].data; await expect( - p2pPairStaking + paraApeStaking .connect(user1.signer) .matchPairStakingList(user1SignedOrder1, user2SignedOrder) - ).to.be.revertedWith("ape coin order already matched"); + ).to.be.revertedWith(ProtocolErrors.INVALID_ORDER_STATUS); await waitForTx( - await p2pPairStaking.connect(user1.signer).breakUpMatchedOrder(orderHash0) + await paraApeStaking.connect(user1.signer).breakUpMatchedOrder(orderHash0) ); await waitForTx( - await p2pPairStaking + await paraApeStaking .connect(user1.signer) .matchPairStakingList(user1SignedOrder1, user2SignedOrder) ); @@ -1216,46 +1167,47 @@ describe("P2P Pair Staking Test", () => { } = await loadFixture(fixture); await supplyAndValidate(mayc, "1", user1, true); - await mintAndValidate(ape, "1000000", user2); - const apeAmount = await p2pPairStaking.getApeCoinStakingCap(1); + const apeAmount = await paraApeStaking.getApeCoinStakingCap(1); await waitForTx( - await cApe.connect(user2.signer).deposit(user2.address, apeAmount) + await paraApeStaking + .connect(user2.signer) + .depositFreeSApe(ape.address, apeAmount) ); const user1SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 1, - mayc, + mayc.address, 0, 2000, user1 ); const user2SignedOrder = await getSignedListingOrder( - p2pPairStaking, + paraApeStaking, 1, - cApe, + ONE_ADDRESS, 0, 8000, user2 ); await expect( - p2pPairStaking.connect(user1.signer).pause() + paraApeStaking.connect(user1.signer).pause() ).to.be.revertedWith(ProtocolErrors.CALLER_NOT_POOL_OR_EMERGENCY_ADMIN); - await waitForTx(await p2pPairStaking.connect(poolAdmin.signer).pause()); + await waitForTx(await paraApeStaking.connect(poolAdmin.signer).pause()); await expect( - p2pPairStaking + paraApeStaking .connect(user1.signer) .matchPairStakingList(user1SignedOrder, user2SignedOrder) ).to.be.revertedWith("paused"); - await waitForTx(await p2pPairStaking.connect(poolAdmin.signer).unpause()); + await waitForTx(await paraApeStaking.connect(poolAdmin.signer).unpause()); const txReceipt = await waitForTx( - await p2pPairStaking + await paraApeStaking .connect(user1.signer) .matchPairStakingList(user1SignedOrder, user2SignedOrder) ); @@ -1264,32 +1216,192 @@ describe("P2P Pair Staking Test", () => { await advanceTimeAndBlock(parseInt("3600")); - await waitForTx(await p2pPairStaking.connect(poolAdmin.signer).pause()); + await waitForTx(await paraApeStaking.connect(poolAdmin.signer).pause()); await expect( - p2pPairStaking + paraApeStaking .connect(user1.signer) .claimForMatchedOrderAndCompound([orderHash]) ).to.be.revertedWith("paused"); - await waitForTx(await p2pPairStaking.connect(poolAdmin.signer).unpause()); + await waitForTx(await paraApeStaking.connect(poolAdmin.signer).unpause()); await waitForTx( - await p2pPairStaking + await paraApeStaking .connect(user1.signer) .claimForMatchedOrderAndCompound([orderHash]) ); - await waitForTx(await p2pPairStaking.connect(poolAdmin.signer).pause()); + await waitForTx(await paraApeStaking.connect(poolAdmin.signer).pause()); await expect( - p2pPairStaking.connect(user1.signer).claimCApeReward(user1.address) + paraApeStaking.connect(user1.signer).claimCApeReward(user1.address) ).to.be.revertedWith("paused"); - await waitForTx(await p2pPairStaking.connect(poolAdmin.signer).unpause()); + await waitForTx(await paraApeStaking.connect(poolAdmin.signer).unpause()); + + await waitForTx( + await paraApeStaking.connect(user1.signer).claimCApeReward(user1.address) + ); + }); + + it("ApeCoin order staked sApe can be liquidate", async () => { + const { + users: [user1, user2, liquidator], + ape, + weth, + bayc, + pool, + } = await loadFixture(fixture); + const sApeAddress = ONE_ADDRESS; + + await supplyAndValidate(bayc, "1", user1, true); + + const apeAmount = await paraApeStaking.getApeCoinStakingCap(0); + await waitForTx( + await paraApeStaking + .connect(user2.signer) + .depositFreeSApe(ape.address, apeAmount) + ); + + const user1SignedOrder = await getSignedListingOrder( + paraApeStaking, + 0, + bayc.address, + 0, + 2000, + user1 + ); + const user2SignedOrder = await getSignedListingOrder( + paraApeStaking, + 0, + ONE_ADDRESS, + 0, + 8000, + user2 + ); + + const txReceipt = await waitForTx( + await paraApeStaking + .connect(user1.signer) + .matchPairStakingList(user1SignedOrder, user2SignedOrder) + ); + const logLength = txReceipt.logs.length; + const orderHash = txReceipt.logs[logLength - 1].data; + + expect(await paraApeStaking.freeSApeBalance(user2.address)).to.be.closeTo( + "0", + parseEther("1") + ); + expect(await paraApeStaking.stakedSApeBalance(user2.address)).to.be.equal( + apeAmount + ); + + await waitForTx( + await pool + .connect(user2.signer) + .setUserUseERC20AsCollateral(sApeAddress, true) + ); + + await changePriceAndValidate(ape, "0.001"); + await changeSApePriceAndValidate(sApeAddress, "0.001"); + await supplyAndValidate(weth, "100", liquidator, true); + + //collateral value: 200000 * 0.001 = 200 eth + //borrow value: 30 eth + await waitForTx( + await pool + .connect(user2.signer) + .borrow(weth.address, parseEther("30"), 0, user2.address) + ); + + await expect( + paraApeStaking.connect(liquidator.signer).breakUpMatchedOrder(orderHash) + ).to.be.revertedWith(ProtocolErrors.NO_BREAK_UP_PERMISSION); + + await changePriceAndValidate(ape, "0.0001"); + await changeSApePriceAndValidate(sApeAddress, "0.0001"); + + await waitForTx( + await paraApeStaking + .connect(liquidator.signer) + .breakUpMatchedOrder(orderHash) + ); + + expect(await paraApeStaking.freeSApeBalance(user2.address)).to.be.closeTo( + apeAmount, + parseEther("1") + ); + expect(await paraApeStaking.stakedSApeBalance(user2.address)).to.be.equal( + "0" + ); + await waitForTx( + await pool + .connect(liquidator.signer) + .liquidateERC20( + sApeAddress, + weth.address, + user2.address, + MAX_UINT_AMOUNT, + true, + { + value: parseEther("100"), + gasLimit: 5000000, + } + ) + ); + + expect(await paraApeStaking.freeSApeBalance(user2.address)).to.be.closeTo( + "0", + parseEther("1") + ); + expect(await paraApeStaking.stakedSApeBalance(user2.address)).to.be.equal( + "0" + ); + expect( + await paraApeStaking.freeSApeBalance(liquidator.address) + ).to.be.closeTo(apeAmount, parseEther("1")); + }); + + it("test invalid order", async () => { + const { + users: [user1, user2], + ape, + bayc, + mayc, + } = await loadFixture(fixture); + + await supplyAndValidate(bayc, "1", user1, true); + await supplyAndValidate(mayc, "1", user1, true); + const apeAmount = await paraApeStaking.getApeCoinStakingCap(0); await waitForTx( - await p2pPairStaking.connect(user1.signer).claimCApeReward(user1.address) + await paraApeStaking + .connect(user2.signer) + .depositFreeSApe(ape.address, apeAmount) + ); + + const user1SignedOrder = await getSignedListingOrder( + paraApeStaking, + 0, + mayc.address, + 0, + 2000, + user1 + ); + const user2SignedOrder = await getSignedListingOrder( + paraApeStaking, + 0, + ONE_ADDRESS, + 0, + 8000, + user2 ); + + await expect( + paraApeStaking + .connect(user1.signer) + .matchPairStakingList(user1SignedOrder, user2SignedOrder) + ).to.be.revertedWith(ProtocolErrors.INVALID_STAKING_TYPE); }); }); diff --git a/test/para_ape_staking.spec.ts b/test/para_ape_staking.spec.ts new file mode 100644 index 000000000..db2816e04 --- /dev/null +++ b/test/para_ape_staking.spec.ts @@ -0,0 +1,1682 @@ +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {expect} from "chai"; +import {AutoCompoundApe, ParaApeStaking, VariableDebtToken} from "../types"; +import {TestEnv} from "./helpers/make-suite"; +import {testEnvFixture} from "./helpers/setup-env"; +import {mintAndValidate, supplyAndValidate} from "./helpers/validated-steps"; +import { + getAutoCompoundApe, + getParaApeStaking, + getVariableDebtToken, +} from "../helpers/contracts-getters"; +import {MAX_UINT_AMOUNT} from "../helpers/constants"; +import {advanceTimeAndBlock, waitForTx} from "../helpers/misc-utils"; +import {parseEther} from "ethers/lib/utils"; +import {ProtocolErrors} from "../helpers/types"; + +describe("Para Ape Staking Test", () => { + let testEnv: TestEnv; + let variableDebtCApeCoin: VariableDebtToken; + let paraApeStaking: ParaApeStaking; + let cApe: AutoCompoundApe; + let MINIMUM_LIQUIDITY; + + const fixture = async () => { + testEnv = await loadFixture(testEnvFixture); + const { + ape, + users: [user1, , , user4, , user6], + apeCoinStaking, + pool, + protocolDataProvider, + configurator, + poolAdmin, + } = testEnv; + + paraApeStaking = await getParaApeStaking(); + + await waitForTx( + await paraApeStaking + .connect(poolAdmin.signer) + .setApeStakingBot(user4.address) + ); + + cApe = await getAutoCompoundApe(); + MINIMUM_LIQUIDITY = await cApe.MINIMUM_LIQUIDITY(); + + const {variableDebtTokenAddress: variableDebtCApeCoinAddress} = + await protocolDataProvider.getReserveTokensAddresses(cApe.address); + variableDebtCApeCoin = await getVariableDebtToken( + variableDebtCApeCoinAddress + ); + + // send extra tokens to the apestaking contract for rewards + await waitForTx( + await ape + .connect(user1.signer) + ["mint(address,uint256)"]( + apeCoinStaking.address, + parseEther("100000000000") + ) + ); + + // user6 deposit MINIMUM_LIQUIDITY to make test case easy + await mintAndValidate(ape, "1", user6); + await waitForTx( + await ape.connect(user6.signer).approve(cApe.address, MAX_UINT_AMOUNT) + ); + await waitForTx( + await cApe.connect(user6.signer).deposit(user6.address, MINIMUM_LIQUIDITY) + ); + + // user4 deposit and supply cApe to MM + expect( + await configurator + .connect(poolAdmin.signer) + .setSupplyCap(cApe.address, "20000000000") + ); + await mintAndValidate(ape, "10000000000", user4); + await waitForTx( + await ape.connect(user4.signer).approve(cApe.address, MAX_UINT_AMOUNT) + ); + await waitForTx( + await cApe + .connect(user4.signer) + .deposit(user4.address, parseEther("10000000000")) + ); + await waitForTx( + await cApe.connect(user4.signer).approve(pool.address, MAX_UINT_AMOUNT) + ); + await waitForTx( + await pool + .connect(user4.signer) + .supply(cApe.address, parseEther("10000000000"), user4.address, 0) + ); + + return testEnv; + }; + + it("test BAYC + BAKC pool logic", async () => { + const { + users: [user1, user2, , user4], + bayc, + bakc, + nBAYC, + nBAKC, + poolAdmin, + apeCoinStaking, + } = await loadFixture(fixture); + + await waitForTx( + await paraApeStaking.connect(poolAdmin.signer).setCompoundFee(1000) + ); + + await supplyAndValidate(bayc, "3", user1, true); + await supplyAndValidate(bakc, "3", user1, true); + + await waitForTx( + await nBAYC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 2) + ); + await waitForTx( + await nBAKC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 2) + ); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .depositPairNFT(true, [0, 1], [0, 1]) + ); + await waitForTx( + await paraApeStaking.connect(user2.signer).depositPairNFT(true, [2], [2]) + ); + expect(await bayc.ownerOf(0)).to.be.equal(paraApeStaking.address); + expect(await bayc.ownerOf(1)).to.be.equal(paraApeStaking.address); + expect(await bayc.ownerOf(2)).to.be.equal(paraApeStaking.address); + expect(await bakc.ownerOf(0)).to.be.equal(paraApeStaking.address); + expect(await bakc.ownerOf(1)).to.be.equal(paraApeStaking.address); + expect(await bakc.ownerOf(2)).to.be.equal(paraApeStaking.address); + + await waitForTx( + await paraApeStaking + .connect(user4.signer) + .stakingPairNFT(true, [0, 1, 2], [0, 1, 2]) + ); + expect((await apeCoinStaking.nftPosition(1, 0)).stakedAmount).to.be.eq( + parseEther("200000") + ); + expect((await apeCoinStaking.nftPosition(1, 1)).stakedAmount).to.be.eq( + parseEther("200000") + ); + expect((await apeCoinStaking.nftPosition(1, 2)).stakedAmount).to.be.eq( + parseEther("200000") + ); + expect((await apeCoinStaking.nftPosition(3, 0)).stakedAmount).to.be.eq( + parseEther("50000") + ); + expect((await apeCoinStaking.nftPosition(3, 1)).stakedAmount).to.be.eq( + parseEther("50000") + ); + expect((await apeCoinStaking.nftPosition(3, 2)).stakedAmount).to.be.eq( + parseEther("50000") + ); + expect( + await variableDebtCApeCoin.balanceOf(paraApeStaking.address) + ).to.be.closeTo(parseEther("750000"), parseEther("10")); + + await advanceTimeAndBlock(parseInt("3600")); + + await waitForTx( + await paraApeStaking + .connect(user4.signer) + .compoundPairNFT(true, [0, 1, 2], [0, 1, 2]) + ); + let compoundFee = await paraApeStaking.pendingCApeReward( + paraApeStaking.address + ); + expect(compoundFee).to.be.closeTo(parseEther("720"), parseEther("10")); + + const user1PendingReward = await paraApeStaking.getPendingReward(1, [0, 1]); + const user2PendingReward = await paraApeStaking.getPendingReward(1, [2]); + expect(user1PendingReward).to.be.closeTo( + parseEther("4320"), + parseEther("50") + ); + expect(user2PendingReward).to.be.closeTo( + parseEther("2160"), + parseEther("50") + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).claimPendingReward(1, [0, 1]) + ); + await waitForTx( + await paraApeStaking.connect(user2.signer).claimPendingReward(1, [2]) + ); + let user1Balance = await cApe.balanceOf(user1.address); + let user2Balance = await cApe.balanceOf(user2.address); + expect(user1Balance).to.be.closeTo(user1PendingReward, parseEther("1")); + expect(user2Balance).to.be.closeTo(user2PendingReward, parseEther("1")); + expect(user1Balance).to.be.closeTo(user2Balance.mul(2), parseEther("10")); + + const newUser1PendingReward = await paraApeStaking.getPendingReward( + 1, + [0, 1] + ); + const newUser2PendingReward = await paraApeStaking.getPendingReward(1, [2]); + expect(newUser1PendingReward).to.be.equal(0); + expect(newUser2PendingReward).to.be.equal(0); + + await advanceTimeAndBlock(parseInt("3600")); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .withdrawPairNFT(true, [0, 1], [0, 1]) + ); + await waitForTx( + await paraApeStaking.connect(user2.signer).withdrawPairNFT(true, [2], [2]) + ); + expect(await bayc.ownerOf(0)).to.be.equal(nBAYC.address); + expect(await bayc.ownerOf(1)).to.be.equal(nBAYC.address); + expect(await bayc.ownerOf(2)).to.be.equal(nBAYC.address); + expect(await bakc.ownerOf(0)).to.be.equal(nBAKC.address); + expect(await bakc.ownerOf(1)).to.be.equal(nBAKC.address); + expect(await bakc.ownerOf(2)).to.be.equal(nBAKC.address); + + //720 + 720 + 2160(user2's reward part) = 3600 + compoundFee = await paraApeStaking.pendingCApeReward( + paraApeStaking.address + ); + expect(compoundFee).to.be.closeTo(parseEther("3600"), parseEther("50")); + + await waitForTx( + await paraApeStaking.connect(user4.signer).claimCompoundFee(user4.address) + ); + const compoundFeeBalance = await cApe.balanceOf(user4.address); + expect(compoundFeeBalance).to.be.closeTo(compoundFee, parseEther("1")); + //withdraw cannot claim pending reward + user1Balance = await cApe.balanceOf(user1.address); + user2Balance = await cApe.balanceOf(user2.address); + expect(user1Balance).to.be.closeTo(user1PendingReward, parseEther("1")); + //user2 get user1's part + expect(user2Balance).to.be.closeTo( + user1PendingReward.add(user2PendingReward), + parseEther("20") + ); + + expect( + await variableDebtCApeCoin.balanceOf(paraApeStaking.address) + ).to.be.equal(0); + + expect(await cApe.balanceOf(paraApeStaking.address)).to.be.closeTo( + "0", + parseEther("10") + ); + }); + + it("test MAYC + BAKC pool logic", async () => { + const { + users: [user1, user2, , user4], + mayc, + bakc, + nMAYC, + nBAKC, + apeCoinStaking, + poolAdmin, + } = await loadFixture(fixture); + + await waitForTx( + await paraApeStaking.connect(poolAdmin.signer).setCompoundFee(1000) + ); + + await supplyAndValidate(mayc, "3", user1, true); + await supplyAndValidate(bakc, "3", user1, true); + + await waitForTx( + await nMAYC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 2) + ); + await waitForTx( + await nBAKC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 2) + ); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .depositPairNFT(false, [0, 1], [0, 1]) + ); + await waitForTx( + await paraApeStaking.connect(user2.signer).depositPairNFT(false, [2], [2]) + ); + expect(await mayc.ownerOf(0)).to.be.equal(paraApeStaking.address); + expect(await mayc.ownerOf(1)).to.be.equal(paraApeStaking.address); + expect(await mayc.ownerOf(2)).to.be.equal(paraApeStaking.address); + expect(await bakc.ownerOf(0)).to.be.equal(paraApeStaking.address); + expect(await bakc.ownerOf(1)).to.be.equal(paraApeStaking.address); + expect(await bakc.ownerOf(2)).to.be.equal(paraApeStaking.address); + + await waitForTx( + await paraApeStaking + .connect(user4.signer) + .stakingPairNFT(false, [0, 1, 2], [0, 1, 2]) + ); + expect((await apeCoinStaking.nftPosition(2, 0)).stakedAmount).to.be.eq( + parseEther("100000") + ); + expect((await apeCoinStaking.nftPosition(2, 1)).stakedAmount).to.be.eq( + parseEther("100000") + ); + expect((await apeCoinStaking.nftPosition(2, 2)).stakedAmount).to.be.eq( + parseEther("100000") + ); + expect((await apeCoinStaking.nftPosition(3, 0)).stakedAmount).to.be.eq( + parseEther("50000") + ); + expect((await apeCoinStaking.nftPosition(3, 1)).stakedAmount).to.be.eq( + parseEther("50000") + ); + expect((await apeCoinStaking.nftPosition(3, 2)).stakedAmount).to.be.eq( + parseEther("50000") + ); + expect( + await variableDebtCApeCoin.balanceOf(paraApeStaking.address) + ).to.be.closeTo(parseEther("450000"), parseEther("10")); + + await advanceTimeAndBlock(parseInt("3600")); + + await waitForTx( + await paraApeStaking + .connect(user4.signer) + .compoundPairNFT(false, [0, 1, 2], [0, 1, 2]) + ); + let compoundFee = await paraApeStaking.pendingCApeReward( + paraApeStaking.address + ); + expect(compoundFee).to.be.closeTo(parseEther("720"), parseEther("10")); + + const user1PendingReward = await paraApeStaking.getPendingReward(2, [0, 1]); + const user2PendingReward = await paraApeStaking.getPendingReward(2, [2]); + expect(user1PendingReward).to.be.closeTo( + parseEther("4320"), + parseEther("50") + ); + expect(user2PendingReward).to.be.closeTo( + parseEther("2160"), + parseEther("50") + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).claimPendingReward(2, [0, 1]) + ); + await waitForTx( + await paraApeStaking.connect(user2.signer).claimPendingReward(2, [2]) + ); + let user1Balance = await cApe.balanceOf(user1.address); + let user2Balance = await cApe.balanceOf(user2.address); + expect(user1Balance).to.be.closeTo(user1PendingReward, parseEther("1")); + expect(user2Balance).to.be.closeTo(user2PendingReward, parseEther("1")); + expect(user1Balance).to.be.closeTo(user2Balance.mul(2), parseEther("10")); + + const newUser1PendingReward = await paraApeStaking.getPendingReward( + 2, + [0, 1] + ); + const newUser2PendingReward = await paraApeStaking.getPendingReward(2, [2]); + expect(newUser1PendingReward).to.be.equal(0); + expect(newUser2PendingReward).to.be.equal(0); + + await advanceTimeAndBlock(parseInt("3600")); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .withdrawPairNFT(false, [0, 1], [0, 1]) + ); + await waitForTx( + await paraApeStaking + .connect(user2.signer) + .withdrawPairNFT(false, [2], [2]) + ); + expect(await mayc.ownerOf(0)).to.be.equal(nMAYC.address); + expect(await mayc.ownerOf(1)).to.be.equal(nMAYC.address); + expect(await mayc.ownerOf(2)).to.be.equal(nMAYC.address); + expect(await bakc.ownerOf(0)).to.be.equal(nBAKC.address); + expect(await bakc.ownerOf(1)).to.be.equal(nBAKC.address); + expect(await bakc.ownerOf(2)).to.be.equal(nBAKC.address); + + //720 + 720 + 2160(user2's reward part) = 3600 + compoundFee = await paraApeStaking.pendingCApeReward( + paraApeStaking.address + ); + expect(compoundFee).to.be.closeTo(parseEther("3600"), parseEther("50")); + + await waitForTx( + await paraApeStaking.connect(user4.signer).claimCompoundFee(user4.address) + ); + const compoundFeeBalance = await cApe.balanceOf(user4.address); + expect(compoundFeeBalance).to.be.closeTo(compoundFee, parseEther("1")); + //withdraw cannot claim pending reward + user1Balance = await cApe.balanceOf(user1.address); + user2Balance = await cApe.balanceOf(user2.address); + expect(user1Balance).to.be.closeTo(user1PendingReward, parseEther("1")); + //user2 get user1's part + expect(user2Balance).to.be.closeTo( + user1PendingReward.add(user2PendingReward), + parseEther("20") + ); + + expect( + await variableDebtCApeCoin.balanceOf(paraApeStaking.address) + ).to.be.equal(0); + + expect(await cApe.balanceOf(paraApeStaking.address)).to.be.closeTo( + "0", + parseEther("1") + ); + }); + + it("test single pool logic", async () => { + const { + users: [user1, user2, user3, user4], + bayc, + mayc, + bakc, + nBAYC, + nMAYC, + nBAKC, + apeCoinStaking, + poolAdmin, + } = await loadFixture(fixture); + + await waitForTx( + await paraApeStaking.connect(poolAdmin.signer).setCompoundFee(1000) + ); + + await supplyAndValidate(bayc, "3", user1, true); + await supplyAndValidate(mayc, "3", user2, true); + await supplyAndValidate(bakc, "3", user3, true); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .depositNFT(bayc.address, [0, 1, 2]) + ); + await waitForTx( + await paraApeStaking + .connect(user2.signer) + .depositNFT(mayc.address, [0, 1, 2]) + ); + await waitForTx( + await paraApeStaking + .connect(user3.signer) + .depositNFT(bakc.address, [0, 1, 2]) + ); + expect(await bayc.ownerOf(0)).to.be.equal(paraApeStaking.address); + expect(await bayc.ownerOf(1)).to.be.equal(paraApeStaking.address); + expect(await bayc.ownerOf(2)).to.be.equal(paraApeStaking.address); + expect(await mayc.ownerOf(0)).to.be.equal(paraApeStaking.address); + expect(await mayc.ownerOf(1)).to.be.equal(paraApeStaking.address); + expect(await mayc.ownerOf(2)).to.be.equal(paraApeStaking.address); + expect(await bakc.ownerOf(0)).to.be.equal(paraApeStaking.address); + expect(await bakc.ownerOf(1)).to.be.equal(paraApeStaking.address); + expect(await bakc.ownerOf(2)).to.be.equal(paraApeStaking.address); + + await waitForTx( + await paraApeStaking.connect(user4.signer).stakingApe(true, [0, 1, 2]) + ); + await waitForTx( + await paraApeStaking.connect(user4.signer).stakingApe(false, [0, 1, 2]) + ); + await waitForTx( + await paraApeStaking.connect(user4.signer).stakingBAKC({ + baycTokenIds: [0, 1], + bakcPairBaycTokenIds: [0, 1], + maycTokenIds: [2], + bakcPairMaycTokenIds: [2], + }) + ); + expect((await apeCoinStaking.nftPosition(1, 0)).stakedAmount).to.be.eq( + parseEther("200000") + ); + expect((await apeCoinStaking.nftPosition(1, 1)).stakedAmount).to.be.eq( + parseEther("200000") + ); + expect((await apeCoinStaking.nftPosition(1, 2)).stakedAmount).to.be.eq( + parseEther("200000") + ); + expect((await apeCoinStaking.nftPosition(2, 0)).stakedAmount).to.be.eq( + parseEther("100000") + ); + expect((await apeCoinStaking.nftPosition(2, 1)).stakedAmount).to.be.eq( + parseEther("100000") + ); + expect((await apeCoinStaking.nftPosition(2, 2)).stakedAmount).to.be.eq( + parseEther("100000") + ); + expect((await apeCoinStaking.nftPosition(3, 0)).stakedAmount).to.be.eq( + parseEther("50000") + ); + expect((await apeCoinStaking.nftPosition(3, 1)).stakedAmount).to.be.eq( + parseEther("50000") + ); + expect((await apeCoinStaking.nftPosition(3, 2)).stakedAmount).to.be.eq( + parseEther("50000") + ); + expect( + await variableDebtCApeCoin.balanceOf(paraApeStaking.address) + ).to.be.closeTo(parseEther("1050000"), parseEther("10")); + + await advanceTimeAndBlock(parseInt("3600")); + + await waitForTx( + await paraApeStaking.connect(user4.signer).compoundApe(true, [0, 1, 2]) + ); + await waitForTx( + await paraApeStaking.connect(user4.signer).compoundApe(false, [0, 1, 2]) + ); + await waitForTx( + await paraApeStaking.connect(user4.signer).compoundBAKC({ + baycTokenIds: [0, 1], + bakcPairBaycTokenIds: [0, 1], + maycTokenIds: [2], + bakcPairMaycTokenIds: [2], + }) + ); + let compoundFee = await paraApeStaking.pendingCApeReward( + paraApeStaking.address + ); + expect(compoundFee).to.be.closeTo(parseEther("1080"), parseEther("10")); + + const user1PendingReward = await paraApeStaking.getPendingReward( + 3, + [0, 1, 2] + ); + const user2PendingReward = await paraApeStaking.getPendingReward( + 4, + [0, 1, 2] + ); + const user3PendingReward = await paraApeStaking.getPendingReward( + 5, + [0, 1, 2] + ); + expect(user1PendingReward).to.be.closeTo( + parseEther("3240"), + parseEther("100") + ); + expect(user2PendingReward).to.be.closeTo( + parseEther("3240"), + parseEther("100") + ); + expect(user3PendingReward).to.be.closeTo( + parseEther("3240"), + parseEther("100") + ); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .claimPendingReward(3, [0, 1, 2]) + ); + await waitForTx( + await paraApeStaking + .connect(user2.signer) + .claimPendingReward(4, [0, 1, 2]) + ); + await waitForTx( + await paraApeStaking + .connect(user3.signer) + .claimPendingReward(5, [0, 1, 2]) + ); + let user1Balance = await cApe.balanceOf(user1.address); + let user2Balance = await cApe.balanceOf(user2.address); + let user3Balance = await cApe.balanceOf(user3.address); + expect(user1Balance).to.be.closeTo(user1PendingReward, parseEther("100")); + expect(user2Balance).to.be.closeTo(user2PendingReward, parseEther("100")); + expect(user3Balance).to.be.closeTo(user3PendingReward, parseEther("100")); + + const newUser1PendingReward = await paraApeStaking.getPendingReward( + 3, + [0, 1, 2] + ); + const newUser2PendingReward = await paraApeStaking.getPendingReward( + 4, + [0, 1, 2] + ); + const newUser3PendingReward = await paraApeStaking.getPendingReward( + 5, + [0, 1, 2] + ); + expect(newUser1PendingReward).to.be.equal(0); + expect(newUser2PendingReward).to.be.equal(0); + expect(newUser3PendingReward).to.be.equal(0); + + await advanceTimeAndBlock(parseInt("3600")); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .withdrawNFT(bayc.address, [0, 1, 2]) + ); + await waitForTx( + await paraApeStaking + .connect(user2.signer) + .withdrawNFT(mayc.address, [0, 1, 2]) + ); + await waitForTx( + await paraApeStaking + .connect(user3.signer) + .withdrawNFT(bakc.address, [0, 1, 2]) + ); + expect(await bayc.ownerOf(0)).to.be.equal(nBAYC.address); + expect(await bayc.ownerOf(1)).to.be.equal(nBAYC.address); + expect(await bayc.ownerOf(2)).to.be.equal(nBAYC.address); + expect(await mayc.ownerOf(0)).to.be.equal(nMAYC.address); + expect(await mayc.ownerOf(1)).to.be.equal(nMAYC.address); + expect(await mayc.ownerOf(2)).to.be.equal(nMAYC.address); + expect(await bakc.ownerOf(0)).to.be.equal(nBAKC.address); + expect(await bakc.ownerOf(1)).to.be.equal(nBAKC.address); + expect(await bakc.ownerOf(2)).to.be.equal(nBAKC.address); + + //1080 + 1080 + 3240(user1's reward part) + 3240 (user2's reward part) + compoundFee = await paraApeStaking.pendingCApeReward( + paraApeStaking.address + ); + expect(compoundFee).to.be.closeTo(parseEther("8640"), parseEther("100")); + + await waitForTx( + await paraApeStaking.connect(user4.signer).claimCompoundFee(user4.address) + ); + const compoundFeeBalance = await cApe.balanceOf(user4.address); + expect(compoundFeeBalance).to.be.closeTo(compoundFee, parseEther("1")); + + //withdraw cannot claim pending reward + user1Balance = await cApe.balanceOf(user1.address); + user2Balance = await cApe.balanceOf(user2.address); + user3Balance = await cApe.balanceOf(user3.address); + expect(user1Balance).to.be.closeTo(user1PendingReward, parseEther("1")); + expect(user2Balance).to.be.closeTo(user2PendingReward, parseEther("1")); + expect(user3Balance).to.be.closeTo( + user3PendingReward.mul(2), + parseEther("10") + ); + + expect( + await variableDebtCApeCoin.balanceOf(paraApeStaking.address) + ).to.be.closeTo("0", "10"); + + expect(await cApe.balanceOf(paraApeStaking.address)).to.be.closeTo( + "0", + parseEther("10") + ); + }); + + it("depositPairNFT revert test", async () => { + const { + users: [user1, user2], + ape, + bayc, + bakc, + apeCoinStaking, + } = await loadFixture(fixture); + + await mintAndValidate(bayc, "3", user1); + await mintAndValidate(bakc, "3", user1); + await mintAndValidate(ape, "1000000", user1); + + await waitForTx( + await ape + .connect(user1.signer) + .approve(apeCoinStaking.address, MAX_UINT_AMOUNT) + ); + await waitForTx( + await apeCoinStaking + .connect(user1.signer) + .depositBAYC([{tokenId: 0, amount: parseEther("10")}]) + ); + await waitForTx( + await apeCoinStaking + .connect(user1.signer) + .depositBAKC( + [{mainTokenId: 1, bakcTokenId: 1, amount: parseEther("10")}], + [] + ) + ); + + await supplyAndValidate(bayc, "3", user1, false); + await supplyAndValidate(bakc, "3", user1, false); + + await expect( + paraApeStaking.connect(user2.signer).depositPairNFT(true, [0, 1], [0, 1]) + ).to.be.revertedWith(ProtocolErrors.NOT_THE_OWNER); + + await expect( + paraApeStaking.connect(user1.signer).depositPairNFT(true, [0], [0]) + ).to.be.revertedWith(ProtocolErrors.APE_POSITION_EXISTED); + + await expect( + paraApeStaking.connect(user1.signer).depositPairNFT(true, [2], [1]) + ).to.be.revertedWith(ProtocolErrors.BAKC_POSITION_EXISTED); + + await expect( + paraApeStaking.connect(user1.signer).depositPairNFT(true, [1], [0]) + ).to.be.revertedWith(ProtocolErrors.PAIR_POSITION_EXISTED); + + await waitForTx( + await paraApeStaking.connect(user1.signer).depositPairNFT(true, [2], [2]) + ); + }); + + it("stakingPairNFT revert test", async () => { + const { + users: [user1, , , user4], + bayc, + bakc, + } = await loadFixture(fixture); + + await supplyAndValidate(bayc, "3", user1, true); + await supplyAndValidate(bakc, "3", user1, true); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .depositPairNFT(true, [0, 1, 2], [0, 1, 2]) + ); + + await expect( + paraApeStaking.connect(user4.signer).stakingPairNFT(true, [1], [0]) + ).to.be.revertedWith(ProtocolErrors.NOT_PAIRED_APE_AND_BAKC); + }); + + it("compoundPairNFT revert test", async () => { + const { + users: [user1, , , user4], + bayc, + bakc, + } = await loadFixture(fixture); + + await supplyAndValidate(bayc, "3", user1, true); + await supplyAndValidate(bakc, "3", user1, true); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .depositPairNFT(true, [0, 1, 2], [0, 1, 2]) + ); + + await expect( + paraApeStaking + .connect(user1.signer) + .compoundPairNFT(true, [0, 1, 2], [0, 1, 2]) + ).to.be.revertedWith(ProtocolErrors.NOT_APE_STAKING_BOT); + + await expect( + paraApeStaking.connect(user4.signer).compoundPairNFT(true, [1], [0]) + ).to.be.revertedWith(ProtocolErrors.NOT_PAIRED_APE_AND_BAKC); + }); + + it("claimPairNFT revert test", async () => { + const { + users: [user1, user2, , user4], + bayc, + bakc, + nBAYC, + } = await loadFixture(fixture); + + await supplyAndValidate(bayc, "4", user1, true); + await supplyAndValidate(bakc, "3", user1, true); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .depositPairNFT(true, [0, 1, 2], [0, 1, 2]) + ); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .stakingPairNFT(true, [0, 1, 2], [0, 1, 2]) + ); + + await advanceTimeAndBlock(parseInt("3600")); + + await waitForTx( + await paraApeStaking + .connect(user4.signer) + .compoundPairNFT(true, [0, 1, 2], [0, 1, 2]) + ); + + await waitForTx( + await nBAYC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 2) + ); + + await expect( + paraApeStaking.connect(user1.signer).claimPendingReward(1, [0, 1, 2]) + ).to.be.revertedWith(ProtocolErrors.NOT_THE_SAME_OWNER); + + await expect( + paraApeStaking.connect(user1.signer).claimPendingReward(1, [3]) + ).to.be.revertedWith(ProtocolErrors.NFT_NOT_IN_POOL); + }); + + it("withdrawPairNFT revert test", async () => { + const { + users: [user1, user2], + bayc, + bakc, + nBAYC, + } = await loadFixture(fixture); + + await supplyAndValidate(bayc, "3", user1, true); + await supplyAndValidate(bakc, "3", user1, true); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .depositPairNFT(true, [0, 1, 2], [0, 1, 2]) + ); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .stakingPairNFT(true, [0, 1], [0, 1]) + ); + + await waitForTx( + await nBAYC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 2) + ); + + await expect( + paraApeStaking.connect(user1.signer).withdrawPairNFT(true, [0, 1], [1, 0]) + ).to.be.revertedWith(ProtocolErrors.NOT_PAIRED_APE_AND_BAKC); + + await expect( + paraApeStaking + .connect(user1.signer) + .withdrawPairNFT(true, [0, 1, 2], [0, 1, 2]) + ).to.be.revertedWith(ProtocolErrors.NOT_THE_SAME_OWNER); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .withdrawPairNFT(true, [0, 1], [0, 1]) + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).withdrawPairNFT(true, [2], [2]) + ); + }); + + it("depositNFT revert test", async () => { + const { + users: [user1, user2], + ape, + bayc, + bakc, + apeCoinStaking, + } = await loadFixture(fixture); + + await mintAndValidate(bayc, "3", user1); + await mintAndValidate(bakc, "3", user1); + await mintAndValidate(ape, "1000000", user1); + + await waitForTx( + await ape + .connect(user1.signer) + .approve(apeCoinStaking.address, MAX_UINT_AMOUNT) + ); + await waitForTx( + await apeCoinStaking + .connect(user1.signer) + .depositBAYC([{tokenId: 0, amount: parseEther("10")}]) + ); + await waitForTx( + await apeCoinStaking + .connect(user1.signer) + .depositBAKC( + [{mainTokenId: 1, bakcTokenId: 1, amount: parseEther("10")}], + [] + ) + ); + + await supplyAndValidate(bayc, "3", user1, false); + await supplyAndValidate(bakc, "3", user1, false); + + await expect( + paraApeStaking.connect(user2.signer).depositNFT(bayc.address, [0]) + ).to.be.revertedWith(ProtocolErrors.NOT_THE_OWNER); + + await expect( + paraApeStaking.connect(user1.signer).depositNFT(bayc.address, [0]) + ).to.be.revertedWith(ProtocolErrors.APE_POSITION_EXISTED); + + await expect( + paraApeStaking.connect(user1.signer).depositNFT(bayc.address, [1]) + ).to.be.revertedWith(ProtocolErrors.PAIR_POSITION_EXISTED); + + await expect( + paraApeStaking.connect(user2.signer).depositNFT(bakc.address, [0]) + ).to.be.revertedWith(ProtocolErrors.NOT_THE_OWNER); + + await expect( + paraApeStaking.connect(user1.signer).depositNFT(bakc.address, [1]) + ).to.be.revertedWith(ProtocolErrors.APE_POSITION_EXISTED); + }); + + it("stakingApe revert test", async () => { + const { + users: [user1, , , user4], + bayc, + } = await loadFixture(fixture); + + await supplyAndValidate(bayc, "3", user1, true); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .depositNFT(bayc.address, [0, 1]) + ); + + await expect( + paraApeStaking.connect(user4.signer).stakingApe(true, [2]) + ).to.be.revertedWith(ProtocolErrors.NFT_NOT_IN_POOL); + + await waitForTx( + await paraApeStaking.connect(user1.signer).stakingApe(true, [0, 1]) + ); + }); + + it("stakingBAKC revert test", async () => { + const { + users: [user1, , , user4], + bayc, + bakc, + } = await loadFixture(fixture); + + await supplyAndValidate(bayc, "3", user1, true); + await supplyAndValidate(bakc, "3", user1, true); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .depositNFT(bayc.address, [0, 1]) + ); + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .depositNFT(bakc.address, [0, 1]) + ); + + await expect( + paraApeStaking.connect(user4.signer).stakingBAKC({ + baycTokenIds: [2], + bakcPairBaycTokenIds: [0], + maycTokenIds: [], + bakcPairMaycTokenIds: [], + }) + ).to.be.revertedWith(ProtocolErrors.NFT_NOT_IN_POOL); + + await expect( + paraApeStaking.connect(user4.signer).stakingBAKC({ + baycTokenIds: [0], + bakcPairBaycTokenIds: [2], + maycTokenIds: [], + bakcPairMaycTokenIds: [], + }) + ).to.be.revertedWith(ProtocolErrors.NFT_NOT_IN_POOL); + + await waitForTx( + await paraApeStaking.connect(user1.signer).stakingBAKC({ + baycTokenIds: [0, 1], + bakcPairBaycTokenIds: [0, 1], + maycTokenIds: [], + bakcPairMaycTokenIds: [], + }) + ); + }); + + it("compoundApe revert test", async () => { + const { + users: [user1, , , user4], + bayc, + } = await loadFixture(fixture); + + await supplyAndValidate(bayc, "3", user1, true); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .depositNFT(bayc.address, [0, 1]) + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).stakingApe(true, [0, 1]) + ); + + await advanceTimeAndBlock(parseInt("3600")); + + await expect( + paraApeStaking.connect(user4.signer).compoundApe(true, [2]) + ).to.be.revertedWith(ProtocolErrors.NFT_NOT_IN_POOL); + + await waitForTx( + await paraApeStaking.connect(user4.signer).compoundApe(true, [0, 1]) + ); + }); + + it("compoundBAKC revert test", async () => { + const { + users: [user1, , , user4], + bayc, + bakc, + } = await loadFixture(fixture); + + await supplyAndValidate(bayc, "3", user1, true); + await supplyAndValidate(bakc, "3", user1, true); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .depositNFT(bayc.address, [0, 1]) + ); + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .depositNFT(bakc.address, [0, 1]) + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).stakingBAKC({ + baycTokenIds: [0, 1], + bakcPairBaycTokenIds: [0, 1], + maycTokenIds: [], + bakcPairMaycTokenIds: [], + }) + ); + + await advanceTimeAndBlock(parseInt("3600")); + + await expect( + paraApeStaking.connect(user4.signer).compoundBAKC({ + baycTokenIds: [2], + bakcPairBaycTokenIds: [1], + maycTokenIds: [], + bakcPairMaycTokenIds: [], + }) + ).to.be.reverted; + + await expect( + paraApeStaking.connect(user4.signer).compoundBAKC({ + baycTokenIds: [1], + bakcPairBaycTokenIds: [2], + maycTokenIds: [], + bakcPairMaycTokenIds: [], + }) + ).to.be.revertedWith(ProtocolErrors.NFT_NOT_IN_POOL); + + await waitForTx( + await paraApeStaking.connect(user4.signer).compoundBAKC({ + baycTokenIds: [0, 1], + bakcPairBaycTokenIds: [0, 1], + maycTokenIds: [], + bakcPairMaycTokenIds: [], + }) + ); + }); + + it("claimNFT revert test", async () => { + const { + users: [user1, user2, , user4], + bayc, + bakc, + nBAYC, + nBAKC, + } = await loadFixture(fixture); + + await supplyAndValidate(bayc, "3", user1, true); + await supplyAndValidate(bakc, "3", user1, true); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .depositNFT(bayc.address, [0, 1]) + ); + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .depositNFT(bakc.address, [0, 1]) + ); + + await waitForTx( + await nBAYC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 1) + ); + await waitForTx( + await nBAKC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 1) + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).stakingApe(true, [0, 1]) + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).stakingBAKC({ + baycTokenIds: [0, 1], + bakcPairBaycTokenIds: [0, 1], + maycTokenIds: [], + bakcPairMaycTokenIds: [], + }) + ); + + await advanceTimeAndBlock(parseInt("3600")); + + await waitForTx( + await paraApeStaking.connect(user4.signer).compoundApe(true, [0, 1]) + ); + + await waitForTx( + await paraApeStaking.connect(user4.signer).compoundBAKC({ + baycTokenIds: [0, 1], + bakcPairBaycTokenIds: [0, 1], + maycTokenIds: [], + bakcPairMaycTokenIds: [], + }) + ); + + await expect( + paraApeStaking.connect(user1.signer).claimPendingReward(3, [0, 1]) + ).to.be.revertedWith(ProtocolErrors.NOT_THE_SAME_OWNER); + + await expect( + paraApeStaking.connect(user1.signer).claimPendingReward(3, [2]) + ).to.be.revertedWith(ProtocolErrors.NFT_NOT_IN_POOL); + + await expect( + paraApeStaking.connect(user1.signer).claimPendingReward(5, [0, 1]) + ).to.be.revertedWith(ProtocolErrors.NOT_THE_SAME_OWNER); + + await expect( + paraApeStaking.connect(user1.signer).claimPendingReward(5, [2]) + ).to.be.revertedWith(ProtocolErrors.NFT_NOT_IN_POOL); + + await waitForTx( + await paraApeStaking.connect(user1.signer).claimPendingReward(3, [0]) + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).claimPendingReward(5, [0]) + ); + + await waitForTx( + await paraApeStaking.connect(user2.signer).claimPendingReward(3, [1]) + ); + + await waitForTx( + await paraApeStaking.connect(user2.signer).claimPendingReward(5, [1]) + ); + }); + + it("withdrawNFT revert test", async () => { + const { + users: [user1, user2], + bayc, + bakc, + nBAYC, + nBAKC, + } = await loadFixture(fixture); + + await supplyAndValidate(bayc, "3", user1, true); + await supplyAndValidate(bakc, "3", user1, true); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .depositNFT(bayc.address, [0, 1]) + ); + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .depositNFT(bakc.address, [0, 1]) + ); + + await waitForTx( + await nBAYC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 1) + ); + await waitForTx( + await nBAKC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 1) + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).stakingApe(true, [0, 1]) + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).stakingBAKC({ + baycTokenIds: [0, 1], + bakcPairBaycTokenIds: [0, 1], + maycTokenIds: [], + bakcPairMaycTokenIds: [], + }) + ); + + await expect( + paraApeStaking.connect(user1.signer).withdrawNFT(bayc.address, [0, 1]) + ).to.be.revertedWith(ProtocolErrors.NOT_THE_SAME_OWNER); + + await expect( + paraApeStaking.connect(user1.signer).withdrawNFT(bayc.address, [1]) + ).to.be.revertedWith(ProtocolErrors.NOT_THE_OWNER); + + await expect( + paraApeStaking.connect(user1.signer).withdrawNFT(bakc.address, [0, 1]) + ).to.be.revertedWith(ProtocolErrors.NOT_THE_SAME_OWNER); + + await expect( + paraApeStaking.connect(user1.signer).withdrawNFT(bakc.address, [1]) + ).to.be.revertedWith(ProtocolErrors.NOT_THE_OWNER); + + await waitForTx( + await paraApeStaking.connect(user1.signer).withdrawNFT(bayc.address, [0]) + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).withdrawNFT(bakc.address, [0]) + ); + + await waitForTx( + await paraApeStaking.connect(user2.signer).withdrawNFT(bayc.address, [1]) + ); + + await waitForTx( + await paraApeStaking.connect(user2.signer).withdrawNFT(bakc.address, [1]) + ); + }); + + it("multicall test", async () => { + const { + users: [user1, , , user4], + bayc, + mayc, + bakc, + } = await loadFixture(fixture); + + await supplyAndValidate(bayc, "4", user1, true); + await supplyAndValidate(mayc, "4", user1, true); + await supplyAndValidate(bakc, "4", user1, true); + + let tx0 = paraApeStaking.interface.encodeFunctionData("depositPairNFT", [ + true, + [0, 1], + [0, 1], + ]); + let tx1 = paraApeStaking.interface.encodeFunctionData("depositPairNFT", [ + false, + [0, 1], + [2, 3], + ]); + let tx2 = paraApeStaking.interface.encodeFunctionData("depositNFT", [ + bayc.address, + [2, 3], + ]); + let tx3 = paraApeStaking.interface.encodeFunctionData("depositNFT", [ + mayc.address, + [2, 3], + ]); + + await waitForTx( + await paraApeStaking.connect(user1.signer).multicall([tx0, tx1, tx2, tx3]) + ); + + tx0 = paraApeStaking.interface.encodeFunctionData("stakingPairNFT", [ + true, + [0, 1], + [0, 1], + ]); + tx1 = paraApeStaking.interface.encodeFunctionData("stakingPairNFT", [ + false, + [0, 1], + [2, 3], + ]); + tx2 = paraApeStaking.interface.encodeFunctionData("stakingApe", [ + true, + [2, 3], + ]); + tx3 = paraApeStaking.interface.encodeFunctionData("stakingApe", [ + false, + [2, 3], + ]); + + await waitForTx( + await paraApeStaking.connect(user1.signer).multicall([tx0, tx1, tx2, tx3]) + ); + + await advanceTimeAndBlock(parseInt("3600")); + + await waitForTx( + await paraApeStaking + .connect(user4.signer) + .compoundPairNFT(true, [0, 1], [0, 1]) + ); + await waitForTx( + await paraApeStaking + .connect(user4.signer) + .compoundPairNFT(false, [0, 1], [2, 3]) + ); + await waitForTx( + await paraApeStaking.connect(user4.signer).compoundApe(true, [2, 3]) + ); + await waitForTx( + await paraApeStaking.connect(user4.signer).compoundApe(false, [2, 3]) + ); + + tx0 = paraApeStaking.interface.encodeFunctionData("claimPendingReward", [ + 1, + [0, 1], + ]); + tx1 = paraApeStaking.interface.encodeFunctionData("claimPendingReward", [ + 2, + [0, 1], + ]); + tx2 = paraApeStaking.interface.encodeFunctionData("claimPendingReward", [ + 3, + [2, 3], + ]); + tx3 = paraApeStaking.interface.encodeFunctionData("claimPendingReward", [ + 4, + [2, 3], + ]); + + await waitForTx( + await paraApeStaking.connect(user1.signer).multicall([tx0, tx1, tx2, tx3]) + ); + + await advanceTimeAndBlock(parseInt("3600")); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .withdrawPairNFT(true, [0, 1], [0, 1]) + ); + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .withdrawPairNFT(false, [0, 1], [2, 3]) + ); + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .withdrawNFT(bayc.address, [2, 3]) + ); + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .withdrawNFT(mayc.address, [2, 3]) + ); + }); + + it("ape pair staking reward ratio test", async () => { + const { + users: [user1, user2, user3, user4], + bayc, + mayc, + bakc, + poolAdmin, + } = await loadFixture(fixture); + + await waitForTx( + await paraApeStaking + .connect(poolAdmin.signer) + .setSinglePoolApeRewardRatio(5000) + ); + + await supplyAndValidate(bayc, "2", user1, true); + await supplyAndValidate(mayc, "2", user2, true); + await supplyAndValidate(bakc, "4", user3, true); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .depositNFT(bayc.address, [0, 1]) + ); + await waitForTx( + await paraApeStaking + .connect(user2.signer) + .depositNFT(mayc.address, [0, 1]) + ); + await waitForTx( + await paraApeStaking + .connect(user3.signer) + .depositNFT(bakc.address, [0, 1, 2, 3]) + ); + + await waitForTx( + await paraApeStaking.connect(user4.signer).stakingBAKC({ + baycTokenIds: [0, 1], + bakcPairBaycTokenIds: [0, 1], + maycTokenIds: [0, 1], + bakcPairMaycTokenIds: [2, 3], + }) + ); + + await advanceTimeAndBlock(parseInt("3600")); + + await waitForTx( + await paraApeStaking.connect(user4.signer).compoundBAKC({ + baycTokenIds: [0, 1], + bakcPairBaycTokenIds: [0, 1], + maycTokenIds: [0, 1], + bakcPairMaycTokenIds: [2, 3], + }) + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).claimPendingReward(3, [0, 1]) + ); + await waitForTx( + await paraApeStaking.connect(user2.signer).claimPendingReward(4, [0, 1]) + ); + await waitForTx( + await paraApeStaking + .connect(user3.signer) + .claimPendingReward(5, [0, 1, 2, 3]) + ); + + //user1: 3600 * 0.5 * 0.5 + expect(await cApe.balanceOf(user1.address)).to.be.closeTo( + parseEther("900"), + parseEther("10") + ); + //user1: 3600 * 0.5 * 0.5 + expect(await cApe.balanceOf(user2.address)).to.be.closeTo( + parseEther("900"), + parseEther("10") + ); + //user3: 3600 * 0.5 + expect(await cApe.balanceOf(user3.address)).to.be.closeTo( + parseEther("1800"), + parseEther("10") + ); + + await advanceTimeAndBlock(parseInt("3600")); + + //user1: 900 + 0 + //user2: 900 + 900 + //user3: 1800 + 900 + //user4: 0 + 0 + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .withdrawNFT(bayc.address, [0, 1]) + ); + //user1: 900 + 0 + 0 + //user2: 900 + 900 + 0 + //user3: 1800 + 900 + 900 + //user4: 0 + 900 + await waitForTx( + await paraApeStaking + .connect(user2.signer) + .withdrawNFT(mayc.address, [0, 1]) + ); + //user1: 900 + 0 + 0 + 0 + //user2: 900 + 900 + 0 + 0 + //user3: 1800 + 900 + 900 + 0 + //user4: 0 + 900 + 0 + 0 + await waitForTx( + await paraApeStaking + .connect(user3.signer) + .withdrawNFT(bakc.address, [0, 1, 2, 3]) + ); + await waitForTx( + await paraApeStaking.connect(user4.signer).claimCompoundFee(user4.address) + ); + + expect(await cApe.balanceOf(user1.address)).to.be.closeTo( + parseEther("900"), + parseEther("10") + ); + expect(await cApe.balanceOf(user2.address)).to.be.closeTo( + parseEther("1800"), + parseEther("30") + ); + expect(await cApe.balanceOf(user3.address)).to.be.closeTo( + parseEther("3600"), + parseEther("50") + ); + expect(await cApe.balanceOf(user4.address)).to.be.closeTo( + parseEther("900"), + parseEther("10") + ); + }); + + it("test bakc single pool logic0", async () => { + const { + users: [user1, user2, user3, user4], + bayc, + mayc, + bakc, + poolAdmin, + } = await loadFixture(fixture); + + await waitForTx( + await paraApeStaking + .connect(poolAdmin.signer) + .setSinglePoolApeRewardRatio(5000) + ); + + await supplyAndValidate(bayc, "3", user1, true); + await supplyAndValidate(mayc, "3", user2, true); + await supplyAndValidate(bakc, "4", user3, true); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .depositNFT(bayc.address, [0, 1, 2]) + ); + await waitForTx( + await paraApeStaking + .connect(user2.signer) + .depositNFT(mayc.address, [0, 1, 2]) + ); + await waitForTx( + await paraApeStaking + .connect(user3.signer) + .depositNFT(bakc.address, [0, 1, 2, 3]) + ); + + await waitForTx( + await paraApeStaking.connect(user4.signer).stakingApe(true, [0, 1, 2]) + ); + await waitForTx( + await paraApeStaking.connect(user4.signer).stakingApe(false, [0, 1, 2]) + ); + await waitForTx( + await paraApeStaking.connect(user4.signer).stakingBAKC({ + baycTokenIds: [0, 1], + bakcPairBaycTokenIds: [0, 1], + maycTokenIds: [0, 1], + bakcPairMaycTokenIds: [2, 3], + }) + ); + expect( + await variableDebtCApeCoin.balanceOf(paraApeStaking.address) + ).to.be.closeTo(parseEther("1100000"), parseEther("10")); + + await advanceTimeAndBlock(parseInt("3600")); + + await waitForTx( + await paraApeStaking.connect(user4.signer).compoundBAKC({ + baycTokenIds: [0, 1], + bakcPairBaycTokenIds: [0, 1], + maycTokenIds: [], + bakcPairMaycTokenIds: [], + }) + ); + const user3PendingReward0 = await paraApeStaking.getPendingReward( + 5, + [0, 1, 2, 3] + ); + expect(user3PendingReward0).to.be.closeTo( + parseEther("900"), + parseEther("10") + ); + + await waitForTx( + await paraApeStaking.connect(user4.signer).compoundBAKC({ + baycTokenIds: [], + bakcPairBaycTokenIds: [], + maycTokenIds: [0, 1], + bakcPairMaycTokenIds: [2, 3], + }) + ); + const user3PendingReward1 = await paraApeStaking.getPendingReward( + 5, + [0, 1, 2, 3] + ); + expect(user3PendingReward1).to.be.closeTo( + parseEther("1800"), + parseEther("10") + ); + const user1PendingReward = await paraApeStaking.getPendingReward(3, [0, 1]); + //900 * 2 / 3 + expect(user1PendingReward).to.be.closeTo( + parseEther("600"), + parseEther("10") + ); + const user2PendingReward = await paraApeStaking.getPendingReward(4, [0, 1]); + //900 * 2 / 3 + expect(user2PendingReward).to.be.closeTo( + parseEther("600"), + parseEther("10") + ); + }); + + it("test bakc single pool logic1", async () => { + const { + users: [user1, user2, user3, user4], + bayc, + mayc, + bakc, + poolAdmin, + } = await loadFixture(fixture); + + await waitForTx( + await paraApeStaking + .connect(poolAdmin.signer) + .setSinglePoolApeRewardRatio(5000) + ); + + await supplyAndValidate(bayc, "3", user1, true); + await supplyAndValidate(mayc, "3", user2, true); + await supplyAndValidate(bakc, "4", user3, true); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .depositNFT(bayc.address, [0, 1, 2]) + ); + await waitForTx( + await paraApeStaking + .connect(user2.signer) + .depositNFT(mayc.address, [0, 1, 2]) + ); + await waitForTx( + await paraApeStaking + .connect(user3.signer) + .depositNFT(bakc.address, [0, 1, 2, 3]) + ); + + await waitForTx( + await paraApeStaking.connect(user4.signer).stakingApe(true, [0, 1, 2]) + ); + await waitForTx( + await paraApeStaking.connect(user4.signer).stakingApe(false, [0, 1, 2]) + ); + await waitForTx( + await paraApeStaking.connect(user4.signer).stakingBAKC({ + baycTokenIds: [0, 1], + bakcPairBaycTokenIds: [0, 1], + maycTokenIds: [0, 1], + bakcPairMaycTokenIds: [2, 3], + }) + ); + expect( + await variableDebtCApeCoin.balanceOf(paraApeStaking.address) + ).to.be.closeTo(parseEther("1100000"), parseEther("10")); + + await advanceTimeAndBlock(parseInt("3600")); + + await waitForTx( + await paraApeStaking + .connect(user3.signer) + .withdrawNFT(bakc.address, [0, 1, 2, 3]) + ); + const user1PendingReward = await paraApeStaking.getPendingReward(3, [0, 1]); + //900 * 2 / 3 + expect(user1PendingReward).to.be.closeTo( + parseEther("600"), + parseEther("10") + ); + const user2PendingReward = await paraApeStaking.getPendingReward(4, [0, 1]); + expect(user1PendingReward).to.be.closeTo( + user2PendingReward, + parseEther("1") + ); + }); +}); diff --git a/test/para_pool_ape_staking.spec.ts b/test/para_pool_ape_staking.spec.ts new file mode 100644 index 000000000..1f08b91c2 --- /dev/null +++ b/test/para_pool_ape_staking.spec.ts @@ -0,0 +1,2008 @@ +import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; +import {expect} from "chai"; +import {MAX_UINT_AMOUNT, ONE_ADDRESS} from "../helpers/constants"; +import { + getAutoCompoundApe, + getParaApeStaking, + getPTokenSApe, + getVariableDebtToken, +} from "../helpers/contracts-getters"; +import { + advanceBlock, + advanceTimeAndBlock, + waitForTx, +} from "../helpers/misc-utils"; +import {PTokenSApe, AutoCompoundApe, ParaApeStaking} from "../types"; +import {TestEnv} from "./helpers/make-suite"; +import {testEnvFixture} from "./helpers/setup-env"; + +import { + changePriceAndValidate, + changeSApePriceAndValidate, + mintAndValidate, + supplyAndValidate, +} from "./helpers/validated-steps"; +import {ProtocolErrors} from "../helpers/types"; +import {parseEther} from "ethers/lib/utils"; +import {BigNumber} from "ethers"; +import {isUsingAsCollateral} from "../helpers/contracts-helpers"; + +describe("Para Ape staking ape coin pool test", () => { + let testEnv: TestEnv; + let paraApeStaking: ParaApeStaking; + let cApe: AutoCompoundApe; + let MINIMUM_LIQUIDITY; + let pSApeCoin: PTokenSApe; + const sApeAddress = ONE_ADDRESS; + + const fixture = async () => { + testEnv = await loadFixture(testEnvFixture); + const { + ape, + users: [user1, user2, user3, user4, , user6], + apeCoinStaking, + pool, + protocolDataProvider, + configurator, + poolAdmin, + } = testEnv; + + paraApeStaking = await getParaApeStaking(); + + await waitForTx( + await paraApeStaking + .connect(poolAdmin.signer) + .setApeStakingBot(user4.address) + ); + + cApe = await getAutoCompoundApe(); + MINIMUM_LIQUIDITY = await cApe.MINIMUM_LIQUIDITY(); + + const {xTokenAddress: pSApeCoinAddress} = + await protocolDataProvider.getReserveTokensAddresses(sApeAddress); + pSApeCoin = await getPTokenSApe(pSApeCoinAddress); + + // send extra tokens to the apestaking contract for rewards + await waitForTx( + await ape + .connect(user1.signer) + ["mint(address,uint256)"]( + apeCoinStaking.address, + parseEther("100000000000") + ) + ); + + // user6 deposit MINIMUM_LIQUIDITY to make test case easy + await mintAndValidate(ape, "1", user6); + await waitForTx( + await ape.connect(user6.signer).approve(cApe.address, MAX_UINT_AMOUNT) + ); + await waitForTx( + await cApe.connect(user6.signer).deposit(user6.address, MINIMUM_LIQUIDITY) + ); + + // user4 deposit and supply cApe to MM + expect( + await configurator + .connect(poolAdmin.signer) + .setSupplyCap(cApe.address, "20000000000") + ); + await mintAndValidate(ape, "10000000000", user4); + await waitForTx( + await ape.connect(user4.signer).approve(cApe.address, MAX_UINT_AMOUNT) + ); + await waitForTx( + await cApe + .connect(user4.signer) + .deposit(user4.address, parseEther("10000000000")) + ); + await waitForTx( + await cApe.connect(user4.signer).approve(pool.address, MAX_UINT_AMOUNT) + ); + await waitForTx( + await pool + .connect(user4.signer) + .supply(cApe.address, parseEther("10000000000"), user4.address, 0) + ); + + // user approve ape coin to Para ape staking + await waitForTx( + await ape + .connect(user1.signer) + .approve(paraApeStaking.address, MAX_UINT_AMOUNT) + ); + await waitForTx( + await ape + .connect(user2.signer) + .approve(paraApeStaking.address, MAX_UINT_AMOUNT) + ); + await waitForTx( + await ape + .connect(user3.signer) + .approve(paraApeStaking.address, MAX_UINT_AMOUNT) + ); + + return testEnv; + }; + + it("test borrowAndStakingApeCoin", async () => { + const { + users: [user1, user2, , user4], + ape, + bayc, + mayc, + bakc, + nBAKC, + apeCoinStaking, + pool, + protocolDataProvider, + poolAdmin, + } = await loadFixture(fixture); + + await waitForTx( + await pool + .connect(poolAdmin.signer) + .unlimitedApproveTo(ape.address, paraApeStaking.address) + ); + await waitForTx( + await pool + .connect(poolAdmin.signer) + .unlimitedApproveTo(cApe.address, paraApeStaking.address) + ); + await waitForTx( + await ape.connect(user1.signer).approve(pool.address, MAX_UINT_AMOUNT) + ); + await waitForTx( + await cApe.connect(user2.signer).approve(pool.address, MAX_UINT_AMOUNT) + ); + + //prepare user3 asset + await mintAndValidate(ape, "20000000", user4); + await waitForTx( + await ape.connect(user4.signer).approve(pool.address, MAX_UINT_AMOUNT) + ); + await waitForTx( + await ape.connect(user4.signer).approve(cApe.address, MAX_UINT_AMOUNT) + ); + await waitForTx( + await cApe.connect(user4.signer).approve(pool.address, MAX_UINT_AMOUNT) + ); + await waitForTx( + await pool + .connect(user4.signer) + .supply(ape.address, parseEther("10000000"), user4.address, 0) + ); + await waitForTx( + await cApe + .connect(user4.signer) + .deposit(user4.address, parseEther("10000000")) + ); + await waitForTx( + await pool + .connect(user4.signer) + .supply(cApe.address, parseEther("10000000"), user4.address, 0) + ); + + //prepare user1 user2 asset + await supplyAndValidate(bayc, "1", user1, true); + await supplyAndValidate(bakc, "2", user1, true); + await mintAndValidate(ape, "100000", user1); + await supplyAndValidate(mayc, "1", user2, true); + await waitForTx( + await nBAKC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 1) + ); + await waitForTx( + await ape + .connect(user1.signer) + .approve(paraApeStaking.address, MAX_UINT_AMOUNT) + ); + await waitForTx( + await cApe + .connect(user2.signer) + .approve(paraApeStaking.address, MAX_UINT_AMOUNT) + ); + + await changePriceAndValidate(bayc, "100"); + await changePriceAndValidate(mayc, "50"); + await changePriceAndValidate(bakc, "25"); + await changePriceAndValidate(ape, "0.001"); + await changePriceAndValidate(cApe, "0.001"); + await changeSApePriceAndValidate(sApeAddress, "0.001"); + + //collateral value = 100 * 0.3 + 25 * 0.3 + 250000*0.001 * 0.2 = + //borrow value = 150000 * 0.001 + await expect( + pool.connect(user1.signer).borrowAndStakingApeCoin( + [ + { + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("200000"), + isBAYC: true, + tokenIds: [0], + }, + ], + [ + { + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("50000"), + isBAYC: true, + apeTokenIds: [0], + bakcTokenIds: [0], + }, + ], + ape.address, + parseEther("100000"), + parseEther("150000"), + true + ) + ).to.be.revertedWith(ProtocolErrors.COLLATERAL_CANNOT_COVER_NEW_BORROW); + + await mintAndValidate(ape, "20000000", user2); + await waitForTx( + await ape.connect(user2.signer).approve(pool.address, MAX_UINT_AMOUNT) + ); + await expect( + pool.connect(user2.signer).borrowAndStakingApeCoin( + [ + { + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("200000"), + isBAYC: true, + tokenIds: [0], + }, + ], + [ + { + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("50000"), + isBAYC: true, + apeTokenIds: [0], + bakcTokenIds: [0], + }, + ], + ape.address, + parseEther("100000"), + parseEther("150000"), + true + ) + ).to.be.revertedWith(ProtocolErrors.CALLER_NOT_ALLOWED); + + await changePriceAndValidate(ape, "0.00001"); + await changePriceAndValidate(cApe, "0.00001"); + await changeSApePriceAndValidate(sApeAddress, "0.00001"); + + //user1 borrow ape to stake + await waitForTx( + await pool.connect(user1.signer).borrowAndStakingApeCoin( + [ + { + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("200000"), + isBAYC: true, + tokenIds: [0], + }, + ], + [ + { + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("50000"), + isBAYC: true, + apeTokenIds: [0], + bakcTokenIds: [0], + }, + ], + ape.address, + parseEther("100000"), + parseEther("150000"), + true + ) + ); + + //user2 borrow cApe to stake + await waitForTx( + await pool.connect(user2.signer).borrowAndStakingApeCoin( + [ + { + onBehalf: user2.address, + cashToken: cApe.address, + cashAmount: parseEther("100000"), + isBAYC: false, + tokenIds: [0], + }, + ], + [ + { + onBehalf: user2.address, + cashToken: cApe.address, + cashAmount: parseEther("50000"), + isBAYC: false, + apeTokenIds: [0], + bakcTokenIds: [1], + }, + ], + cApe.address, + parseEther("0"), + parseEther("150000"), + true + ) + ); + const sApeData = await pool.getReserveData(sApeAddress); + const user1Config = BigNumber.from( + (await pool.getUserConfiguration(user1.address)).data + ); + const user2Config = BigNumber.from( + (await pool.getUserConfiguration(user2.address)).data + ); + expect(isUsingAsCollateral(user1Config, sApeData.id)).to.be.true; + expect(isUsingAsCollateral(user2Config, sApeData.id)).to.be.true; + + const {variableDebtTokenAddress: variableDebtApeCoinAddress} = + await protocolDataProvider.getReserveTokensAddresses(ape.address); + const variableDebtApeCoin = await getVariableDebtToken( + variableDebtApeCoinAddress + ); + const {variableDebtTokenAddress: variableDebtCApeCoinAddress} = + await protocolDataProvider.getReserveTokensAddresses(cApe.address); + const variableDebtCApeCoin = await getVariableDebtToken( + variableDebtCApeCoinAddress + ); + //check user1 debt + expect(await variableDebtApeCoin.balanceOf(user1.address)).to.be.closeTo( + parseEther("150000"), + parseEther("50") + ); + expect(await variableDebtCApeCoin.balanceOf(user1.address)).to.be.equal( + "0" + ); + + //check user2 debt + expect(await variableDebtApeCoin.balanceOf(user2.address)).to.be.eq("0"); + expect(await variableDebtCApeCoin.balanceOf(user2.address)).to.be.closeTo( + parseEther("150000"), + parseEther("50") + ); + + expect((await apeCoinStaking.nftPosition(1, 0)).stakedAmount).to.be.eq( + parseEther("200000") + ); + expect((await apeCoinStaking.nftPosition(2, 0)).stakedAmount).to.be.eq( + parseEther("100000") + ); + expect((await apeCoinStaking.nftPosition(3, 0)).stakedAmount).to.be.eq( + parseEther("50000") + ); + expect((await apeCoinStaking.nftPosition(3, 1)).stakedAmount).to.be.eq( + parseEther("50000") + ); + }); + + it("test BAYC + ApeCoin pool logic", async () => { + const { + users: [user1, user2, , user4], + ape, + bayc, + bakc, + nBAYC, + nBAKC, + poolAdmin, + apeCoinStaking, + } = await loadFixture(fixture); + + //mint ape + await mintAndValidate(ape, "1000000", user1); + await mintAndValidate(ape, "1000000", user2); + + await waitForTx( + await paraApeStaking.connect(poolAdmin.signer).setCompoundFee(1000) + ); + + await supplyAndValidate(bayc, "3", user1, true); + await supplyAndValidate(bakc, "3", user1, true); + + await waitForTx( + await nBAYC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 2) + ); + await waitForTx( + await nBAKC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 2) + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).depositApeCoinPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("400000"), + isBAYC: true, + tokenIds: [0, 1], + }) + ); + await waitForTx( + await paraApeStaking.connect(user2.signer).depositApeCoinPool({ + onBehalf: user2.address, + cashToken: ape.address, + cashAmount: parseEther("200000"), + isBAYC: true, + tokenIds: [2], + }) + ); + expect(await bayc.ownerOf(0)).to.be.equal(paraApeStaking.address); + expect(await bayc.ownerOf(1)).to.be.equal(paraApeStaking.address); + expect(await bayc.ownerOf(2)).to.be.equal(paraApeStaking.address); + + await waitForTx( + await paraApeStaking.connect(user1.signer).depositApeCoinPairPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("100000"), + isBAYC: true, + apeTokenIds: [0, 1], + bakcTokenIds: [0, 1], + }) + ); + await waitForTx( + await paraApeStaking.connect(user2.signer).depositApeCoinPairPool({ + onBehalf: user2.address, + cashToken: ape.address, + cashAmount: parseEther("50000"), + isBAYC: true, + apeTokenIds: [2], + bakcTokenIds: [2], + }) + ); + expect(await bakc.ownerOf(0)).to.be.equal(paraApeStaking.address); + expect(await bakc.ownerOf(1)).to.be.equal(paraApeStaking.address); + expect(await bakc.ownerOf(2)).to.be.equal(paraApeStaking.address); + + expect((await apeCoinStaking.nftPosition(1, 0)).stakedAmount).to.be.eq( + parseEther("200000") + ); + expect((await apeCoinStaking.nftPosition(1, 1)).stakedAmount).to.be.eq( + parseEther("200000") + ); + expect((await apeCoinStaking.nftPosition(1, 2)).stakedAmount).to.be.eq( + parseEther("200000") + ); + expect((await apeCoinStaking.nftPosition(3, 0)).stakedAmount).to.be.eq( + parseEther("50000") + ); + expect((await apeCoinStaking.nftPosition(3, 1)).stakedAmount).to.be.eq( + parseEther("50000") + ); + expect((await apeCoinStaking.nftPosition(3, 2)).stakedAmount).to.be.eq( + parseEther("50000") + ); + + await advanceTimeAndBlock(parseInt("3600")); + + await waitForTx( + await paraApeStaking + .connect(user4.signer) + .compoundApeCoinPool(true, [0, 1, 2]) + ); + let compoundFee = await paraApeStaking.pendingCApeReward( + paraApeStaking.address + ); + expect(compoundFee).to.be.closeTo(parseEther("360"), parseEther("1")); + + let user1PendingReward = await paraApeStaking.getPendingReward(6, [0, 1]); + let user2PendingReward = await paraApeStaking.getPendingReward(6, [2]); + expect(user1PendingReward).to.be.closeTo( + parseEther("2160"), + parseEther("1") + ); + expect(user2PendingReward).to.be.closeTo( + parseEther("1080"), + parseEther("1") + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).claimPendingReward(6, [0, 1]) + ); + await waitForTx( + await paraApeStaking.connect(user2.signer).claimPendingReward(6, [2]) + ); + let user1Balance = await cApe.balanceOf(user1.address); + let user2Balance = await cApe.balanceOf(user2.address); + expect(user1Balance).to.be.closeTo(user1PendingReward, parseEther("1")); + expect(user2Balance).to.be.closeTo(user2PendingReward, parseEther("1")); + + user1PendingReward = await paraApeStaking.getPendingReward(6, [0, 1]); + user2PendingReward = await paraApeStaking.getPendingReward(6, [2]); + expect(user1PendingReward).to.be.equal(0); + expect(user2PendingReward).to.be.equal(0); + + await waitForTx( + await paraApeStaking + .connect(user4.signer) + .compoundApeCoinPairPool(true, [0, 1, 2], [0, 1, 2]) + ); + compoundFee = await paraApeStaking.pendingCApeReward( + paraApeStaking.address + ); + expect(compoundFee).to.be.closeTo(parseEther("720"), parseEther("1")); + + user1PendingReward = await paraApeStaking.getPendingReward(8, [0, 1]); + user2PendingReward = await paraApeStaking.getPendingReward(8, [2]); + expect(user1PendingReward).to.be.closeTo( + parseEther("2160"), + parseEther("1") + ); + expect(user2PendingReward).to.be.closeTo( + parseEther("1080"), + parseEther("1") + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).claimPendingReward(8, [0, 1]) + ); + await waitForTx( + await paraApeStaking.connect(user2.signer).claimPendingReward(8, [2]) + ); + user1Balance = await cApe.balanceOf(user1.address); + user2Balance = await cApe.balanceOf(user2.address); + expect(user1Balance).to.be.closeTo( + user1PendingReward.mul(2), + parseEther("1") + ); + expect(user2Balance).to.be.closeTo( + user2PendingReward.mul(2), + parseEther("1") + ); + + user1PendingReward = await paraApeStaking.getPendingReward(8, [0, 1]); + user2PendingReward = await paraApeStaking.getPendingReward(8, [2]); + expect(user1PendingReward).to.be.equal(0); + expect(user2PendingReward).to.be.equal(0); + + await advanceTimeAndBlock(parseInt("3600")); + + await waitForTx( + await paraApeStaking.connect(user1.signer).withdrawApeCoinPool({ + cashToken: ape.address, + cashAmount: parseEther("400000"), + isBAYC: true, + tokenIds: [0, 1], + }) + ); + await waitForTx( + await paraApeStaking.connect(user2.signer).withdrawApeCoinPool({ + cashToken: ape.address, + cashAmount: parseEther("200000"), + isBAYC: true, + tokenIds: [2], + }) + ); + expect(await bayc.ownerOf(0)).to.be.equal(paraApeStaking.address); + expect(await bayc.ownerOf(1)).to.be.equal(paraApeStaking.address); + expect(await bayc.ownerOf(2)).to.be.equal(paraApeStaking.address); + await waitForTx( + await paraApeStaking.connect(user1.signer).withdrawApeCoinPairPool({ + cashToken: ape.address, + cashAmount: parseEther("100000"), + isBAYC: true, + apeTokenIds: [0, 1], + bakcTokenIds: [0, 1], + }) + ); + await waitForTx( + await paraApeStaking.connect(user2.signer).withdrawApeCoinPairPool({ + cashToken: ape.address, + cashAmount: parseEther("50000"), + isBAYC: true, + apeTokenIds: [2], + bakcTokenIds: [2], + }) + ); + expect(await bayc.ownerOf(0)).to.be.equal(nBAYC.address); + expect(await bayc.ownerOf(1)).to.be.equal(nBAYC.address); + expect(await bayc.ownerOf(2)).to.be.equal(nBAYC.address); + expect(await bakc.ownerOf(0)).to.be.equal(nBAKC.address); + expect(await bakc.ownerOf(1)).to.be.equal(nBAKC.address); + expect(await bakc.ownerOf(2)).to.be.equal(nBAKC.address); + + compoundFee = await paraApeStaking.pendingCApeReward( + paraApeStaking.address + ); + //720 + 720 + 3600 * 0.9 / 3 * 2 + expect(compoundFee).to.be.closeTo(parseEther("3600"), parseEther("1")); + await waitForTx( + await paraApeStaking.connect(user4.signer).claimCompoundFee(user4.address) + ); + const compoundFeeBalance = await cApe.balanceOf(user4.address); + expect(compoundFeeBalance).to.be.closeTo(compoundFee, parseEther("1")); + + user1Balance = await cApe.balanceOf(user1.address); + user2Balance = await cApe.balanceOf(user2.address); + //2160 * 2 + 0 + expect(user1Balance).to.be.closeTo(parseEther("4320"), parseEther("1")); + //1080 * 2 + 2160 * 2 + expect(user2Balance).to.be.closeTo(parseEther("6480"), parseEther("1")); + + expect(await ape.balanceOf(user1.address)).to.be.equal( + parseEther("1000000") + ); + expect(await ape.balanceOf(user2.address)).to.be.equal( + parseEther("1000000") + ); + }); + + it("test MAYC + ApeCoin pool logic", async () => { + const { + users: [user1, user2, , user4], + ape, + mayc, + bakc, + nMAYC, + nBAKC, + poolAdmin, + apeCoinStaking, + } = await loadFixture(fixture); + + //mint ape + await mintAndValidate(ape, "1000000", user1); + await mintAndValidate(ape, "1000000", user2); + + await waitForTx( + await paraApeStaking.connect(poolAdmin.signer).setCompoundFee(1000) + ); + + await supplyAndValidate(mayc, "3", user1, true); + await supplyAndValidate(bakc, "3", user1, true); + + await waitForTx( + await nMAYC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 2) + ); + await waitForTx( + await nBAKC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 2) + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).depositApeCoinPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("200000"), + isBAYC: false, + tokenIds: [0, 1], + }) + ); + await waitForTx( + await paraApeStaking.connect(user2.signer).depositApeCoinPool({ + onBehalf: user2.address, + cashToken: ape.address, + cashAmount: parseEther("100000"), + isBAYC: false, + tokenIds: [2], + }) + ); + expect(await mayc.ownerOf(0)).to.be.equal(paraApeStaking.address); + expect(await mayc.ownerOf(1)).to.be.equal(paraApeStaking.address); + expect(await mayc.ownerOf(2)).to.be.equal(paraApeStaking.address); + + await waitForTx( + await paraApeStaking.connect(user1.signer).depositApeCoinPairPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("100000"), + isBAYC: false, + apeTokenIds: [0, 1], + bakcTokenIds: [0, 1], + }) + ); + await waitForTx( + await paraApeStaking.connect(user2.signer).depositApeCoinPairPool({ + onBehalf: user2.address, + cashToken: ape.address, + cashAmount: parseEther("50000"), + isBAYC: false, + apeTokenIds: [2], + bakcTokenIds: [2], + }) + ); + expect(await bakc.ownerOf(0)).to.be.equal(paraApeStaking.address); + expect(await bakc.ownerOf(1)).to.be.equal(paraApeStaking.address); + expect(await bakc.ownerOf(2)).to.be.equal(paraApeStaking.address); + + expect((await apeCoinStaking.nftPosition(2, 0)).stakedAmount).to.be.eq( + parseEther("100000") + ); + expect((await apeCoinStaking.nftPosition(2, 1)).stakedAmount).to.be.eq( + parseEther("100000") + ); + expect((await apeCoinStaking.nftPosition(2, 2)).stakedAmount).to.be.eq( + parseEther("100000") + ); + expect((await apeCoinStaking.nftPosition(3, 0)).stakedAmount).to.be.eq( + parseEther("50000") + ); + expect((await apeCoinStaking.nftPosition(3, 1)).stakedAmount).to.be.eq( + parseEther("50000") + ); + expect((await apeCoinStaking.nftPosition(3, 2)).stakedAmount).to.be.eq( + parseEther("50000") + ); + + await advanceTimeAndBlock(parseInt("3600")); + + await waitForTx( + await paraApeStaking + .connect(user4.signer) + .compoundApeCoinPool(false, [0, 1, 2]) + ); + let compoundFee = await paraApeStaking.pendingCApeReward( + paraApeStaking.address + ); + expect(compoundFee).to.be.closeTo(parseEther("360"), parseEther("1")); + + let user1PendingReward = await paraApeStaking.getPendingReward(7, [0, 1]); + let user2PendingReward = await paraApeStaking.getPendingReward(7, [2]); + expect(user1PendingReward).to.be.closeTo( + parseEther("2160"), + parseEther("1") + ); + expect(user2PendingReward).to.be.closeTo( + parseEther("1080"), + parseEther("1") + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).claimPendingReward(7, [0, 1]) + ); + await waitForTx( + await paraApeStaking.connect(user2.signer).claimPendingReward(7, [2]) + ); + let user1Balance = await cApe.balanceOf(user1.address); + let user2Balance = await cApe.balanceOf(user2.address); + expect(user1Balance).to.be.closeTo(user1PendingReward, parseEther("1")); + expect(user2Balance).to.be.closeTo(user2PendingReward, parseEther("1")); + + user1PendingReward = await paraApeStaking.getPendingReward(7, [0, 1]); + user2PendingReward = await paraApeStaking.getPendingReward(7, [2]); + expect(user1PendingReward).to.be.equal(0); + expect(user2PendingReward).to.be.equal(0); + + await waitForTx( + await paraApeStaking + .connect(user4.signer) + .compoundApeCoinPairPool(false, [0, 1, 2], [0, 1, 2]) + ); + compoundFee = await paraApeStaking.pendingCApeReward( + paraApeStaking.address + ); + expect(compoundFee).to.be.closeTo(parseEther("720"), parseEther("1")); + + user1PendingReward = await paraApeStaking.getPendingReward(9, [0, 1]); + user2PendingReward = await paraApeStaking.getPendingReward(9, [2]); + expect(user1PendingReward).to.be.closeTo( + parseEther("2160"), + parseEther("1") + ); + expect(user2PendingReward).to.be.closeTo( + parseEther("1080"), + parseEther("1") + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).claimPendingReward(9, [0, 1]) + ); + await waitForTx( + await paraApeStaking.connect(user2.signer).claimPendingReward(9, [2]) + ); + user1Balance = await cApe.balanceOf(user1.address); + user2Balance = await cApe.balanceOf(user2.address); + expect(user1Balance).to.be.closeTo( + user1PendingReward.mul(2), + parseEther("1") + ); + expect(user2Balance).to.be.closeTo( + user2PendingReward.mul(2), + parseEther("1") + ); + + user1PendingReward = await paraApeStaking.getPendingReward(9, [0, 1]); + user2PendingReward = await paraApeStaking.getPendingReward(9, [2]); + expect(user1PendingReward).to.be.equal(0); + expect(user2PendingReward).to.be.equal(0); + + await advanceTimeAndBlock(parseInt("3600")); + + await waitForTx( + await paraApeStaking.connect(user1.signer).withdrawApeCoinPool({ + cashToken: ape.address, + cashAmount: parseEther("200000"), + isBAYC: false, + tokenIds: [0, 1], + }) + ); + await waitForTx( + await paraApeStaking.connect(user2.signer).withdrawApeCoinPool({ + cashToken: ape.address, + cashAmount: parseEther("100000"), + isBAYC: false, + tokenIds: [2], + }) + ); + expect(await mayc.ownerOf(0)).to.be.equal(paraApeStaking.address); + expect(await mayc.ownerOf(1)).to.be.equal(paraApeStaking.address); + expect(await mayc.ownerOf(2)).to.be.equal(paraApeStaking.address); + await waitForTx( + await paraApeStaking.connect(user1.signer).withdrawApeCoinPairPool({ + cashToken: ape.address, + cashAmount: parseEther("100000"), + isBAYC: false, + apeTokenIds: [0, 1], + bakcTokenIds: [0, 1], + }) + ); + await waitForTx( + await paraApeStaking.connect(user2.signer).withdrawApeCoinPairPool({ + cashToken: ape.address, + cashAmount: parseEther("50000"), + isBAYC: false, + apeTokenIds: [2], + bakcTokenIds: [2], + }) + ); + expect(await mayc.ownerOf(0)).to.be.equal(nMAYC.address); + expect(await mayc.ownerOf(1)).to.be.equal(nMAYC.address); + expect(await mayc.ownerOf(2)).to.be.equal(nMAYC.address); + expect(await bakc.ownerOf(0)).to.be.equal(nBAKC.address); + expect(await bakc.ownerOf(1)).to.be.equal(nBAKC.address); + expect(await bakc.ownerOf(2)).to.be.equal(nBAKC.address); + + compoundFee = await paraApeStaking.pendingCApeReward( + paraApeStaking.address + ); + //720 + 720 + 3600 * 0.9 / 3 * 2 + expect(compoundFee).to.be.closeTo(parseEther("3600"), parseEther("1")); + await waitForTx( + await paraApeStaking.connect(user4.signer).claimCompoundFee(user4.address) + ); + const compoundFeeBalance = await cApe.balanceOf(user4.address); + expect(compoundFeeBalance).to.be.closeTo(compoundFee, parseEther("1")); + + user1Balance = await cApe.balanceOf(user1.address); + user2Balance = await cApe.balanceOf(user2.address); + //2160 * 2 + 0 + expect(user1Balance).to.be.closeTo(parseEther("4320"), parseEther("1")); + //1080 * 2 + 2160 * 2 + expect(user2Balance).to.be.closeTo(parseEther("6480"), parseEther("1")); + + expect(await ape.balanceOf(user1.address)).to.be.equal( + parseEther("1000000") + ); + expect(await ape.balanceOf(user2.address)).to.be.equal( + parseEther("1000000") + ); + }); + + it("sApe test0: unstake sApe when user hf < 1", async () => { + const { + users: [user1, user2, liquidator], + ape, + bayc, + mayc, + bakc, + pool, + nBAYC, + nMAYC, + } = await loadFixture(fixture); + + await changePriceAndValidate(bayc, "100"); + await changePriceAndValidate(mayc, "50"); + await changePriceAndValidate(bakc, "25"); + await changePriceAndValidate(ape, "0.00001"); + + //user1 collateral 200eth + await supplyAndValidate(bayc, "1", user1, true); + await supplyAndValidate(mayc, "1", user1, true); + await supplyAndValidate(bakc, "2", user1, true); + + await supplyAndValidate(ape, "2000000", user2, true); + + //user1 borrow value 0.00001 * 1000000 = 10eth + await waitForTx( + await pool + .connect(user1.signer) + .borrow(ape.address, parseEther("1000000"), 0, user1.address) + ); + expect(await ape.balanceOf(user1.address)).to.be.equal( + parseEther("1000000") + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).depositApeCoinPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("200000"), + isBAYC: true, + tokenIds: [0], + }) + ); + await waitForTx( + await paraApeStaking.connect(user1.signer).depositApeCoinPairPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("50000"), + isBAYC: true, + apeTokenIds: [0], + bakcTokenIds: [0], + }) + ); + await waitForTx( + await paraApeStaking.connect(user1.signer).depositApeCoinPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("100000"), + isBAYC: false, + tokenIds: [0], + }) + ); + await waitForTx( + await paraApeStaking.connect(user1.signer).depositApeCoinPairPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("50000"), + isBAYC: false, + apeTokenIds: [0], + bakcTokenIds: [1], + }) + ); + + await waitForTx( + await pool + .connect(user1.signer) + .setUserUseERC20AsCollateral(sApeAddress, true) + ); + + expect(await ape.balanceOf(user1.address)).to.be.equal( + parseEther("600000") + ); + expect(await pSApeCoin.balanceOf(user1.address)).to.be.equal( + parseEther("400000") + ); + expect(await paraApeStaking.stakedSApeBalance(user1.address)).to.be.equal( + parseEther("400000") + ); + expect(await paraApeStaking.freeSApeBalance(user1.address)).to.be.equal( + parseEther("0") + ); + + await expect( + nBAYC + .connect(liquidator.signer) + .unstakeApeStakingPosition(user2.address, [0]) + ).to.be.revertedWith(ProtocolErrors.NOT_THE_OWNER); + await expect( + nBAYC + .connect(liquidator.signer) + .unstakeApeStakingPosition(user1.address, [0]) + ).to.be.revertedWith(ProtocolErrors.HEALTH_FACTOR_NOT_BELOW_THRESHOLD); + + //user1 borrow value = 200 eth + await changePriceAndValidate(ape, "0.002"); + await changeSApePriceAndValidate(sApeAddress, "0.002"); + + await waitForTx( + await nBAYC + .connect(liquidator.signer) + .unstakeApeStakingPosition(user1.address, [0]) + ); + await waitForTx( + await nMAYC + .connect(liquidator.signer) + .unstakeApeStakingPosition(user1.address, [0]) + ); + + expect(await pSApeCoin.balanceOf(user1.address)).to.be.equal( + parseEther("400000") + ); + expect(await paraApeStaking.stakedSApeBalance(user1.address)).to.be.equal( + parseEther("0") + ); + expect(await paraApeStaking.freeSApeBalance(user1.address)).to.be.equal( + parseEther("400000") + ); + }); + + it("sApe test1: Ape coin pool sApe liquidation", async () => { + const { + users: [user1, user2, liquidator], + ape, + weth, + bayc, + mayc, + bakc, + pool, + nBAYC, + nMAYC, + } = await loadFixture(fixture); + + await changePriceAndValidate(bayc, "100"); + await changePriceAndValidate(mayc, "50"); + await changePriceAndValidate(bakc, "25"); + await changePriceAndValidate(ape, "0.00001"); + + //user1 collateral 200eth + await supplyAndValidate(bayc, "1", user1, true); + await supplyAndValidate(mayc, "1", user1, true); + await supplyAndValidate(bakc, "2", user1, true); + + await supplyAndValidate(ape, "2000000", user2, true); + + //user1 borrow value 0.00001 * 1000000 = 10eth + await waitForTx( + await pool + .connect(user1.signer) + .borrow(ape.address, parseEther("1000000"), 0, user1.address) + ); + expect(await ape.balanceOf(user1.address)).to.be.equal( + parseEther("1000000") + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).depositApeCoinPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("200000"), + isBAYC: true, + tokenIds: [0], + }) + ); + await waitForTx( + await paraApeStaking.connect(user1.signer).depositApeCoinPairPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("50000"), + isBAYC: true, + apeTokenIds: [0], + bakcTokenIds: [0], + }) + ); + await waitForTx( + await paraApeStaking.connect(user1.signer).depositApeCoinPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("100000"), + isBAYC: false, + tokenIds: [0], + }) + ); + await waitForTx( + await paraApeStaking.connect(user1.signer).depositApeCoinPairPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("50000"), + isBAYC: false, + apeTokenIds: [0], + bakcTokenIds: [1], + }) + ); + expect(await ape.balanceOf(user1.address)).to.be.equal( + parseEther("600000") + ); + expect(await pSApeCoin.balanceOf(user1.address)).to.be.equal( + parseEther("400000") + ); + expect(await paraApeStaking.stakedSApeBalance(user1.address)).to.be.equal( + parseEther("400000") + ); + expect(await paraApeStaking.freeSApeBalance(user1.address)).to.be.equal( + parseEther("0") + ); + + //user1 borrow value = 200 eth + await changePriceAndValidate(ape, "0.0002"); + await changeSApePriceAndValidate(sApeAddress, "0.0002"); + + await mintAndValidate(weth, "200", liquidator); + await waitForTx( + await weth + .connect(liquidator.signer) + .approve(pool.address, MAX_UINT_AMOUNT) + ); + + // start auction + await waitForTx( + await pool + .connect(liquidator.signer) + .startAuction(user1.address, bayc.address, 0) + ); + let auctionData = await pool.getAuctionData(nBAYC.address, 0); + await advanceBlock( + auctionData.startTime + .add(auctionData.tickLength.mul(BigNumber.from(40))) + .toNumber() + ); + + // try to liquidate the NFT + expect( + await pool + .connect(liquidator.signer) + .liquidateERC721( + bayc.address, + user1.address, + 0, + parseEther("100"), + true, + {gasLimit: 5000000} + ) + ); + expect(await pSApeCoin.balanceOf(user1.address)).to.be.closeTo( + parseEther("400000"), + parseEther("1") + ); + expect(await paraApeStaking.stakedSApeBalance(user1.address)).to.be.closeTo( + parseEther("150000"), + parseEther("1") + ); + expect(await paraApeStaking.freeSApeBalance(user1.address)).to.be.closeTo( + parseEther("250000"), + parseEther("1") + ); + + await waitForTx( + await pool + .connect(liquidator.signer) + .startAuction(user1.address, mayc.address, 0) + ); + auctionData = await pool.getAuctionData(nMAYC.address, 0); + await advanceBlock( + auctionData.startTime + .add(auctionData.tickLength.mul(BigNumber.from(40))) + .toNumber() + ); + + expect( + await pool + .connect(liquidator.signer) + .liquidateERC721( + mayc.address, + user1.address, + 0, + parseEther("50"), + true, + {gasLimit: 5000000} + ) + ); + expect(await pSApeCoin.balanceOf(user1.address)).to.be.closeTo( + parseEther("400000"), + parseEther("1") + ); + expect(await paraApeStaking.stakedSApeBalance(user1.address)).to.be.closeTo( + parseEther("0"), + parseEther("1") + ); + expect(await paraApeStaking.freeSApeBalance(user1.address)).to.be.closeTo( + parseEther("400000"), + parseEther("1") + ); + + const accountData0 = await pool.getUserAccountData(user1.address); + await waitForTx( + await pool + .connect(user1.signer) + .setUserUseERC20AsCollateral(sApeAddress, true) + ); + const accountData1 = await pool.getUserAccountData(user1.address); + //400000 * 0.0002 = 80 + expect( + accountData1.totalCollateralBase.sub(accountData0.totalCollateralBase) + ).to.be.closeTo(parseEther("80"), parseEther("1")); + + await changePriceAndValidate(ape, "0.0004"); + await changeSApePriceAndValidate(sApeAddress, "0.0004"); + + //liquidate sApe + await mintAndValidate(ape, "1000000", liquidator); + await waitForTx( + await ape + .connect(liquidator.signer) + .approve(pool.address, MAX_UINT_AMOUNT) + ); + + await waitForTx( + await pool + .connect(liquidator.signer) + .liquidateERC20( + sApeAddress, + ape.address, + user1.address, + parseEther("400000"), + true + ) + ); + const user1Balance = await pSApeCoin.balanceOf(user1.address); + const liquidatorBalance = await pSApeCoin.balanceOf(liquidator.address); + expect(user1Balance).to.be.closeTo("0", parseEther("1")); + expect(liquidatorBalance).to.be.closeTo( + parseEther("400000"), + parseEther("1") + ); + }); + + it("sApe test2: sApe deposit and withdraw", async () => { + const { + users: [user1], + ape, + } = await loadFixture(fixture); + await mintAndValidate(ape, "1000000", user1); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .depositFreeSApe(ape.address, parseEther("1000000")) + ); + + expect(await ape.balanceOf(user1.address)).to.be.equal("0"); + expect(await paraApeStaking.totalSApeBalance(user1.address)).to.be.closeTo( + parseEther("1000000"), + parseEther("1") + ); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .withdrawFreeSApe(ape.address, parseEther("1000000")) + ); + + expect(await ape.balanceOf(user1.address)).to.be.closeTo( + parseEther("1000000"), + parseEther("1") + ); + expect(await paraApeStaking.totalSApeBalance(user1.address)).to.be.closeTo( + "0", + parseEther("1") + ); + + await waitForTx( + await ape.connect(user1.signer).approve(cApe.address, MAX_UINT_AMOUNT) + ); + await waitForTx( + await cApe + .connect(user1.signer) + .deposit(user1.address, parseEther("1000000")) + ); + expect(await ape.balanceOf(user1.address)).to.be.equal("0"); + expect(await cApe.balanceOf(user1.address)).to.be.closeTo( + parseEther("1000000"), + parseEther("1") + ); + + await waitForTx( + await cApe + .connect(user1.signer) + .approve(paraApeStaking.address, MAX_UINT_AMOUNT) + ); + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .depositFreeSApe(cApe.address, parseEther("1000000")) + ); + expect(await cApe.balanceOf(user1.address)).to.be.equal("0"); + expect(await paraApeStaking.totalSApeBalance(user1.address)).to.be.closeTo( + parseEther("1000000"), + parseEther("1") + ); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .withdrawFreeSApe(cApe.address, parseEther("1000000")) + ); + + expect(await cApe.balanceOf(user1.address)).to.be.closeTo( + parseEther("1000000"), + parseEther("1") + ); + expect(await paraApeStaking.totalSApeBalance(user1.address)).to.be.closeTo( + "0", + parseEther("1") + ); + }); + + it("depositApeCoinPool revert test", async () => { + const { + users: [user1, user2], + ape, + bayc, + } = await loadFixture(fixture); + + await mintAndValidate(ape, "2000000", user1); + await supplyAndValidate(bayc, "1", user1, true); + + await expect( + paraApeStaking.connect(user1.signer).depositApeCoinPool({ + onBehalf: user2.address, + cashToken: ape.address, + cashAmount: parseEther("200000"), + isBAYC: true, + tokenIds: [0], + }) + ).to.be.revertedWith(ProtocolErrors.CALLER_NOT_ALLOWED); + + await expect( + paraApeStaking.connect(user2.signer).depositApeCoinPool({ + onBehalf: user2.address, + cashToken: ape.address, + cashAmount: parseEther("200000"), + isBAYC: true, + tokenIds: [0], + }) + ).to.be.revertedWith(ProtocolErrors.NOT_THE_OWNER); + + await expect( + paraApeStaking.connect(user1.signer).depositApeCoinPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("100000"), + isBAYC: true, + tokenIds: [0], + }) + ).to.be.revertedWith(ProtocolErrors.SAPE_FREE_BALANCE_NOT_ENOUGH); + }); + + it("compoundApeCoinPool revert test", async () => { + const { + users: [user1, , , user4], + ape, + bayc, + bakc, + } = await loadFixture(fixture); + + await mintAndValidate(ape, "2000000", user1); + await supplyAndValidate(bayc, "1", user1, true); + await supplyAndValidate(bakc, "1", user1, true); + + await waitForTx( + await paraApeStaking.connect(user1.signer).depositApeCoinPairPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("50000"), + isBAYC: true, + apeTokenIds: [0], + bakcTokenIds: [0], + }) + ); + + await expect( + paraApeStaking.connect(user4.signer).compoundApeCoinPool(true, [0]) + ).to.be.revertedWith(ProtocolErrors.NFT_NOT_IN_POOL); + }); + + it("claimApeCoinPool revert test", async () => { + const { + users: [user1, user2, , user4], + ape, + bayc, + bakc, + nBAYC, + } = await loadFixture(fixture); + + await mintAndValidate(ape, "2000000", user1); + await mintAndValidate(ape, "2000000", user2); + await supplyAndValidate(bayc, "3", user1, true); + await supplyAndValidate(bakc, "1", user1, true); + + await waitForTx( + await nBAYC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 1) + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).depositApeCoinPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("200000"), + isBAYC: true, + tokenIds: [0], + }) + ); + await waitForTx( + await paraApeStaking.connect(user2.signer).depositApeCoinPool({ + onBehalf: user2.address, + cashToken: ape.address, + cashAmount: parseEther("200000"), + isBAYC: true, + tokenIds: [1], + }) + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).depositApeCoinPairPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("50000"), + isBAYC: true, + apeTokenIds: [2], + bakcTokenIds: [0], + }) + ); + + await advanceTimeAndBlock(parseInt("3600")); + await waitForTx( + await paraApeStaking + .connect(user4.signer) + .compoundApeCoinPool(true, [0, 1]) + ); + + await expect( + paraApeStaking.connect(user1.signer).claimPendingReward(6, [0, 1]) + ).to.be.revertedWith(ProtocolErrors.NOT_THE_SAME_OWNER); + + await expect( + paraApeStaking.connect(user1.signer).claimPendingReward(6, [2]) + ).to.be.revertedWith(ProtocolErrors.NFT_NOT_IN_POOL); + }); + + it("withdrawApeCoinPool revert test", async () => { + const { + users: [user1, user2], + ape, + bayc, + bakc, + nBAYC, + } = await loadFixture(fixture); + + await mintAndValidate(ape, "2000000", user1); + await mintAndValidate(ape, "2000000", user2); + await supplyAndValidate(bayc, "2", user1, true); + await supplyAndValidate(bakc, "1", user1, true); + + await waitForTx( + await nBAYC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 1) + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).depositApeCoinPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("200000"), + isBAYC: true, + tokenIds: [0], + }) + ); + await waitForTx( + await paraApeStaking.connect(user2.signer).depositApeCoinPool({ + onBehalf: user2.address, + cashToken: ape.address, + cashAmount: parseEther("200000"), + isBAYC: true, + tokenIds: [1], + }) + ); + + await expect( + paraApeStaking.connect(user1.signer).withdrawApeCoinPool({ + cashToken: ape.address, + cashAmount: parseEther("200000"), + isBAYC: true, + tokenIds: [1], + }) + ).to.be.revertedWith(ProtocolErrors.NOT_THE_OWNER); + + await expect( + paraApeStaking.connect(user1.signer).withdrawApeCoinPool({ + cashToken: ape.address, + cashAmount: parseEther("300000"), + isBAYC: true, + tokenIds: [0], + }) + ).to.be.revertedWith(ProtocolErrors.INVALID_CASH_AMOUNT); + }); + + it("depositApeCoinPairPool revert test", async () => { + const { + users: [user1, user2], + ape, + bayc, + bakc, + } = await loadFixture(fixture); + + await mintAndValidate(ape, "2000000", user1); + await supplyAndValidate(bayc, "1", user1, true); + await supplyAndValidate(bakc, "1", user1, true); + + await expect( + paraApeStaking.connect(user1.signer).depositApeCoinPairPool({ + onBehalf: user2.address, + cashToken: ape.address, + cashAmount: parseEther("50000"), + isBAYC: true, + apeTokenIds: [0], + bakcTokenIds: [0], + }) + ).to.be.revertedWith(ProtocolErrors.CALLER_NOT_ALLOWED); + + await expect( + paraApeStaking.connect(user2.signer).depositApeCoinPairPool({ + onBehalf: user2.address, + cashToken: ape.address, + cashAmount: parseEther("50000"), + isBAYC: true, + apeTokenIds: [0], + bakcTokenIds: [0], + }) + ).to.be.revertedWith(ProtocolErrors.NOT_THE_OWNER); + + await expect( + paraApeStaking.connect(user1.signer).depositApeCoinPairPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("1"), + isBAYC: true, + apeTokenIds: [0], + bakcTokenIds: [0], + }) + ).to.be.revertedWith(ProtocolErrors.SAPE_FREE_BALANCE_NOT_ENOUGH); + }); + + it("compoundApeCoinPairPool revert test", async () => { + const { + users: [user1, , , user4], + ape, + bayc, + bakc, + } = await loadFixture(fixture); + + await mintAndValidate(ape, "2000000", user1); + await supplyAndValidate(bayc, "1", user1, true); + await supplyAndValidate(bakc, "1", user1, true); + + await waitForTx( + await paraApeStaking.connect(user1.signer).depositApeCoinPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("200000"), + isBAYC: true, + tokenIds: [0], + }) + ); + + await expect( + paraApeStaking + .connect(user4.signer) + .compoundApeCoinPairPool(true, [0], [0]) + ).to.be.revertedWith(ProtocolErrors.NFT_NOT_IN_POOL); + }); + + it("claimApeCoinPairPool revert test", async () => { + const { + users: [user1, user2, , user4], + ape, + bayc, + bakc, + nBAYC, + nBAKC, + } = await loadFixture(fixture); + + await mintAndValidate(ape, "2000000", user1); + await mintAndValidate(ape, "2000000", user2); + await supplyAndValidate(bayc, "3", user1, true); + await supplyAndValidate(bakc, "2", user1, true); + + await waitForTx( + await nBAYC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 1) + ); + await waitForTx( + await nBAKC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 1) + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).depositApeCoinPairPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("50000"), + isBAYC: true, + apeTokenIds: [0], + bakcTokenIds: [0], + }) + ); + await waitForTx( + await paraApeStaking.connect(user2.signer).depositApeCoinPairPool({ + onBehalf: user2.address, + cashToken: ape.address, + cashAmount: parseEther("50000"), + isBAYC: true, + apeTokenIds: [1], + bakcTokenIds: [1], + }) + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).depositApeCoinPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("200000"), + isBAYC: true, + tokenIds: [2], + }) + ); + + await advanceTimeAndBlock(parseInt("3600")); + await waitForTx( + await paraApeStaking + .connect(user4.signer) + .compoundApeCoinPairPool(true, [0, 1], [0, 1]) + ); + + await expect( + paraApeStaking.connect(user1.signer).claimPendingReward(8, [0, 1]) + ).to.be.revertedWith(ProtocolErrors.NOT_THE_SAME_OWNER); + + await expect( + paraApeStaking.connect(user1.signer).claimPendingReward(8, [2]) + ).to.be.revertedWith(ProtocolErrors.NFT_NOT_IN_POOL); + }); + + it("withdrawApeCoinPairPool revert test", async () => { + const { + users: [user1, user2], + ape, + bayc, + bakc, + nBAYC, + nBAKC, + } = await loadFixture(fixture); + + await mintAndValidate(ape, "2000000", user1); + await mintAndValidate(ape, "2000000", user2); + await supplyAndValidate(bayc, "2", user1, true); + await supplyAndValidate(bakc, "2", user1, true); + + await waitForTx( + await nBAYC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 1) + ); + await waitForTx( + await nBAKC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 1) + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).depositApeCoinPairPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("50000"), + isBAYC: true, + apeTokenIds: [0], + bakcTokenIds: [0], + }) + ); + await waitForTx( + await paraApeStaking.connect(user2.signer).depositApeCoinPairPool({ + onBehalf: user2.address, + cashToken: ape.address, + cashAmount: parseEther("50000"), + isBAYC: true, + apeTokenIds: [1], + bakcTokenIds: [1], + }) + ); + + await expect( + paraApeStaking.connect(user1.signer).withdrawApeCoinPairPool({ + cashToken: ape.address, + cashAmount: parseEther("50000"), + isBAYC: true, + apeTokenIds: [1], + bakcTokenIds: [1], + }) + ).to.be.revertedWith(ProtocolErrors.NOT_THE_OWNER); + + await expect( + paraApeStaking.connect(user1.signer).withdrawApeCoinPairPool({ + cashToken: ape.address, + cashAmount: parseEther("300000"), + isBAYC: true, + apeTokenIds: [0], + bakcTokenIds: [0], + }) + ).to.be.revertedWith(ProtocolErrors.INVALID_CASH_AMOUNT); + }); + + it("sApe revert test", async () => { + const { + users: [user1, user2, liquidator], + ape, + weth, + bayc, + pool, + nBAYC, + } = await loadFixture(fixture); + + await changePriceAndValidate(bayc, "100"); + await changePriceAndValidate(ape, "0.00001"); + + //user1 collateral 200eth + await supplyAndValidate(bayc, "1", user1, true); + + await supplyAndValidate(ape, "2000000", user2, true); + + //user1 borrow value 0.00001 * 2000000 = 20eth + await waitForTx( + await pool + .connect(user1.signer) + .borrow(ape.address, parseEther("2000000"), 0, user1.address) + ); + + await waitForTx( + await paraApeStaking.connect(user1.signer).depositApeCoinPool({ + onBehalf: user1.address, + cashToken: ape.address, + cashAmount: parseEther("200000"), + isBAYC: true, + tokenIds: [0], + }) + ); + expect(await pSApeCoin.balanceOf(user1.address)).to.be.closeTo( + parseEther("200000"), + parseEther("1") + ); + expect(await paraApeStaking.stakedSApeBalance(user1.address)).to.be.equal( + parseEther("200000") + ); + expect(await paraApeStaking.freeSApeBalance(user1.address)).to.be.equal( + parseEther("0") + ); + + await waitForTx( + await pool + .connect(user1.signer) + .setUserUseERC20AsCollateral(sApeAddress, true) + ); + + //user1 borrow value = 2000 eth, collateral value = 100 + 200 = 300 + await changePriceAndValidate(ape, "0.001"); + await changeSApePriceAndValidate(sApeAddress, "0.001"); + + await waitForTx( + await pool + .connect(user1.signer) + .setUserUseERC20AsCollateral(sApeAddress, true) + ); + + await expect( + paraApeStaking + .connect(user1.signer) + .withdrawFreeSApe(ape.address, parseEther("200000")) + ).to.be.revertedWith(ProtocolErrors.SAPE_FREE_BALANCE_NOT_ENOUGH); + + await mintAndValidate(weth, "200", liquidator); + await waitForTx( + await weth + .connect(liquidator.signer) + .approve(pool.address, MAX_UINT_AMOUNT) + ); + + // start auction + await waitForTx( + await pool + .connect(liquidator.signer) + .startAuction(user1.address, bayc.address, 0) + ); + const auctionData = await pool.getAuctionData(nBAYC.address, 0); + await advanceBlock( + auctionData.startTime + .add(auctionData.tickLength.mul(BigNumber.from(40))) + .toNumber() + ); + + // try to liquidate the NFT + expect( + await pool + .connect(liquidator.signer) + .liquidateERC721( + bayc.address, + user1.address, + 0, + parseEther("100"), + true, + {gasLimit: 5000000} + ) + ); + expect(await pSApeCoin.balanceOf(user1.address)).to.be.closeTo( + parseEther("200000"), + parseEther("1") + ); + expect(await paraApeStaking.stakedSApeBalance(user1.address)).to.be.eq(0); + expect(await paraApeStaking.freeSApeBalance(user1.address)).to.be.closeTo( + parseEther("200000"), + parseEther("1") + ); + + await expect( + paraApeStaking + .connect(user1.signer) + .withdrawFreeSApe(cApe.address, parseEther("200000")) + ).to.be.revertedWith( + ProtocolErrors.HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD + ); + + await expect( + paraApeStaking + .connect(user1.signer) + .transferFreeSApeBalance( + user1.address, + user2.address, + parseEther("200000") + ) + ).to.be.revertedWith(ProtocolErrors.CALLER_NOT_ALLOWED); + + await changePriceAndValidate(ape, "0.00001"); + await changeSApePriceAndValidate(sApeAddress, "0.00001"); + + await waitForTx( + await paraApeStaking + .connect(user1.signer) + .withdrawFreeSApe(cApe.address, parseEther("200000")) + ); + + expect(await cApe.balanceOf(user1.address)).to.be.closeTo( + parseEther("200000"), + parseEther("1") + ); + }); + + it("auto claim reward test", async () => { + const { + users: [user1, user2, , user4], + bayc, + mayc, + bakc, + nBAYC, + nMAYC, + nBAKC, + } = await loadFixture(fixture); + + await supplyAndValidate(bayc, "2", user1, true); + await supplyAndValidate(mayc, "2", user1, true); + await supplyAndValidate(bakc, "3", user1, true); + + await waitForTx( + await paraApeStaking.connect(user1.signer).depositPairNFT(true, [0], [0]) + ); + await waitForTx( + await paraApeStaking.connect(user1.signer).depositPairNFT(false, [0], [1]) + ); + await waitForTx( + await paraApeStaking.connect(user1.signer).depositNFT(bayc.address, [1]) + ); + await waitForTx( + await paraApeStaking.connect(user1.signer).depositNFT(mayc.address, [1]) + ); + await waitForTx( + await paraApeStaking.connect(user1.signer).depositNFT(bakc.address, [2]) + ); + + await waitForTx( + await paraApeStaking.connect(user4.signer).stakingPairNFT(true, [0], [0]) + ); + await waitForTx( + await paraApeStaking.connect(user4.signer).stakingPairNFT(false, [0], [1]) + ); + await waitForTx( + await paraApeStaking.connect(user4.signer).stakingApe(true, [1]) + ); + await waitForTx( + await paraApeStaking.connect(user4.signer).stakingApe(false, [1]) + ); + await waitForTx( + await paraApeStaking.connect(user4.signer).stakingBAKC({ + baycTokenIds: [1], + bakcPairBaycTokenIds: [2], + maycTokenIds: [], + bakcPairMaycTokenIds: [], + }) + ); + + await advanceTimeAndBlock(parseInt("3600")); + + await waitForTx( + await paraApeStaking.connect(user4.signer).compoundPairNFT(true, [0], [0]) + ); + await waitForTx( + await paraApeStaking + .connect(user4.signer) + .compoundPairNFT(false, [0], [1]) + ); + await waitForTx( + await paraApeStaking.connect(user4.signer).compoundApe(true, [1]) + ); + await waitForTx( + await paraApeStaking.connect(user4.signer).compoundApe(false, [1]) + ); + await waitForTx( + await paraApeStaking.connect(user4.signer).compoundBAKC({ + baycTokenIds: [1], + bakcPairBaycTokenIds: [2], + maycTokenIds: [], + bakcPairMaycTokenIds: [], + }) + ); + + const baycPairReward = await paraApeStaking.getPendingReward(1, [0]); + const maycPairReward = await paraApeStaking.getPendingReward(2, [0]); + const baycSingleReward = await paraApeStaking.getPendingReward(3, [1]); + const maycSingleReward = await paraApeStaking.getPendingReward(4, [1]); + const bakcSingleReward = await paraApeStaking.getPendingReward(5, [2]); + //1800 + 1200 + expect(baycPairReward).to.be.closeTo(parseEther("3000"), parseEther("50")); + //1800 + 1200 + expect(maycPairReward).to.be.closeTo(parseEther("3000"), parseEther("50")); + //1800 + 0 + expect(baycSingleReward).to.be.closeTo( + parseEther("1800"), + parseEther("50") + ); + //1800 + expect(maycSingleReward).to.be.closeTo( + parseEther("1800"), + parseEther("50") + ); + //1200 + expect(bakcSingleReward).to.be.closeTo( + parseEther("1200"), + parseEther("50") + ); + + await waitForTx( + await nBAYC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 0) + ); + let cApeBalance = await cApe.balanceOf(user1.address); + expect(cApeBalance).to.be.closeTo(parseEther("3000"), parseEther("50")); + await waitForTx( + await nMAYC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 0) + ); + cApeBalance = await cApe.balanceOf(user1.address); + expect(cApeBalance).to.be.closeTo(parseEther("6000"), parseEther("100")); + await waitForTx( + await nBAYC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 1) + ); + cApeBalance = await cApe.balanceOf(user1.address); + expect(cApeBalance).to.be.closeTo(parseEther("7800"), parseEther("150")); + await waitForTx( + await nMAYC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 1) + ); + cApeBalance = await cApe.balanceOf(user1.address); + expect(cApeBalance).to.be.closeTo(parseEther("9600"), parseEther("200")); + await waitForTx( + await nBAKC + .connect(user1.signer) + .transferFrom(user1.address, user2.address, 2) + ); + cApeBalance = await cApe.balanceOf(user1.address); + expect(cApeBalance).to.be.closeTo(parseEther("10800"), parseEther("250")); + }); +}); diff --git a/test/pnm/ParaTest.sol b/test/pnm/ParaTest.sol index b0715515d..7bf4edaf4 100644 --- a/test/pnm/ParaTest.sol +++ b/test/pnm/ParaTest.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import {PTest} from "pnm-contracts/PTest.sol"; import "forge-std/console.sol"; diff --git a/test/pnm/Supply.t.sol b/test/pnm/Supply.t.sol index 93615f4ec..c84a8cc0a 100644 --- a/test/pnm/Supply.t.sol +++ b/test/pnm/Supply.t.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.8.10; +pragma solidity ^0.8.0; import "./ParaTest.sol"; import "../../contracts/mocks/tokens/MintableERC20.sol"; diff --git a/test/xtoken_ntoken_bakc.spec.ts b/test/xtoken_ntoken_bakc.spec.ts deleted file mode 100644 index bfe5ab253..000000000 --- a/test/xtoken_ntoken_bakc.spec.ts +++ /dev/null @@ -1,410 +0,0 @@ -import {loadFixture} from "@nomicfoundation/hardhat-network-helpers"; -import {expect} from "chai"; -import {MAX_UINT_AMOUNT, ONE_ADDRESS} from "../helpers/constants"; -import {convertToCurrencyDecimals} from "../helpers/contracts-helpers"; -import {advanceTimeAndBlock, waitForTx} from "../helpers/misc-utils"; -import {TestEnv} from "./helpers/make-suite"; -import {testEnvFixture} from "./helpers/setup-env"; -import { - changePriceAndValidate, - changeSApePriceAndValidate, - mintAndValidate, - supplyAndValidate, -} from "./helpers/validated-steps"; -import {parseEther} from "ethers/lib/utils"; -import {getAutoCompoundApe} from "../helpers/contracts-getters"; - -describe("APE Coin Staking Test", () => { - let testEnv: TestEnv; - const sApeAddress = ONE_ADDRESS; - - const fixture = async () => { - testEnv = await loadFixture(testEnvFixture); - const { - ape, - mayc, - bayc, - users: [user1, depositor, , , , user4], - pool, - apeCoinStaking, - bakc, - } = testEnv; - - const cApe = await getAutoCompoundApe(); - - await supplyAndValidate(ape, "20000", depositor, true); - await changePriceAndValidate(ape, "0.001"); - await changeSApePriceAndValidate(sApeAddress, "0.001"); - - await changePriceAndValidate(mayc, "50"); - await changePriceAndValidate(bayc, "50"); - - await waitForTx( - await ape.connect(user1.signer).approve(pool.address, MAX_UINT_AMOUNT) - ); - await waitForTx( - await bakc.connect(user1.signer).setApprovalForAll(pool.address, true) - ); - - // send extra tokens to the apestaking contract for rewards - await waitForTx( - await ape - .connect(user1.signer) - ["mint(address,uint256)"]( - apeCoinStaking.address, - parseEther("100000000000") - ) - ); - - // user4 deposit MINIMUM_LIQUIDITY to make test case easy - await mintAndValidate(ape, "1", user4); - await waitForTx( - await ape.connect(user4.signer).approve(cApe.address, MAX_UINT_AMOUNT) - ); - const MINIMUM_LIQUIDITY = await cApe.MINIMUM_LIQUIDITY(); - await waitForTx( - await cApe.connect(user4.signer).deposit(user4.address, MINIMUM_LIQUIDITY) - ); - - return testEnv; - }; - - it("user can supply bakc first and stake paired nft", async () => { - const { - users: [user1], - ape, - mayc, - pool, - bakc, - nMAYC, - nBAKC, - } = await loadFixture(fixture); - await supplyAndValidate(bakc, "1", user1, true); - await supplyAndValidate(mayc, "1", user1, true); - await mintAndValidate(ape, "10000", user1); - - const amount = await convertToCurrencyDecimals(ape.address, "10000"); - const halfAmount = await convertToCurrencyDecimals(ape.address, "5000"); - - await waitForTx( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: amount, - }, - [], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount}], - true - ) - ); - - const totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - expect(totalStake).equal(amount); - - // advance in time - await advanceTimeAndBlock(parseInt("3600")); - await waitForTx( - await pool - .connect(user1.signer) - .claimBAKC(mayc.address, [{mainTokenId: 0, bakcTokenId: 0}]) - ); - let apeBalance = await ape.balanceOf(user1.address); - expect(apeBalance).to.be.equal(parseEther("3600")); - - await advanceTimeAndBlock(parseInt("3600")); - await waitForTx( - await pool - .connect(user1.signer) - .claimBAKC(mayc.address, [{mainTokenId: 0, bakcTokenId: 0}]) - ); - apeBalance = await ape.balanceOf(user1.address); - expect(apeBalance).to.be.equal(parseEther("7200")); - - await waitForTx( - await pool.connect(user1.signer).withdrawBAKC(mayc.address, [ - { - mainTokenId: 0, - bakcTokenId: 0, - amount: halfAmount, - isUncommit: false, - }, - ]) - ); - - apeBalance = await ape.balanceOf(user1.address); - expect(apeBalance).to.be.equal(parseEther("12200")); - - await waitForTx( - await pool.connect(user1.signer).withdrawBAKC(mayc.address, [ - { - mainTokenId: 0, - bakcTokenId: 0, - amount: halfAmount, - isUncommit: true, - }, - ]) - ); - - apeBalance = await ape.balanceOf(user1.address); - expect(apeBalance).to.be.equal(parseEther("17200")); - - await waitForTx( - await pool - .connect(user1.signer) - .withdrawERC721(bakc.address, [0], user1.address) - ); - expect(await nBAKC.balanceOf(user1.address)).to.be.equal(0); - expect(await bakc.balanceOf(user1.address)).to.be.equal(1); - }); - - it("unstakeApePositionAndRepay when bakc in user wallet: bakc reward should transfer to user wallet", async () => { - const { - users: [user1], - ape, - mayc, - pool, - bakc, - } = await loadFixture(fixture); - - await waitForTx(await bakc["mint(uint256,address)"]("1", user1.address)); - await supplyAndValidate(mayc, "1", user1, true); - await mintAndValidate(ape, "10000", user1); - const amount = await convertToCurrencyDecimals(ape.address, "10000"); - - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: amount, - }, - [], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount}], - true - ) - ); - - // advance in time - await advanceTimeAndBlock(parseInt("86400")); - - expect( - await pool - .connect(user1.signer) - .unstakeApePositionAndRepay(mayc.address, 0) - ); - - const userBalance = await ape.balanceOf(user1.address); - expect(userBalance).to.be.eq(parseEther("86400")); - }); - - it("unstakeApePositionAndRepay when bakc has been supplied: bakc reward should transfer to user wallet", async () => { - const { - users: [user1], - ape, - mayc, - pool, - bakc, - } = await loadFixture(fixture); - - await supplyAndValidate(bakc, "1", user1, true); - await supplyAndValidate(mayc, "1", user1, true); - await mintAndValidate(ape, "10000", user1); - const amount = await convertToCurrencyDecimals(ape.address, "10000"); - - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: amount, - }, - [], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount}], - true - ) - ); - - // advance in time - await advanceTimeAndBlock(parseInt("86400")); - - expect( - await pool - .connect(user1.signer) - .unstakeApePositionAndRepay(mayc.address, 0) - ); - - const userBalance = await ape.balanceOf(user1.address); - expect(userBalance).to.be.eq(parseEther("86400")); - }); - - it("liquidate bakc will unstake user ape staking position", async () => { - const { - users: [user1, liquidator], - ape, - mayc, - pool, - weth, - bakc, - nMAYC, - } = await loadFixture(fixture); - await supplyAndValidate(ape, "20000", liquidator, true); - await changePriceAndValidate(ape, "0.001"); - await changeSApePriceAndValidate(sApeAddress, "0.001"); - await changePriceAndValidate(mayc, "50"); - await changePriceAndValidate(bakc, "5"); - - await supplyAndValidate(mayc, "1", user1, true); - await supplyAndValidate(bakc, "1", user1, true); - - const amount = parseEther("10000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount}], - true - ) - ); - let totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - expect(totalStake).equal(amount); - - await supplyAndValidate(weth, "91", liquidator, true, "200000"); - - await advanceTimeAndBlock(parseInt("3600")); - - // drop HF and ERC-721_HF below 1 - await changePriceAndValidate(ape, "1"); - await changeSApePriceAndValidate(sApeAddress, "1"); - await changePriceAndValidate(mayc, "1"); - await changePriceAndValidate(bakc, "1"); - - // start auction - await waitForTx( - await pool - .connect(liquidator.signer) - .startAuction(user1.address, bakc.address, 0) - ); - - expect(await ape.balanceOf(user1.address)).to.be.equal(0); - // try to liquidate the NFT - expect( - await pool - .connect(liquidator.signer) - .liquidateERC721( - bakc.address, - user1.address, - 0, - parseEther("10"), - false, - {gasLimit: 5000000} - ) - ); - expect(await bakc.ownerOf("0")).to.be.eq(liquidator.address); - totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - expect(totalStake).equal(0); - expect(await ape.balanceOf(user1.address)).to.be.equal(parseEther("3600")); - }); - - it("transfer nbakc will unstake user ape staking position", async () => { - const { - users: [user1, user2], - ape, - mayc, - pool, - bakc, - nBAKC, - nMAYC, - } = await loadFixture(fixture); - await mintAndValidate(ape, "10000", user1); - await supplyAndValidate(mayc, "1", user1, true); - await supplyAndValidate(bakc, "1", user1, true); - - const amount = parseEther("10000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: 0, - cashAmount: amount, - }, - [], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount}], - true - ) - ); - let totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - expect(totalStake).equal(amount); - - await advanceTimeAndBlock(parseInt("3600")); - - expect(await nBAKC.ownerOf("0")).to.be.eq(user1.address); - expect(await ape.balanceOf(user1.address)).to.be.equal(0); - expect( - await nBAKC - .connect(user1.signer) - ["safeTransferFrom(address,address,uint256)"]( - user1.address, - user2.address, - 0, - {gasLimit: 5000000} - ) - ); - expect(await nBAKC.ownerOf("0")).to.be.eq(user2.address); - expect(await ape.balanceOf(user1.address)).to.be.equal(parseEther("3600")); - totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - expect(totalStake).equal(0); - }); - - it("withdraw bakc will not unstake user ape staking position", async () => { - const { - users: [user1, user2], - ape, - mayc, - pool, - bakc, - nMAYC, - } = await loadFixture(fixture); - - await supplyAndValidate(ape, "20000", user2, true); - await supplyAndValidate(mayc, "1", user1, true); - await supplyAndValidate(bakc, "1", user1, true); - - const amount = parseEther("10000"); - expect( - await pool.connect(user1.signer).borrowApeAndStake( - { - nftAsset: mayc.address, - borrowAsset: ape.address, - borrowAmount: amount, - cashAmount: 0, - }, - [], - [{mainTokenId: 0, bakcTokenId: 0, amount: amount}], - true - ) - ); - let totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - expect(totalStake).equal(amount); - - // start auction - await waitForTx( - await pool - .connect(user1.signer) - .withdrawERC721(bakc.address, [0], user1.address) - ); - - expect(await bakc.ownerOf("0")).to.be.eq(user1.address); - totalStake = await nMAYC.getUserApeStakingAmount(user1.address); - expect(totalStake).equal(amount); - }); -}); diff --git a/yarn.lock b/yarn.lock index f74227879..13858b1df 100644 --- a/yarn.lock +++ b/yarn.lock @@ -41,6 +41,13 @@ __metadata: languageName: node linkType: hard +"@balena/dockerignore@npm:^1.0.2": + version: 1.0.2 + resolution: "@balena/dockerignore@npm:1.0.2" + checksum: 0d39f8fbcfd1a983a44bced54508471ab81aaaa40e2c62b46a9f97eac9d6b265790799f16919216db486331dedaacdde6ecbd6b7abe285d39bc50de111991699 + languageName: node + linkType: hard + "@chainsafe/as-sha256@npm:^0.3.1": version: 0.3.1 resolution: "@chainsafe/as-sha256@npm:0.3.1" @@ -792,7 +799,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/wallet@npm:5.7.0": +"@ethersproject/wallet@npm:5.7.0, @ethersproject/wallet@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/wallet@npm:5.7.0" dependencies: @@ -931,6 +938,71 @@ __metadata: languageName: node linkType: hard +"@matterlabs/hardhat-zksync-deploy@npm:^0.6.3": + version: 0.6.3 + resolution: "@matterlabs/hardhat-zksync-deploy@npm:0.6.3" + dependencies: + chalk: 4.1.2 + peerDependencies: + ethers: ~5.7.2 + hardhat: ^2.13.0 + zksync-web3: ^0.14.3 + checksum: 6cf67fa0032159e27247b3334014ecda1a8c6ad37379798cbd44b428fb29043aeb148a2439c9e7994cc2ee83037c0769dd64ce8fabc15e614a46a3ebea5b066a + languageName: node + linkType: hard + +"@matterlabs/hardhat-zksync-solc@npm:0.3.17": + version: 0.3.17 + resolution: "@matterlabs/hardhat-zksync-solc@npm:0.3.17" + dependencies: + "@nomiclabs/hardhat-docker": ^2.0.0 + chalk: 4.1.2 + dockerode: ^3.3.4 + peerDependencies: + hardhat: ^2.14.0 + checksum: 2b069bcad29381a8a007ccae36c51f36b62b667ab5623a6271639663c77976c5ff202cc3f28dd7b58f57b3c5d21a86a5e29c1a05fd13d9867203dfd08f61c554 + languageName: node + linkType: hard + +"@matterlabs/hardhat-zksync-solc@npm:^0.4.0": + version: 0.4.1 + resolution: "@matterlabs/hardhat-zksync-solc@npm:0.4.1" + dependencies: + "@nomiclabs/hardhat-docker": ^2.0.0 + chalk: 4.1.2 + dockerode: ^3.3.4 + fs-extra: ^11.1.1 + semver: ^7.5.1 + peerDependencies: + hardhat: ^2.14.0 + checksum: 8f5377858d0810124b11bb6a208c805abdf42f04f23b9c7e160abc8b44ef552b38809bc6e7c1a7df9bd29976167e1408d066f62721dbbb082c29c71b47a6954c + languageName: node + linkType: hard + +"@matterlabs/hardhat-zksync-verify@npm:^0.1.8": + version: 0.1.8 + resolution: "@matterlabs/hardhat-zksync-verify@npm:0.1.8" + dependencies: + "@matterlabs/hardhat-zksync-solc": 0.3.17 + axios: ^1.4.0 + chalk: 4.1.2 + dockerode: ^3.3.4 + peerDependencies: + "@nomiclabs/hardhat-etherscan": ^3.1.2 + checksum: dc6b872fd95877ecf4c2f0c68b75917e76f3e4f552a2647d8bb1cffb3dd677d13741efa977e888e3a1531556d9caa2a3e359ed2aa57a02d4f058de4042ef4ea4 + languageName: node + linkType: hard + +"@matterlabs/zksync-contracts@npm:^0.6.1": + version: 0.6.1 + resolution: "@matterlabs/zksync-contracts@npm:0.6.1" + peerDependencies: + "@openzeppelin/contracts": 4.6.0 + "@openzeppelin/contracts-upgradeable": 4.6.0 + checksum: 736215697fb7529de2bfbb1d73f2a2656d4d048cd2b6fa46e67deceb6c0cbe7ceebc1c6dcb762c7522f527f7bfcd335bf4421061e85d9779c36602f967da4f25 + languageName: node + linkType: hard + "@metamask/eth-sig-util@npm:^4.0.0": version: 4.0.1 resolution: "@metamask/eth-sig-util@npm:4.0.1" @@ -1270,6 +1342,17 @@ __metadata: languageName: node linkType: hard +"@nomiclabs/hardhat-docker@npm:^2.0.0": + version: 2.0.2 + resolution: "@nomiclabs/hardhat-docker@npm:2.0.2" + dependencies: + dockerode: ^2.5.8 + fs-extra: ^7.0.1 + node-fetch: ^2.6.0 + checksum: 1e019c2050668326e006a046d3285a11bf1830bfc222c2957eb8f9a5b262c9b5061ae42abbf2346f3e1bb46c98aa767c3651c0f842192f3171b28b1deafc4d05 + languageName: node + linkType: hard + "@nomiclabs/hardhat-ethers@npm:^2.0.0, @nomiclabs/hardhat-ethers@npm:^2.0.1": version: 2.1.1 resolution: "@nomiclabs/hardhat-ethers@npm:2.1.1" @@ -1280,23 +1363,23 @@ __metadata: languageName: node linkType: hard -"@nomiclabs/hardhat-etherscan@npm:^3.1.0": - version: 3.1.0 - resolution: "@nomiclabs/hardhat-etherscan@npm:3.1.0" +"@nomiclabs/hardhat-etherscan@npm:^3.1.7": + version: 3.1.7 + resolution: "@nomiclabs/hardhat-etherscan@npm:3.1.7" dependencies: "@ethersproject/abi": ^5.1.2 "@ethersproject/address": ^5.0.2 - cbor: ^5.0.2 + cbor: ^8.1.0 chalk: ^2.4.2 debug: ^4.1.1 fs-extra: ^7.0.1 lodash: ^4.17.11 semver: ^6.3.0 table: ^6.8.0 - undici: ^5.4.0 + undici: ^5.14.0 peerDependencies: hardhat: ^2.0.4 - checksum: 3f28abc39edce2936226b6d0087c3be78bffcba68b6935f3f60767f0e10233e940ddc74803dff91f7ddf9464a7199aab00fba08d8b3865dbc2f8936f53a7a5a5 + checksum: 32d74e567e78a940a79cbe49c5dee0eb5cda0a4c0c34a9badfaf13d45e6054d9e717c28b8d2b0b20f29721a484af15a52d391fb60768222c4b13de92ef0f72b3 languageName: node linkType: hard @@ -1408,9 +1491,13 @@ __metadata: "@commitlint/config-conventional": ^17.0.3 "@flashbots/ethers-provider-bundle": ^0.6.1 "@looksrare/sdk": ^0.7.4 + "@matterlabs/hardhat-zksync-deploy": ^0.6.3 + "@matterlabs/hardhat-zksync-solc": ^0.4.0 + "@matterlabs/hardhat-zksync-verify": ^0.1.8 + "@matterlabs/zksync-contracts": ^0.6.1 "@nomicfoundation/hardhat-network-helpers": ^1.0.6 "@nomiclabs/hardhat-ethers": ^2.0.0 - "@nomiclabs/hardhat-etherscan": ^3.1.0 + "@nomiclabs/hardhat-etherscan": ^3.1.7 "@nomiclabs/hardhat-waffle": 2.0.3 "@openzeppelin/contracts": 4.2.0 "@openzeppelin/contracts-upgradeable": 4.2.0 @@ -1421,7 +1508,7 @@ __metadata: "@safe-global/safe-ethers-lib": ^1.7.0 "@safe-global/safe-service-client": ^1.5.0 "@tenderly/hardhat-tenderly": 1.1.0-beta.5 - "@typechain/ethers-v5": ^10.1.0 + "@typechain/ethers-v5": ^11.0.0 "@typechain/hardhat": ^6.1.2 "@types/chai": ^4.2.11 "@types/lowdb": 1.0.9 @@ -1449,9 +1536,9 @@ __metadata: ethers-multisend: ^2.4.0 evm-bn: ^1.1.2 git-rev-sync: ^3.0.2 - hardhat: ^2.12.2 + hardhat: ^2.13.0 hardhat-contract-sizer: ^2.0.3 - hardhat-deploy: ^0.11.4 + hardhat-deploy: ^0.11.30 hardhat-gas-reporter: ^1.0.9 hardhat-typechain: ^0.3.3 husky: ^8.0.1 @@ -1466,11 +1553,13 @@ __metadata: shelljs: ^0.8.5 solhint: ^3.3.6 solidity-coverage: ^0.8.2 - solidity-docgen-forked: ^0.6.0-beta.29 + solidity-docgen: ^0.6.0-beta.35 ts-generator: ^0.1.1 ts-node: ^10.9.1 typechain: ^8.1.0 typescript: 4.7.4 + walkdir: ^0.4.1 + zksync-web3: ^0.14.3 languageName: unknown linkType: soft @@ -1809,20 +1898,19 @@ __metadata: languageName: node linkType: hard -"@typechain/ethers-v5@npm:^10.1.0": - version: 10.1.0 - resolution: "@typechain/ethers-v5@npm:10.1.0" +"@typechain/ethers-v5@npm:^11.0.0": + version: 11.0.0 + resolution: "@typechain/ethers-v5@npm:11.0.0" dependencies: lodash: ^4.17.15 ts-essentials: ^7.0.1 peerDependencies: "@ethersproject/abi": ^5.0.0 - "@ethersproject/bytes": ^5.0.0 "@ethersproject/providers": ^5.0.0 ethers: ^5.1.3 - typechain: ^8.1.0 + typechain: ^8.2.0 typescript: ">=4.3.0" - checksum: 452ad685ce792ddefebdcb8ae72f4343ed1411f91701250e273c1a0dd79753d0d40f311cff19ec0c4fd6a9b9cf23e55eb9ae1b94cb388fbc54c122ae4d0e6f47 + checksum: 4f2986070b3e4492e64db308e437b887d73b689c9ddbf52c6f0874f3a7467b39fa53352172d8cd649568f9d44cb5393c92bdfc05f26cb917db1aa45fc0d5fe85 languageName: node linkType: hard @@ -2415,6 +2503,18 @@ __metadata: languageName: node linkType: hard +"JSONStream@npm:1.3.2": + version: 1.3.2 + resolution: "JSONStream@npm:1.3.2" + dependencies: + jsonparse: ^1.2.0 + through: ">=2.2.7 <3" + bin: + JSONStream: ./bin.js + checksum: d83b86f846eaeba7b947181245b977bb7e32c49e25d210234ecbf6b2d9128924610224e150558deeb65d063b07b8c28e5a1a4ab8daeb89d4c34e718047f046fd + languageName: node + linkType: hard + "JSONStream@npm:^1.0.4": version: 1.3.5 resolution: "JSONStream@npm:1.3.5" @@ -2951,7 +3051,7 @@ __metadata: languageName: node linkType: hard -"asn1@npm:~0.2.3": +"asn1@npm:^0.2.6, asn1@npm:~0.2.3": version: 0.2.6 resolution: "asn1@npm:0.2.6" dependencies: @@ -3122,6 +3222,17 @@ __metadata: languageName: node linkType: hard +"axios@npm:^1.4.0": + version: 1.4.0 + resolution: "axios@npm:1.4.0" + dependencies: + follow-redirects: ^1.15.0 + form-data: ^4.0.0 + proxy-from-env: ^1.1.0 + checksum: 7fb6a4313bae7f45e89d62c70a800913c303df653f19eafec88e56cea2e3821066b8409bc68be1930ecca80e861c52aa787659df0ffec6ad4d451c7816b9386b + languageName: node + linkType: hard + "babel-code-frame@npm:^6.26.0": version: 6.26.0 resolution: "babel-code-frame@npm:6.26.0" @@ -3805,7 +3916,7 @@ __metadata: languageName: node linkType: hard -"bcrypt-pbkdf@npm:^1.0.0": +"bcrypt-pbkdf@npm:^1.0.0, bcrypt-pbkdf@npm:^1.0.2": version: 1.0.2 resolution: "bcrypt-pbkdf@npm:1.0.2" dependencies: @@ -3844,7 +3955,7 @@ __metadata: languageName: node linkType: hard -"bignumber.js@npm:^9.0.0, bignumber.js@npm:^9.0.1": +"bignumber.js@npm:^9.0.0": version: 9.1.0 resolution: "bignumber.js@npm:9.1.0" checksum: 52ec2bb5a3874d7dc1a1018f28f8f7aff4683515ffd09d6c2d93191343c76567ae0ee32cc45149d53afb2b904bc62ed471a307b35764beea7e9db78e56bef6c6 @@ -3878,6 +3989,27 @@ __metadata: languageName: node linkType: hard +"bl@npm:^1.0.0": + version: 1.2.3 + resolution: "bl@npm:1.2.3" + dependencies: + readable-stream: ^2.3.5 + safe-buffer: ^5.1.1 + checksum: 123f097989ce2fa9087ce761cd41176aaaec864e28f7dfe5c7dab8ae16d66d9844f849c3ad688eb357e3c5e4f49b573e3c0780bb8bc937206735a3b6f8569a5f + languageName: node + linkType: hard + +"bl@npm:^4.0.3": + version: 4.1.0 + resolution: "bl@npm:4.1.0" + dependencies: + buffer: ^5.5.0 + inherits: ^2.0.4 + readable-stream: ^3.4.0 + checksum: 9e8521fa7e83aa9427c6f8ccdcba6e8167ef30cc9a22df26effcc5ab682ef91d2cbc23a239f945d099289e4bbcfae7a192e9c28c84c6202e710a0dfec3722662 + languageName: node + linkType: hard + "blakejs@npm:^1.1.0": version: 1.2.1 resolution: "blakejs@npm:1.2.1" @@ -4101,6 +4233,30 @@ __metadata: languageName: node linkType: hard +"buffer-alloc-unsafe@npm:^1.1.0": + version: 1.1.0 + resolution: "buffer-alloc-unsafe@npm:1.1.0" + checksum: c5e18bf51f67754ec843c9af3d4c005051aac5008a3992938dda1344e5cfec77c4b02b4ca303644d1e9a6e281765155ce6356d85c6f5ccc5cd21afc868def396 + languageName: node + linkType: hard + +"buffer-alloc@npm:^1.2.0": + version: 1.2.0 + resolution: "buffer-alloc@npm:1.2.0" + dependencies: + buffer-alloc-unsafe: ^1.1.0 + buffer-fill: ^1.0.0 + checksum: 560cd27f3cbe73c614867da373407d4506309c62fe18de45a1ce191f3785ec6ca2488d802ff82065798542422980ca25f903db078c57822218182c37c3576df5 + languageName: node + linkType: hard + +"buffer-fill@npm:^1.0.0": + version: 1.0.0 + resolution: "buffer-fill@npm:1.0.0" + checksum: c29b4723ddeab01e74b5d3b982a0c6828f2ded49cef049ddca3dac661c874ecdbcecb5dd8380cf0f4adbeb8cff90a7de724126750a1f1e5ebd4eb6c59a1315b1 + languageName: node + linkType: hard + "buffer-from@npm:^1.0.0": version: 1.1.2 resolution: "buffer-from@npm:1.1.2" @@ -4172,6 +4328,13 @@ __metadata: languageName: node linkType: hard +"buildcheck@npm:~0.0.6": + version: 0.0.6 + resolution: "buildcheck@npm:0.0.6" + checksum: ad61759dc98d62e931df2c9f54ccac7b522e600c6e13bdcfdc2c9a872a818648c87765ee209c850f022174da4dd7c6a450c00357c5391705d26b9c5807c2a076 + languageName: node + linkType: hard + "busboy@npm:^1.6.0": version: 1.6.0 resolution: "busboy@npm:1.6.0" @@ -4399,17 +4562,7 @@ __metadata: languageName: node linkType: hard -"cbor@npm:^5.0.2": - version: 5.2.0 - resolution: "cbor@npm:5.2.0" - dependencies: - bignumber.js: ^9.0.1 - nofilter: ^1.0.4 - checksum: b3c39dae64370f361526dbec88f51d0f1b47027224cdd21dbd64c228f0fe7eaa945932d349ec5324068a6c6dcdbb1e3b46242852524fd53c526d14cb60514bdc - languageName: node - linkType: hard - -"cbor@npm:^8.0.0": +"cbor@npm:^8.0.0, cbor@npm:^8.1.0": version: 8.1.0 resolution: "cbor@npm:8.1.0" dependencies: @@ -4439,6 +4592,16 @@ __metadata: languageName: node linkType: hard +"chalk@npm:4.1.2, chalk@npm:^4.0.0, chalk@npm:^4.1.0, chalk@npm:^4.1.2": + version: 4.1.2 + resolution: "chalk@npm:4.1.2" + dependencies: + ansi-styles: ^4.1.0 + supports-color: ^7.1.0 + checksum: fe75c9d5c76a7a98d45495b91b2172fa3b7a09e0cc9370e5c8feb1c567b85c4288e2b3fded7cfdd7359ac28d6b3844feb8b82b8686842e93d23c827c417e83fc + languageName: node + linkType: hard + "chalk@npm:^1.1.3": version: 1.1.3 resolution: "chalk@npm:1.1.3" @@ -4473,16 +4636,6 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^4.0.0, chalk@npm:^4.1.0, chalk@npm:^4.1.2": - version: 4.1.2 - resolution: "chalk@npm:4.1.2" - dependencies: - ansi-styles: ^4.1.0 - supports-color: ^7.1.0 - checksum: fe75c9d5c76a7a98d45495b91b2172fa3b7a09e0cc9370e5c8feb1c567b85c4288e2b3fded7cfdd7359ac28d6b3844feb8b82b8686842e93d23c827c417e83fc - languageName: node - linkType: hard - "chardet@npm:^0.7.0": version: 0.7.0 resolution: "chardet@npm:0.7.0" @@ -4551,7 +4704,7 @@ __metadata: languageName: node linkType: hard -"chownr@npm:^1.1.4": +"chownr@npm:^1.0.1, chownr@npm:^1.1.1, chownr@npm:^1.1.4": version: 1.1.4 resolution: "chownr@npm:1.1.4" checksum: 115648f8eb38bac5e41c3857f3e663f9c39ed6480d1349977c4d96c95a47266fcacc5a5aabf3cb6c481e22d72f41992827db47301851766c4fd77ac21a4f081d @@ -4908,7 +5061,7 @@ __metadata: languageName: node linkType: hard -"concat-stream@npm:^1.5.1, concat-stream@npm:^1.6.0, concat-stream@npm:^1.6.2": +"concat-stream@npm:^1.5.1, concat-stream@npm:^1.6.0, concat-stream@npm:^1.6.2, concat-stream@npm:~1.6.2": version: 1.6.2 resolution: "concat-stream@npm:1.6.2" dependencies: @@ -5110,6 +5263,17 @@ __metadata: languageName: node linkType: hard +"cpu-features@npm:~0.0.7": + version: 0.0.8 + resolution: "cpu-features@npm:0.0.8" + dependencies: + buildcheck: ~0.0.6 + nan: ^2.17.0 + node-gyp: latest + checksum: 7b52da1e538beb31185c63a874c8b88c40048ee7ebb5dfd37bb15d9c9044fffa2da048c2bc46d9f2e0916ec86d38c6812c7c6baafdddd504d56594eeff614444 + languageName: node + linkType: hard + "crc-32@npm:^1.2.0": version: 1.2.2 resolution: "crc-32@npm:1.2.2" @@ -5302,7 +5466,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:^3.1.0": +"debug@npm:^3.1.0, debug@npm:^3.2.6": version: 3.2.7 resolution: "debug@npm:3.2.7" dependencies: @@ -5640,6 +5804,52 @@ __metadata: languageName: node linkType: hard +"docker-modem@npm:^1.0.8": + version: 1.0.9 + resolution: "docker-modem@npm:1.0.9" + dependencies: + JSONStream: 1.3.2 + debug: ^3.2.6 + readable-stream: ~1.0.26-4 + split-ca: ^1.0.0 + checksum: b34829f5abecf28332f1870c88bdf795750520264e9fdc8e9041058f18b1846543061ee32fb21ff14e9da6b5498af6b2cb4d96422d8c2dc02d9f622b01f34fe6 + languageName: node + linkType: hard + +"docker-modem@npm:^3.0.0": + version: 3.0.8 + resolution: "docker-modem@npm:3.0.8" + dependencies: + debug: ^4.1.1 + readable-stream: ^3.5.0 + split-ca: ^1.0.1 + ssh2: ^1.11.0 + checksum: e3675c9b1ad800be8fb1cb9c5621fbef20a75bfedcd6e01b69808eadd7f0165681e4e30d1700897b788a67dbf4769964fcccd19c3d66f6d2499bb7aede6b34df + languageName: node + linkType: hard + +"dockerode@npm:^2.5.8": + version: 2.5.8 + resolution: "dockerode@npm:2.5.8" + dependencies: + concat-stream: ~1.6.2 + docker-modem: ^1.0.8 + tar-fs: ~1.16.3 + checksum: 01381da98f98a3236b735fb2bb2a66f521da39200a2a11b83777cee3b104b32966ba7dfeb93f3fa8ab85b5e639265842d66f576e7db9562b1049564c2af6ec84 + languageName: node + linkType: hard + +"dockerode@npm:^3.3.4": + version: 3.3.5 + resolution: "dockerode@npm:3.3.5" + dependencies: + "@balena/dockerignore": ^1.0.2 + docker-modem: ^3.0.0 + tar-fs: ~2.0.1 + checksum: 7f6650422b07fa7ea9d5801f04b1a432634446b5fe37b995b8302b953b64e93abf1bb4596c2fb574ba47aafee685ef2ab959cc86c9654add5a26d09541bbbcc6 + languageName: node + linkType: hard + "doctrine@npm:^3.0.0": version: 3.0.0 resolution: "doctrine@npm:3.0.0" @@ -5793,7 +6003,7 @@ __metadata: languageName: node linkType: hard -"end-of-stream@npm:^1.1.0": +"end-of-stream@npm:^1.0.0, end-of-stream@npm:^1.1.0, end-of-stream@npm:^1.4.1": version: 1.4.4 resolution: "end-of-stream@npm:1.4.4" dependencies: @@ -7413,7 +7623,7 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.12.1, follow-redirects@npm:^1.14.0, follow-redirects@npm:^1.14.9": +"follow-redirects@npm:^1.12.1, follow-redirects@npm:^1.14.0, follow-redirects@npm:^1.14.9, follow-redirects@npm:^1.15.0": version: 1.15.2 resolution: "follow-redirects@npm:1.15.2" peerDependenciesMeta: @@ -7541,6 +7751,13 @@ __metadata: languageName: node linkType: hard +"fs-constants@npm:^1.0.0": + version: 1.0.0 + resolution: "fs-constants@npm:1.0.0" + checksum: 18f5b718371816155849475ac36c7d0b24d39a11d91348cfcb308b4494824413e03572c403c86d3a260e049465518c4f0d5bd00f0371cdfcad6d4f30a85b350d + languageName: node + linkType: hard + "fs-extra@npm:^0.30.0": version: 0.30.0 resolution: "fs-extra@npm:0.30.0" @@ -7565,6 +7782,17 @@ __metadata: languageName: node linkType: hard +"fs-extra@npm:^11.1.1": + version: 11.1.1 + resolution: "fs-extra@npm:11.1.1" + dependencies: + graceful-fs: ^4.2.0 + jsonfile: ^6.0.1 + universalify: ^2.0.0 + checksum: fb883c68245b2d777fbc1f2082c9efb084eaa2bbf9fddaa366130d196c03608eebef7fb490541276429ee1ca99f317e2d73e96f5ca0999eefedf5a624ae1edfd + languageName: node + linkType: hard + "fs-extra@npm:^4.0.2, fs-extra@npm:^4.0.3": version: 4.0.3 resolution: "fs-extra@npm:4.0.3" @@ -8221,10 +8449,21 @@ __metadata: languageName: node linkType: hard -"hardhat-deploy@npm:^0.11.4": - version: 0.11.16 - resolution: "hardhat-deploy@npm:0.11.16" +"hardhat-deploy@npm:^0.11.30": + version: 0.11.30 + resolution: "hardhat-deploy@npm:0.11.30" dependencies: + "@ethersproject/abi": ^5.7.0 + "@ethersproject/abstract-signer": ^5.7.0 + "@ethersproject/address": ^5.7.0 + "@ethersproject/bignumber": ^5.7.0 + "@ethersproject/bytes": ^5.7.0 + "@ethersproject/constants": ^5.7.0 + "@ethersproject/contracts": ^5.7.0 + "@ethersproject/providers": ^5.7.2 + "@ethersproject/solidity": ^5.7.0 + "@ethersproject/transactions": ^5.7.0 + "@ethersproject/wallet": ^5.7.0 "@types/qs": ^6.9.7 axios: ^0.21.1 chalk: ^4.1.2 @@ -8237,8 +8476,8 @@ __metadata: match-all: ^1.2.6 murmur-128: ^0.2.1 qs: ^6.9.4 - zksync-web3: ^0.8.1 - checksum: 531ea02eef28cfecb4518fa3769c6bdfcf7c51095ff1c1fb4a1ac481fd3ea21252b32109b7f96975ee075ab31ce69604ad429f44cc5eaab05de6b5d761200612 + zksync-web3: ^0.14.3 + checksum: 7b9ac9d856097be1df88ed86cbec88e5bdeb6258c7167c097d6ad4e80a1131b9288fc7704ff6457253f293f57c9992d83383f15ce8f22190d94966b8bb05d832 languageName: node linkType: hard @@ -8277,9 +8516,9 @@ __metadata: languageName: node linkType: hard -"hardhat@npm:^2.12.2": - version: 2.14.0 - resolution: "hardhat@npm:2.14.0" +"hardhat@npm:^2.13.0": + version: 2.14.1 + resolution: "hardhat@npm:2.14.1" dependencies: "@ethersproject/abi": ^5.1.2 "@metamask/eth-sig-util": ^4.0.0 @@ -8341,7 +8580,7 @@ __metadata: optional: true bin: hardhat: internal/cli/bootstrap.js - checksum: 7a11ad4650759851306d65c30252ccffa2aca9cb461c66f3fcef5f29d38fe66402d6bc295d293670fa0a72bf3572cc95029c5cd0b0fd45f45edd99d6eb5b7586 + checksum: 151fda00b4cbc049c29af4249755ee28af7a588d66fed1ff308b2b19e260462649798a13acbc758e24fbfdc8a90fd43809c9cf2d3383fbab3eea0d0e0b00bb22 languageName: node linkType: hard @@ -10798,6 +11037,13 @@ __metadata: languageName: node linkType: hard +"mkdirp-classic@npm:^0.5.2": + version: 0.5.3 + resolution: "mkdirp-classic@npm:0.5.3" + checksum: 3f4e088208270bbcc148d53b73e9a5bd9eef05ad2cbf3b3d0ff8795278d50dd1d11a8ef1875ff5aea3fa888931f95bfcb2ad5b7c1061cfefd6284d199e6776ac + languageName: node + linkType: hard + "mkdirp-promise@npm:^5.0.1": version: 5.0.1 resolution: "mkdirp-promise@npm:5.0.1" @@ -11080,6 +11326,15 @@ __metadata: languageName: node linkType: hard +"nan@npm:^2.17.0": + version: 2.17.0 + resolution: "nan@npm:2.17.0" + dependencies: + node-gyp: latest + checksum: ec609aeaf7e68b76592a3ba96b372aa7f5df5b056c1e37410b0f1deefbab5a57a922061e2c5b369bae9c7c6b5e6eecf4ad2dac8833a1a7d3a751e0a7c7f849ed + languageName: node + linkType: hard + "nano-json-stream-parser@npm:^0.1.2": version: 0.1.2 resolution: "nano-json-stream-parser@npm:0.1.2" @@ -11240,13 +11495,6 @@ __metadata: languageName: node linkType: hard -"nofilter@npm:^1.0.4": - version: 1.0.4 - resolution: "nofilter@npm:1.0.4" - checksum: 54d864f745de5c3312994e880cf2d4f55e34830d6adc8275dce3731507ca380d21040336e4a277a4901551c07f04c452fbeffd57fad1dc8f68a2943eaf894a04 - languageName: node - linkType: hard - "nofilter@npm:^3.1.0": version: 3.1.0 resolution: "nofilter@npm:3.1.0" @@ -12184,6 +12432,13 @@ __metadata: languageName: node linkType: hard +"proxy-from-env@npm:^1.1.0": + version: 1.1.0 + resolution: "proxy-from-env@npm:1.1.0" + checksum: ed7fcc2ba0a33404958e34d95d18638249a68c430e30fcb6c478497d72739ba64ce9810a24f53a7d921d0c065e5b78e3822759800698167256b04659366ca4d4 + languageName: node + linkType: hard + "prr@npm:~1.0.1": version: 1.0.1 resolution: "prr@npm:1.0.1" @@ -12281,6 +12536,16 @@ __metadata: languageName: node linkType: hard +"pump@npm:^1.0.0": + version: 1.0.3 + resolution: "pump@npm:1.0.3" + dependencies: + end-of-stream: ^1.1.0 + once: ^1.3.1 + checksum: 61fe58694f9900020a5cf5bc765d74396891c201afecf06659df2f5874fd832be4e19e2f95cc72d8b9eb98ace0a4db3cebf7343f9fc893a930577be29e3ad8b5 + languageName: node + linkType: hard + "pump@npm:^3.0.0": version: 3.0.0 resolution: "pump@npm:3.0.0" @@ -12503,7 +12768,33 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:~1.0.15": +"readable-stream@npm:^2.3.0, readable-stream@npm:^2.3.5": + version: 2.3.8 + resolution: "readable-stream@npm:2.3.8" + dependencies: + core-util-is: ~1.0.0 + inherits: ~2.0.3 + isarray: ~1.0.0 + process-nextick-args: ~2.0.0 + safe-buffer: ~5.1.1 + string_decoder: ~1.1.1 + util-deprecate: ~1.0.1 + checksum: 65645467038704f0c8aaf026a72fbb588a9e2ef7a75cd57a01702ee9db1c4a1e4b03aaad36861a6a0926546a74d174149c8c207527963e0c2d3eee2f37678a42 + languageName: node + linkType: hard + +"readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.5.0": + version: 3.6.2 + resolution: "readable-stream@npm:3.6.2" + dependencies: + inherits: ^2.0.3 + string_decoder: ^1.1.1 + util-deprecate: ^1.0.1 + checksum: bdcbe6c22e846b6af075e32cf8f4751c2576238c5043169a1c221c92ee2878458a816a4ea33f4c67623c0b6827c8a400409bfb3cf0bf3381392d0b1dfb52ac8d + languageName: node + linkType: hard + +"readable-stream@npm:~1.0.15, readable-stream@npm:~1.0.26-4": version: 1.0.34 resolution: "readable-stream@npm:1.0.34" dependencies: @@ -13224,6 +13515,17 @@ __metadata: languageName: node linkType: hard +"semver@npm:^7.5.1": + version: 7.5.4 + resolution: "semver@npm:7.5.4" + dependencies: + lru-cache: ^6.0.0 + bin: + semver: bin/semver.js + checksum: 12d8ad952fa353b0995bf180cdac205a4068b759a140e5d3c608317098b3575ac2f1e09182206bf2eb26120e1c0ed8fb92c48c592f6099680de56bb071423ca3 + languageName: node + linkType: hard + "semver@npm:~5.4.1": version: 5.4.1 resolution: "semver@npm:5.4.1" @@ -13625,13 +13927,20 @@ __metadata: languageName: node linkType: hard -"solidity-ast@npm:^0.4.15, solidity-ast@npm:^0.4.31": +"solidity-ast@npm:^0.4.15": version: 0.4.35 resolution: "solidity-ast@npm:0.4.35" checksum: 6cde9e656dee814fa3d7ce9ef42f1cd0344162515d0d215dbd7d18bf931ed9cd6ce4093aed0a8abbcfb5a4a6faf6638f615aaad479e4657054c6a4ae2cb5092e languageName: node linkType: hard +"solidity-ast@npm:^0.4.38": + version: 0.4.49 + resolution: "solidity-ast@npm:0.4.49" + checksum: f5b0354ddfa882346cf12d33f79c6123796a07637b248ceb9cfeec9f81540e270407f6fca660cf75666e1ba1866270319ab3fbe54b01491dbd35adffd1405243 + languageName: node + linkType: hard + "solidity-comments-extractor@npm:^0.0.7": version: 0.0.7 resolution: "solidity-comments-extractor@npm:0.0.7" @@ -13671,15 +13980,15 @@ __metadata: languageName: node linkType: hard -"solidity-docgen-forked@npm:^0.6.0-beta.29": - version: 0.6.0-beta.29 - resolution: "solidity-docgen-forked@npm:0.6.0-beta.29" +"solidity-docgen@npm:^0.6.0-beta.35": + version: 0.6.0-beta.35 + resolution: "solidity-docgen@npm:0.6.0-beta.35" dependencies: handlebars: ^4.7.7 - solidity-ast: ^0.4.31 + solidity-ast: ^0.4.38 peerDependencies: hardhat: ^2.8.0 - checksum: 809f18952718aa68d76f6420b3ea13e896c542eaabeabdc10211b3aa91cff068ca35a0fcb02d9a63c02212d2ae1884940adb943c9c546258319a44a4abfb9ebc + checksum: 5b773b8b2959109efca409ebd6eaa9eaa535989b52de7653bed75ad9195a145653c6436c258eb78cc819e220d79ecb4ed0efe9fcb8f9aed56e5b5d386149349d languageName: node linkType: hard @@ -13789,6 +14098,13 @@ __metadata: languageName: node linkType: hard +"split-ca@npm:^1.0.0, split-ca@npm:^1.0.1": + version: 1.0.1 + resolution: "split-ca@npm:1.0.1" + checksum: 1e7409938a95ee843fe2593156a5735e6ee63772748ee448ea8477a5a3e3abde193c3325b3696e56a5aff07c7dcf6b1f6a2f2a036895b4f3afe96abb366d893f + languageName: node + linkType: hard + "split-string@npm:^3.0.1, split-string@npm:^3.0.2": version: 3.1.0 resolution: "split-string@npm:3.1.0" @@ -13814,6 +14130,23 @@ __metadata: languageName: node linkType: hard +"ssh2@npm:^1.11.0": + version: 1.13.0 + resolution: "ssh2@npm:1.13.0" + dependencies: + asn1: ^0.2.6 + bcrypt-pbkdf: ^1.0.2 + cpu-features: ~0.0.7 + nan: ^2.17.0 + dependenciesMeta: + cpu-features: + optional: true + nan: + optional: true + checksum: 56df3eb9d0c579230001af99b8b83cec12c3cc393720f27af59eefbe542b453a3190ecd1ab56fbb8b71ae3e5381b39387dc3587bc7b413c495ccb74e62f7689f + languageName: node + linkType: hard + "sshpk@npm:^1.7.0": version: 1.17.0 resolution: "sshpk@npm:1.17.0" @@ -14262,6 +14595,58 @@ __metadata: languageName: node linkType: hard +"tar-fs@npm:~1.16.3": + version: 1.16.3 + resolution: "tar-fs@npm:1.16.3" + dependencies: + chownr: ^1.0.1 + mkdirp: ^0.5.1 + pump: ^1.0.0 + tar-stream: ^1.1.2 + checksum: 0c78aa173cde0df44e5fbbd85077240b8340444bff5ec026539e9e20806ca31b5d4b8cee58befe5c1dae7fa47cd1bb3f9a0efebf2212c2bfbad31f23de329c79 + languageName: node + linkType: hard + +"tar-fs@npm:~2.0.1": + version: 2.0.1 + resolution: "tar-fs@npm:2.0.1" + dependencies: + chownr: ^1.1.1 + mkdirp-classic: ^0.5.2 + pump: ^3.0.0 + tar-stream: ^2.0.0 + checksum: 26cd297ed2421bc8038ce1a4ca442296b53739f409847d495d46086e5713d8db27f2c03ba2f461d0f5ddbc790045628188a8544f8ae32cbb6238b279b68d0247 + languageName: node + linkType: hard + +"tar-stream@npm:^1.1.2": + version: 1.6.2 + resolution: "tar-stream@npm:1.6.2" + dependencies: + bl: ^1.0.0 + buffer-alloc: ^1.2.0 + end-of-stream: ^1.0.0 + fs-constants: ^1.0.0 + readable-stream: ^2.3.0 + to-buffer: ^1.1.1 + xtend: ^4.0.0 + checksum: a5d49e232d3e33321bbd150381b6a4e5046bf12b1c2618acb95435b7871efde4d98bd1891eb2200478a7142ef7e304e033eb29bbcbc90451a2cdfa1890e05245 + languageName: node + linkType: hard + +"tar-stream@npm:^2.0.0": + version: 2.2.0 + resolution: "tar-stream@npm:2.2.0" + dependencies: + bl: ^4.0.3 + end-of-stream: ^1.4.1 + fs-constants: ^1.0.0 + inherits: ^2.0.3 + readable-stream: ^3.1.1 + checksum: 699831a8b97666ef50021c767f84924cfee21c142c2eb0e79c63254e140e6408d6d55a065a2992548e72b06de39237ef2b802b99e3ece93ca3904a37622a66f3 + languageName: node + linkType: hard + "tar@npm:^4.0.2": version: 4.4.19 resolution: "tar@npm:4.4.19" @@ -14413,6 +14798,13 @@ __metadata: languageName: node linkType: hard +"to-buffer@npm:^1.1.1": + version: 1.1.1 + resolution: "to-buffer@npm:1.1.1" + checksum: 6c897f58c2bdd8b8b1645ea515297732fec6dafb089bf36d12370c102ff5d64abf2be9410e0b1b7cfc707bada22d9a4084558010bfc78dd7023748dc5dd9a1ce + languageName: node + linkType: hard + "to-fast-properties@npm:^1.0.3": version: 1.0.3 resolution: "to-fast-properties@npm:1.0.3" @@ -14944,15 +15336,6 @@ __metadata: languageName: node linkType: hard -"undici@npm:^5.4.0": - version: 5.11.0 - resolution: "undici@npm:5.11.0" - dependencies: - busboy: ^1.6.0 - checksum: 20669ef4023d24a75e81ed8142829f525f16af14d61f833b5f19cfc6bed7c706adde343a190d764dcceb227eba3211222d2b194010462a2ca221a7da0487f563 - languageName: node - linkType: hard - "unfetch@npm:^4.2.0": version: 4.2.0 resolution: "unfetch@npm:4.2.0" @@ -15210,6 +15593,13 @@ __metadata: languageName: node linkType: hard +"walkdir@npm:^0.4.1": + version: 0.4.1 + resolution: "walkdir@npm:0.4.1" + checksum: 71045c21dc19aae3321f897b6e9e507cf8039202665c35a0b908eecccaf25636aab769b31cbd61ef8267237fe22fc316923a691ecc2d9d38840a15c59c0f2594 + languageName: node + linkType: hard + "web3-bzz@npm:1.2.11": version: 1.2.11 resolution: "web3-bzz@npm:1.2.11" @@ -16198,11 +16588,11 @@ __metadata: languageName: node linkType: hard -"zksync-web3@npm:^0.8.1": - version: 0.8.1 - resolution: "zksync-web3@npm:0.8.1" +"zksync-web3@npm:^0.14.3": + version: 0.14.4 + resolution: "zksync-web3@npm:0.14.4" peerDependencies: - ethers: ~5.7.0 - checksum: 613ebe822df1bef0af4d62386f3aaf65917d45dd80932b0ddf5b81eba6b0a46376f3e74263d153915dcfb8be954f730ded2e34d7806b6b199bbc74e0f124a0fb + ethers: ^5.7.0 + checksum: f702a3437f48a8d42c4bb35b8dd13671a168aadfc4e23ce723d62959220ccb6bf9c529c60331fe5b91afaa622147c6a37490551474fe3e35c06ac476524b5160 languageName: node linkType: hard