Address Details
contract
token

0xe481988Ef9065CcD024568BBf962f378A7Fa80B8

Token
Test Goddess Nature Token Plus (TGNT+)
Creator
0x15933c–ed3d58 at 0xd82950–8ba2cd
Balance
0 CELO ( )
Locked CELO Balance
0.00 CELO
Voting CELO Balance
0.00 CELO
Pending Unlocked Gold
0.00 CELO
Tokens
Fetching tokens...
Transactions
7 Transactions
Transfers
23 Transfers
Gas Used
184,984
Last Balance Update
13304071
Minimal Proxy Contract for 0x18f7fd11ee989b8b708cddfedbd1b75887d83523.
EIP-1167 - minimal bytecode implementation that delegates all calls to a known address
Contract name:
CarbonCreditBundleToken




Optimization enabled
true
Compiler version
v0.8.13+commit.abaa5c0e




Optimization runs
200
Verified at
2022-05-19T08:42:54.100249Z

project:/contracts/CarbonCreditBundleToken.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.13;

import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";
import "./abstracts/AbstractToken.sol";
import './CarbonCreditToken.sol';

/// @author FlowCarbon LLC
/// @title A Carbon Credit Bundle Token Reference Implementation
contract CarbonCreditBundleToken is AbstractToken {

    using SafeERC20Upgradeable for CarbonCreditToken;
    using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;

    struct TokenChecksums {
        address _tokenAddress;
        uint256 _amount;
    }

    /// @notice Emitted when someone bundles tokens into the bundle token
    /// @param account - the token sender
    /// @param amount - the amount of tokens to bundle
    /// @param tokenAddress - the address of the vanilla underlying
    event Bundle(address account, uint256 amount, address tokenAddress);

    /// @notice Emitted when someone unbundles tokens from the bundle
    /// @param account - the token recipient
    /// @param amount - the amount of tokens to bundle
    /// @param tokenAddress - the address of the vanilla underlying
    event Unbundle(address account, uint256 amount, address tokenAddress);

    /// @notice Emitted when a new token is added to the bundle
    /// @param tokenAddress - the new token that is added
    event TokenAdded(address tokenAddress);

    /// @notice Emitted when a new token is removed from the bundle
    /// @param tokenAddress - the token that has been removed
    event TokenRemoved(address tokenAddress);

    /// @notice Emitted when the minimum vintage requirements change
    /// @param vintage - the new vintage after the update
    event VintageIncremented(uint16 vintage);

    /// @notice The fee divisor taken upon unbundling
    /// @dev 1/feeDivisor is the fee in %
    uint256 public feeDivisor;

    /// @notice The minimal vintage
    uint16 public vintage;

    /// @notice The CarbonCreditTokens that form this bundle
    EnumerableSetUpgradeable.AddressSet private _tokenAddresses;

    /// @notice Keeps track of checksums, amounts and underlying tokens
    mapping (bytes32 => TokenChecksums) private _offsetChecksums;

    function initialize(
        string memory name_,
        string memory symbol_,
        uint16 vintage_,
        CarbonCreditToken[]
        memory tokens_,
        address owner_,
        uint256 feeDivisor_
    ) external initializer {
        require(vintage_ > 2000, 'vintage out of bounds');
        require(vintage_ < 2100, 'vintage out of bounds');

        __AbstractToken_init(name_, symbol_, owner_);
        vintage = vintage_;

        feeDivisor = feeDivisor_;
        for (uint256 i = 0; i < tokens_.length; i++) {
            _addToken(tokens_[i]);
        }
    }

    /// @notice increasing the vintage
    /// @dev existing tokens can no longer be bundled, new tokens require the new vintage
    /// @param years_ - number of years to increment the vintage, needs to be smaller than 10
    function incrementVintage(uint16 years_) external onlyOwner returns (uint16) {
        require(years_ <= 10, "vintage increment out of bounds");

        vintage += years_;
        emit VintageIncremented(vintage);
        return vintage;
    }

    /// @notice Checks if a token exists
    /// @param token_ - a carbon credit token
    function hasToken(CarbonCreditToken token_) public view returns (bool) {
        return _tokenAddresses.contains(address(token_));
    }

    /// @notice Number of tokens in this bundle
    function tokenCount() external view returns (uint256) {
        return _tokenAddresses.length();
    }

    /// @notice A token from the bundle
    /// @param index_ - the index position taken from tokenCount()
    function tokenAtIndex(uint256 index_) external view returns (address) {
        return _tokenAddresses.at(index_);
    }

    /// @notice Adds a new token to the bundle. The token has to match the TokenDetails signature of the bundle
    /// @param token_ - a carbon credit token that is added to the bundle.
    function addToken(CarbonCreditToken token_) external onlyOwner returns (bool) {
        _addToken(token_);
        return true;
    }

    /// @dev Private function to execute addToken so it can be used in the initalizer
    function _addToken(CarbonCreditToken token_) private returns (bool) {
        require(!hasToken(token_), "token already exists");
        require(token_.vintage() >= vintage, "vintage mismatch");
        require(address(token_) != address(this), "cannot add to self");

        _tokenAddresses.add(address(token_));
        emit TokenAdded(address(token_));
        return true;
    }

    /// @notice Removes a token from the bundle
    /// @param token_ - the carbon credit token to remove
    function removeToken(CarbonCreditToken token_) external onlyOwner returns (bool) {
        address tokenAddress = address(token_);
        require(_tokenAddresses.contains(tokenAddress), "token does not exists");
        require(token_.balanceOf(address(this)) == 0, "token has remaining balance");

        _tokenAddresses.remove(tokenAddress);
        emit TokenRemoved(tokenAddress);
        return true;
    }

    /// @notice Bundles an underlying into the bundle, bundle need to be approved beforehand
    /// @param token_ - the carbon credit token to bundle
    /// @param amount_ - the amount one wants to bundle
    function bundle(CarbonCreditToken token_, uint256 amount_) external returns (bool) {
        address tokenAddress = address(token_);
        require(_tokenAddresses.contains(tokenAddress), "token does not exists");
        require(token_.vintage() >= vintage, "token outdated");

        _mint(_msgSender(), amount_);
        token_.safeTransferFrom(_msgSender(), address(this), amount_);

        emit Bundle(_msgSender(), amount_, tokenAddress);
        return true;
    }

    /// @notice Unbundles an underlying from the bundle, note that a fee may apply
    /// @param token_ - the carbon credit token to undbundle
    /// @param amount_ - the amount one wants to unbundle (including fee)
    /// @return the amount of tokens after fees
    function unbundle(CarbonCreditToken token_, uint256 amount_) external returns (uint256) {
        address tokenAddress = address(token_);
        require(_tokenAddresses.contains(tokenAddress), "token does not exists");
        require(token_.balanceOf(address(this)) >= amount_, "amount exceeds the token balance");

        _burn(_msgSender(), amount_);

        uint256 amountToUnbundle = amount_;
        if (feeDivisor > 0) {
            uint256 feeAmount = amount_ / feeDivisor;
            amountToUnbundle = amount_ - feeAmount;
            token_.safeTransfer(owner(), feeAmount);
        }

        token_.safeTransfer(_msgSender(), amountToUnbundle);

        emit Unbundle(_msgSender(), amountToUnbundle, tokenAddress);
        return amountToUnbundle;
    }

    /// @notice The contract owner can finalize the offsetting process once the underlying tokens have been offset
    /// @param token_ - the carbon credit token to finalize the offsetting process for
    /// @param amount_ - the number of token to finalize offsetting process for
    /// @param checksum_ - the checksum associated with the underlying offset event
    function finalizeOffset(CarbonCreditToken token_, uint256 amount_, bytes32 checksum_) external onlyOwner returns (bool) {
        address tokenAddress = address(token_);

        require(_tokenAddresses.contains(tokenAddress), "token does not exists");
        require(_offsetChecksums[checksum_]._amount == 0, "checksum was already used");
        require(amount_ <= pendingBalance, 'offset exceeds pending balance');
        require(token_.balanceOf(address(this)) >= amount_, "amount exceeds the token balance");

        pendingBalance -= amount_;
        _offsetChecksums[checksum_] = TokenChecksums(tokenAddress, amount_);
        offsetBalance += amount_;

        token_.burn(amount_);
        emit FinalizeOffset(amount_, checksum_);
        return true;
    }

    /// @dev See ICarbonCreditTokenInterface
    function amountOffsettedWithChecksum(bytes32 checksum_) external view returns (uint256) {
        return _offsetChecksums[checksum_]._amount;
    }

    /// @param checksum_ - the checksum of the associated offset event of the underlying
    /// @return the address of the CarbonCreditToken that has been offset with this checksum
    function tokenAddressOffsettedWithChecksum(bytes32 checksum_) external view returns (address) {
        return _offsetChecksums[checksum_]._tokenAddress;
    }
}
        

Contract ABI

[{"type":"event","name":"Approval","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"address","name":"spender","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Bundle","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"address","name":"tokenAddress","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"FinalizeOffset","inputs":[{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"bytes32","name":"checksum","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"Offset","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"TokenAdded","inputs":[{"type":"address","name":"tokenAddress","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"TokenRemoved","inputs":[{"type":"address","name":"tokenAddress","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Unbundle","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"address","name":"tokenAddress","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"VintageIncremented","inputs":[{"type":"uint16","name":"vintage","internalType":"uint16","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"addToken","inputs":[{"type":"address","name":"token_","internalType":"contract CarbonCreditToken"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"allowance","inputs":[{"type":"address","name":"owner","internalType":"address"},{"type":"address","name":"spender","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"amountOffsettedWithChecksum","inputs":[{"type":"bytes32","name":"checksum_","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"approve","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"bundle","inputs":[{"type":"address","name":"token_","internalType":"contract CarbonCreditToken"},{"type":"uint256","name":"amount_","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"decimals","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"decreaseAllowance","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"subtractedValue","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"feeDivisor","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"finalizeOffset","inputs":[{"type":"address","name":"token_","internalType":"contract CarbonCreditToken"},{"type":"uint256","name":"amount_","internalType":"uint256"},{"type":"bytes32","name":"checksum_","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"hasToken","inputs":[{"type":"address","name":"token_","internalType":"contract CarbonCreditToken"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"increaseAllowance","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"addedValue","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint16","name":"","internalType":"uint16"}],"name":"incrementVintage","inputs":[{"type":"uint16","name":"years_","internalType":"uint16"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"string","name":"name_","internalType":"string"},{"type":"string","name":"symbol_","internalType":"string"},{"type":"uint16","name":"vintage_","internalType":"uint16"},{"type":"address[]","name":"tokens_","internalType":"contract CarbonCreditToken[]"},{"type":"address","name":"owner_","internalType":"address"},{"type":"uint256","name":"feeDivisor_","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"name","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"offset","inputs":[{"type":"uint256","name":"amount_","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"offsetAmountAtIndex","inputs":[{"type":"address","name":"address_","internalType":"address"},{"type":"uint256","name":"index_","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"offsetBalance","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"offsetBalanceOf","inputs":[{"type":"address","name":"account_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"offsetCountOf","inputs":[{"type":"address","name":"address_","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"offsetOnBehalfOf","inputs":[{"type":"address","name":"account_","internalType":"address"},{"type":"uint256","name":"amount_","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"offsetTimeAtIndex","inputs":[{"type":"address","name":"address_","internalType":"address"},{"type":"uint256","name":"index_","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"pendingBalance","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"removeToken","inputs":[{"type":"address","name":"token_","internalType":"contract CarbonCreditToken"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"symbol","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"tokenAddressOffsettedWithChecksum","inputs":[{"type":"bytes32","name":"checksum_","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"tokenAtIndex","inputs":[{"type":"uint256","name":"index_","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"tokenCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSupply","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transfer","inputs":[{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transferFrom","inputs":[{"type":"address","name":"sender","internalType":"address"},{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"unbundle","inputs":[{"type":"address","name":"token_","internalType":"contract CarbonCreditToken"},{"type":"uint256","name":"amount_","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint16","name":"","internalType":"uint16"}],"name":"vintage","inputs":[]}]
              

Contract Creation Code

Verify & Publish
0x3d602d80600a3d3981f3363d3d373d3d3d363d7318f7fd11ee989b8b708cddfedbd1b75887d835235af43d82803e903d91602b57fd5bf3

Deployed ByteCode

0x363d3d373d3d3d363d7318f7fd11ee989b8b708cddfedbd1b75887d835235af43d82803e903d91602b57fd5bf3