Skip to content

Commit

Permalink
chore: early access implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
zhoujia6139 committed Jan 2, 2024
1 parent f9b85ee commit ce07cbd
Show file tree
Hide file tree
Showing 17 changed files with 715 additions and 477 deletions.
8 changes: 4 additions & 4 deletions contracts/cross-chain/L1/IVaultApeStaking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -154,24 +154,24 @@ interface IVaultApeStaking {
* @notice enter ape staking pool when bayc/mayc/bakc transferred to vault contract.
* It's an interceptor call, can only be called by vault self.
* @param nft Identify pool
* @param tokenId The tokenId of the nft
* @param tokenIds The tokenId array of the nft
* @param beneficiary The reward beneficiary for the pool position
*/
function onboardCheckApeStakingPosition(
address nft,
uint32 tokenId,
uint32[] calldata tokenIds,
address beneficiary
) external;

/**
* @notice exit ape staking pool when bayc/mayc/bakc transferred out from vault contract.
* It's an interceptor call, can only be called by vault self.
* @param nft Identify pool
* @param tokenId The tokenId of the nft
* @param tokenIds The tokenId array of the nft
*/
function offboardCheckApeStakingPosition(
address nft,
uint32 tokenId
uint32[] calldata tokenIds
) external;

/**
Expand Down
54 changes: 50 additions & 4 deletions contracts/cross-chain/L1/IVaultEarlyAccess.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,55 @@
pragma solidity ^0.8.0;

interface IVaultEarlyAccess {
function depositERC721(address nft, uint32[] calldata tokenIds) external;
enum StrategyType {
NONE,
NORMAL, //no yield or AAVE
CAPE,
APESTAKING
}

// function offboardNFTs(address nft, uint32[] calldata tokenIds) external;
//
// function offboardNFT(address nft, uint32 tokenId) external;
function updateAccessListStatus(
address[] calldata assets,
bool[] calldata statuses
) external;

function setCollectionStrategy(
address[] calldata assets,
StrategyType[] calldata strategies
) external;

function addETHCollection(address asset) external;

function ethCollection() external view returns (address[] memory);

function isInETHList(address asset) external view returns (bool);

function depositETHCollection(
address asset,
uint256 amount
) external payable;

function totalETHValue() external view returns (uint256);

function totalETHShare() external view returns (uint256);

function addUSDCollection(address asset) external;

function usdCollection() external view returns (address[] memory);

function isInUSDList(address asset) external view returns (bool);

function depositUSDCollection(address asset, uint256 amount) external;

function totalUSDValue() external view returns (uint256);

function totalUSDShare() external view returns (uint256);

function cApeCollection() external view returns (address[] memory);

function depositCApeCollection(address asset, uint256 amount) external;

function depositERC20(address asset, uint256 amount) external;

function depositERC721(address asset, uint32[] calldata tokenIds) external;
}
138 changes: 81 additions & 57 deletions contracts/cross-chain/L1/VaultApeStaking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -353,88 +353,112 @@ contract VaultApeStaking is ReentrancyGuard, Pausable, IVaultApeStaking {
/// @inheritdoc IVaultApeStaking
function onboardCheckApeStakingPosition(
address nft,
uint32 tokenId,
uint32[] calldata tokenIds,
address beneficiary
) external override {
require(msg.sender == address(this), Errors.INVALID_CALLER);

if (nft == bayc || nft == mayc || nft == bakc) {
//ensure no ape position
uint256 poolId = (nft == bayc) ? 1 : ((nft == mayc) ? 2 : 3);
(uint256 stakedAmount, ) = apeCoinStaking.nftPosition(
poolId,
tokenId
);
require(stakedAmount == 0, Errors.ALREADY_STAKING);
if (nft == bayc || nft == mayc) {
(, bool isPaired) = apeCoinStaking.mainToBakc(poolId, tokenId);
require(!isPaired, Errors.ALREADY_STAKING);
}

PoolState storage poolState = apeStakingStorage().poolStates[nft];
TokenStatus memory tokenStatus = poolState.tokenStatus[tokenId];
require(
tokenStatus.beneficiary == address(0),
Errors.INVALID_STATUS
);

tokenStatus.beneficiary = beneficiary;
tokenStatus.rewardsDebt = poolState.accumulatedRewardsPerNft;
poolState.tokenStatus[tokenId] = tokenStatus;
uint256 arrayLength = tokenIds.length;
for (uint256 index = 0; index < arrayLength; index++) {
uint32 tokenId = tokenIds[index];
(uint256 stakedAmount, ) = apeCoinStaking.nftPosition(
poolId,
tokenId
);
require(stakedAmount == 0, Errors.ALREADY_STAKING);
if (nft == bayc || nft == mayc) {
(, bool isPaired) = apeCoinStaking.mainToBakc(
poolId,
tokenId
);
require(!isPaired, Errors.ALREADY_STAKING);
}

poolState.totalPosition += 1;
TokenStatus memory tokenStatus = poolState.tokenStatus[tokenId];
require(
tokenStatus.beneficiary == address(0),
Errors.INVALID_STATUS
);

tokenStatus.beneficiary = beneficiary;
tokenStatus.rewardsDebt = poolState.accumulatedRewardsPerNft;
poolState.tokenStatus[tokenId] = tokenStatus;
}

poolState.totalPosition += arrayLength.toUint32();
}
}

/// @inheritdoc IVaultApeStaking
function offboardCheckApeStakingPosition(
address nft,
uint32 tokenId
uint32[] calldata tokenIds
) external override {
ApeStakingStorage storage ds = apeStakingStorage();
//ensure ownership by bridge, don't validate ownership here
require(msg.sender == address(this), Errors.INVALID_CALLER);
require(
msg.sender == address(this) || msg.sender == ds.apeStakingBot,
Errors.INVALID_CALLER
);

PoolState storage poolState = apeStakingStorage().poolStates[nft];
PoolState storage poolState = ds.poolStates[nft];
if (poolState.totalPosition > 0) {
if (poolState.stakingPosition > 0) {
TokenStatus memory tokenStatus = poolState.tokenStatus[tokenId];
if (nft == bakc) {
if (tokenStatus.isStaking) {
uint32[] memory tokenIds = new uint32[](1);
tokenIds[0] = tokenStatus.pairTokenId;
_unstakeApe(tokenStatus.isPairedWithBayc, tokenIds);
}
} else {
if (tokenStatus.isStaking || tokenStatus.isPairedStaking) {
bool isBAYC = (nft == bayc);
uint32[] memory tokenIds = new uint32[](1);
tokenIds[0] = tokenId;
_unstakeApe(isBAYC, tokenIds);
uint256 arrayLength = tokenIds.length;
for (uint256 index = 0; index < arrayLength; index++) {
uint32 tokenId = tokenIds[index];

if (poolState.stakingPosition > 0) {
TokenStatus memory tokenStatus = poolState.tokenStatus[
tokenId
];
if (nft == bakc) {
if (tokenStatus.isStaking) {
uint32[] memory ids = new uint32[](1);
ids[0] = tokenStatus.pairTokenId;
_unstakeApe(tokenStatus.isPairedWithBayc, ids);
}
} else {
if (
tokenStatus.isStaking || tokenStatus.isPairedStaking
) {
bool isBAYC = (nft == bayc);
uint32[] memory ids = new uint32[](1);
ids[0] = tokenId;
_unstakeApe(isBAYC, ids);
}
}
}
}

//claim pending reward
uint256 cApeExchangeRate = cApe.getPooledApeByShares(
WadRayMath.RAY
);
uint256 rewardShare = _claimPendingReward(
poolState.tokenStatus[tokenId],
poolState.accumulatedRewardsPerNft,
nft,
tokenId,
cApeExchangeRate
);
if (rewardShare > 0) {
uint256 pendingReward = rewardShare.rayMul(cApeExchangeRate);
cApe.transfer(
poolState.tokenStatus[tokenId].beneficiary,
pendingReward
//claim one by one, since every token id may have a different beneficiary
uint256 cApeExchangeRate = cApe.getPooledApeByShares(
WadRayMath.RAY
);
}
uint256 rewardShare = _claimPendingReward(
poolState.tokenStatus[tokenId],
poolState.accumulatedRewardsPerNft,
nft,
tokenId,
cApeExchangeRate
);
if (rewardShare > 0) {
uint256 pendingReward = rewardShare.rayMul(
cApeExchangeRate
);
cApe.transfer(
poolState.tokenStatus[tokenId].beneficiary,
pendingReward
);
}

poolState.totalPosition -= 1;
delete poolState.tokenStatus[tokenId];
// we also reduce totalPosition one by one for accuracy
poolState.totalPosition -= 1;
delete poolState.tokenStatus[tokenId];
}
}
}

Expand Down
Loading

0 comments on commit ce07cbd

Please sign in to comment.