Description:
ERC20 token contract with Factory capabilities. Standard implementation for fungible tokens on Ethereum.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"src/converters/cbBTCConverterImmutable.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.27;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../IStrBTC.sol";
/**
* @title CBBTCConverterImmutable
* @notice Contract for conversion between cbBTC and strBTC at immutable rates
* @dev Allows users to exchange cbBTC for strBTC and vice versa with separate rates
*/
contract CBBTCConverterImmutable {
error AmountMustBeGreaterThanZero();
error ConversionResultedInZeroTokens();
error InsufficientCBBTCBalance();
error MintingLimitExceeded();
error NotWithdrawer();
IStrBTC public immutable strbtc;
IERC20 public immutable cbbtc;
address public immutable withdrawer;
uint256 public immutable mintingLimit;
uint256 public immutable rateNumerator;
uint256 public immutable rateDenominator;
uint256 public totalMinted;
uint256 public totalBurned;
event CBBTCConverted(address indexed user, uint256 cbbtcAmount, uint256 strbtcAmount);
event StrBTCConverted(address indexed user, uint256 strbtcAmount, uint256 cbbtcAmount);
modifier onlyWithdrawer() {
if (msg.sender != withdrawer) revert NotWithdrawer();
_;
}
/**
* @notice constructor of the CBBTCConverterImmutable contract
* @param _cbbtc cbBTC Token Address
* @param _strbtc strBTC Token Address
* @param _withdrawer Address authorized to withdraw fees
*/
constructor(address _cbbtc, address _strbtc, address _withdrawer) {
cbbtc = IERC20(_cbbtc);
strbtc = IStrBTC(_strbtc);
withdrawer = _withdrawer;
rateNumerator = 999;
rateDenominator = 1000;
mintingLimit = 500 * 10 ** 8; // 500 cbBTC
totalMinted = 0;
totalBurned = 0;
}
/**
* @notice Returns the current amount of minted strBTC through this contract
* @return The net amount currently minted (totalMinted - totalBurned)
*/
function currentlyMinted() public view returns (uint256) {
return totalMinted - totalBurned;
}
/**
* @notice Converts cbBTC to strBTC at the incoming rate
* @param cbbtcAmount The amount of cbBTC to convert
* @return The amount of strBTC received
*/
function convertCBBTCToStrBTC(uint256 cbbtcAmount) external returns (uint256) {
if (cbbtcAmount == 0) revert AmountMustBeGreaterThanZero();
uint256 strbtcAmount = (cbbtcAmount * rateNumerator) / rateDenominator;
if (strbtcAmount == 0) revert ConversionResultedInZeroTokens();
if (currentlyMinted() + strbtcAmount > mintingLimit) revert MintingLimitExceeded();
totalMinted += strbtcAmount;
cbbtc.transferFrom(msg.sender, address(this), cbbtcAmount);
strbtc.converterMint(msg.sender, strbtcAmount);
emit CBBTCConverted(msg.sender, cbbtcAmount, strbtcAmount);
return strbtcAmount;
}
/**
* @notice Converts strBTC back to cbBTC at the outgoing rate
* @param strbtcAmount The amount of strBTC to convert
* @return The amount of cbBTC received
*/
function convertStrBTCToCBBTC(uint256 strbtcAmount) external returns (uint256) {
if (strbtcAmount == 0) revert AmountMustBeGreaterThanZero();
uint256 cbbtcAmount = (strbtcAmount * rateNumerator) / rateDenominator;
if (cbbtcAmount == 0) revert ConversionResultedInZeroTokens();
if (cbbtc.balanceOf(address(this)) < cbbtcAmount) revert InsufficientCBBTCBalance();
totalBurned += strbtcAmount;
strbtc.transferFrom(msg.sender, address(this), strbtcAmount);
strbtc.converterBurn(address(this), strbtcAmount);
cbbtc.transfer(msg.sender, cbbtcAmount);
emit StrBTCConverted(msg.sender, strbtcAmount, cbbtcAmount);
return cbbtcAmount;
}
/**
* @notice Withdrawal collected fees from the contract
* @param token The address of the token to withdraw
* @param recipient The address of the recipient
* @param amount The amount of tokens
*/
function withdraw(address token, address recipient, uint256 amount) external onlyWithdrawer {
IERC20(token).transfer(recipient, amount);
}
}
"
},
"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
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 value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` 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 value) external returns (bool);
}
"
},
"src/IStrBTC.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.27;
interface IStrBTC {
function totalSupply() external view returns (uint256);
function totalShares() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function transfer(address recipient, uint256 amount) external returns (bool);
function getSharesByPooledBTC(uint256 btcAmount) external view returns (uint256);
function getPooledBTCByShares(uint256 sharesAmount) external view returns (uint256);
function converterMint(address to, uint256 amount) external;
function converterBurn(address from, uint256 amount) external;
}
"
}
},
"settings": {
"remappings": [
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/",
"bip340-solidity/=lib/bip340-solidity/",
"blockchain-tools/=lib/blockchain-tools/",
"ds-test/=lib/blockchain-tools/forge-std/lib/ds-test/src/",
"elliptic-curve-solidity/=lib/blockchain-tools/lib/elliptic-curve-solidity/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"foundry-devops/=lib/blockchain-tools/lib/foundry-devops/",
"halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/",
"safe-contracts/=lib/safe-contracts/",
"@safe-global/safe-contracts/=lib/safe-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "prague",
"viaIR": false
}
}}
Submitted on: 2025-09-17 17:16:19
Comments
Log in to comment.
No comments yet.