Skip to content

Instantly share code, notes, and snippets.

@rfikki
Created August 21, 2025 11:06
Show Gist options
  • Save rfikki/4fbbe77a53c901dedced44973007c215 to your computer and use it in GitHub Desktop.
Save rfikki/4fbbe77a53c901dedced44973007c215 to your computer and use it in GitHub Desktop.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
/// @title CurrencyCoin Interface
/// @notice Interface for interacting with the CurrencyCoin contract
interface CurrencyCoin {
/// @notice Get the coin balance of an address
/// @param _owner The address to check the balance of
/// @return The balance of the address
function coinBalanceOf(address _owner) external returns (uint256);
/// @notice Send coins to a receiver
/// @param _amount The amount of coins to send
/// @param _receiver The address to send the coins to
function sendCoin(uint256 _amount, address _receiver) external;
}
/// @title DropBox Contract
/// @notice Contract for collecting and storing coins
contract DropBox is Ownable(msg.sender) {
/// @notice Collect coins from the CurrencyCoin contract
/// @param value The amount of coins to collect
/// @param ccInt The CurrencyCoin interface instance
function collect(uint256 value, CurrencyCoin ccInt) public onlyOwner {
ccInt.sendCoin(value, owner());
}
}
/// @title WrappedCurrencyCoin Contract
/// @notice Contract for wrapping and unwrapping CurrencyCoin tokens
contract WrappedCurrencyCoin is ERC20 {
/// @notice Event emitted when a drop box is created
/// @param owner The address of the drop box owner
event DropBoxCreated(address indexed owner);
/// @notice Event emitted when coins are wrapped
/// @param value The amount of coins wrapped
/// @param owner The address of the owner who wrapped the coins
event Wrapped(uint256 indexed value, address indexed owner);
/// @notice Event emitted when coins are unwrapped
/// @param value The amount of coins unwrapped
/// @param owner The address of the owner who unwrapped the coins
event Unwrapped(uint256 indexed value, address indexed owner);
/// @notice The address of the CurrencyCoin contract
address constant ccAddr = 0x8494F777d13503BE928BB22b1F4ae3289E634FD3;
/// @notice The CurrencyCoin interface instance
CurrencyCoin constant ccInt = CurrencyCoin(ccAddr);
/// @notice Mapping from owner addresses to their drop box addresses
mapping(address => address) public dropBoxes;
/// @notice Constructor for the WrappedCurrencyCoin contract
constructor() ERC20("Wrapped CurrencyCoin", "CC") {}
/// @notice Create a drop box for the sender
function createDropBox() public {
require(dropBoxes[msg.sender] == address(0), "Drop box already exists");
dropBoxes[msg.sender] = address(new DropBox());
emit DropBoxCreated(msg.sender);
}
/// @notice Wrap CurrencyCoin tokens into WrappedCurrencyCoin tokens
/// @param value The amount of tokens to wrap
function wrap(uint256 value) public {
address dropBox = dropBoxes[msg.sender];
require(dropBox != address(0), "You must create a drop box first");
require(ccInt.coinBalanceOf(dropBox) >= value, "Not enough coins in drop box");
DropBox(dropBox).collect(value, ccInt);
_mint(msg.sender, value);
emit Wrapped(value, msg.sender);
}
/// @notice Unwrap WrappedCurrencyCoin tokens back into CurrencyCoin tokens
/// @param value The amount of tokens to unwrap
function unwrap(uint256 value) public {
require(balanceOf(msg.sender) >= value, "Not enough coins to unwrap");
ccInt.sendCoin(value, msg.sender);
_burn(msg.sender, value);
emit Unwrapped(value, msg.sender);
}
/// @notice Override the decimals function to return 0
/// @return The number of decimals for the token
function decimals() public pure override returns (uint8) {
return 0;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment