Skip to content

Commit

Permalink
review code
Browse files Browse the repository at this point in the history
  • Loading branch information
akashiceth committed Apr 24, 2023
1 parent 3a904c6 commit fa48e9a
Show file tree
Hide file tree
Showing 28 changed files with 3,211 additions and 3,115 deletions.
703 changes: 71 additions & 632 deletions LICENSE

Large diffs are not rendered by default.

83 changes: 83 additions & 0 deletions contracts/BendCoinPool.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.18;
import {ERC4626Upgradeable, IERC4626Upgradeable, IERC20MetadataUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC4626Upgradeable.sol";
import {IERC20Upgradeable, SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {MathUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol";
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";

import {IApeCoinStaking} from "./interfaces/IApeCoinStaking.sol";
import {ICoinPool} from "./interfaces/ICoinPool.sol";
import {IStakeManager} from "./interfaces/IStakeManager.sol";

contract BendCoinPool is ICoinPool, ERC4626Upgradeable, ReentrancyGuardUpgradeable, OwnableUpgradeable {
using MathUpgradeable for uint256;
using SafeERC20Upgradeable for IERC20Upgradeable;

IApeCoinStaking public apeCoinStaking;
IStakeManager public staker;

uint256 public override pendingApeCoin;

modifier onlyStaker() {
require(_msgSender() == address(staker), "BendCoinPool: caller is not staker");
_;
}

function initialize(IApeCoinStaking apeStaking_, IStakeManager staker_) external initializer {
IERC20MetadataUpgradeable apeCoin = IERC20MetadataUpgradeable(apeStaking_.apeCoin());
__Ownable_init();
__ERC20_init("Bend Auto-compund ApeCoin", "bacAPE");
__ERC4626_init(apeCoin);
apeCoinStaking = apeStaking_;
staker = staker_;
}

function totalAssets() public view override(ERC4626Upgradeable, IERC4626Upgradeable) returns (uint256) {
return pendingApeCoin + staker.totalPendingRewards() + staker.totalStakedApeCoin() + staker.totalRefund();
}

function _deposit(
address caller,
address receiver,
uint256 assets,
uint256 shares
) internal override(ERC4626Upgradeable) {
// transfer ape coin from caller
super._deposit(caller, receiver, assets, shares);
// increase pending amount
pendingApeCoin += assets;
}

function _withdraw(
address caller,
address receiver,
address owner,
uint256 assets,
uint256 shares
) internal override(ERC4626Upgradeable) {
if (pendingApeCoin < assets) {
uint256 required = assets - pendingApeCoin;
require(staker.withdrawApeCoin(required) >= (required), "BendCoinPool: withdraw failed");
}
// transfer ape coin to receiver
super._withdraw(caller, receiver, owner, assets, shares);
// decrease pending amount
pendingApeCoin -= assets;
}

function assetBalanceOf(address account) external view override returns (uint256) {
return convertToAssets(balanceOf(account));
}

function receiveApeCoin(uint256 amount) external override onlyStaker {
IERC20Upgradeable(asset()).safeTransferFrom(_msgSender(), address(this), amount);
pendingApeCoin += amount;
emit RewardDistributed(amount);
}

function pullApeCoin(uint256 amount_) external override onlyStaker {
pendingApeCoin -= amount_;
IERC20Upgradeable(asset()).safeTransfer(address(staker), amount_);
}
}
175 changes: 175 additions & 0 deletions contracts/BendNftPool.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.8.18;
import {IERC20Upgradeable, SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import {IERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";

import {INftVault} from "./interfaces/INftVault.sol";
import {IStakeManager} from "./interfaces/IStakeManager.sol";
import {INftPool, IStakedNft, IApeCoinStaking} from "./interfaces/INftPool.sol";
import {ICoinPool} from "./interfaces/ICoinPool.sol";
import {IDelegationRegistry} from "./interfaces/IDelegationRegistry.sol";

import {ApeStakingLib} from "./libraries/ApeStakingLib.sol";

contract BendApePool is INftPool, ReentrancyGuardUpgradeable, OwnableUpgradeable {
using SafeERC20Upgradeable for IERC20Upgradeable;
using SafeERC20Upgradeable for ICoinPool;
using ApeStakingLib for IApeCoinStaking;
mapping(address => PoolState) public poolStates;

IStakeManager public override staker;
ICoinPool public coinPool;
IDelegationRegistry public delegation;
address public bayc;
address public mayc;
address public bakc;

modifier onlyApe(address nft_) {
require(bayc == nft_ || mayc == nft_ || bakc == nft_, "BendApePool: not ape");
_;
}

modifier onlyStaker() {
require(_msgSender() == address(staker), "BendApePool: caller is not staker");
_;
}

function initialize(
IDelegationRegistry delegation_,
ICoinPool coinPool_,
IStakeManager staker_,
IStakedNft stBayc,
IStakedNft stMayc,
IStakedNft stBakc
) external initializer {
__Ownable_init();
__ReentrancyGuard_init();
staker = staker_;
coinPool = coinPool_;
delegation = delegation_;
bayc = stBayc.underlyingAsset();
mayc = stMayc.underlyingAsset();
bakc = stBakc.underlyingAsset();
poolStates[bayc].stakedNft = stBayc;
poolStates[mayc].stakedNft = stMayc;
poolStates[bakc].stakedNft = stBakc;
}

function deposit(address nft_, uint256[] calldata tokenIds_) external override onlyApe(nft_) {
PoolState storage pool = poolStates[nft_];

uint256 tokenId_;

for (uint256 i = 0; i < tokenIds_.length; i++) {
tokenId_ = tokenIds_[i];
IERC721Upgradeable(nft_).safeTransferFrom(_msgSender(), address(this), tokenId_);

pool.rewardsDebt[tokenId_] = pool.accumulatedRewardsPerNft;
}

pool.stakedNft.mint(address(staker), _msgSender(), tokenIds_);
}

function withdraw(address nft_, uint256[] calldata tokenIds_) external override onlyApe(nft_) {
_claim(_msgSender(), _msgSender(), nft_, tokenIds_);
PoolState storage pool = poolStates[nft_];
uint256 tokenId_;
for (uint256 i = 0; i < tokenIds_.length; i++) {
tokenId_ = tokenIds_[i];
pool.stakedNft.safeTransferFrom(_msgSender(), address(this), tokenId_);
}
pool.stakedNft.burn(tokenIds_);
}

function _claim(
address owner_,
address receiver_,
address nft_,
uint256[] calldata tokenIds_
) internal {
PoolState storage pool = poolStates[nft_];
uint256 tokenId_;
uint256 claimableRewards;

for (uint256 i = 0; i < tokenIds_.length; i++) {
tokenId_ = tokenIds_[i];
require(
pool.stakedNft.ownerOf(tokenId_) == owner_ &&
pool.stakedNft.minterOf(tokenId_) == address(this) &&
pool.stakedNft.stakerOf(tokenId_) == address(staker),
"BendApePool: invalid token id"
);

if (pool.accumulatedRewardsPerNft > pool.rewardsDebt[tokenId_]) {
claimableRewards += (pool.accumulatedRewardsPerNft - pool.rewardsDebt[tokenId_]);
pool.rewardsDebt[tokenId_] = pool.accumulatedRewardsPerNft;
}
}
coinPool.safeTransfer(receiver_, claimableRewards);
}

function claim(
address nft_,
uint256[] calldata tokenIds_,
address delegateVault_
) external override onlyApe(nft_) {
address owner = _msgSender();
address receiver = _msgSender();
if (delegateVault_ != address(0)) {
uint256 tokenId_;
for (uint256 i = 0; i < tokenIds_.length; i++) {
tokenId_ = tokenIds_[i];
PoolState storage pool = poolStates[nft_];
bool isDelegateValid = delegation.checkDelegateForToken(
msg.sender,
delegateVault_,
address(pool.stakedNft),
tokenId_
);
require(isDelegateValid, "BendApePool: invalid delegate-vault pairing");
}

owner = delegateVault_;
}
_claim(owner, receiver, nft_, tokenIds_);
}

function receiveApeCoin(address nft_, uint256 rewardsAmount_) external override onlyApe(nft_) onlyStaker {
IERC20Upgradeable(staker.apeCoinStaking().apeCoin()).safeTransferFrom(
_msgSender(),
address(this),
rewardsAmount_
);
PoolState storage pool = poolStates[nft_];
pool.accumulatedRewardsPerNft += (rewardsAmount_ / pool.stakedNft.totalStaked(address(staker)));

coinPool.deposit(rewardsAmount_, address(this));

emit RewardDistributed(
nft_,
rewardsAmount_,
pool.stakedNft.totalStaked(address(staker)),
pool.accumulatedRewardsPerNft
);
}

function claimable(address nft_, uint256[] calldata tokenIds_)
external
view
override
onlyApe(nft_)
returns (uint256 amount)
{
PoolState storage pool = poolStates[nft_];
uint256 tokenId_ = 0;
for (uint256 i = 0; i < tokenIds_.length; i++) {
tokenId_ = tokenIds_[i];
if (pool.accumulatedRewardsPerNft > pool.rewardsDebt[tokenId_]) {
amount += (pool.accumulatedRewardsPerNft - pool.rewardsDebt[tokenId_]);
}
}
}
}
Loading

0 comments on commit fa48e9a

Please sign in to comment.