Contract Name:
BridgeToken
Contract Source Code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./sources/OZ/Ownable.sol";
import "./BridgeToken.sol";
import "./chiefValidator.sol";
contract EmoliumTokenFactory is Ownable {
struct TokenInfo {
address tokenAddress;
address initialOwner;
string name;
string symbol;
}
TokenInfo[] public deployedTokens; // Deployed Emolium Liquid Tokens
event TokenDeployed(address indexed initialOwner, address indexed tokenAddress, string name, string symbol);
address payable public chiefValidator; // Emolium ChiefValidator address
address public chainRouter; // Emolium ChainRouter address
constructor(address initialOwner, address payable _chiefValidatorAddress, address _chainRouterAddress)
Ownable(initialOwner)
{
transferOwnership(initialOwner);
chiefValidator = _chiefValidatorAddress;
chainRouter = _chainRouterAddress;
}
// Deploy Liquid token
function deployLiquidToken(string[] calldata namesAndSymbols, address initialOwner) external onlyOwner {
require(namesAndSymbols.length % 2 == 0, "Input array must have an even length");
require(initialOwner != address(0), "Invalid initialOwner address");
require(chainRouter != address(0), "Invalid ChainRouter address");
for (uint256 i = 0; i < namesAndSymbols.length; i += 2) {
string memory name = namesAndSymbols[i];
string memory symbol = namesAndSymbols[i + 1];
BridgeToken newToken = new BridgeToken(name, symbol, initialOwner, chainRouter);
deployedTokens.push(TokenInfo(address(newToken), initialOwner, name, symbol));
emit TokenDeployed(initialOwner, address(newToken), name, symbol);
}
}
// Register Liquid Tokens in ChiefValidator
function registerTokens() external onlyOwner {
require(chiefValidator != address(0), "ChiefValidator address not set");
address[] memory tokenAddresses = new address[](deployedTokens.length);
for (uint256 i = 0; i < deployedTokens.length; i++) {
tokenAddresses[i] = deployedTokens[i].tokenAddress;
}
ChiefValidator(chiefValidator).registerBridgeTokens(tokenAddresses);
}
// Function to get the list of deployed tokens
function getDeployedTokens() external view returns (TokenInfo[] memory) {
return deployedTokens;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./sources/OZ/Ownable.sol";
import "./sources/OZ/ReentrancyGuard.sol";
import "./sources/OZ/IERC20.sol";
import "./sources/OZ/Address.sol";
import "./sources/IWETH.sol";
import "./sources/IMintableERC20.sol";
import "./sources/IBridgedToken.sol";
import "./validatorFactory.sol";
import "./validator.sol";
interface IBurnableERC20 {
function burn(uint256 amount) external;
}
contract ChiefValidator is Ownable, ReentrancyGuard {
address public EMLTokenAddress;
ValidatorFactory public validatorFactory;
uint256 public emlRewardAmount;
address public bridgeDeposit;
address public wethAddress;
address public devAddress;
IWETH public weth;
// Retreive Bridge Tokens
mapping(address => bool) public bridgeTokens;
// Store Proofs
mapping(bytes32 => bool) public proofs; // bool => true (legit) or false (not submitted or fraud)
// Mapping of authorized Contracts
mapping(address => bool) public authorizedContracts;
// Events
event TokenDeployed(address indexed initialOwner, address indexed tokenAddress, string name, string symbol);
event ProofVerified(bytes32 indexed proofHash, bool valid);
event EMLMinted(address indexed validator, uint256 amount);
event BridgeTokenRegistered(address indexed tokenAddress);
event BridgedETH(address to, uint256 amount);
event BridgeFee(address to, uint256 amount);
event TokenBridgedIn(address indexed tokenAddress, address to, uint256 amount);
event BridgedTokenTransfered(address indexed tokenAddress, address to, uint256 amount);
event DeployerAuthorized(address indexed contractAddress, bool isAuthorized);
// Modifier
modifier onlyAuthorized() {
require(authorizedContracts[msg.sender], "Caller is not authorized");
_;
}
constructor(
address _EMLTokenAddress,
address _wethAddress,
address _devAddress,
address _initialOwner,
address _validatorFactory
) Ownable(_initialOwner)
{
EMLTokenAddress = _EMLTokenAddress;
validatorFactory = ValidatorFactory(_validatorFactory);
wethAddress = _wethAddress;
devAddress = _devAddress;
transferOwnership(_initialOwner);
}
// Autorize contracts for validator creation
function setAuthorization(address _contract, bool _isAuthorized) external onlyOwner {
authorizedContracts[_contract] = _isAuthorized;
emit DeployerAuthorized(_contract, _isAuthorized);
}
// Register Bridge Tokens
function registerBridgeTokens(address[] calldata tokens) external onlyAuthorized {
for (uint256 i = 0; i < tokens.length; i++) {
bridgeTokens[tokens[i]] = true;
emit BridgeTokenRegistered(tokens[i]);
}
}
// Update Bridge Tokens
function updateBridgeTokens(address tokenAddress, bool isRegistered) external onlyOwner {
bridgeTokens[tokenAddress] = isRegistered;
}
function isBridgeTokenRegistered(address token) external view returns (bool) {
return bridgeTokens[token];
}
// Verify Proof & Mint EML Rewards to validators
function verifyProof(string[] calldata proofData, bytes32 proofHash) external nonReentrant onlyOwner {
require(proofData.length == 6, "Invalid proof data length");
require(!proofs[proofHash], "Proof already submitted");
address[] memory validators = validatorFactory.getDeployedValidators();
uint256 activeValidatorCount = 0;
address[] memory activeValidators = new address[](validators.length);
for (uint256 i = 0; i < validators.length; i++) {
if (Validator(validators[i]).isActive()) {
activeValidators[activeValidatorCount] = validators[i];
activeValidatorCount++;
}
}
require(activeValidatorCount > 0, "No active validators found");
bool proofValid = false;
for (uint256 i = 0; i < activeValidatorCount; i++) {
bytes32 keccakResult = Validator(activeValidators[i]).calculateKeccak256(proofData);
if (keccakResult == proofHash) {
proofValid = true;
break;
}
}
if (proofValid) {
mintEMLRewards();
handleBridgedToken(proofData);
proofs[proofHash] = true;
emit ProofVerified(proofHash, true);
} else {
emit ProofVerified(proofHash, false);
}
}
// Mint EML Rewards
function mintEMLRewards() internal {
address[] memory validators = validatorFactory.getDeployedValidators();
uint256 totalActiveValidators = 0;
// Number of active Validators
for (uint256 i = 0; i < validators.length; i++) {
if (Validator(validators[i]).isActive()) {
totalActiveValidators++;
}
}
require(totalActiveValidators > 0, "No active validators found");
uint256 rewardPerValidator = emlRewardAmount / totalActiveValidators;
// EML Mint to Active Validators only & equally
for (uint256 i = 0; i < validators.length; i++) {
if (Validator(validators[i]).isActive()) {
address validatorOwner = Validator(validators[i]).getValidatorOwner();
// Call EML Mint function
IMintableERC20(EMLTokenAddress).mint(validatorOwner, rewardPerValidator);
emit EMLMinted(validatorOwner, rewardPerValidator);
}
}
}
// Handle Bridge Operations
function handleBridgedToken(string[] calldata proofData) internal {
address tokenAddress = parseAddress(proofData[0]);
uint256 amount = parseUint(proofData[1]);
address destination = parseAddress(proofData[2]);
uint256 timestamp = parseUint(proofData[3]);
string memory emoliumSaltData = proofData[4];
uint256 providedFee = parseUint(proofData[5]);
require(timestamp >= 0, "Invalid timestamp");
require(bytes(emoliumSaltData).length > 0, "Invalid salt data");
require(providedFee >= 0, "Invalid fee");
// Fee calculation and validation
uint256 calculatedFee = (amount * providedFee) / 10000;
uint256 netAmount = amount - calculatedFee;
// Handle ETH & WETH
if (tokenAddress == wethAddress) {
IWETH(wethAddress).withdraw(amount);
payable(devAddress).transfer(calculatedFee);
payable(destination).transfer(netAmount);
emit BridgedETH(destination, netAmount);
if (calculatedFee > 0) emit BridgeFee(devAddress, calculatedFee);
}
// Handle Emolium Bridge Registered Token
else if (bridgeTokens[tokenAddress]) {
IBridgedToken(tokenAddress).mint(destination, netAmount);
IBridgedToken(tokenAddress).mint(devAddress, calculatedFee);
emit TokenBridgedIn(tokenAddress, destination, netAmount);
if (calculatedFee > 0) emit BridgeFee(devAddress, calculatedFee);
}
// Handle all other ERC20 tokens
else {
IERC20(tokenAddress).transfer(destination, netAmount);
IERC20(tokenAddress).transfer(devAddress, calculatedFee);
emit BridgedTokenTransfered(tokenAddress, destination, netAmount);
if (calculatedFee > 0) emit BridgeFee(devAddress, calculatedFee);
}
}
// Convert string to uint
function parseUint(string memory _value) internal pure returns (uint256) {
bytes memory b = bytes(_value);
uint256 number = 0;
for (uint256 i = 0; i < b.length; i++) {
number = number * 10 + (uint256(uint8(b[i])) - 48);
}
return number;
}
// Convert string to address
function parseAddress(string memory _value) internal pure returns (address) {
bytes memory b = bytes(_value);
require(b.length == 42, "Invalid address length"); // Inclut '0x' au début
uint160 number;
for (uint256 i = 2; i < b.length; i++) { // Skip '0x'
number *= 16;
uint8 c = uint8(b[i]);
if (c >= 48 && c <= 57) {
number += c - 48;
} else if (c >= 97 && c <= 102) {
number += c - 87;
} else if (c >= 65 && c <= 70) {
number += c - 55;
}
}
return address(number);
}
// Setters for addresses
function setBridgeDeposit(address _bridgeDeposit) external onlyOwner {
bridgeDeposit = _bridgeDeposit;
}
function setWethAddress(address _wethAddress) external onlyOwner {
wethAddress = _wethAddress;
}
// Set EML Reward Amount
function setEMLRewardAmount(uint256 _amount) external onlyOwner {
emlRewardAmount = _amount;
}
// Get Proof Status
function getProofStatus(bytes32 proofHash) external view returns (bool) {
return proofs[proofHash];
}
// Emergency & Rescue Functions
function rescueETH() external onlyOwner {
require(address(this).balance > 0, "Insufficient ETH balance");
payable(devAddress).transfer(address(this).balance);
}
function rescueERC20(address token, uint256 amount) external onlyOwner {
IERC20 erc20 = IERC20(token);
require(erc20.balanceOf(address(this)) >= amount, "Insufficient token balance");
erc20.transfer(devAddress, amount);
}
function rescueWETH(uint256 amount) external onlyOwner {
require(weth.balanceOf(address(this)) >= amount, "Insufficient WETH balance");
weth.transfer(devAddress, amount);
}
receive() external payable {}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./sources/OZ/ERC20.sol";
import "./sources/OZ/Ownable.sol";
import "./sources/OZ/ERC20Burnable.sol";
import "./sources/OZ/Pausable.sol";
interface IChainRouter {
function getChainInfo(uint256 networkId) external view returns (string memory, uint256);
}
contract BridgeToken is ERC20, ERC20Burnable, Ownable, Pausable {
uint256 public initialSupply = 0 * 10**18; // No supply at deployment
// Authorized minters and burners
mapping(address => bool) public authorizedMinters;
mapping(address => bool) public authorizedBurners;
// Reference to the ChainRouter contract
IChainRouter public chainRouter;
event MinterAdded(address indexed minter);
event MinterRemoved(address indexed minter);
event BurnerAdded(address indexed burner);
event BurnerRemoved(address indexed burner);
// The constructor takes the initial owner address and calls the Ownable constructor
constructor (
string memory _name,
string memory _symbol,
address initialOwner,
address chainRouterAddress
)
ERC20 (_name, _symbol)
Ownable (initialOwner)
{
_mint(initialOwner, initialSupply);
chainRouter = IChainRouter(chainRouterAddress); // Initialize ChainRouter contract address
}
// Modifiers
modifier onlyAuthorizedMinter() {
require(authorizedMinters[msg.sender], "Not an authorized minter");
_;
}
modifier onlyAuthorizedBurner() {
require(authorizedBurners[msg.sender], "Not an authorized burner");
_;
}
function addMinter(address minter) external onlyOwner {
authorizedMinters[minter] = true;
emit MinterAdded(minter);
}
function removeMinter(address minter) external onlyOwner {
authorizedMinters[minter] = false;
emit MinterRemoved(minter);
}
function addBurner(address burner) external onlyOwner {
authorizedBurners[burner] = true;
emit BurnerAdded(burner);
}
function removeBurner(address burner) external onlyOwner {
authorizedBurners[burner] = false;
emit BurnerRemoved(burner);
}
function mint(address to, uint256 amount) external onlyAuthorizedMinter whenNotPaused {
_mint(to, amount);
}
function burn(uint256 amount) public override onlyAuthorizedBurner whenNotPaused {
super.burn(amount);
}
function burnFrom(address account, uint256 amount) public override onlyAuthorizedBurner whenNotPaused {
super.burnFrom(account, amount);
}
// Function to get the name of a registered blockchain from its ID (using ChainRouter)
function getBlockchainById(uint256 networkId) external view returns (string memory) {
// Fetch blockchain info from ChainRouter
(string memory chainName, ) = chainRouter.getChainInfo(networkId);
return chainName;
}
function pause() external onlyOwner {_pause();}
function unpause() external onlyOwner {_unpause();}
function transfer(address recipient, uint256 amount) public override whenNotPaused returns (bool) {
return super.transfer(recipient, amount);
}
function transferFrom(address sender, address recipient, uint256 amount) public override whenNotPaused returns (bool) {
return super.transferFrom(sender, recipient, amount);
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import "./Context.sol";
abstract contract Ownable is Context {
address private _owner;
error OwnableUnauthorizedAccount(address account);
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./sources/OZ/IERC20.sol";
import "./sources/OZ/Ownable.sol";
contract Validator is Ownable {
address public EMLTokenAddress;
address public validatorFactory;
uint256 public validatorPrice;
address public admin;
bool public active = false;
// Validator Current Owner
mapping(address => address) public validatorOwners;
// Mapping to associate the contract address with the validator address
mapping(address => address) public validatorContracts;
// Events
event EMLBalanceChecked(uint256 balance);
event ValidatorCount(uint256 activeCount, uint256 maxCount);
event ValidatorClosed(address indexed owner, uint256 amount);
event ValidatorOpened();
event ValidatorClosedEvent();
constructor(address _EMLTokenAddress, address _initialOwner, address _validatorFactory) Ownable(_initialOwner) {
EMLTokenAddress = _EMLTokenAddress;
admin = _initialOwner;
validatorFactory = _validatorFactory; // Set the validatorFactory by default
validatorContracts[address(this)] = address(this);
validatorOwners[address(this)] = _initialOwner;
}
// Keccak hash function for an array of strings
function calculateKeccak256(string[] calldata inputs) external view returns (bytes32) {
require(active, "Validator is not active"); // Check if the validator is active
// Concatenate all strings in the array
bytes memory concatenatedString;
for (uint256 i = 0; i < inputs.length; i++) {
concatenatedString = abi.encodePacked(concatenatedString, inputs[i]);
}
// Calculate the Keccak256 hash of the concatenated string
bytes32 hash = keccak256(concatenatedString);
return hash;
}
// Set a new validator factory
function setValidatorFactory(address _validatorFactory) external onlyOwner {
require(_validatorFactory != address(0), "Invalid validator factory address");
validatorFactory = _validatorFactory;
}
// Return the validator contract address
function getValidatorContractAddress() external view returns (address) {
return validatorContracts[address(this)];
}
// Return the current validator owner
function getValidatorOwner() external view returns (address) {
return validatorOwners[address(this)];
}
// Return the amount of EML available in the contract
function getEMLBalance() external view returns (uint256) {
return IERC20(EMLTokenAddress).balanceOf(address(this));
}
// Function to close the validator and send the EML balance to the owner
function closeValidator() external onlyOwner {
uint256 balance = IERC20(EMLTokenAddress).balanceOf(address(this));
require(balance > 0, "No EML tokens to transfer");
IERC20(EMLTokenAddress).transfer(owner(), balance);
active = false;
emit ValidatorClosed(owner(), balance);
emit ValidatorClosedEvent();
}
// Open the validator if it holds at least 20,000 EML
function openValidator() external onlyOwner {
uint256 emlBalance = IERC20(EMLTokenAddress).balanceOf(address(this));
emit EMLBalanceChecked(emlBalance); // Log la balance
require(emlBalance >= 20000 * 10**18, "Validator must hold at least 20,000 EML");
active = true;
emit ValidatorOpened();
}
// Function to check if the validator is active
function isActive() external view returns (bool) {
return active;
}
// Function to get the admin address
function getAdmin() external view returns (address) {
return admin;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./sources/OZ/Ownable.sol";
import "./validator.sol";
contract ValidatorFactory is Ownable {
// Mapping to store the addresses of deployed validators
mapping(address => bool) public validators;
// Mapping of authorized Contracts
mapping(address => bool) public authorizedContracts;
// List of deployed validators
address[] public deployedValidators;
// Maximum number of active validators
uint256 public constant MAX_ACTIVE_VALIDATORS = 25;
// Events
event ValidatorCreated(address indexed validatorAddress);
event ContractAuthorized(address indexed contractAddress, bool isAuthorized);
// Modifier
modifier onlyAuthorized() {
require(authorizedContracts[msg.sender], "Caller is not authorized");
_;
}
constructor(address _initialOwner) Ownable(_initialOwner) {
}
// Autorize contracts for validator creation
function setAuthorization(address _contract, bool _isAuthorized) external onlyOwner {
authorizedContracts[_contract] = _isAuthorized;
emit ContractAuthorized(_contract, _isAuthorized);
}
// Function to create a single Validator and assign ownership to the provided owner
function createValidator(address _EMLTokenAddress, address _owner) external onlyAuthorized returns (address) {
// Check the number of active validators
uint256 activeValidatorCount = 0;
for (uint256 i = 0; i < deployedValidators.length; i++) {
if (Validator(deployedValidators[i]).isActive()) {
activeValidatorCount++;
}
}
require(
activeValidatorCount < MAX_ACTIVE_VALIDATORS,
"Maximum number of active validators reached"
);
// Create the validator and pass this factory address in the constructor
Validator newValidator = new Validator(_EMLTokenAddress, _owner, address(this));
// Register the new validator in the factory
address validatorAddress = address(newValidator);
validators[validatorAddress] = true;
deployedValidators.push(validatorAddress);
emit ValidatorCreated(validatorAddress);
return validatorAddress;
}
// Create a batch of Validators
function createInitialValidators(address _EMLTokenAddress, uint256 numberOfValidators) external onlyOwner {
require(numberOfValidators > 0, "Number of validators must be greater than 0");
require(numberOfValidators <= MAX_ACTIVE_VALIDATORS, "Cannot create more than the maximum allowed validators");
// Check active Validators number
uint256 activeValidatorCount = 0;
for (uint256 i = 0; i < deployedValidators.length; i++) {
if (Validator(deployedValidators[i]).isActive()) {
activeValidatorCount++;
}
}
require(
deployedValidators.length + numberOfValidators <= MAX_ACTIVE_VALIDATORS || activeValidatorCount < MAX_ACTIVE_VALIDATORS,
"Cannot exceed the maximum number of validators"
);
for (uint256 i = 0; i < numberOfValidators; i++) {
Validator newValidator = new Validator(_EMLTokenAddress, msg.sender, address(this));
address validatorAddress = address(newValidator);
validators[validatorAddress] = true;
deployedValidators.push(validatorAddress);
emit ValidatorCreated(validatorAddress);
}
}
// Check if a validator is active
function isValidatorActive(address validatorAddress) external view returns (bool) {
require(validators[validatorAddress], "Validator not found");
return Validator(validatorAddress).isActive();
}
// Get the owner of a validator
function getValidatorOwner(address validatorAddress) external view returns (address) {
require(validators[validatorAddress], "Validator not found");
return Validator(validatorAddress).getValidatorOwner();
}
// Get the list of deployed validators
function getDeployedValidators() external view returns (address[] memory) {
return deployedValidators;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IBridgedToken {
function mint(address to, uint256 amount) external;
function burn(address from, uint256 amount) external;
function burnFrom(address from, uint256 amount) external;
function transfer(address to, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function decimals() external view returns (uint8);
function symbol() external view returns (string memory);
function name() external view returns (string memory);
function tokenAddress() external view returns (address);
function mintable() external view returns (bool);
function burnable() external view returns (bool);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IMintableERC20 {
function mint(address to, uint256 amount) external;
function burn(address from, uint256 amount) external;
function transfer(address to, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function decimals() external view returns (uint8);
function symbol() external view returns (string memory);
function name() external view returns (string memory);
function tokenAddress() external view returns (address);
function mintable() external view returns (bool);
function burnable() external view returns (bool);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IWETH {
function deposit() external payable;
function withdraw(uint256 wad) external;
function balanceOf(address guy) external view returns (uint256);
function transfer(address dst, uint256 wad) external returns (bool);
function approve(address usr, uint256 wad) external returns (bool);
function transferFrom(address src, address dst, uint256 wad) external returns (bool);
function allowance(address src, address dst) external view returns (uint256);
event Deposit(address indexed dst, uint256 wad);
event Withdrawal(address indexed src, uint256 wad);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
import "./Errors.sol";
library Address {
error AddressEmptyCode(address target);
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert Errors.InsufficientBalance(address(this).balance, amount);
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert Errors.FailedCall();
}
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
assembly ("memory-safe") {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert Errors.FailedCall();
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
abstract contract ReentrancyGuard {
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
_status = ENTERED;
}
function _nonReentrantAfter() private {
_status = NOT_ENTERED;
}
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)
pragma solidity ^0.8.20;
import {Context} from "./Context.sol";
abstract contract Pausable is Context {
bool private _paused;
event Paused(address account);
event Unpaused(address account);
error EnforcedPause();
error ExpectedPause();
constructor() {
_paused = false;
}
modifier whenNotPaused() {
_requireNotPaused();
_;
}
modifier whenPaused() {
_requirePaused();
_;
}
function paused() public view virtual returns (bool) {
return _paused;
}
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Burnable.sol)
pragma solidity ^0.8.20;
import "./ERC20.sol";
import "./Context.sol";
abstract contract ERC20Burnable is Context, ERC20 {
function burn(uint256 value) public virtual {
_burn(_msgSender(), value);
}
function burnFrom(address account, uint256 value) public virtual {
_spendAllowance(account, _msgSender(), value);
_burn(account, value);
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.20;
import "./IERC20.sol";
import "./IERC20Metadata.sol";
import "./Context.sol";
import "./draft-IERC6093.sol";
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function name() public view virtual returns (string memory) {
return _name;
}
function symbol() public view virtual returns (string memory) {
return _symbol;
}
function decimals() public view virtual returns (uint8) {
return 18;
}
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
_totalSupply -= value;
}
} else {
unchecked {
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
interface IERC20Errors {
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
error ERC20InvalidSender(address sender);
error ERC20InvalidReceiver(address receiver);
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
error ERC20InvalidApprover(address approver);
error ERC20InvalidSpender(address spender);
}
interface IERC721Errors {
error ERC721InvalidOwner(address owner);
error ERC721NonexistentToken(uint256 tokenId);
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
error ERC721InvalidSender(address sender);
error ERC721InvalidReceiver(address receiver);
error ERC721InsufficientApproval(address operator, uint256 tokenId);
error ERC721InvalidApprover(address approver);
error ERC721InvalidOperator(address operator);
}
interface IERC1155Errors {
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
error ERC1155InvalidSender(address sender);
error ERC1155InvalidReceiver(address receiver);
error ERC1155MissingApprovalForAll(address operator, address owner);
error ERC1155InvalidApprover(address approver);
error ERC1155InvalidOperator(address operator);
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import "./IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
library Errors {
error InsufficientBalance(uint256 balance, uint256 needed);
error FailedCall();
error FailedDeployment();
error MissingPrecompile(address);
}