编译器
0.8.18+commit.87f61d96
文件 1 的 20:AvatarsEscrow.sol
pragma solidity 0.8.18;
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "./modules/Ownable/Ownable.sol";
import "./modules/Upgradeable/Upgradeable.sol";
import "./TransferHelper.sol";
import "./IAvatarsEscrow.sol";
import "./IAvatarsRental.sol";
import "./IAvatars_ERC721.sol";
import "./AvatarsEscrowStorage.sol";
contract AvatarsEscrow is Context, ERC165, IAvatarsEscrow, Ownable, ReentrancyGuard, Upgradeable {
using SafeCast for uint256;
using ECDSA for bytes32;
using EnumerableSet for EnumerableSet.UintSet;
constructor(address _rewardTokenAddress, address _avatars) {
require(_rewardTokenAddress != address(0), "E0");
require(address(_avatars) != address(0), "E0");
AvatarsEscrowStorage.layout().rewardTokenAddress = _rewardTokenAddress;
AvatarsEscrowStorage.layout().Avatars_ERC721 = IAvatars_ERC721(_avatars);
}
function setRewards(uint32 _start, uint32 _end, uint96 _rate) external onlyOwner checkForUpgrade {
require(_start <= _end, "E1");
require(_rate > 0.03 ether && _rate < 30 ether, "E2");
require(AvatarsEscrowStorage.layout().rewardTokenAddress != address(0), "E3");
require(
block.timestamp.toUint32() < AvatarsEscrowStorage.layout().rewardsPeriod.start
|| block.timestamp.toUint32() > AvatarsEscrowStorage.layout().rewardsPeriod.end,
"E4"
);
AvatarsEscrowStorage.layout().rewardsPeriod.start = _start;
AvatarsEscrowStorage.layout().rewardsPeriod.end = _end;
AvatarsEscrowStorage.layout().rewardsPerWeight.lastUpdated = _start;
AvatarsEscrowStorage.layout().rewardsPerWeight.rate = _rate;
emit RewardsSet(_start, _end, _rate);
}
function setWeight(uint256[] calldata _tokenIds, uint256[] calldata _weights) external onlyOwner checkForUpgrade {
require(_tokenIds.length == _weights.length, "E6");
for (uint256 i = 0; i < _tokenIds.length; i++) {
uint256 tokenId = _tokenIds[i];
require(AvatarsEscrowStorage.layout().avatarInfo[tokenId].weight == 0, "E8");
AvatarsEscrowStorage.layout().avatarInfo[tokenId].weight = _weights[i].toUint16();
}
}
function setSigner(address _signer) external onlyOwner checkForUpgrade {
AvatarsEscrowStorage.layout().signer = _signer;
}
function setRentalContract(IAvatarsRental _rental) external onlyOwner checkForUpgrade {
require(_rental.supportsInterface(type(IAvatarsRental).interfaceId), "E0");
AvatarsEscrowStorage.layout().AvatarsRental = _rental;
}
function setRewardTokenAddress(address _rewardTokenAddress) external onlyOwner checkForUpgrade {
AvatarsEscrowStorage.layout().rewardTokenAddress = _rewardTokenAddress;
}
function setAvatarsERC721(IAvatars_ERC721 _avatars) external onlyOwner checkForUpgrade {
AvatarsEscrowStorage.layout().Avatars_ERC721 = _avatars;
}
function setAvatarsRental(IAvatarsRental _rental) external onlyOwner checkForUpgrade {
AvatarsEscrowStorage.layout().AvatarsRental = _rental;
}
function initialStake(
uint256[] calldata _tokenIds,
uint256[] calldata _weights,
address _stakeTo,
uint16 _deposit,
uint16 _rentalPerDay,
uint16 _minRentDays,
uint32 _rentableUntil,
uint32 _maxTimestamp,
bytes calldata _signature
) external nonReentrant checkForUpgrade {
require(uint256(_deposit) <= uint256(_rentalPerDay) * (uint256(_minRentDays) + 1), "ER");
require(_tokenIds.length == _weights.length, "E6");
require(block.timestamp <= _maxTimestamp, "EX");
require(
_verifySignerSignature(
keccak256(abi.encode(_tokenIds, _weights, _msgSender(), _maxTimestamp, address(this))), _signature
),
"E7"
);
_ensureEOAorERC721Receiver(_stakeTo);
require(_stakeTo != address(this), "ES");
uint256 totalWeights = 0;
for (uint256 i = 0; i < _tokenIds.length; i++) {
{
uint256 tokenId = _tokenIds[i];
uint256 _weight = AvatarsEscrowStorage.layout().avatarInfo[tokenId].weight;
require(_weight == 0 || _weight == _weights[i], "E8");
require(AvatarsEscrowStorage.layout().Avatars_ERC721.ownerOf(tokenId) == _msgSender(), "E9");
AvatarsEscrowStorage.layout().Avatars_ERC721.safeTransferFrom(_msgSender(), address(this), tokenId);
emit AvatarStaked(tokenId, _stakeTo);
}
AvatarsEscrowStorage.layout().avatarInfo[_tokenIds[i]] =
AvatarInfo(_weights[i].toUint16(), _stakeTo, _deposit, _rentalPerDay, _minRentDays, _rentableUntil);
AvatarsEscrowStorage.layout().userStakes[_stakeTo].add(_tokenIds[i]);
totalWeights += _weights[i];
}
_updateRewardsPerWeight(totalWeights.toUint32(), true);
_updateUserRewards(_stakeTo, totalWeights.toUint32(), true);
}
function stake(
uint256[] calldata _tokenIds,
address _stakeTo,
uint16 _deposit,
uint16 _rentalPerDay,
uint16 _minRentDays,
uint32 _rentableUntil
) external nonReentrant checkForUpgrade {
require(uint256(_deposit) <= uint256(_rentalPerDay) * (uint256(_minRentDays) + 1), "ER");
_ensureEOAorERC721Receiver(_stakeTo);
require(_stakeTo != address(this), "ES");
uint256 totalWeights = 0;
for (uint256 i = 0; i < _tokenIds.length; i++) {
uint256 tokenId = _tokenIds[i];
uint16 _weight = AvatarsEscrowStorage.layout().avatarInfo[tokenId].weight;
require(_weight != 0, "EA");
require(AvatarsEscrowStorage.layout().Avatars_ERC721.ownerOf(tokenId) == _msgSender(), "E9");
AvatarsEscrowStorage.layout().Avatars_ERC721.safeTransferFrom(_msgSender(), address(this), tokenId);
totalWeights += _weight;
AvatarsEscrowStorage.layout().avatarInfo[tokenId] =
AvatarInfo(_weight, _stakeTo, _deposit, _rentalPerDay, _minRentDays, _rentableUntil);
AvatarsEscrowStorage.layout().userStakes[_stakeTo].add(tokenId);
emit AvatarStaked(tokenId, _stakeTo);
}
_updateRewardsPerWeight(totalWeights.toUint32(), true);
_updateUserRewards(_stakeTo, totalWeights.toUint32(), true);
}
function updateRent(
uint256[] calldata _tokenIds,
uint16 _deposit,
uint16 _rentalPerDay,
uint16 _minRentDays,
uint32 _rentableUntil
) external checkForUpgrade {
require(uint256(_deposit) <= uint256(_rentalPerDay) * (uint256(_minRentDays) + 1), "ER");
for (uint256 i = 0; i < _tokenIds.length; i++) {
uint256 tokenId = _tokenIds[i];
AvatarInfo storage avatarInfo_ = AvatarsEscrowStorage.layout().avatarInfo[tokenId];
require(avatarInfo_.weight != 0, "EA");
require(
AvatarsEscrowStorage.layout().Avatars_ERC721.ownerOf(tokenId) == address(this)
&& avatarInfo_.owner == _msgSender(),
"E9"
);
require(!AvatarsEscrowStorage.layout().AvatarsRental.isRentActive(tokenId), "EB");
avatarInfo_.deposit = _deposit;
avatarInfo_.rentalPerDay = _rentalPerDay;
avatarInfo_.minRentDays = _minRentDays;
avatarInfo_.rentableUntil = _rentableUntil;
}
}
function extendRentalPeriod(uint256 _tokenId, uint32 _rentableUntil) external checkForUpgrade {
AvatarInfo storage avatarInfo_ = AvatarsEscrowStorage.layout().avatarInfo[_tokenId];
require(avatarInfo_.weight != 0, "EA");
require(
AvatarsEscrowStorage.layout().Avatars_ERC721.ownerOf(_tokenId) == address(this)
&& avatarInfo_.owner == _msgSender(),
"E9"
);
avatarInfo_.rentableUntil = _rentableUntil;
}
function unstake(uint256[] calldata _tokenIds, address _unstakeTo) external nonReentrant checkForUpgrade {
_ensureEOAorERC721Receiver(_unstakeTo);
require(_unstakeTo != address(this), "ES");
uint256 totalWeights = 0;
for (uint256 i = 0; i < _tokenIds.length; i++) {
uint256 tokenId = _tokenIds[i];
require(AvatarsEscrowStorage.layout().avatarInfo[tokenId].owner == _msgSender(), "E9");
require(!AvatarsEscrowStorage.layout().AvatarsRental.isRentActive(tokenId), "EB");
AvatarsEscrowStorage.layout().Avatars_ERC721.safeTransferFrom(address(this), _unstakeTo, tokenId);
uint16 _weight = AvatarsEscrowStorage.layout().avatarInfo[tokenId].weight;
totalWeights += _weight;
AvatarsEscrowStorage.layout().avatarInfo[tokenId] = AvatarInfo(_weight, address(0), 0, 0, 0, 0);
AvatarsEscrowStorage.layout().userStakes[_msgSender()].remove(tokenId);
emit AvatarUnstaked(tokenId, _msgSender());
}
_updateRewardsPerWeight(totalWeights.toUint32(), false);
_updateUserRewards(_msgSender(), totalWeights.toUint32(), false);
}
function updateAvatar(
uint256 _tokenId,
string calldata _ipfsHash,
uint256 _nonce,
bytes calldata _updateApproverSignature
) external checkForUpgrade {
require(
(
AvatarsEscrowStorage.layout().avatarInfo[_tokenId].owner == _msgSender()
&& !AvatarsEscrowStorage.layout().AvatarsRental.isRentActive(_tokenId)
)
|| (
AvatarsEscrowStorage.layout().avatarInfo[_tokenId].owner != address(0)
&& AvatarsEscrowStorage.layout().AvatarsRental.getTenant(_tokenId) == _msgSender()
),
"EH"
);
AvatarsEscrowStorage.layout().Avatars_ERC721.updateAvatar(_tokenId, _ipfsHash, _nonce, _updateApproverSignature);
}
function claim(address _to) external nonReentrant checkForUpgrade {
_updateRewardsPerWeight(0, false);
uint256 rewardAmount = _updateUserRewards(_msgSender(), 0, false);
AvatarsEscrowStorage.layout().rewards[_msgSender()].accumulated = 0;
TransferHelper.safeTransfer(AvatarsEscrowStorage.layout().rewardTokenAddress, _to, rewardAmount);
emit RewardClaimed(_to, rewardAmount);
}
function getAvatarInfo(uint256 _tokenId) external view override returns (AvatarInfo memory) {
return AvatarsEscrowStorage.layout().avatarInfo[_tokenId];
}
function checkUserRewards(address _user) external view returns (uint256) {
RewardsPerWeight memory rewardsPerWeight_ = AvatarsEscrowStorage.layout().rewardsPerWeight;
UserRewards memory userRewards_ = AvatarsEscrowStorage.layout().rewards[_user];
uint32 end = min(block.timestamp.toUint32(), AvatarsEscrowStorage.layout().rewardsPeriod.end);
uint256 unaccountedTime = end - rewardsPerWeight_.lastUpdated;
if (unaccountedTime != 0) {
if (rewardsPerWeight_.totalWeight != 0) {
rewardsPerWeight_.accumulated = (
rewardsPerWeight_.accumulated
+ unaccountedTime * rewardsPerWeight_.rate / rewardsPerWeight_.totalWeight
).toUint96();
}
}
return userRewards_.accumulated
+ userRewards_.stakedWeight * (rewardsPerWeight_.accumulated - userRewards_.checkpoint);
}
function rewardsPeriod() external view returns (IAvatarsEscrow.RewardsPeriod memory) {
return AvatarsEscrowStorage.layout().rewardsPeriod;
}
function rewardsPerWeight() external view returns (IAvatarsEscrow.RewardsPerWeight memory) {
return AvatarsEscrowStorage.layout().rewardsPerWeight;
}
function rewards(address user) external view returns (UserRewards memory) {
return AvatarsEscrowStorage.layout().rewards[user];
}
function userStakedAvatars(address _user) external view returns (uint256[] memory) {
uint256 length = AvatarsEscrowStorage.layout().userStakes[_user].length();
uint256[] memory stakedAvatars = new uint256[](length);
for (uint256 i = 0; i < length; i++) {
stakedAvatars[i] = AvatarsEscrowStorage.layout().userStakes[_user].at(i);
}
return stakedAvatars;
}
function supportsInterface(bytes4 _interfaceId) public view override(ERC165, IERC165) returns (bool) {
return _interfaceId == type(IAvatarsEscrow).interfaceId || super.supportsInterface(_interfaceId);
}
function _verifySignerSignature(bytes32 _hash, bytes calldata _signature) internal view returns (bool) {
return _hash.toEthSignedMessageHash().recover(_signature) == AvatarsEscrowStorage.layout().signer;
}
function min(uint32 _x, uint32 _y) internal pure returns (uint32 z) {
z = (_x < _y) ? _x : _y;
}
function _updateRewardsPerWeight(uint32 _weight, bool _increase) internal checkForUpgrade {
RewardsPerWeight memory rewardsPerWeight_ = AvatarsEscrowStorage.layout().rewardsPerWeight;
RewardsPeriod memory rewardsPeriod_ = AvatarsEscrowStorage.layout().rewardsPeriod;
if (block.timestamp.toUint32() >= rewardsPeriod_.start) {
uint32 end = min(block.timestamp.toUint32(), rewardsPeriod_.end);
uint256 unaccountedTime = end - rewardsPerWeight_.lastUpdated;
if (unaccountedTime != 0) {
if (rewardsPerWeight_.totalWeight != 0) {
rewardsPerWeight_.accumulated = (
rewardsPerWeight_.accumulated
+ unaccountedTime * rewardsPerWeight_.rate / rewardsPerWeight_.totalWeight
).toUint96();
}
rewardsPerWeight_.lastUpdated = end;
}
}
if (_increase) {
rewardsPerWeight_.totalWeight += _weight;
} else {
rewardsPerWeight_.totalWeight -= _weight;
}
AvatarsEscrowStorage.layout().rewardsPerWeight = rewardsPerWeight_;
emit RewardsPerWeightUpdated(rewardsPerWeight_.accumulated);
}
function _updateUserRewards(
address _user,
uint32 _weight,
bool _increase
) internal checkForUpgrade returns (uint96) {
UserRewards memory userRewards_ = AvatarsEscrowStorage.layout().rewards[_user];
RewardsPerWeight memory rewardsPerWeight_ = AvatarsEscrowStorage.layout().rewardsPerWeight;
userRewards_.accumulated = userRewards_.accumulated
+ userRewards_.stakedWeight * (rewardsPerWeight_.accumulated - userRewards_.checkpoint);
userRewards_.checkpoint = rewardsPerWeight_.accumulated;
if (_weight != 0) {
if (_increase) {
userRewards_.stakedWeight += _weight;
} else {
userRewards_.stakedWeight -= _weight;
}
emit WeightUpdated(_user, _increase, _weight, block.timestamp);
}
AvatarsEscrowStorage.layout().rewards[_user] = userRewards_;
emit UserRewardsUpdated(_user, userRewards_.accumulated, userRewards_.checkpoint);
return userRewards_.accumulated;
}
function _ensureEOAorERC721Receiver(address _to) internal checkForUpgrade {
uint32 size;
assembly {
size := extcodesize(_to)
}
if (size > 0) {
try IERC721Receiver(_to).onERC721Received(address(this), address(this), 0, "") returns (bytes4 retval) {
require(retval == IERC721Receiver.onERC721Received.selector, "ET");
} catch (bytes memory) {
revert("ET");
}
}
}
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external view override returns (bytes4) {
from;
tokenId;
data;
if (operator == address(this)) {
return this.onERC721Received.selector;
} else {
return 0x00000000;
}
}
}
文件 2 的 20:AvatarsEscrowStorage.sol
pragma solidity 0.8.18;
import "./IAvatars_ERC721.sol";
import "./IAvatarsEscrow.sol";
import "./IAvatarsRental.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
library AvatarsEscrowStorage {
bytes32 private constant STORAGE_SLOT = keccak256("slot.avatars.escrow");
struct Layout {
address rewardTokenAddress;
IAvatars_ERC721 Avatars_ERC721;
IAvatarsRental AvatarsRental;
IAvatarsEscrow.AvatarInfo[15000] avatarInfo;
IAvatarsEscrow.RewardsPeriod rewardsPeriod;
IAvatarsEscrow.RewardsPerWeight rewardsPerWeight;
mapping(address => IAvatarsEscrow.UserRewards) rewards;
mapping(address => EnumerableSet.UintSet) userStakes;
address signer;
}
function layout() internal pure returns (Layout storage _layout) {
bytes32 slot = STORAGE_SLOT;
assembly {
_layout.slot := slot
}
}
}
文件 3 的 20:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 4 的 20:ECDSA.sol
pragma solidity ^0.8.0;
import "../Strings.sol";
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return;
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
} else if (error == RecoverError.InvalidSignatureV) {
revert("ECDSA: invalid signature 'v' value");
}
}
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else if (signature.length == 64) {
bytes32 r;
bytes32 vs;
assembly {
r := mload(add(signature, 0x20))
vs := mload(add(signature, 0x40))
}
return tryRecover(hash, r, vs);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
function recover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError) {
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
if (v != 27 && v != 28) {
return (address(0), RecoverError.InvalidSignatureV);
}
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
function recover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}
文件 5 的 20:ERC165.sol
pragma solidity ^0.8.0;
import "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 6 的 20:EnumerableSet.sol
pragma solidity ^0.8.0;
library EnumerableSet {
struct Set {
bytes32[] _values;
mapping(bytes32 => uint256) _indexes;
}
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
function _remove(Set storage set, bytes32 value) private returns (bool) {
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastvalue = set._values[lastIndex];
set._values[toDeleteIndex] = lastvalue;
set._indexes[lastvalue] = valueIndex;
}
set._values.pop();
delete set._indexes[value];
return true;
} else {
return false;
}
}
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
struct Bytes32Set {
Set _inner;
}
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
return _values(set._inner);
}
struct AddressSet {
Set _inner;
}
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly {
result := store
}
return result;
}
struct UintSet {
Set _inner;
}
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly {
result := store
}
return result;
}
}
文件 7 的 20:IAvatarsEscrow.sol
pragma solidity 0.8.18;
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
interface IAvatarsEscrow is IERC165, IERC721Receiver {
event WeightUpdated(address indexed user, bool increase, uint weight, uint timestamp);
event AvatarStaked(uint256 indexed tokenId, address indexed user);
event AvatarUnstaked(uint256 indexed tokenId, address indexed user);
event RewardsSet(uint32 start, uint32 end, uint256 rate);
event RewardsUpdated(uint32 start, uint32 end, uint256 rate);
event RewardsPerWeightUpdated(uint256 accumulated);
event UserRewardsUpdated(address user, uint256 userRewards, uint256 paidRewardPerWeight);
event RewardClaimed(address receiver, uint256 claimed);
struct AvatarInfo {
uint16 weight;
address owner;
uint16 deposit;
uint16 rentalPerDay;
uint16 minRentDays;
uint32 rentableUntil;
}
struct RewardsPeriod {
uint32 start;
uint32 end;
}
struct RewardsPerWeight {
uint32 totalWeight;
uint96 accumulated;
uint32 lastUpdated;
uint96 rate;
}
struct UserRewards {
uint32 stakedWeight;
uint96 accumulated;
uint96 checkpoint;
}
function getAvatarInfo(uint _tokenId) external view returns(AvatarInfo memory);
function checkUserRewards(address _user) external view returns(uint);
function rewardsPeriod() external view returns (IAvatarsEscrow.RewardsPeriod memory);
function rewardsPerWeight() external view returns(RewardsPerWeight memory);
function rewards(address _user) external view returns (UserRewards memory);
function userStakedAvatars(address _user) external view returns (uint256[] memory);
function onERC721Received(address, address, uint256, bytes calldata) external view override returns(bytes4);
function initialStake(
uint[] calldata _tokenIds,
uint[] calldata _weights,
address _stakeTo,
uint16 _deposit,
uint16 _rentalPerDay,
uint16 _minRentDays,
uint32 _rentableUntil,
uint32 _maxTimestamp,
bytes calldata _signature
) external;
function stake(
uint[] calldata _tokenIds,
address _stakeTo,
uint16 _deposit,
uint16 _rentalPerDay,
uint16 _minRentDays,
uint32 _rentableUntil
) external;
function updateRent(
uint[] calldata _tokenIds,
uint16 _deposit,
uint16 _rentalPerDay,
uint16 _minRentDays,
uint32 _rentableUntil
) external;
function extendRentalPeriod(uint _tokenId, uint32 _rentableUntil) external;
function unstake(uint[] calldata _tokenIds, address unstakeTo) external;
function claim(address _to) external;
}
文件 8 的 20:IAvatarsRental.sol
pragma solidity 0.8.18;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
interface IAvatarsRental is IERC165 {
event AvatarRented(uint256 indexed tokenId, address indexed tenant, uint256 payment);
event RentalPaid(uint256 indexed tokenId, address indexed tenant, uint256 payment);
event RentalTerminated(uint256 indexed tokenId, address indexed tenant);
struct AvatarRentInfo {
address tenant;
uint32 rentStartTime;
uint32 rentalPaid;
uint32 paymentAlert;
}
function isRentActive(uint _tokenId) external view returns(bool);
function getTenant(uint _tokenId) external view returns(address);
function rentedByIndex(address _tenant, uint _index) external view returns(uint);
function isRentable(uint _tokenId) external view returns(bool state);
function rentalPaidUntil(uint _tokenId) external view returns(uint paidUntil);
function rentAvatar(uint _tokenId, uint32 _paymentAlert, uint32 initialPayment) external;
function payRent(uint _tokenId, uint32 _payment) external;
function terminateRental(uint _tokenId) external;
}
文件 9 的 20:IAvatars_ERC721.sol
pragma solidity 0.8.18;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
interface IAvatars_ERC721 is IERC721 {
function updateAvatar(
uint _tokenId,
string calldata _ipfsHash,
uint256 _nonce,
bytes calldata _updateApproverSignature
) external;
}
文件 10 的 20:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 11 的 20: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
) external;
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
function approve(address to, uint256 tokenId) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function setApprovalForAll(address operator, bool _approved) external;
function isApprovedForAll(address owner, address operator) external view returns (bool);
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
}
文件 12 的 20:IERC721Receiver.sol
pragma solidity ^0.8.0;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 13 的 20:Ownable.sol
pragma solidity ^0.8.18;
import "@openzeppelin/contracts/utils/Context.sol";
import "./OwnableStorage.sol";
abstract contract Ownable is Context {
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return OwnableStorage.layout().owner;
}
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = OwnableStorage.layout().owner;
OwnableStorage.layout().owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 14 的 20:OwnableStorage.sol
pragma solidity 0.8.18;
library OwnableStorage {
bytes32 private constant STORAGE_SLOT = keccak256("gg.topia.worlds.Ownable");
struct Layout {
address owner;
}
function layout() internal pure returns (Layout storage _layout) {
bytes32 slot = STORAGE_SLOT;
assembly {
_layout.slot := slot
}
}
}
文件 15 的 20:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 16 的 20:SafeCast.sol
pragma solidity ^0.8.0;
library SafeCast {
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
function toInt128(int256 value) internal pure returns (int128) {
require(value >= type(int128).min && value <= type(int128).max, "SafeCast: value doesn't fit in 128 bits");
return int128(value);
}
function toInt64(int256 value) internal pure returns (int64) {
require(value >= type(int64).min && value <= type(int64).max, "SafeCast: value doesn't fit in 64 bits");
return int64(value);
}
function toInt32(int256 value) internal pure returns (int32) {
require(value >= type(int32).min && value <= type(int32).max, "SafeCast: value doesn't fit in 32 bits");
return int32(value);
}
function toInt16(int256 value) internal pure returns (int16) {
require(value >= type(int16).min && value <= type(int16).max, "SafeCast: value doesn't fit in 16 bits");
return int16(value);
}
function toInt8(int256 value) internal pure returns (int8) {
require(value >= type(int8).min && value <= type(int8).max, "SafeCast: value doesn't fit in 8 bits");
return int8(value);
}
function toInt256(uint256 value) internal pure returns (int256) {
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}
文件 17 的 20:Strings.sol
pragma solidity ^0.8.0;
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
function toString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}
文件 18 的 20:TransferHelper.sol
pragma solidity 0.8.18;
library TransferHelper {
function safeTransfer(address _token, address _to, uint _value) internal {
(bool success, bytes memory data) = _token.call(abi.encodeWithSelector(0xa9059cbb, _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(0x23b872dd, _from, _to, _value));
require(success && (data.length == 0 || abi.decode(data, (bool))), "TransferHelper: TRANSFER_FROM_FAILED");
}
}
文件 19 的 20:Upgradeable.sol
pragma solidity 0.8.18;
import "../Ownable/Ownable.sol";
import "./UpgradeableStorage.sol";
contract Upgradeable is Ownable {
function setUpgrade(bytes4 _sig, address _target) external onlyOwner {
UpgradeableStorage.layout().upgrades[_sig] = _target;
}
function hasUpgrade(bytes4 _sig) private view returns (bool) {
return UpgradeableStorage.layout().upgrades[_sig] != address(0);
}
function executeUpgrade(bytes4 _sig) private returns (bool) {
address target = UpgradeableStorage.layout().upgrades[_sig];
assembly {
calldatacopy(0, 0, calldatasize())
let result := delegatecall(gas(), target, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 {revert(0, returndatasize())}
default {return (0, returndatasize())}
}
}
modifier checkForUpgrade() {
if (hasUpgrade(msg.sig)) {
executeUpgrade(msg.sig);
} else {
_;
}
}
fallback() external payable {
require(hasUpgrade(msg.sig));
executeUpgrade(msg.sig);
}
receive() external payable {}
}
文件 20 的 20:UpgradeableStorage.sol
pragma solidity 0.8.18;
library UpgradeableStorage {
bytes32 private constant STORAGE_SLOT = keccak256("gg.topia.worlds.Upgradeable");
struct Layout {
mapping(bytes4 => address) upgrades;
}
function layout() internal pure returns (Layout storage _layout) {
bytes32 slot = STORAGE_SLOT;
assembly {
_layout.slot := slot
}
}
}
{
"compilationTarget": {
"contracts/AvatarsEscrow.sol": "AvatarsEscrow"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 800
},
"remappings": [
":@create3-factory/=lib/create3-factory/src/",
":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
":ds-test/=lib/forge-std/lib/ds-test/src/",
":forge-std/=lib/forge-std/src/",
":hardhat/=node_modules/hardhat/",
":openzeppelin-contracts/=lib/openzeppelin-contracts/",
":src/=src/"
]
}
[{"inputs":[{"internalType":"address","name":"_rewardTokenAddress","type":"address"},{"internalType":"address","name":"_avatars","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"AvatarStaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"AvatarUnstaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"claimed","type":"uint256"}],"name":"RewardClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"accumulated","type":"uint256"}],"name":"RewardsPerWeightUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"start","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"end","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"}],"name":"RewardsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"start","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"end","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"}],"name":"RewardsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"userRewards","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"paidRewardPerWeight","type":"uint256"}],"name":"UserRewardsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"bool","name":"increase","type":"bool"},{"indexed":false,"internalType":"uint256","name":"weight","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WeightUpdated","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"checkUserRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint32","name":"_rentableUntil","type":"uint32"}],"name":"extendRentalPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getAvatarInfo","outputs":[{"components":[{"internalType":"uint16","name":"weight","type":"uint16"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint16","name":"deposit","type":"uint16"},{"internalType":"uint16","name":"rentalPerDay","type":"uint16"},{"internalType":"uint16","name":"minRentDays","type":"uint16"},{"internalType":"uint32","name":"rentableUntil","type":"uint32"}],"internalType":"struct IAvatarsEscrow.AvatarInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_weights","type":"uint256[]"},{"internalType":"address","name":"_stakeTo","type":"address"},{"internalType":"uint16","name":"_deposit","type":"uint16"},{"internalType":"uint16","name":"_rentalPerDay","type":"uint16"},{"internalType":"uint16","name":"_minRentDays","type":"uint16"},{"internalType":"uint32","name":"_rentableUntil","type":"uint32"},{"internalType":"uint32","name":"_maxTimestamp","type":"uint32"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"initialStake","outputs":[],"stateMutability":"nonpayable","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":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rewards","outputs":[{"components":[{"internalType":"uint32","name":"stakedWeight","type":"uint32"},{"internalType":"uint96","name":"accumulated","type":"uint96"},{"internalType":"uint96","name":"checkpoint","type":"uint96"}],"internalType":"struct IAvatarsEscrow.UserRewards","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsPerWeight","outputs":[{"components":[{"internalType":"uint32","name":"totalWeight","type":"uint32"},{"internalType":"uint96","name":"accumulated","type":"uint96"},{"internalType":"uint32","name":"lastUpdated","type":"uint32"},{"internalType":"uint96","name":"rate","type":"uint96"}],"internalType":"struct IAvatarsEscrow.RewardsPerWeight","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsPeriod","outputs":[{"components":[{"internalType":"uint32","name":"start","type":"uint32"},{"internalType":"uint32","name":"end","type":"uint32"}],"internalType":"struct IAvatarsEscrow.RewardsPeriod","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IAvatars_ERC721","name":"_avatars","type":"address"}],"name":"setAvatarsERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IAvatarsRental","name":"_rental","type":"address"}],"name":"setAvatarsRental","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IAvatarsRental","name":"_rental","type":"address"}],"name":"setRentalContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardTokenAddress","type":"address"}],"name":"setRewardTokenAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_start","type":"uint32"},{"internalType":"uint32","name":"_end","type":"uint32"},{"internalType":"uint96","name":"_rate","type":"uint96"}],"name":"setRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"}],"name":"setSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_sig","type":"bytes4"},{"internalType":"address","name":"_target","type":"address"}],"name":"setUpgrade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_weights","type":"uint256[]"}],"name":"setWeight","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"internalType":"address","name":"_stakeTo","type":"address"},{"internalType":"uint16","name":"_deposit","type":"uint16"},{"internalType":"uint16","name":"_rentalPerDay","type":"uint16"},{"internalType":"uint16","name":"_minRentDays","type":"uint16"},{"internalType":"uint32","name":"_rentableUntil","type":"uint32"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"internalType":"address","name":"_unstakeTo","type":"address"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"string","name":"_ipfsHash","type":"string"},{"internalType":"uint256","name":"_nonce","type":"uint256"},{"internalType":"bytes","name":"_updateApproverSignature","type":"bytes"}],"name":"updateAvatar","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"internalType":"uint16","name":"_deposit","type":"uint16"},{"internalType":"uint16","name":"_rentalPerDay","type":"uint16"},{"internalType":"uint16","name":"_minRentDays","type":"uint16"},{"internalType":"uint32","name":"_rentableUntil","type":"uint32"}],"name":"updateRent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"userStakedAvatars","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]