Carbon Credit Trading Contract
What it does:
Tokenizes carbon credits as on-chain assets, enabling transparent issuance, transfer, trading, and retirement of verified emissions reductions.
Why it matters:
Prevents double-counting, increases trust in carbon markets, reduces reliance on opaque intermediaries, and makes climate action auditable and global.
How it works:
-
Verified projects issue carbon credits as on-chain tokens
-
Each token represents a fixed amount of CO₂ offset (e.g. 1 ton)
-
Credits can be transferred or traded on secondary markets
-
Buyers retire credits on-chain to offset emissions
-
Retired credits are permanently removed from circulation
-
All issuance, transfers, and retirements are publicly auditable
-
Integrates with registries, oracles, and sustainability reporting tools
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
/**
* @title CarbonCreditToken
* @author Nam
* @notice Tokenized carbon credits with on-chain retirement
*/
contract CarbonCreditToken is ERC20, Ownable {
uint256 public retiredSupply;
mapping(address => uint256) public retiredBalance;
mapping(bytes32 => bool) public retiredReferences;
// e.g. company report IDs to prevent double claims
// -------------------- EVENTS --------------------
event CreditsIssued(address indexed project, uint256 amount);
event CreditsRetired(address indexed account, uint256 amount, bytes32 referenceId);
// -------------------- CONSTRUCTOR --------------------
constructor(
string memory _name,
string memory _symbol
) ERC20(_name, _symbol) {}
// -------------------- ISSUANCE --------------------
function issueCredits(address _to, uint256 _amount) external onlyOwner {
require(_amount > 0, "Invalid amount");
_mint(_to, _amount);
emit CreditsIssued(_to, _amount);
}
// -------------------- RETIREMENT --------------------
function retireCredits(uint256 _amount, bytes32 _referenceId) external {
require(_amount > 0, "Invalid amount");
require(balanceOf(msg.sender) >= _amount, "Insufficient balance");
require(!retiredReferences[_referenceId], "Reference already used");
_burn(msg.sender, _amount);
retiredSupply += _amount;
retiredBalance[msg.sender] += _amount;
retiredReferences[_referenceId] = true;
emit CreditsRetired(msg.sender, _amount, _referenceId);
}
// -------------------- VIEW --------------------
function totalActiveSupply() external view returns (uint256) {
return totalSupply();
}
}