文件 1 的 11: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 functionCall(target, data, "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");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(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) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(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) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 11:AggregatorV3Interface.sol
pragma solidity ^0.8.0;
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
function getRoundData(uint80 _roundId)
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
}
文件 3 的 11: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 的 11:ERC20.sol
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function name() public view virtual override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function decimals() public view virtual override returns (uint8) {
return 18;
}
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, _allowances[owner][spender] + addedValue);
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = _allowances[owner][spender];
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
}
_balances[to] += amount;
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
}
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}
文件 5 的 11:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
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);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 6 的 11:IERC20Metadata.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 7 的 11:MWWDomain.sol
pragma solidity >=0.8.4 <0.9.0;
import "@openzeppelin/contracts/access/Ownable.sol";
library MWWStructs {
struct Domain {
address owner;
uint256 planId;
uint256 expiryTime;
string domain;
string configIpfsHash;
uint256 registeredAt;
}
}
contract MWWDomain is Ownable {
mapping(address => bool) private admins;
mapping(string => MWWStructs.Domain) public domains;
mapping(address => string[]) private accountDomains;
mapping(string => address[]) private domainDelegates;
address public registerContract;
event MWWSubscribed(
address indexed subscriber,
uint256 planId,
uint256 expiryTime,
string domain
);
event MWWDomainChanged(
address indexed subscriber,
string originalDomain,
string newDomain
);
constructor(address _registar) {
admins[msg.sender] = true;
registerContract = _registar;
}
modifier onlyAdmin() {
require(admins[msg.sender], "Only admin can do it");
_;
}
modifier onlyRegisterContract() {
require(
msg.sender == registerContract,
"Only the register can call this"
);
_;
}
function setRegisterContract(address _address) public onlyOwner {
registerContract = _address;
}
function removeAdmin(address admin) public onlyOwner {
admins[admin] = false;
}
function addAdmin(address admin) public onlyAdmin {
admins[admin] = true;
}
function isDelegate(string calldata domain) public view returns (bool) {
address[] memory delegates = domainDelegates[domain];
for (uint256 i = 0; i < delegates.length; i++) {
if (delegates[i] == msg.sender) {
return true;
}
}
return false;
}
function isAllowedToManageDomain(string calldata domain)
private
view
returns (bool)
{
return isDelegate(domain) || domains[domain].owner == msg.sender;
}
function addDelegate(string calldata domain, address delegate) public {
require(
domains[domain].owner == msg.sender,
"You are not allowed to do this"
);
domainDelegates[domain].push(delegate);
}
function removeDelegate(string calldata domain, address delegate) public {
require(
domains[domain].owner == msg.sender,
"You are not allowed to do this"
);
uint256 j = 0;
uint256 size = domainDelegates[domain].length;
address[] memory auxDelegates = new address[](
size - 1
);
for (uint256 i = 0; i < size; i++) {
if (domainDelegates[domain][i] != delegate) {
auxDelegates[j] = domainDelegates[domain][i];
j = j + 1;
}
}
domainDelegates[domain] = auxDelegates;
}
function subscribe(
address originalCaller,
uint256 planId,
address planOwner,
uint256 duration,
string calldata domain,
string calldata ipfsHash
) public onlyRegisterContract returns (MWWStructs.Domain memory) {
return
_subscribe(
originalCaller,
planId,
planOwner,
duration,
domain,
ipfsHash
);
}
function addDomains(
MWWStructs.Domain[] calldata domainsToAdd
) public onlyAdmin returns (bool) {
uint256 size = domainsToAdd.length;
for (uint256 i = 0; i < size; i++) {
MWWStructs.Domain calldata domain = domainsToAdd[i];
_subscribe(
address(0),
domain.planId,
domain.owner,
domain.expiryTime - block.timestamp,
domain.domain,
domain.configIpfsHash
);
}
return true;
}
function _subscribe(
address originalCaller,
uint256 planId,
address planOwner,
uint256 duration,
string calldata domain,
string calldata ipfsHash
) private returns (MWWStructs.Domain memory) {
if (
domains[domain].owner != address(0) &&
domains[domain].expiryTime > block.timestamp
) {
require(
domains[domain].owner == planOwner,
"Domain registered for someone else"
);
require(
domains[domain].planId == planId,
"Domain registered with another plan"
);
MWWStructs.Domain storage existingDomain = domains[domain];
existingDomain.expiryTime = existingDomain.expiryTime + duration;
return existingDomain;
}
MWWStructs.Domain memory _domain = MWWStructs.Domain({
owner: planOwner,
planId: planId,
expiryTime: block.timestamp + duration,
domain: domain,
configIpfsHash: ipfsHash,
registeredAt: block.timestamp
});
if (originalCaller != address(0) && planOwner != originalCaller) {
domainDelegates[domain].push(originalCaller);
}
domains[domain] = _domain;
accountDomains[planOwner].push(domain);
emit MWWSubscribed(planOwner, planId, duration, domain);
return _domain;
}
function changeDomain(string calldata domain, string calldata newDomain)
public
returns (MWWStructs.Domain memory)
{
require(
isAllowedToManageDomain(domain),
"Only the owner or delegates can manage the domain"
);
require(isSubscriptionActive(domain), "Subscription expired");
require(
!isSubscriptionActive(newDomain),
"New Domain must be unregistered or expired."
);
MWWStructs.Domain memory subs = domains[domain];
domains[newDomain] = MWWStructs.Domain({
owner: subs.owner,
planId: subs.planId,
expiryTime: subs.expiryTime,
domain: newDomain,
configIpfsHash: subs.configIpfsHash,
registeredAt: subs.registeredAt
});
delete domains[domain];
string[] memory auxDomains = new string[](
accountDomains[subs.owner].length
);
auxDomains[0] = newDomain;
uint256 j = 1;
bytes32 oldDomainHash = keccak256(bytes(domain));
for (uint256 i = 0; i < accountDomains[subs.owner].length; i++) {
if (
keccak256(bytes(accountDomains[subs.owner][i])) != oldDomainHash
) {
auxDomains[j] = accountDomains[subs.owner][i];
j++;
}
}
accountDomains[subs.owner] = auxDomains;
emit MWWDomainChanged(subs.owner, domain, newDomain);
return domains[newDomain];
}
function changeDomainConfigHash(
string calldata domain,
string calldata ipfsHash
) public {
require(
isAllowedToManageDomain(domain),
"Only the owner or delegates can manage the domain"
);
domains[domain].configIpfsHash = ipfsHash;
}
function isSubscriptionActive(string calldata domain)
public
view
returns (bool)
{
return domains[domain].expiryTime > block.timestamp;
}
function getDomainsForAccount(address account)
public
view
returns (string[] memory)
{
return accountDomains[account];
}
function getDelegatesForDomain(string memory domain)
public
view
returns (address[] memory)
{
return domainDelegates[domain];
}
}
文件 8 的 11:MWWRegistarBase.sol
pragma solidity >=0.8.4 <0.9.0;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "./MWWDomain.sol";
abstract contract MWWRegistarBase is Ownable {
using SafeERC20 for ERC20;
struct PlanInfo {
string name;
uint256 usdPrice;
}
MWWDomain public domainContract;
mapping(address => bool) private acceptableTokens;
mapping(uint8 => PlanInfo) private availablePlans;
uint8[] private planIds;
event MWWPurchase(address planOwner, uint256 timestamp);
constructor(address[] memory _acceptableTokens) {
for (uint256 i = 0; i < _acceptableTokens.length; i++) {
acceptableTokens[_acceptableTokens[i]] = true;
}
}
function withdraw(
address tokenAddress,
uint256 amount,
address destination
) public onlyOwner {
require(amount > 0, "Amount can't be zero");
require(destination != address(0), "Destination can't be zero");
require(destination != address(this), "Can't send to this contract");
if (tokenAddress == address(0)) {
(bool ok, ) = destination.call{value: amount}("");
require(ok, "Failed to withdraw funds");
} else {
require(acceptableTokens[tokenAddress], "Token not accepted");
ERC20(tokenAddress).safeTransfer(destination, amount);
}
}
function setDomainContract(address _address) public onlyOwner {
domainContract = MWWDomain(_address);
}
function addAcceptableToken(address tokenAddress) public onlyOwner {
acceptableTokens[tokenAddress] = true;
}
function removeAcceptableToken(address tokenAddress) public onlyOwner {
delete acceptableTokens[tokenAddress];
}
function addPlan(
string memory _name,
uint256 _usdPrice,
uint8 _planId
) public onlyOwner {
require(_usdPrice != 0, "usdPrice can't be 0");
require(availablePlans[_planId].usdPrice == 0, "Plan already exists");
availablePlans[_planId] = PlanInfo(_name, _usdPrice);
planIds.push(_planId);
}
function removePlan(uint8 _index, uint8 planId) public onlyOwner {
planIds[_index] = planIds[planIds.length - 1];
planIds.pop();
delete availablePlans[planId];
}
function purchaseWithNative(
uint8 planId,
address planOwner,
uint256 duration,
string memory domain,
string memory ipfsHash
) public payable returns (MWWStructs.Domain memory) {
require(
address(domainContract) != address(0),
"Subscription contract not set"
);
require(availablePlans[planId].usdPrice != 0, "Plan does not exists");
(uint256 amount, uint256 timestamp) = getNativeConvertedValue(
availablePlans[planId].usdPrice
);
require(timestamp > block.timestamp - 3 hours, "Price is outdated");
uint256 finalPrice = getProportionalPriceForDuration(duration, amount);
require(msg.value >= finalPrice, "Value is lower then plan price");
return _purchase(planId, planOwner, duration, domain, ipfsHash);
}
function purchaseWithToken(
address tokenAddress,
uint8 planId,
address planOwner,
uint256 duration,
string calldata domain,
string calldata ipfsHash
) public payable returns (MWWStructs.Domain memory) {
require(
address(domainContract) != address(0),
"Subscription contract not set"
);
require(availablePlans[planId].usdPrice != 0, "Plan does not exists");
require(acceptableTokens[tokenAddress], "Token not accepted");
ERC20 token = ERC20(tokenAddress);
uint256 finalPrice = getProportionalPriceForDuration(
duration,
availablePlans[planId].usdPrice * 10**token.decimals()
);
token.safeTransferFrom(msg.sender, address(this), finalPrice);
return _purchase(planId, planOwner, duration, domain, ipfsHash);
}
function _purchase(
uint8 planId,
address planOwner,
uint256 duration,
string memory domain,
string memory ipfsHash
) private returns (MWWStructs.Domain memory) {
MWWStructs.Domain memory subs = domainContract.subscribe(
msg.sender,
planId,
planOwner,
duration,
domain,
ipfsHash
);
emit MWWPurchase(planOwner, block.timestamp);
return subs;
}
function getAvailablePlans() public view returns (PlanInfo[] memory) {
PlanInfo[] memory plans = new PlanInfo[](planIds.length);
for (uint256 i = 0; i < planIds.length; i++) {
plans[i] = availablePlans[planIds[i]];
}
return plans;
}
function getProportionalPriceForDuration(
uint256 duration,
uint256 yearlyPrice
) private pure returns (uint256) {
uint256 proportion = (duration * 10**8) / 31_540_000;
return (yearlyPrice * proportion) / (10**8);
}
function getNativeConvertedValue(uint256 usdPrice)
public
view
virtual
returns (uint256 amountInNative, uint256 timestamp);
}
文件 9 的 11:MWWRegistarEthereum.sol
pragma solidity >=0.8.4 <0.9.0;
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "./MWWRegistarBase.sol";
contract MWWRegistarEthereum is MWWRegistarBase {
AggregatorV3Interface public priceFeed;
constructor(address[] memory acceptableTokenAddresses)
MWWRegistarBase(acceptableTokenAddresses)
{}
function setPriceFeed(address _priceFeedAddress) public onlyOwner {
priceFeed = AggregatorV3Interface(_priceFeedAddress);
}
function getNativeConvertedValue(uint256 usdPrice)
public
view
override
returns (uint256 amountInNative, uint256 timestamp)
{
(
uint80 roundID,
int256 price,
uint256 startedAt,
uint256 timeStamp,
uint80 answeredInRound
) = priceFeed.latestRoundData();
uint8 decimals = priceFeed.decimals();
uint256 usdToWei = uint256(10**(18 + decimals)) / (uint256(price));
uint256 _amountInNative = usdPrice * usdToWei;
return (_amountInNative, timeStamp);
}
}
文件 10 的 11: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());
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
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);
}
}
文件 11 的 11:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.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 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
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");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
{
"compilationTarget": {
"contracts/MWWRegistarEthereum.sol": "MWWRegistarEthereum"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address[]","name":"acceptableTokenAddresses","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"planOwner","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"MWWPurchase","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"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"addAcceptableToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"uint256","name":"_usdPrice","type":"uint256"},{"internalType":"uint8","name":"_planId","type":"uint8"}],"name":"addPlan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"domainContract","outputs":[{"internalType":"contract MWWDomain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAvailablePlans","outputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"usdPrice","type":"uint256"}],"internalType":"struct MWWRegistarBase.PlanInfo[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"usdPrice","type":"uint256"}],"name":"getNativeConvertedValue","outputs":[{"internalType":"uint256","name":"amountInNative","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceFeed","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"planId","type":"uint8"},{"internalType":"address","name":"planOwner","type":"address"},{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"string","name":"domain","type":"string"},{"internalType":"string","name":"ipfsHash","type":"string"}],"name":"purchaseWithNative","outputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"planId","type":"uint256"},{"internalType":"uint256","name":"expiryTime","type":"uint256"},{"internalType":"string","name":"domain","type":"string"},{"internalType":"string","name":"configIpfsHash","type":"string"},{"internalType":"uint256","name":"registeredAt","type":"uint256"}],"internalType":"struct MWWStructs.Domain","name":"","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint8","name":"planId","type":"uint8"},{"internalType":"address","name":"planOwner","type":"address"},{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"string","name":"domain","type":"string"},{"internalType":"string","name":"ipfsHash","type":"string"}],"name":"purchaseWithToken","outputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"planId","type":"uint256"},{"internalType":"uint256","name":"expiryTime","type":"uint256"},{"internalType":"string","name":"domain","type":"string"},{"internalType":"string","name":"configIpfsHash","type":"string"},{"internalType":"uint256","name":"registeredAt","type":"uint256"}],"internalType":"struct MWWStructs.Domain","name":"","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"removeAcceptableToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_index","type":"uint8"},{"internalType":"uint8","name":"planId","type":"uint8"}],"name":"removePlan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"setDomainContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_priceFeedAddress","type":"address"}],"name":"setPriceFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"destination","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]