编译器
0.8.21+commit.d9974bed
文件 1 的 16:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
文件 2 的 16:BatchWorkerV2.sol
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../interfaces/ITrustedWrapperV2.sol";
import "@envelop-protocol-v1/interfaces/IERC20Extended.sol";
import "@envelop-subscription/contracts/ServiceProviderOwnable.sol";
pragma solidity 0.8.21;
contract BatchWorkerV2 is ServiceProviderOwnable {
using SafeERC20 for IERC20Extended;
ITrustedWrapperV2 public trustedWrapper;
constructor (address _subscrRegistry)
ServiceProviderOwnable(_subscrRegistry)
{}
function wrapBatch(
ETypes.INData[] calldata _inDataS,
ETypes.AssetItem[] calldata _collateralERC20,
address[] memory _receivers
) public payable {
_checkAndFixSubscription(msg.sender);
require(
_inDataS.length == _receivers.length,
"Array params must have equal length"
);
for (uint256 i = 0; i < _inDataS.length; i++) {
trustedWrapper.wrapUnsafe{value: (msg.value / _receivers.length)}(
_inDataS[i],
_collateralERC20,
_receivers[i]
);
if (_inDataS[i].inAsset.asset.assetType == ETypes.AssetType.ERC721 ||
_inDataS[i].inAsset.asset.assetType == ETypes.AssetType.ERC1155 )
{
trustedWrapper.transferIn(
_inDataS[i].inAsset,
msg.sender
);
}
}
ETypes.AssetItem memory totalERC20Collateral;
uint256 totalNativeAmount;
for (uint256 i = 0; i < _collateralERC20.length; i ++) {
if (_collateralERC20[i].asset.assetType == ETypes.AssetType.ERC20) {
totalERC20Collateral.asset.assetType = _collateralERC20[i].asset.assetType;
totalERC20Collateral.asset.contractAddress = _collateralERC20[i].asset.contractAddress;
totalERC20Collateral.tokenId = _collateralERC20[i].tokenId;
totalERC20Collateral.amount = _collateralERC20[i].amount * _receivers.length;
uint256 amountTransfered = trustedWrapper.transferIn(
totalERC20Collateral,
msg.sender
);
require(amountTransfered == totalERC20Collateral.amount, "Check transfer ERC20 amount fail");
}
if (_collateralERC20[i].asset.assetType == ETypes.AssetType.NATIVE) {
totalNativeAmount += _collateralERC20[i].amount * _receivers.length;
}
}
require(totalNativeAmount == msg.value, "Native amount check failed");
}
function addCollateralBatch(
address[] calldata _wNFTAddress,
uint256[] calldata _wNFTTokenId,
ETypes.AssetItem[] calldata _collateralERC20
) public payable {
_checkAndFixSubscription(msg.sender);
require(_wNFTAddress.length == _wNFTTokenId.length, "Array params must have equal length");
for (uint256 i = 0; i < _collateralERC20.length; i ++) {
if (_collateralERC20[i].asset.assetType == ETypes.AssetType.ERC20) {
IERC20Extended(_collateralERC20[i].asset.contractAddress).safeTransferFrom(
msg.sender,
address(this),
_collateralERC20[i].amount * _wNFTAddress.length
);
IERC20Extended(_collateralERC20[i].asset.contractAddress).safeIncreaseAllowance(
address(trustedWrapper),
_collateralERC20[i].amount * _wNFTAddress.length
);
}
}
uint256 valuePerWNFT = msg.value / _wNFTAddress.length;
for (uint256 i = 0; i < _wNFTAddress.length; i ++){
trustedWrapper.addCollateral{value: valuePerWNFT}(
_wNFTAddress[i],
_wNFTTokenId[i],
_collateralERC20
);
}
if (valuePerWNFT * _wNFTAddress.length < msg.value ){
address payable s = payable(msg.sender);
s.transfer(msg.value - valuePerWNFT * _wNFTAddress.length);
}
}
function setTrustedWrapper(address _wrapper) public onlyOwner {
trustedWrapper = ITrustedWrapperV2(_wrapper);
require(trustedWrapper.trustedOperator(address(this)), "Only for exact wrapper");
}
function checkUser(address _user) external view returns (bool ok, bool needFix) {
return _checkUserSubscription(_user);
}
}
文件 3 的 16: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 的 16: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);
}
文件 5 的 16:IERC20Extended.sol
pragma solidity 0.8.21;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IERC20Extended is IERC20 {
function mint(address _to, uint256 _value) external;
}
文件 6 的 16:IERC20Permit.sol
pragma solidity ^0.8.0;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
文件 7 的 16:ISubscriptionRegistry.sol
pragma solidity 0.8.21;
import {SubscriptionType, PayOption, Tariff, Ticket} from "../contracts/SubscriptionRegistry.sol";
interface ISubscriptionRegistry {
function registerServiceTariff(Tariff calldata _newTariff) external returns(uint256);
function authorizeAgentForService(
address _agent,
uint256[] calldata _serviceTariffIndexes
) external returns (uint256[] memory);
function buySubscription(
address _service,
uint256 _tariffIndex,
uint256 _payWithIndex,
address _buyFor,
address _payer
) external payable returns(Ticket memory ticket);
function editServiceTariff(
uint256 _tariffIndex,
uint256 _timelockPeriod,
uint256 _ticketValidPeriod,
uint256 _counter,
bool _isAvailable,
address _beneficiary
) external;
function addTariffPayOption(
uint256 _tariffIndex,
address _paymentToken,
uint256 _paymentAmount,
uint16 _agentFeePercent
) external returns(uint256);
function editTariffPayOption(
uint256 _tariffIndex,
uint256 _payWithIndex,
address _paymentToken,
uint256 _paymentAmount,
uint16 _agentFeePercent
) external;
function checkUserSubscription(
address _user,
address _service
) external view returns (bool ok, bool needFix);
function checkAndFixUserSubscription(address _user) external returns (bool ok);
function fixUserSubscription(address _user, address _serviceFromProxy) external;
function getUserTicketForService(
address _service,
address _user
) external view returns(Ticket memory);
function getTariffsForService(address _service) external view returns (Tariff[] memory);
function getTicketPrice(
address _service,
uint256 _tariffIndex,
uint256 _payWithIndex
) external view returns (address, uint256);
function getAvailableAgentsTariffForService(
address _agent,
address _service
) external view returns(Tariff[] memory);
}
文件 8 的 16:ITrustedWrapper.sol
pragma solidity 0.8.21;
import "./IWrapper.sol";
interface ITrustedWrapper is IWrapper {
function trustedOperator() external view returns(address);
function wrapUnsafe(
ETypes.INData calldata _inData,
ETypes.AssetItem[] calldata _collateral,
address _wrappFor
)
external
payable
returns (ETypes.AssetItem memory);
function transferIn(
ETypes.AssetItem memory _assetItem,
address _from
)
external
payable
returns (uint256 _transferedValue);
}
文件 9 的 16:ITrustedWrapperV2.sol
pragma solidity 0.8.21;
import "@envelop-protocol-v1/interfaces/IWrapper.sol";
interface ITrustedWrapperV2 is IWrapper {
function trustedOperator(address _operator) external view returns(bool);
function wrapUnsafe(
ETypes.INData calldata _inData,
ETypes.AssetItem[] calldata _collateral,
address _wrappFor
)
external
payable
returns (ETypes.AssetItem memory);
function transferIn(
ETypes.AssetItem memory _assetItem,
address _from
)
external
payable
returns (uint256 _transferedValue);
}
文件 10 的 16:IWrapper.sol
pragma solidity 0.8.21;
import "../contracts/LibEnvelopTypes.sol";
interface IWrapper {
event WrappedV1(
address indexed inAssetAddress,
address indexed outAssetAddress,
uint256 indexed inAssetTokenId,
uint256 outTokenId,
address wnftFirstOwner,
uint256 nativeCollateralAmount,
bytes2 rules
);
event UnWrappedV1(
address indexed wrappedAddress,
address indexed originalAddress,
uint256 indexed wrappedId,
uint256 originalTokenId,
address beneficiary,
uint256 nativeCollateralAmount,
bytes2 rules
);
event CollateralAdded(
address indexed wrappedAddress,
uint256 indexed wrappedId,
uint8 assetType,
address collateralAddress,
uint256 collateralTokenId,
uint256 collateralBalance
);
event PartialUnWrapp(
address indexed wrappedAddress,
uint256 indexed wrappedId,
uint256 lastCollateralIndex
);
event SuspiciousFail(
address indexed wrappedAddress,
uint256 indexed wrappedId,
address indexed failedContractAddress
);
event EnvelopFee(
address indexed receiver,
address indexed wNFTConatract,
uint256 indexed wNFTTokenId,
uint256 amount
);
function wrap(
ETypes.INData calldata _inData,
ETypes.AssetItem[] calldata _collateral,
address _wrappFor
)
external
payable
returns (ETypes.AssetItem memory);
function addCollateral(
address _wNFTAddress,
uint256 _wNFTTokenId,
ETypes.AssetItem[] calldata _collateral
) external payable;
function unWrap(
address _wNFTAddress,
uint256 _wNFTTokenId
) external;
function unWrap(
ETypes.AssetType _wNFTType,
address _wNFTAddress,
uint256 _wNFTTokenId
) external;
function unWrap(
ETypes.AssetType _wNFTType,
address _wNFTAddress,
uint256 _wNFTTokenId,
bool _isEmergency
) external;
function chargeFees(
address _wNFTAddress,
uint256 _wNFTTokenId,
address _from,
address _to,
bytes1 _feeType
)
external
returns (bool);
function MAX_COLLATERAL_SLOTS() external view returns (uint256);
function protocolTechToken() external view returns (address);
function protocolWhiteList() external view returns (address);
function getWrappedToken(address _wNFTAddress, uint256 _wNFTTokenId)
external
view
returns (ETypes.WNFT memory);
function getOriginalURI(address _wNFTAddress, uint256 _wNFTTokenId)
external
view
returns(string memory);
function getCollateralBalanceAndIndex(
address _wNFTAddress,
uint256 _wNFTTokenId,
ETypes.AssetType _collateralType,
address _erc,
uint256 _tokenId
) external view returns (uint256, uint256);
}
文件 11 的 16:LibEnvelopTypes.sol
pragma solidity 0.8.21;
library ETypes {
enum AssetType {EMPTY, NATIVE, ERC20, ERC721, ERC1155, FUTURE1, FUTURE2, FUTURE3}
struct Asset {
AssetType assetType;
address contractAddress;
}
struct AssetItem {
Asset asset;
uint256 tokenId;
uint256 amount;
}
struct NFTItem {
address contractAddress;
uint256 tokenId;
}
struct Fee {
bytes1 feeType;
uint256 param;
address token;
}
struct Lock {
bytes1 lockType;
uint256 param;
}
struct Royalty {
address beneficiary;
uint16 percent;
}
struct WNFT {
AssetItem inAsset;
AssetItem[] collateral;
address unWrapDestination;
Fee[] fees;
Lock[] locks;
Royalty[] royalties;
bytes2 rules;
}
struct INData {
AssetItem inAsset;
address unWrapDestination;
Fee[] fees;
Lock[] locks;
Royalty[] royalties;
AssetType outType;
uint256 outBalance;
bytes2 rules;
}
struct WhiteListItem {
bool enabledForFee;
bool enabledForCollateral;
bool enabledRemoveFromCollateral;
address transferFeeModel;
}
struct Rules {
bytes2 onlythis;
bytes2 disabled;
}
}
文件 12 的 16:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _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 = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 13 的 16:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}
文件 14 的 16:ServiceProvider.sol
pragma solidity 0.8.21;
import "../interfaces/ISubscriptionRegistry.sol";
abstract contract ServiceProvider {
address public serviceProvider;
ISubscriptionRegistry public subscriptionRegistry;
bool public isEnabled = true;
constructor(address _subscrRegistry) {
require(_subscrRegistry != address(0), 'Non zero only');
serviceProvider = address(this);
subscriptionRegistry = ISubscriptionRegistry(_subscrRegistry);
}
function _registerServiceTariff(Tariff memory _newTariff)
internal virtual returns(uint256)
{
return subscriptionRegistry.registerServiceTariff(_newTariff);
}
function _editServiceTariff(
uint256 _tariffIndex,
uint256 _timelockPeriod,
uint256 _ticketValidPeriod,
uint256 _counter,
bool _isAvailable,
address _beneficiary
) internal virtual
{
subscriptionRegistry.editServiceTariff(
_tariffIndex,
_timelockPeriod,
_ticketValidPeriod,
_counter,
_isAvailable,
_beneficiary
);
}
function _addTariffPayOption(
uint256 _tariffIndex,
address _paymentToken,
uint256 _paymentAmount,
uint16 _agentFeePercent
) internal virtual returns(uint256)
{
return subscriptionRegistry.addTariffPayOption(
_tariffIndex,
_paymentToken,
_paymentAmount,
_agentFeePercent
);
}
function _editTariffPayOption(
uint256 _tariffIndex,
uint256 _payWithIndex,
address _paymentToken,
uint256 _paymentAmount,
uint16 _agentFeePercent
) internal virtual
{
subscriptionRegistry.editTariffPayOption(
_tariffIndex,
_payWithIndex,
_paymentToken,
_paymentAmount,
_agentFeePercent
);
}
function _authorizeAgentForService(
address _agent,
uint256[] memory _serviceTariffIndexes
) internal virtual returns (uint256[] memory)
{
return subscriptionRegistry.authorizeAgentForService(
_agent,
_serviceTariffIndexes
);
}
function _checkAndFixSubscription(address _user)
internal
returns (bool ok)
{
if (isEnabled) {
ok = subscriptionRegistry.checkAndFixUserSubscription(
_user
);
} else {
ok = true;
}
}
function _checkUserSubscription(address _user)
internal
view
returns (bool ok, bool needFix)
{
if (isEnabled) {
(ok, needFix) = subscriptionRegistry.checkUserSubscription(
_user,
address(this)
);
} else {
ok = true;
}
}
}
文件 15 的 16:ServiceProviderOwnable.sol
pragma solidity 0.8.21;
import "@openzeppelin/contracts/access/Ownable.sol";
import "./ServiceProvider.sol";
contract ServiceProviderOwnable is ServiceProvider, Ownable {
constructor(address _subscrRegistry)
ServiceProvider(_subscrRegistry)
{
}
function newTariff(Tariff memory _newTariff) external onlyOwner returns(uint256 tariffIndex) {
tariffIndex = _registerServiceTariff(_newTariff);
}
function registerServiceTariff(Tariff memory _newTariff)
external onlyOwner returns(uint256)
{
return _registerServiceTariff(_newTariff);
}
function editServiceTariff(
uint256 _tariffIndex,
uint256 _timelockPeriod,
uint256 _ticketValidPeriod,
uint256 _counter,
bool _isAvailable,
address _beneficiary
) external onlyOwner
{
_editServiceTariff(
_tariffIndex,
_timelockPeriod,
_ticketValidPeriod,
_counter,
_isAvailable,
_beneficiary
);
}
function addPayOption(
uint256 _tariffIndex,
address _paymentToken,
uint256 _paymentAmount,
uint16 _agentFeePercent
) external onlyOwner returns(uint256 index)
{
index = _addTariffPayOption(
_tariffIndex,
_paymentToken,
_paymentAmount,
_agentFeePercent
);
}
function editPayOption(
uint256 _tariffIndex,
uint256 _payWithIndex,
address _paymentToken,
uint256 _paymentAmount,
uint16 _agentFeePercent
) external onlyOwner
{
_editTariffPayOption(
_tariffIndex,
_payWithIndex,
_paymentToken,
_paymentAmount,
_agentFeePercent
);
}
function authorizeAgentForService(
address _agent,
uint256[] memory _serviceTariffIndexes
) external onlyOwner returns (uint256[] memory actualTariffs)
{
actualTariffs = _authorizeAgentForService(
_agent,
_serviceTariffIndexes
);
}
function setSubscriptionRegistry(address _subscrRegistry) external onlyOwner {
subscriptionRegistry = ISubscriptionRegistry(_subscrRegistry);
}
function setSubscriptionOnOff(bool _isEnable) external onlyOwner {
isEnabled = _isEnable;
}
}
文件 16 的 16:SubscriptionRegistry.sol
pragma solidity 0.8.21;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@envelop-protocol-v1/interfaces/ITrustedWrapper.sol";
import "@envelop-protocol-v1/contracts/LibEnvelopTypes.sol";
import "../interfaces/ISubscriptionRegistry.sol";
struct SubscriptionType {
uint256 timelockPeriod;
uint256 ticketValidPeriod;
uint256 counter;
bool isAvailable;
address beneficiary;
}
struct PayOption {
address paymentToken;
uint256 paymentAmount;
uint16 agentFeePercent;
}
struct Tariff {
SubscriptionType subscription;
PayOption[] payWith;
}
struct Ticket {
uint256 validUntil;
uint256 countsLeft;
}
contract SubscriptionRegistry is Ownable {
using SafeERC20 for IERC20;
uint256 constant public PERCENT_DENOMINATOR = 10000;
address public platformOwner;
uint16 public platformFeePercent = 50;
address public mainWrapper;
address public previousRegistry;
address public proxyRegistry;
mapping(address => bool) public whiteListedForPayments;
mapping(address => Tariff[]) public availableTariffs;
mapping(address => mapping(address => uint256[])) public agentServiceRegistry;
mapping(address => mapping(address => Ticket)) public userTickets;
event PlatfromFeeChanged(uint16 indexed newPercent);
event WhitelistPaymentTokenChanged(address indexed asset, bool indexed state);
event TariffChanged(address indexed service, uint256 indexed tariffIndex);
event TicketIssued(
address indexed service,
address indexed agent,
address indexed forUser,
uint256 tariffIndex
);
constructor(address _platformOwner) {
require(_platformOwner != address(0),'Zero platform fee receiver');
platformOwner = _platformOwner;
}
function registerServiceTariff(Tariff calldata _newTariff)
external
returns(uint256)
{
return _addTariff(msg.sender, _newTariff);
}
function editServiceTariff(
uint256 _tariffIndex,
uint256 _timelockPeriod,
uint256 _ticketValidPeriod,
uint256 _counter,
bool _isAvailable,
address _beneficiary
)
external
{
_editTariff(
msg.sender,
_tariffIndex,
_timelockPeriod,
_ticketValidPeriod,
_counter,
_isAvailable,
_beneficiary
);
}
function addTariffPayOption(
uint256 _tariffIndex,
address _paymentToken,
uint256 _paymentAmount,
uint16 _agentFeePercent
) external returns(uint256)
{
return _addTariffPayOption(
msg.sender,
_tariffIndex,
_paymentToken,
_paymentAmount,
_agentFeePercent
);
}
function editTariffPayOption(
uint256 _tariffIndex,
uint256 _payWithIndex,
address _paymentToken,
uint256 _paymentAmount,
uint16 _agentFeePercent
) external
{
_editTariffPayOption(
msg.sender,
_tariffIndex,
_payWithIndex,
_paymentToken,
_paymentAmount,
_agentFeePercent
);
}
function authorizeAgentForService(
address _agent,
uint256[] calldata _serviceTariffIndexes
) external virtual returns (uint256[] memory)
{
delete agentServiceRegistry[msg.sender][_agent];
uint256[] storage currentServiceTariffsOfAgent = agentServiceRegistry[msg.sender][_agent];
for(uint256 i; i < _serviceTariffIndexes.length; ++ i) {
if (availableTariffs[msg.sender][_serviceTariffIndexes[i]].subscription.isAvailable){
currentServiceTariffsOfAgent.push(_serviceTariffIndexes[i]);
}
}
return currentServiceTariffsOfAgent;
}
function buySubscription(
address _service,
uint256 _tariffIndex,
uint256 _payWithIndex,
address _buyFor,
address _payer
) external
payable
returns(Ticket memory ticket) {
require(_buyFor != address(0),'Cant buy ticket for nobody');
require(
availableTariffs[_service][_tariffIndex].subscription.isAvailable,
'This subscription not available'
);
require(
_isAgentAuthorized(msg.sender, _service, _tariffIndex),
'Agent not authorized for this service tariff'
);
(bool isValid, bool needFix) = _isTicketValid(_buyFor, _service);
require(!isValid, 'Only one valid ticket at time');
ticket = Ticket(
availableTariffs[_service][_tariffIndex].subscription.ticketValidPeriod + block.timestamp,
availableTariffs[_service][_tariffIndex].subscription.counter
);
userTickets[_buyFor][_service] = ticket;
if (availableTariffs[_service][_tariffIndex].payWith[_payWithIndex].paymentAmount > 0){
_processPayment(_service, _tariffIndex, _payWithIndex, _payer);
}
emit TicketIssued(_service, msg.sender, _buyFor, _tariffIndex);
}
function checkAndFixUserSubscription(
address _user
) external returns (bool ok){
address _service = msg.sender;
(bool isValid, bool needFix) = _isTicketValid(_user, msg.sender);
if (!isValid && previousRegistry != address(0)) {
(isValid, needFix) = ISubscriptionRegistry(previousRegistry).checkUserSubscription(
_user,
_service
);
if (isValid ) {
if (needFix){
ISubscriptionRegistry(previousRegistry).fixUserSubscription(
_user,
_service
);
}
ok = true;
return ok;
}
}
require(isValid,'Valid ticket not found');
if (needFix){
_fixUserSubscription(_user, msg.sender);
}
ok = true;
}
function fixUserSubscription(
address _user,
address _serviceFromProxy
) public {
require(proxyRegistry !=address(0) && msg.sender == proxyRegistry,
'Only for future registry'
);
_fixUserSubscription(_user, _serviceFromProxy);
}
function checkUserSubscription(
address _user,
address _service
) external view returns (bool ok, bool needFix) {
(ok, needFix) = _isTicketValid(_user, _service);
if (!ok && previousRegistry != address(0)) {
(ok, needFix) = ISubscriptionRegistry(previousRegistry).checkUserSubscription(
_user,
_service
);
}
}
function getUserTicketForService(
address _service,
address _user
) public view returns(Ticket memory)
{
return userTickets[_user][_service];
}
function getTariffsForService(address _service) external view returns (Tariff[] memory) {
return availableTariffs[_service];
}
function getTicketPrice(
address _service,
uint256 _tariffIndex,
uint256 _payWithIndex
) public view virtual returns (address, uint256)
{
if (availableTariffs[_service][_tariffIndex].subscription.timelockPeriod != 0)
{
return(
availableTariffs[_service][_tariffIndex].payWith[_payWithIndex].paymentToken,
availableTariffs[_service][_tariffIndex].payWith[_payWithIndex].paymentAmount
);
} else {
return(
availableTariffs[_service][_tariffIndex].payWith[_payWithIndex].paymentToken,
availableTariffs[_service][_tariffIndex].payWith[_payWithIndex].paymentAmount
+ availableTariffs[_service][_tariffIndex].payWith[_payWithIndex].paymentAmount
*availableTariffs[_service][_tariffIndex].payWith[_payWithIndex].agentFeePercent
/PERCENT_DENOMINATOR
+ availableTariffs[_service][_tariffIndex].payWith[_payWithIndex].paymentAmount
*_platformFeePercent(_service, _tariffIndex, _payWithIndex)
/PERCENT_DENOMINATOR
);
}
}
function getAvailableAgentsTariffForService(
address _agent,
address _service
) external view virtual returns(uint256[] memory, Tariff[] memory)
{
uint256 availableCount;
for (uint256 i; i < agentServiceRegistry[_service][_agent].length; ++i){
if (availableTariffs[_service][
agentServiceRegistry[_service][_agent][i]
].subscription.isAvailable
) {++availableCount;}
}
Tariff[] memory tariffs = new Tariff[](availableCount);
uint256[] memory indexes = new uint256[](availableCount);
for (uint256 i; i < agentServiceRegistry[_service][_agent].length; ++i){
if (availableTariffs[_service][
agentServiceRegistry[_service][_agent][i]
].subscription.isAvailable
)
{
tariffs[availableCount - 1] = availableTariffs[_service][
agentServiceRegistry[_service][_agent][i]
];
indexes[availableCount - 1] = agentServiceRegistry[_service][_agent][i];
--availableCount;
}
}
return (indexes, tariffs);
}
function setAssetForPaymentState(address _asset, bool _isEnable)
external onlyOwner
{
whiteListedForPayments[_asset] = _isEnable;
emit WhitelistPaymentTokenChanged(_asset, _isEnable);
}
function setMainWrapper(address _wrapper) external onlyOwner {
mainWrapper = _wrapper;
}
function setPlatformOwner(address _newOwner) external {
require(msg.sender == platformOwner, 'Only platform owner');
require(_newOwner != address(0),'Zero platform fee receiver');
platformOwner = _newOwner;
}
function setPlatformFeePercent(uint16 _newPercent) external {
require(msg.sender == platformOwner, 'Only platform owner');
platformFeePercent = _newPercent;
emit PlatfromFeeChanged(platformFeePercent);
}
function setPreviousRegistry(address _registry) external onlyOwner {
previousRegistry = _registry;
}
function setProxyRegistry(address _registry) external onlyOwner {
proxyRegistry = _registry;
}
function _processPayment(
address _service,
uint256 _tariffIndex,
uint256 _payWithIndex,
address _payer
)
internal
virtual
returns(bool)
{
if (availableTariffs[_service][_tariffIndex].subscription.timelockPeriod != 0){
require(msg.value == 0, 'Ether Not accepted in this method');
IERC20(
availableTariffs[_service][_tariffIndex].payWith[_payWithIndex].paymentToken
).safeTransferFrom(
_payer,
address(this),
availableTariffs[_service][_tariffIndex].payWith[_payWithIndex].paymentAmount
);
IERC20(
availableTariffs[_service][_tariffIndex].payWith[_payWithIndex].paymentToken
).safeApprove(
mainWrapper,
availableTariffs[_service][_tariffIndex].payWith[_payWithIndex].paymentAmount
);
ETypes.INData memory _inData;
ETypes.AssetItem[] memory _collateralERC20 = new ETypes.AssetItem[](1);
ETypes.Lock[] memory timeLock = new ETypes.Lock[](1);
timeLock[0] = ETypes.Lock(
0x00,
availableTariffs[_service][_tariffIndex].subscription.timelockPeriod + block.timestamp
);
_inData = ETypes.INData(
ETypes.AssetItem(
ETypes.Asset(ETypes.AssetType.EMPTY, address(0)),
0,0
),
address(0),
new ETypes.Fee[](0),
timeLock,
new ETypes.Royalty[](0),
ETypes.AssetType.ERC721,
0,
0x0000
);
_collateralERC20[0] = ETypes.AssetItem(
ETypes.Asset(
ETypes.AssetType.ERC20,
availableTariffs[_service][_tariffIndex].payWith[_payWithIndex].paymentToken
),
0,
availableTariffs[_service][_tariffIndex].payWith[_payWithIndex].paymentAmount
);
ITrustedWrapper(mainWrapper).wrap(
_inData,
_collateralERC20,
_payer
);
} else {
if (availableTariffs[_service][_tariffIndex]
.payWith[_payWithIndex]
.paymentToken != address(0)
)
{
require(msg.value == 0, 'Ether Not accepted in this method');
IERC20(
availableTariffs[_service][_tariffIndex].payWith[_payWithIndex].paymentToken
).safeTransferFrom(
_payer,
availableTariffs[_service][_tariffIndex].subscription.beneficiary,
availableTariffs[_service][_tariffIndex].payWith[_payWithIndex].paymentAmount
);
IERC20(
availableTariffs[_service][_tariffIndex].payWith[_payWithIndex].paymentToken
).safeTransferFrom(
_payer,
msg.sender,
availableTariffs[_service][_tariffIndex].payWith[_payWithIndex].paymentAmount
*availableTariffs[_service][_tariffIndex].payWith[_payWithIndex].agentFeePercent
/PERCENT_DENOMINATOR
);
uint256 _pFee = _platformFeePercent(_service, _tariffIndex, _payWithIndex);
if (_pFee > 0) {
IERC20(
availableTariffs[_service][_tariffIndex].payWith[_payWithIndex].paymentToken
).safeTransferFrom(
_payer,
platformOwner,
availableTariffs[_service][_tariffIndex].payWith[_payWithIndex].paymentAmount
*_pFee
/PERCENT_DENOMINATOR
);
}
} else {
(, uint256 needPay) = getTicketPrice(_service, _tariffIndex,_payWithIndex);
require(msg.value >= needPay, 'Not enough ether');
sendValue(
payable(availableTariffs[_service][_tariffIndex].subscription.beneficiary),
availableTariffs[_service][_tariffIndex].payWith[_payWithIndex].paymentAmount
);
sendValue(
payable(msg.sender),
availableTariffs[_service][_tariffIndex].payWith[_payWithIndex].paymentAmount
*availableTariffs[_service][_tariffIndex].payWith[_payWithIndex].agentFeePercent
/PERCENT_DENOMINATOR
);
uint256 _pFee = _platformFeePercent(_service, _tariffIndex, _payWithIndex);
if (_pFee > 0) {
sendValue(
payable(platformOwner),
availableTariffs[_service][_tariffIndex].payWith[_payWithIndex].paymentAmount
*_pFee
/PERCENT_DENOMINATOR
);
}
if ((msg.value - needPay) > 0) {
address payable s = payable(_payer);
s.transfer(msg.value - needPay);
}
}
}
}
function _platformFeePercent(
address _service,
uint256 _tariffIndex,
uint256 _payWithIndex
) internal view virtual returns(uint256)
{
return platformFeePercent;
}
function _addTariff(address _service, Tariff calldata _newTariff)
internal returns(uint256)
{
require (_newTariff.payWith.length > 0, 'No payment method');
for (uint256 i; i < _newTariff.payWith.length; ++i){
require(
whiteListedForPayments[_newTariff.payWith[i].paymentToken],
'Not whitelisted for payments'
);
}
require(
_newTariff.subscription.ticketValidPeriod > 0
|| _newTariff.subscription.counter > 0,
'Tariff has no valid ticket option'
);
availableTariffs[_service].push(_newTariff);
emit TariffChanged(_service, availableTariffs[_service].length - 1);
return availableTariffs[_service].length - 1;
}
function _editTariff(
address _service,
uint256 _tariffIndex,
uint256 _timelockPeriod,
uint256 _ticketValidPeriod,
uint256 _counter,
bool _isAvailable,
address _beneficiary
) internal
{
availableTariffs[_service][_tariffIndex].subscription.timelockPeriod = _timelockPeriod;
availableTariffs[_service][_tariffIndex].subscription.ticketValidPeriod = _ticketValidPeriod;
availableTariffs[_service][_tariffIndex].subscription.counter = _counter;
availableTariffs[_service][_tariffIndex].subscription.isAvailable = _isAvailable;
availableTariffs[_service][_tariffIndex].subscription.beneficiary = _beneficiary;
emit TariffChanged(_service, _tariffIndex);
}
function _addTariffPayOption(
address _service,
uint256 _tariffIndex,
address _paymentToken,
uint256 _paymentAmount,
uint16 _agentFeePercent
) internal returns(uint256)
{
require(whiteListedForPayments[_paymentToken], 'Not whitelisted for payments');
availableTariffs[_service][_tariffIndex].payWith.push(
PayOption(_paymentToken, _paymentAmount, _agentFeePercent)
);
emit TariffChanged(_service, _tariffIndex);
return availableTariffs[_service][_tariffIndex].payWith.length - 1;
}
function _editTariffPayOption(
address _service,
uint256 _tariffIndex,
uint256 _payWithIndex,
address _paymentToken,
uint256 _paymentAmount,
uint16 _agentFeePercent
) internal
{
require(whiteListedForPayments[_paymentToken], 'Not whitelisted for payments');
availableTariffs[_service][_tariffIndex].payWith[_payWithIndex]
= PayOption(_paymentToken, _paymentAmount, _agentFeePercent);
emit TariffChanged(_service, _tariffIndex);
}
function _fixUserSubscription(
address _user,
address _service
) internal {
if (userTickets[_user][_service].countsLeft > 0) {
-- userTickets[_user][_service].countsLeft;
}
}
function _isTicketValid(address _user, address _service)
internal
view
returns (bool isValid, bool needFix )
{
isValid = userTickets[_user][_service].validUntil > block.timestamp
|| userTickets[_user][_service].countsLeft > 0;
needFix = userTickets[_user][_service].countsLeft > 0;
}
function _isAgentAuthorized(
address _agent,
address _service,
uint256 _tariffIndex
)
internal
view
returns(bool authorized)
{
for (uint256 i; i < agentServiceRegistry[_service][_agent].length; ++ i){
if (agentServiceRegistry[_service][_agent][i] == _tariffIndex){
authorized = true;
return authorized;
}
}
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
}
{
"compilationTarget": {
"contracts/BatchWorkerV2.sol": "BatchWorkerV2"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":@envelop-protocol-v1/=lib/envelop-protocol-v1/",
":@envelop-subscription/=lib/subscription/",
":@openzeppelin/=lib/openzeppelin-contracts/",
":@uniswap/=lib/",
":ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
":envelop-protocol-v1/=lib/envelop-protocol-v1/",
":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
":forge-std/=lib/forge-std/src/",
":openzeppelin-contracts/=lib/openzeppelin-contracts/",
":openzeppelin/=lib/openzeppelin-contracts/contracts/",
":subscription/=lib/subscription/"
]
}
[{"inputs":[{"internalType":"address","name":"_subscrRegistry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"address[]","name":"_wNFTAddress","type":"address[]"},{"internalType":"uint256[]","name":"_wNFTTokenId","type":"uint256[]"},{"components":[{"components":[{"internalType":"enum ETypes.AssetType","name":"assetType","type":"uint8"},{"internalType":"address","name":"contractAddress","type":"address"}],"internalType":"struct ETypes.Asset","name":"asset","type":"tuple"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ETypes.AssetItem[]","name":"_collateralERC20","type":"tuple[]"}],"name":"addCollateralBatch","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tariffIndex","type":"uint256"},{"internalType":"address","name":"_paymentToken","type":"address"},{"internalType":"uint256","name":"_paymentAmount","type":"uint256"},{"internalType":"uint16","name":"_agentFeePercent","type":"uint16"}],"name":"addPayOption","outputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_agent","type":"address"},{"internalType":"uint256[]","name":"_serviceTariffIndexes","type":"uint256[]"}],"name":"authorizeAgentForService","outputs":[{"internalType":"uint256[]","name":"actualTariffs","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"checkUser","outputs":[{"internalType":"bool","name":"ok","type":"bool"},{"internalType":"bool","name":"needFix","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tariffIndex","type":"uint256"},{"internalType":"uint256","name":"_payWithIndex","type":"uint256"},{"internalType":"address","name":"_paymentToken","type":"address"},{"internalType":"uint256","name":"_paymentAmount","type":"uint256"},{"internalType":"uint16","name":"_agentFeePercent","type":"uint16"}],"name":"editPayOption","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tariffIndex","type":"uint256"},{"internalType":"uint256","name":"_timelockPeriod","type":"uint256"},{"internalType":"uint256","name":"_ticketValidPeriod","type":"uint256"},{"internalType":"uint256","name":"_counter","type":"uint256"},{"internalType":"bool","name":"_isAvailable","type":"bool"},{"internalType":"address","name":"_beneficiary","type":"address"}],"name":"editServiceTariff","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint256","name":"timelockPeriod","type":"uint256"},{"internalType":"uint256","name":"ticketValidPeriod","type":"uint256"},{"internalType":"uint256","name":"counter","type":"uint256"},{"internalType":"bool","name":"isAvailable","type":"bool"},{"internalType":"address","name":"beneficiary","type":"address"}],"internalType":"struct SubscriptionType","name":"subscription","type":"tuple"},{"components":[{"internalType":"address","name":"paymentToken","type":"address"},{"internalType":"uint256","name":"paymentAmount","type":"uint256"},{"internalType":"uint16","name":"agentFeePercent","type":"uint16"}],"internalType":"struct PayOption[]","name":"payWith","type":"tuple[]"}],"internalType":"struct Tariff","name":"_newTariff","type":"tuple"}],"name":"newTariff","outputs":[{"internalType":"uint256","name":"tariffIndex","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint256","name":"timelockPeriod","type":"uint256"},{"internalType":"uint256","name":"ticketValidPeriod","type":"uint256"},{"internalType":"uint256","name":"counter","type":"uint256"},{"internalType":"bool","name":"isAvailable","type":"bool"},{"internalType":"address","name":"beneficiary","type":"address"}],"internalType":"struct SubscriptionType","name":"subscription","type":"tuple"},{"components":[{"internalType":"address","name":"paymentToken","type":"address"},{"internalType":"uint256","name":"paymentAmount","type":"uint256"},{"internalType":"uint16","name":"agentFeePercent","type":"uint16"}],"internalType":"struct PayOption[]","name":"payWith","type":"tuple[]"}],"internalType":"struct Tariff","name":"_newTariff","type":"tuple"}],"name":"registerServiceTariff","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"serviceProvider","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isEnable","type":"bool"}],"name":"setSubscriptionOnOff","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_subscrRegistry","type":"address"}],"name":"setSubscriptionRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wrapper","type":"address"}],"name":"setTrustedWrapper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"subscriptionRegistry","outputs":[{"internalType":"contract ISubscriptionRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"trustedWrapper","outputs":[{"internalType":"contract ITrustedWrapperV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"components":[{"internalType":"enum ETypes.AssetType","name":"assetType","type":"uint8"},{"internalType":"address","name":"contractAddress","type":"address"}],"internalType":"struct ETypes.Asset","name":"asset","type":"tuple"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ETypes.AssetItem","name":"inAsset","type":"tuple"},{"internalType":"address","name":"unWrapDestination","type":"address"},{"components":[{"internalType":"bytes1","name":"feeType","type":"bytes1"},{"internalType":"uint256","name":"param","type":"uint256"},{"internalType":"address","name":"token","type":"address"}],"internalType":"struct ETypes.Fee[]","name":"fees","type":"tuple[]"},{"components":[{"internalType":"bytes1","name":"lockType","type":"bytes1"},{"internalType":"uint256","name":"param","type":"uint256"}],"internalType":"struct ETypes.Lock[]","name":"locks","type":"tuple[]"},{"components":[{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"uint16","name":"percent","type":"uint16"}],"internalType":"struct ETypes.Royalty[]","name":"royalties","type":"tuple[]"},{"internalType":"enum ETypes.AssetType","name":"outType","type":"uint8"},{"internalType":"uint256","name":"outBalance","type":"uint256"},{"internalType":"bytes2","name":"rules","type":"bytes2"}],"internalType":"struct ETypes.INData[]","name":"_inDataS","type":"tuple[]"},{"components":[{"components":[{"internalType":"enum ETypes.AssetType","name":"assetType","type":"uint8"},{"internalType":"address","name":"contractAddress","type":"address"}],"internalType":"struct ETypes.Asset","name":"asset","type":"tuple"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ETypes.AssetItem[]","name":"_collateralERC20","type":"tuple[]"},{"internalType":"address[]","name":"_receivers","type":"address[]"}],"name":"wrapBatch","outputs":[],"stateMutability":"payable","type":"function"}]