Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0xc3CBd1e850D431adC583f14f03b9B8B651e62A61
Balance 0 ETH
Nonce 1
Code Size 2930 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

2930 bytes
0x608060405234801561001057600080fd5b50600436106100a95760003560e01c80638da5cb5b116100715780638da5cb5b146101585780639f4568ef1461016b578063a695aa4d1461018b578063bbb333ed146101b2578063bedb86fb146101c5578063d51a020b146101d857600080fd5b806313af4035146100ae578063484267a4146100c35780635236be40146100e957806353620494146100fc5780635c975abb1461013b575b600080fd5b6100c16100bc366004610982565b6101ff565b005b6100d66100d1366004610982565b610298565b6040519081526020015b60405180910390f35b6100d66100f73660046109b5565b61046f565b6101237f0000000000000000000000000000000012a0592c154d552c410030e724b2ea0081565b6040516001600160a01b0390911681526020016100e0565b6002546101489060ff1681565b60405190151581526020016100e0565b600054610123906001600160a01b031681565b6100d6610179366004610982565b60016020526000908152604090205481565b6101237f0000000000000000000000007fcc30e97d718864d46a84f13e3ba111a56123d381565b6100d66101c03660046109f5565b610832565b6100c16101d3366004610a0e565b610873565b6101237f000000000000000000000000000000007a58f5f58e697e51ab0357bc9e260a0481565b6000546001600160a01b0316331461024d5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0383169081178255604051909133917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d769190a350565b6040516370a0823160e01b81526001600160a01b03828116600483015260009182917f0000000000000000000000000000000012a0592c154d552c410030e724b2ea0016906370a0823190602401602060405180830381865afa158015610303573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103279190610a2b565b604051639f4568ef60e01b81526001600160a01b0385811660048301529192506000917f0000000000000000000000007fcc30e97d718864d46a84f13e3ba111a56123d31690639f4568ef90602401602060405180830381865afa158015610393573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103b79190610a2b565b6001600160a01b0385166000908152600160205260409020546103da9190610a5a565b90508082036103ed575060009392505050565b4263629bf20081101561040557506000949350505050565b6000636427740082111561041a575082610448565b600061042583610832565b9050670de0b6b3a764000061043a8287610a72565b6104449190610a91565b9150505b82811161045b5750600095945050505050565b6104658382610ab3565b9695505050505050565b60025460009060ff16156104ae5760405162461bcd60e51b815260206004820152600660248201526514105554d15160d21b6044820152606401610244565b6040516370a0823160e01b81523360048201526000907f0000000000000000000000000000000012a0592c154d552c410030e724b2ea006001600160a01b0316906370a0823190602401602060405180830381865afa158015610515573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105399190610a2b565b604051639f4568ef60e01b81523360048201529091506000906001600160a01b037f0000000000000000000000007fcc30e97d718864d46a84f13e3ba111a56123d31690639f4568ef90602401602060405180830381865afa1580156105a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c79190610a2b565b336000908152600160205260409020546105e19190610a5a565b9050808211604051806040016040528060098152602001681393d391481311519560ba1b815250906106265760405162461bcd60e51b81526004016102449190610aca565b504263629bf2008110156106695760405162461bcd60e51b815260206004820152600a6024820152691393d517d59154d5115160b21b6044820152606401610244565b6000636427740082111561067e5750826106ac565b600061068983610832565b9050670de0b6b3a764000061069e8287610a72565b6106a89190610a91565b9150505b6040805180820190915260098152681393d391481311519560ba1b60208201528382116106ec5760405162461bcd60e51b81526004016102449190610aca565b5060006106f98483610ab3565b905080955086610741578881101561073d5760405162461bcd60e51b81526020600482015260076024820152664558434545445360c81b6044820152606401610244565b8895505b3360009081526001602052604081208054889290610760908490610a5a565b909155505060405163a9059cbb60e01b81526001600160a01b038981166004830152602482018890527f000000000000000000000000000000007a58f5f58e697e51ab0357bc9e260a04169063a9059cbb906044016020604051808303816000875af11580156107d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107f89190610b1f565b50604051869033907fe6c82503aaaa3db78b70f183901ae8668918f895b3982b2c851cf2ffe0c6c63990600090a350505050509392505050565b600063629bf20063018b820066470de4df820000670d99a8cec7e200008461085b858886610905565b905061086883828461093a565b979650505050505050565b6000546001600160a01b031633146108bc5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401610244565b6002805460ff191682151590811790915560405190815233907fe8699cf681560fd07de85543bd994263f4557bdc5179dd702f256d15fd083e1d9060200160405180910390a250565b6000806109128585610ab3565b90508261092782670de0b6b3a7640000610a72565b6109319190610a91565b95945050505050565b600080670de0b6b3a76400006109508585610a72565b61095a9190610a91565b90506109318186610a5a565b80356001600160a01b038116811461097d57600080fd5b919050565b60006020828403121561099457600080fd5b61099d82610966565b9392505050565b80151581146109b257600080fd5b50565b6000806000606084860312156109ca57600080fd5b833592506109da60208501610966565b915060408401356109ea816109a4565b809150509250925092565b600060208284031215610a0757600080fd5b5035919050565b600060208284031215610a2057600080fd5b813561099d816109a4565b600060208284031215610a3d57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b60008219821115610a6d57610a6d610a44565b500190565b6000816000190483118215151615610a8c57610a8c610a44565b500290565b600082610aae57634e487b7160e01b600052601260045260246000fd5b500490565b600082821015610ac557610ac5610a44565b500390565b600060208083528351808285015260005b81811015610af757858101830151858201604001528201610adb565b81811115610b09576000604083870101525b50601f01601f1916929092016040019392505050565b600060208284031215610b3157600080fd5b815161099d816109a456fea26469706673582212205a7c1aaaced9bdf2235d902e6069e07974af1ab7311735716d83630ee45fac1464736f6c634300080d0033

Verified Source Code Partial Match

Compiler: v0.8.13+commit.abaa5c0e EVM: london Optimization: Yes (200 runs)
ICNV.sol 8 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.13;

import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";

interface ICNV is IERC20 {
    function mint(address account, uint256 amount) external;
}
IRedeemBBT.sol 41 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.13;


interface IRedeemBBT {

    /// @notice mapping of how many CNV tokens a bbtCNV holder has redeemed
    /// @param      _who    address
    /// @return     amount  amount redeemed so far
    function redeemed(address _who)
        external
        view
        returns(uint256 amount);

    /// @notice             redeem bbtCNV for CNV following vesting schedule
    /// @param  _amount     amount of CNV to redeem, irrelevant if _max = true
    /// @param  _who        address of bbtCNV holder to redeem
    /// @param  _to         address to which to mint CNV
    /// @param  _max        whether to redeem maximum amount possible
    /// @return amountOut   amount of CNV tokens to be minted to _to
    function redeem(uint256 _amount, address _who, address _to, bool _max)
        external
        returns(uint256 amountOut);

    /// @notice         to view how much a holder has redeemable
    /// @param  _who    bbtHolder address
    /// @return         amount redeemable
    function redeemable(address _who)
        external
        view
        returns(uint256);

    /// @notice         returns the percent of holdings vested for a given point
    ///                 in time.
    /// @param  _time   point in time
    /// @return vpct    percent of holdings vested
    function vestedPercent(uint256 _time)
        external
        pure
        returns(uint256 vpct);
}
RedeemBBTV2.sol 226 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.13;

import { IERC20     } from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import { Owned      } from "solmate/auth/Owned.sol";
import { ICNV       } from "./ICNV.sol";
import { IRedeemBBT } from "./IRedeemBBT.sol";

contract RedeemBBTV2 is Owned {

    ////////////////////////////////////////////////////////////////////////////
    // EVENTS
    ////////////////////////////////////////////////////////////////////////////

    // @notice Emitted when a BBT redemption happens.
    event Redemption(
        address indexed _from,
        uint256 indexed _amount
    );

    // @notice Emitted when contract is paused/unpaused
    event Paused (
        address indexed caller,
        bool isPaused
    );

    ////////////////////////////////////////////////////////////////////////////
    // MUTABLE STATE
    ////////////////////////////////////////////////////////////////////////////

    /// @notice address of bbtCNV Token
    address public immutable bbtCNV;
    /// @notice address of CNV Token
    address public immutable CNV;
    /// @notice address of RedeemBBT V1
    address public immutable redeemBBTV1;
    /// @notice mapping of how many CNV tokens a bbtCNV holder has redeemed
    mapping(address => uint256) public redeemed;
    /// @notice redeem paused;
    bool public paused;
    
    ////////////////////////////////////////////////////////////////////////////
    // IMMUTABLE STATE
    ////////////////////////////////////////////////////////////////////////////
    
    string internal constant NONE = "NONE LEFT";
    uint256 internal constant JUNE_5_2022 = 1654387200;
    uint256 internal constant APRIL_1_2023 = 1680307200;


    ////////////////////////////////////////////////////////////////////////////
    // CONSTRUCTOR
    ////////////////////////////////////////////////////////////////////////////
    
    // Better to use cosntants for production here. 
    constructor(
        address _bbtCNV, 
        address _CNV, 
        address _redeemBBTV1
    ) Owned(msg.sender) {
        bbtCNV = _bbtCNV;
        CNV = _CNV;
        redeemBBTV1 = _redeemBBTV1;
    }

    ////////////////////////////////////////////////////////////////////////////
    // ADMIN/MGMT
    ////////////////////////////////////////////////////////////////////////////

    function setPause(
        bool _paused
    ) external onlyOwner {
        paused = _paused;
        emit Paused(msg.sender, _paused);
    }

    ////////////////////////////////////////////////////////////////////////////
    // ACTIONS
    ////////////////////////////////////////////////////////////////////////////

    /// @notice             redeem bbtCNV for CNV following vesting schedule
    /// @param  _amount     amount of CNV to redeem, irrelevant if _max = true
    /// @param  _to         address to which to mint CNV
    /// @param  _max        whether to redeem maximum amount possible
    /// @return amountOut   amount of CNV tokens to be minted to _to
    function redeem(
        uint256 _amount, 
        address _to, 
        bool _max
    ) external returns (uint256 amountOut) {
        // Check if it's paused
        require(!paused, "PAUSED");
        // Get user bbtCNV balance, and get amount already redeemed.
        // If already redeemed full balance - revert on "FULLY_REDEEMED" since
        // all balance has already been redeemed.
        uint256 bbtCNVBalance = IERC20(bbtCNV).balanceOf(msg.sender);
        uint256 amountRedeemed = redeemed[msg.sender] + IRedeemBBT(redeemBBTV1).redeemed(msg.sender);
        require(bbtCNVBalance > amountRedeemed, NONE);

        // Check how much is currently vested for user.
        // Revert if currently no more available to redeem.
        uint256 currentTime = block.timestamp;
        require(currentTime >= JUNE_5_2022, "NOT_VESTED");
        uint256 amountVested;
        
        if (currentTime > APRIL_1_2023) {
            amountVested = bbtCNVBalance;
        } else {
            uint256 vpct = vestedPercent(currentTime);
            amountVested = bbtCNVBalance * vpct / 1e18;
        }
        
        require(amountVested > amountRedeemed, NONE);

        // Calculate amount redeemable as the amountVested minus the amount that
        // has previously been redeemed.
        // If _max was not selected and thus a specified amount is to be
        // redeemed, ensure this amount doesn't exceed amountRedeemable.
        uint256 amountRedeemable = amountVested - amountRedeemed;
        amountOut = amountRedeemable;
        if (!_max) {
            require(amountRedeemable >= _amount,"EXCEEDS");
            amountOut = _amount;
        }

        // Update state to reflect redemption.
        redeemed[msg.sender] += amountOut;

        // Transfer CNV
        ICNV(CNV).transfer(_to, amountOut);

        emit Redemption(msg.sender, amountOut);
    }

    ////////////////////////////////////////////////////////////////////////////
    // VIEW
    ////////////////////////////////////////////////////////////////////////////

    /// @notice         to view how much a holder has redeemable
    /// @param  _who    bbtHolder address
    /// @return         amount redeemable
    function redeemable(
        address _who
    ) external view returns (uint256) {
        uint256 bbtCNVBalance = IERC20(bbtCNV).balanceOf(_who);
        uint256 amountRedeemed = redeemed[_who] + IRedeemBBT(redeemBBTV1).redeemed(_who);
        if (bbtCNVBalance == amountRedeemed) return 0;

        uint256 currentTime = block.timestamp;
        if (currentTime < JUNE_5_2022) return 0;

        uint256 amountVested;
        if (currentTime > APRIL_1_2023) {
            amountVested = bbtCNVBalance;
        } else {
            uint256 vpct = vestedPercent(currentTime);
            amountVested = bbtCNVBalance * vpct / 1e18;
        }
        if (amountVested <= amountRedeemed) return 0;

        return amountVested - amountRedeemed;
    }

    /// @notice         returns the percent of holdings vested for a given point
    ///                 in time.
    /// @param  _time   point in time
    /// @return vpct    percent of holdings vested
    function vestedPercent(
        uint256 _time
    ) public pure returns (uint256 vpct) {
        // Hardcode variables in method to avoid state reads and save gas.
        //
        // vestingTimeStart
        // - time vesting begins: JUNE_5_2022 (Sun Jun 05 2022 00:00:00 GMT+0000)
        //
        // vestingTimeLength
        // - duration of vesting: 25920000 (10 30-day months)
        //
        // vestingAmountStart
        // - vesting begins at 2%
        //
        // vestingAmountLength
        // - vesting grows to 100%, thus has a length of 98

        uint256 vestingTimeStart    = JUNE_5_2022;
        uint256 vestingTimeLength   = 25920000;
        uint256 vestingAmountStart  = 2e16;
        uint256 vestingAmountLength = 98e16;

        uint256 pctOf = _percentOf(vestingTimeStart, _time, vestingTimeLength);
        vpct = _linearMapping(vestingAmountStart, pctOf, vestingAmountLength);
    }

    ////////////////////////////////////////////////////////////////////////////
    // INTERNAL
    ////////////////////////////////////////////////////////////////////////////

    /// @notice             returns the elapsed percentage of a point within
    ///                     a given range
    /// @param  _start      starting point
    /// @param  _point      current point
    /// @param  _length     lenght
    /// @return elapsedPct  percent from _start
    function _percentOf(
        uint256 _start, 
        uint256 _point, 
        uint256 _length
    ) internal pure returns(uint256 elapsedPct) {
        uint256 elapsed             = _point - _start;
                elapsedPct          = elapsed * 1e18 / _length;
    }

    /// @notice             linearly maps a percentage point to a range
    /// @param  _start      starting point
    /// @param  _pct        percentage point
    /// @param  _length     lenght
    /// @return point       point
    function _linearMapping(
        uint256 _start, 
        uint256 _pct, 
        uint256 _length
    ) internal pure returns (uint256 point) {
        uint256 elapsed             = _length * _pct / 1e18;
                point               = _start + elapsed;
    }
}
Owned.sol 44 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Simple single owner authorization mixin.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/Owned.sol)
abstract contract Owned {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event OwnerUpdated(address indexed user, address indexed newOwner);

    /*//////////////////////////////////////////////////////////////
                            OWNERSHIP STORAGE
    //////////////////////////////////////////////////////////////*/

    address public owner;

    modifier onlyOwner() virtual {
        require(msg.sender == owner, "UNAUTHORIZED");

        _;
    }

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(address _owner) {
        owner = _owner;

        emit OwnerUpdated(address(0), _owner);
    }

    /*//////////////////////////////////////////////////////////////
                             OWNERSHIP LOGIC
    //////////////////////////////////////////////////////////////*/

    function setOwner(address newOwner) public virtual onlyOwner {
        owner = newOwner;

        emit OwnerUpdated(msg.sender, newOwner);
    }
}
IERC20.sol 82 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

Read Contract

CNV 0xd51a020b → address
bbtCNV 0x53620494 → address
owner 0x8da5cb5b → address
paused 0x5c975abb → bool
redeemBBTV1 0xa695aa4d → address
redeemable 0x484267a4 → uint256
redeemed 0x9f4568ef → uint256
vestedPercent 0xbbb333ed → uint256

Write Contract 3 functions

These functions modify contract state and require a wallet transaction to execute.

redeem 0x5236be40
uint256 _amount
address _to
bool _max
returns: uint256
setOwner 0x13af4035
address newOwner
setPause 0xbedb86fb
bool _paused

Recent Transactions

No transactions found for this address