编译器
0.8.18+commit.87f61d96
文件 1 的 10:Clones.sol
pragma solidity ^0.8.0;
library Clones {
function clone(address implementation) internal returns (address instance) {
assembly {
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create(0, 0x09, 0x37)
}
require(instance != address(0), "ERC1167: create failed");
}
function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
assembly {
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create2(0, 0x09, 0x37, salt)
}
require(instance != address(0), "ERC1167: create2 failed");
}
function predictDeterministicAddress(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
assembly {
let ptr := mload(0x40)
mstore(add(ptr, 0x38), deployer)
mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
mstore(add(ptr, 0x14), implementation)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
mstore(add(ptr, 0x58), salt)
mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
predicted := keccak256(add(ptr, 0x43), 0x55)
}
}
function predictDeterministicAddress(
address implementation,
bytes32 salt
) internal view returns (address predicted) {
return predictDeterministicAddress(implementation, salt, address(this));
}
}
文件 2 的 10:ERC20.sol
pragma solidity ^0.8.18;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract ERC20 is IERC20 {
uint public totalSupply;
mapping(address => uint) public balanceOf;
mapping(address => mapping(address => uint)) public allowance;
string public name;
string public symbol;
uint8 public decimals;
function transfer(address recipient, uint amount) external returns (bool) {
balanceOf[msg.sender] -= amount;
balanceOf[recipient] += amount;
emit Transfer(msg.sender, recipient, amount);
return true;
}
function approve(address spender, uint amount) external returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transferFrom(
address sender,
address recipient,
uint amount
) external returns (bool) {
allowance[sender][msg.sender] -= amount;
balanceOf[sender] -= amount;
balanceOf[recipient] += amount;
emit Transfer(sender, recipient, amount);
return true;
}
function _mint(address account, uint256 amount) internal {
require(account != address(0), "ERC20: mint to the zero address");
totalSupply += amount;
unchecked {
balanceOf[account] += amount;
}
emit Transfer(address(0), account, amount);
}
}
文件 3 的 10:FERC20.sol
pragma solidity ^0.8.16;
import "./lib/ERC20.sol";
import "./interfaces/IFERC20.sol";
import "./interfaces/IFERC721.sol";
contract FERC20 is ERC20, IFERC20 {
address public immutable bridgeContract;
constructor() {
bridgeContract = msg.sender;
}
function initialize(address _ferc721Address) public {
require(msg.sender == bridgeContract, "only bridge factory can initialize");
name = string(abi.encodePacked(IFERC721(_ferc721Address).symbol(), " {ferc-20}"));
symbol = IFERC721(_ferc721Address).symbol();
decimals = 18;
}
function mint(address account, uint256 amount) public {
require(msg.sender == bridgeContract, "only bridge factory can mint");
_mint(account, amount);
}
}
文件 4 的 10:Ferc721Bridge.sol
pragma solidity ^0.8.16;
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/proxy/Clones.sol";
import "./interfaces/IFERC721.sol";
import "./interfaces/IFERC20.sol";
import "./FERC20.sol";
error NotCreatedByFactory();
error MintNotFinished();
error NotApprovedForAll();
error NotCreatedByBridge();
error AllowanceNotEnough();
error BalanceNotEnough();
error NotMultipleOfLimit();
error WithdrawAmountIsZero();
contract Ferc721Bridge {
address public immutable factoryContractAddress;
address public immutable tokenImplementation;
mapping(address => uint64[]) public nftTokenIds;
mapping(address => address) public ferc20Addresses;
mapping(address => address) public ferc721Addresses;
event DeployERC20(address operator, address indexed from, address indexed ferc721Address, address indexed ferc20Address, uint256 limit);
event ReceivedNFT(address operator, address indexed from, uint256 tokenId, address indexed ferc721Address, address indexed ferc20Address, uint256 limit);
event ReceivedToken(address indexed from, uint256 ferc20Amount, uint256 ferc721Amount, address indexed ferc20Address, address indexed ferc721Address, uint256 limit);
constructor(address _factoryContractAddress) {
factoryContractAddress = _factoryContractAddress;
tokenImplementation = address(new FERC20());
}
function withdraw(address ferc20Address, uint256 amount) public returns (bool) {
IFERC20 ferc20 = IFERC20(ferc20Address);
if(ferc20.bridgeContract() != address(this)) revert NotCreatedByBridge();
if(ferc20.allowance(msg.sender, address(this)) < amount) revert AllowanceNotEnough();
if(ferc20.balanceOf(msg.sender) < amount) revert BalanceNotEnough();
address ferc721Address = ferc721Addresses[ferc20Address];
IFERC721 ferc721 = IFERC721(ferc721Address);
uint limit = ferc721.limit();
if(amount / 1e18 % limit != 0) revert NotMultipleOfLimit();
uint256 amountOfFERC721 = amount / limit / 1e18;
if(amountOfFERC721 == 0) revert WithdrawAmountIsZero();
for(uint i; i < amountOfFERC721; i++) {
ferc721.safeTransferFrom(address(this), msg.sender, nftTokenIds[ferc721Address][nftTokenIds[ferc721Address].length - 1]);
nftTokenIds[ferc721Address].pop();
}
ferc20.transferFrom(msg.sender, address(this), amount);
ferc20.transfer(address(0x0), amount);
emit ReceivedToken(msg.sender, amount, amountOfFERC721, msg.sender, ferc721Address, limit);
return true;
}
function batchDeposit(address inscriptionAddress, uint[] calldata ids) public {
IFERC721 inscription = IFERC721(inscriptionAddress);
IFERC721.TokenData memory tokenData = inscription.tokenData();
if(inscription.factoryContract() != factoryContractAddress) revert NotCreatedByFactory();
if(tokenData.totalSupply < tokenData.max / tokenData.limit) revert MintNotFinished();
if(!inscription.isApprovedForAll(msg.sender, address(this))) revert NotApprovedForAll();
address ferc20Address = ferc20Addresses[inscriptionAddress];
if(ferc20Address == address(0x0)) {
ferc20Address = Clones.clone(tokenImplementation);
FERC20(ferc20Address).initialize(inscriptionAddress);
ferc721Addresses[ferc20Address] = inscriptionAddress;
ferc20Addresses[inscriptionAddress] = ferc20Address;
emit DeployERC20(msg.sender, msg.sender, inscriptionAddress, ferc20Address, tokenData.limit);
}
uint len = ids.length;
for(uint i; i < len; i++) {
inscription.transferFrom(msg.sender, address(this), ids[i]);
nftTokenIds[inscriptionAddress].push(uint64(ids[i]));
emit ReceivedNFT(msg.sender, msg.sender, ids[i], inscriptionAddress, ferc20Address, tokenData.limit);
}
FERC20(ferc20Address).mint(msg.sender, uint(tokenData.limit) * 1e18 * ids.length);
}
function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) public returns (bytes4) {
if(IFERC721(msg.sender).factoryContract() != factoryContractAddress) revert NotCreatedByFactory();
if(IFERC721(msg.sender).totalSupply() < IFERC721(msg.sender).max() / IFERC721(msg.sender).limit()) revert MintNotFinished();
address ferc20Address = ferc20Addresses[msg.sender];
if(ferc20Address == address(0x0)) {
ferc20Address = Clones.clone(tokenImplementation);
FERC20(ferc20Address).initialize(msg.sender);
ferc721Addresses[ferc20Address] = msg.sender;
ferc20Addresses[msg.sender] = ferc20Address;
emit DeployERC20(operator, from, msg.sender, ferc20Address, IFERC721(msg.sender).limit());
}
nftTokenIds[msg.sender].push(uint64(tokenId));
FERC20(ferc20Address).mint(from, IFERC721(msg.sender).limit() * 1e18);
emit ReceivedNFT(operator, from, tokenId, msg.sender, ferc20Address, IFERC721(msg.sender).limit());
return IERC721Receiver.onERC721Received.selector;
}
}
文件 5 的 10:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 6 的 10:IERC20.sol
pragma solidity ^0.8.0;
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 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
文件 7 的 10:IERC721.sol
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
interface IERC721 is IERC165 {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
function safeTransferFrom(address from, address to, uint256 tokenId) external;
function transferFrom(address from, address to, uint256 tokenId) external;
function approve(address to, uint256 tokenId) external;
function setApprovalForAll(address operator, bool approved) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
文件 8 的 10:IERC721Receiver.sol
pragma solidity ^0.8.0;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 9 的 10:IFERC20.sol
pragma solidity ^0.8.18;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IFERC20 is IERC20 {
function bridgeContract() external view returns(address);
function mint(address account, uint256 amount) external;
}
文件 10 的 10:IFERC721.sol
pragma solidity ^0.8.18;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
interface IFERC721 is IERC721 {
struct TokenData {
uint64 max;
uint64 totalSupply;
bool needFerc;
uint24 inscriptionId;
uint24 limit;
bytes9 tick;
}
function factoryContract() external view returns(address);
function swapContract() external view returns(address);
function wethContract() external view returns(address);
function name() external view returns(string memory);
function symbol() external view returns(string memory);
function totalSupply() external view returns(uint);
function max() external view returns(uint);
function limit() external view returns(uint);
function needFerc() external view returns(bool);
function inscriptionId() external view returns(uint);
function tokenData() external view returns(TokenData memory);
function lastMintTimestamp(address addr) external view returns (uint);
}
{
"compilationTarget": {
"contracts/Ferc721Bridge.sol": "Ferc721Bridge"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [],
"viaIR": true
}
[{"inputs":[{"internalType":"address","name":"_factoryContractAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AllowanceNotEnough","type":"error"},{"inputs":[],"name":"BalanceNotEnough","type":"error"},{"inputs":[],"name":"MintNotFinished","type":"error"},{"inputs":[],"name":"NotApprovedForAll","type":"error"},{"inputs":[],"name":"NotCreatedByBridge","type":"error"},{"inputs":[],"name":"NotCreatedByFactory","type":"error"},{"inputs":[],"name":"NotMultipleOfLimit","type":"error"},{"inputs":[],"name":"WithdrawAmountIsZero","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"ferc721Address","type":"address"},{"indexed":true,"internalType":"address","name":"ferc20Address","type":"address"},{"indexed":false,"internalType":"uint256","name":"limit","type":"uint256"}],"name":"DeployERC20","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"ferc721Address","type":"address"},{"indexed":true,"internalType":"address","name":"ferc20Address","type":"address"},{"indexed":false,"internalType":"uint256","name":"limit","type":"uint256"}],"name":"ReceivedNFT","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"ferc20Amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ferc721Amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"ferc20Address","type":"address"},{"indexed":true,"internalType":"address","name":"ferc721Address","type":"address"},{"indexed":false,"internalType":"uint256","name":"limit","type":"uint256"}],"name":"ReceivedToken","type":"event"},{"inputs":[{"internalType":"address","name":"inscriptionAddress","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"batchDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"factoryContractAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"ferc20Addresses","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"ferc721Addresses","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"nftTokenIds","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tokenImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"ferc20Address","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]