编译器
0.8.21+commit.d9974bed
文件 1 的 6:AccessController.sol
pragma solidity =0.8.21;
contract AccessController {
address public ceoAddress;
mapping (address => bool) public isWorker;
event CEOSet(
address newCEO
);
event WorkerAdded(
address newWorker
);
event WorkerRemoved(
address existingWorker
);
constructor() {
address creator = msg.sender;
ceoAddress = creator;
isWorker[creator] = true;
emit CEOSet(
creator
);
emit WorkerAdded(
creator
);
}
modifier onlyCEO() {
require(
msg.sender == ceoAddress,
"AccessControl: CEO_DENIED"
);
_;
}
modifier onlyWorker() {
require(
isWorker[msg.sender] == true,
"AccessControl: WORKER_DENIED"
);
_;
}
modifier nonZeroAddress(
address checkingAddress
) {
require(
checkingAddress != address(0x0),
"AccessControl: INVALID_ADDRESS"
);
_;
}
function setCEO(
address _newCEO
)
external
nonZeroAddress(_newCEO)
onlyCEO
{
ceoAddress = _newCEO;
emit CEOSet(
ceoAddress
);
}
function addWorker(
address _newWorker
)
external
onlyCEO
{
_addWorker(
_newWorker
);
}
function addWorkerBulk(
address[] calldata _newWorkers
)
external
onlyCEO
{
for (uint8 index = 0; index < _newWorkers.length; index++) {
_addWorker(_newWorkers[index]);
}
}
function _addWorker(
address _newWorker
)
internal
nonZeroAddress(_newWorker)
{
require(
isWorker[_newWorker] == false,
'AccessControl: worker already exist'
);
isWorker[_newWorker] = true;
emit WorkerAdded(
_newWorker
);
}
function removeWorker(
address _existingWorker
)
external
onlyCEO
{
_removeWorker(
_existingWorker
);
}
function removeWorkerBulk(
address[] calldata _workerArray
)
external
onlyCEO
{
for (uint8 index = 0; index < _workerArray.length; index++) {
_removeWorker(_workerArray[index]);
}
}
function _removeWorker(
address _existingWorker
)
internal
nonZeroAddress(_existingWorker)
{
require(
isWorker[_existingWorker] == true,
"AccessControl: worker not detected"
);
isWorker[_existingWorker] = false;
emit WorkerRemoved(
_existingWorker
);
}
}
文件 2 的 6:EIP712Base.sol
pragma solidity =0.8.21;
contract EIP712Base {
struct EIP712Domain {
string name;
string version;
uint256 chainId;
address verifyingContract;
}
bytes32 internal constant EIP712_DOMAIN_TYPEHASH = keccak256(
bytes(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
)
);
bytes32 internal domainSeperator;
constructor(
string memory _name,
string memory _version
) {
domainSeperator = keccak256(abi.encode(
EIP712_DOMAIN_TYPEHASH,
keccak256(bytes(_name)),
keccak256(bytes(_version)),
getChainID(),
address(this)
));
}
function getChainID()
internal
pure
returns (uint256 id)
{
assembly {
id := 1
}
}
function getDomainSeperator()
private
view
returns(bytes32)
{
return domainSeperator;
}
function toTypedMessageHash(
bytes32 _messageHash
)
internal
view
returns(bytes32)
{
return keccak256(
abi.encodePacked(
"\x19\x01",
getDomainSeperator(),
_messageHash
)
);
}
}
文件 3 的 6:EIP712MetaTransaction.sol
pragma solidity =0.8.21;
import "./EIP712Base.sol";
abstract contract EIP712MetaTransaction is EIP712Base {
bytes32 private constant META_TRANSACTION_TYPEHASH = keccak256(
bytes(
"MetaTransaction(uint256 nonce,address from,bytes functionSignature)"
)
);
event MetaTransactionExecuted(
address userAddress,
address payable relayerAddress,
bytes functionSignature
);
mapping(address => uint256) internal nonces;
struct MetaTransaction {
uint256 nonce;
address from;
bytes functionSignature;
}
function executeMetaTransaction(
address _userAddress,
bytes memory _functionSignature,
bytes32 _sigR,
bytes32 _sigS,
uint8 _sigV
)
public
payable
returns(bytes memory)
{
MetaTransaction memory metaTx = MetaTransaction(
{
nonce: nonces[_userAddress],
from: _userAddress,
functionSignature: _functionSignature
}
);
require(
verify(
_userAddress,
metaTx,
_sigR,
_sigS,
_sigV
), "EIP712MetaTransaction: INVALID_SIGNATURE"
);
nonces[_userAddress] =
nonces[_userAddress] + 1;
(bool success, bytes memory returnData) = address(this).call(
abi.encodePacked(
_functionSignature,
_userAddress
)
);
require(
success,
"EIP712MetaTransaction: INVALID_CALL"
);
emit MetaTransactionExecuted(
_userAddress,
payable(msg.sender),
_functionSignature
);
return returnData;
}
function hashMetaTransaction(
MetaTransaction memory _metaTx
)
internal
pure
returns (bytes32)
{
return keccak256(
abi.encode(
META_TRANSACTION_TYPEHASH,
_metaTx.nonce,
_metaTx.from,
keccak256(_metaTx.functionSignature)
)
);
}
function verify(
address _user,
MetaTransaction memory _metaTx,
bytes32 _sigR,
bytes32 _sigS,
uint8 _sigV
)
internal
view
returns (bool)
{
address signer = ecrecover(
toTypedMessageHash(
hashMetaTransaction(_metaTx)
),
_sigV,
_sigR,
_sigS
);
require(
signer != address(0x0),
"EIP712MetaTransaction: INVALID_SIGNATURE"
);
return signer == _user;
}
function msgSender()
internal
view
returns(address sender)
{
if (msg.sender == address(this)) {
bytes memory array = msg.data;
uint256 index = msg.data.length;
assembly {
sender := and(mload(add(array, index)), 0xffffffffffffffffffffffffffffffffffffffff)
}
} else {
sender = msg.sender;
}
return sender;
}
function getNonce(
address _user
)
external
view
returns(uint256 nonce)
{
nonce = nonces[_user];
}
}
文件 4 的 6:Interfaces.sol
pragma solidity =0.8.21;
interface ERC721 {
function ownerOf(
uint256 _tokenId
)
external
view
returns (address);
function transferFrom(
address _from,
address _to,
uint256 _tokenId
)
external;
}
interface ERC20 {
function approve(
address spender,
uint256 amount
)
external
returns (bool);
function burn(
uint256 _amount
)
external;
}
interface DGAccessories {
function issueTokens(
address[] calldata _beneficiaries,
uint256[] calldata _itemIds
)
external;
function encodeTokenId(
uint256 _itemId,
uint256 _issuedId
)
external
pure
returns (uint256 id);
function decodeTokenId(
uint256 _tokenId
)
external
pure
returns (
uint256 itemId,
uint256 issuedId
);
function items(
uint256 _id
)
external
view
returns (
string memory rarity,
uint256 maxSupply,
uint256 totalSupply,
uint256 price,
address beneficiary,
string memory metadata,
string memory contentHash
);
function itemsCount()
external
view
returns (uint256);
}
文件 5 的 6:TokenHub.sol
pragma solidity =0.8.21;
import "./Interfaces.sol";
import "./TransferHelper.sol";
import "./AccessController.sol";
import "./EIP712MetaTransaction.sol";
contract TokenHub is
AccessController,
TransferHelper,
EIP712MetaTransaction
{
uint256 public forwardFrame;
address public forwardAddress;
receive()
external
payable
{
emit ReceiveNative(
msg.value
);
}
mapping(address => bool) public supportedTokens;
mapping(address => uint256) public forwardFrames;
event Forward(
address indexed depositorAddress,
address indexed paymentTokenAddress,
uint256 indexed paymentTokenAmount
);
event ForwardNative(
address indexed depositorAddress,
uint256 indexed paymentTokenAmount
);
event ReceiveNative(
uint256 indexed nativeAmount
);
constructor(
address _defaultToken,
uint256 _defaultFrame,
address _defaultAddress
)
EIP712Base(
"TokenHub",
"v3.0"
)
{
forwardFrame = _defaultFrame;
forwardAddress = _defaultAddress;
supportedTokens[_defaultToken] = true;
}
function forwardNative()
external
payable
{
address _depositorAddress = msg.sender;
require(
canDepositAgain(_depositorAddress),
"TokenHub: DEPOSIT_COOLDOWN"
);
forwardFrames[_depositorAddress] = block.number;
payable(forwardAddress).transfer(
msg.value
);
emit ForwardNative(
msg.sender,
msg.value
);
}
function forwardTokens(
address _paymentToken,
uint256 _paymentTokenAmount
)
external
{
address _depositorAddress = msg.sender;
require(
canDepositAgain(_depositorAddress),
"TokenHub: DEPOSIT_COOLDOWN"
);
forwardFrames[_depositorAddress] = block.number;
require(
supportedTokens[_paymentToken],
"TokenHub: UNSUPPORTED_TOKEN"
);
safeTransferFrom(
_paymentToken,
_depositorAddress,
forwardAddress,
_paymentTokenAmount
);
emit Forward(
msg.sender,
_paymentToken,
_paymentTokenAmount
);
}
function forwardTokensByWorker(
address _depositorAddress,
address _paymentTokenAddress,
uint256 _paymentTokenAmount
)
external
onlyWorker
{
require(
canDepositAgain(_depositorAddress),
"TokenHub: DEPOSIT_COOLDOWN"
);
forwardFrames[_depositorAddress] = block.number;
require(
supportedTokens[_paymentTokenAddress],
"TokenHub: UNSUPPORTED_TOKEN"
);
safeTransferFrom(
_paymentTokenAddress,
_depositorAddress,
forwardAddress,
_paymentTokenAmount
);
emit Forward(
_depositorAddress,
_paymentTokenAddress,
_paymentTokenAmount
);
}
function changeForwardFrame(
uint256 _newDepositFrame
)
external
onlyCEO
{
forwardFrame = _newDepositFrame;
}
function changeForwardAddress(
address _newForwardAddress
)
external
onlyCEO
{
forwardAddress = _newForwardAddress;
}
function changeSupportedToken(
address _tokenAddress,
bool _supportStatus
)
external
onlyCEO
{
supportedTokens[_tokenAddress] = _supportStatus;
}
function canDepositAgain(
address _depositorAddress
)
public
view
returns (bool)
{
return block.number - forwardFrames[_depositorAddress] >= forwardFrame;
}
function rescueToken(
address _tokenAddress
)
external
onlyCEO
{
uint256 tokenBalance = safeBalance(
_tokenAddress,
address(this)
);
safeTransfer(
_tokenAddress,
msg.sender,
tokenBalance
);
}
function rescueNative()
external
onlyCEO
{
uint256 etherBalance = address(this).balance;
require(etherBalance > 0, "No Ether balance to rescue");
payable(msg.sender).transfer(etherBalance);
}
}
文件 6 的 6:TransferHelper.sol
pragma solidity =0.8.21;
contract TransferHelper {
bytes4 private constant TRANSFER = bytes4(
keccak256(
bytes(
"transfer(address,uint256)"
)
)
);
bytes4 private constant TRANSFER_FROM = bytes4(
keccak256(
bytes(
"transferFrom(address,address,uint256)"
)
)
);
bytes4 private constant BALANCE_OF = bytes4(
keccak256(
bytes(
"balanceOf(address)"
)
)
);
function safeTransfer(
address _token,
address _to,
uint256 _value
)
internal
{
(bool success, bytes memory data) = _token.call(
abi.encodeWithSelector(
TRANSFER,
_to,
_value
)
);
require(
success && (
data.length == 0 || abi.decode(
data, (bool)
)
),
"TransferHelper: TRANSFER_FAILED"
);
}
function safeTransferFrom(
address _token,
address _from,
address _to,
uint _value
)
internal
{
(bool success, bytes memory data) = _token.call(
abi.encodeWithSelector(
TRANSFER_FROM,
_from,
_to,
_value
)
);
require(
success && (
data.length == 0 || abi.decode(
data, (bool)
)
),
"TransferHelper: TRANSFER_FROM_FAILED"
);
}
function safeBalance(
address _token,
address _owner
)
internal
returns (uint256)
{
(bool success, bytes memory data) = _token.call(
abi.encodeWithSelector(
BALANCE_OF,
_owner
)
);
if (success == false) return 0;
return abi.decode(
data,
(uint256)
);
}
}
{
"compilationTarget": {
"TokenHub.sol": "TokenHub"
},
"evmVersion": "shanghai",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_defaultToken","type":"address"},{"internalType":"uint256","name":"_defaultFrame","type":"uint256"},{"internalType":"address","name":"_defaultAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newCEO","type":"address"}],"name":"CEOSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositorAddress","type":"address"},{"indexed":true,"internalType":"address","name":"paymentTokenAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"paymentTokenAmount","type":"uint256"}],"name":"Forward","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositorAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"paymentTokenAmount","type":"uint256"}],"name":"ForwardNative","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"userAddress","type":"address"},{"indexed":false,"internalType":"address payable","name":"relayerAddress","type":"address"},{"indexed":false,"internalType":"bytes","name":"functionSignature","type":"bytes"}],"name":"MetaTransactionExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nativeAmount","type":"uint256"}],"name":"ReceiveNative","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newWorker","type":"address"}],"name":"WorkerAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"existingWorker","type":"address"}],"name":"WorkerRemoved","type":"event"},{"inputs":[{"internalType":"address","name":"_newWorker","type":"address"}],"name":"addWorker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_newWorkers","type":"address[]"}],"name":"addWorkerBulk","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_depositorAddress","type":"address"}],"name":"canDepositAgain","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ceoAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newForwardAddress","type":"address"}],"name":"changeForwardAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newDepositFrame","type":"uint256"}],"name":"changeForwardFrame","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"bool","name":"_supportStatus","type":"bool"}],"name":"changeSupportedToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_userAddress","type":"address"},{"internalType":"bytes","name":"_functionSignature","type":"bytes"},{"internalType":"bytes32","name":"_sigR","type":"bytes32"},{"internalType":"bytes32","name":"_sigS","type":"bytes32"},{"internalType":"uint8","name":"_sigV","type":"uint8"}],"name":"executeMetaTransaction","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"forwardAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"forwardFrame","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"forwardFrames","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"forwardNative","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_paymentToken","type":"address"},{"internalType":"uint256","name":"_paymentTokenAmount","type":"uint256"}],"name":"forwardTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_depositorAddress","type":"address"},{"internalType":"address","name":"_paymentTokenAddress","type":"address"},{"internalType":"uint256","name":"_paymentTokenAmount","type":"uint256"}],"name":"forwardTokensByWorker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getNonce","outputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isWorker","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_existingWorker","type":"address"}],"name":"removeWorker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_workerArray","type":"address[]"}],"name":"removeWorkerBulk","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rescueNative","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"rescueToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newCEO","type":"address"}],"name":"setCEO","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"supportedTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]