{
  "$schema": "https://evmnow.github.io/contract-metadata/v1/schema.json",
  "chainId": 1,
  "address": "0xedcbf19024e928c9d903fcf4785e42ad7c271193",
  "includes": [
    "interface:erc721",
    "interface:erc721-metadata",
    "interface:erc721-enumerable"
  ],
  "meta": {
    "version": 1,
    "lastUpdated": "2026-04-03T00:00:00Z",
    "locale": "en"
  },
  "name": "EVM.NOW Support",
  "description": "Patronage subscriptions for the EVM.NOW explorer, paid in ETH across tiers and minted as ERC-721 membership NFTs.",
  "about": "## Supporting the world computer's explorer\n\nEVM.NOW is a contract explorer that helps anyone read, interact with, and understand verified smart contracts on Ethereum. Running infrastructure like archive nodes, RPC endpoints, and indexers costs real money. This contract lets users directly fund the project through recurring ETH subscriptions — no intermediaries, no credit cards, just onchain patronage.\n\n## Tiered subscriptions\n\nFour tiers are available: Supporter ($10/month), Gold ($69/month), Platinum ($250/month), and Partner. Prices are denominated in USD and converted to ETH at the current exchange rate via Chainlink's ETH/USD price feed. Committing to 12 or more months earns a 20% discount. The Partner tier cannot be purchased directly — it is granted by the contract owner to select collaborators.\n\nSubscriptions can be extended at the same tier, upgraded to a higher tier, or downgraded. When changing tiers, remaining time is converted pro-rata at the respective tier prices. Upgrades require at least 30 days of new coverage. Anyone can gift or extend a subscription for someone else, though only the recipient (or owner) can change tiers.\n\n## Onchain NFT membership cards\n\nEach subscription is represented as an ERC-721 token — one per wallet. The NFT's metadata and artwork are generated entirely onchain as SVG by a dedicated renderer contract. The card displays the supporter's address (with ENS resolution), their current tier badge, subscription dates, active/expired status, and a full history of tier changes. Transferring the NFT transfers the subscription to the new holder.\n\n## Built for anyone to use\n\nThe Support contracts are open source and designed as composable building blocks. The core subscription logic is separate from the ERC-721 token layer, the pricing hook system, and the onchain renderer — each piece can be swapped, extended, or replaced independently. Hooks let you plug in custom discount logic, tier restrictions, slot limits, or any other business rules without touching the core contract. Anyone can deploy their own Support contract with their own tiers, pricing, and hooks.",
  "risks": [
    "Prices denominated in USD but paid in ETH — volatile exchange rates may affect cost at transaction time",
    "One NFT per wallet — transferring the token transfers subscription ownership to the recipient",
    "Partner tier is grant-only — cannot be purchased even with sufficient ETH",
    "No upgradeability — contract logic cannot be patched after deployment",
    "Excess ETH is refunded to msg.sender — ensure your wallet can receive ETH refunds"
  ],
  "category": "utility",
  "tags": [
    "subscription",
    "patronage",
    "nft",
    "onchain-svg",
    "membership"
  ],
  "links": [
    {
      "label": "Etherscan",
      "url": "https://etherscan.io/address/0xeDCBf19024e928c9D903fCf4785e42AD7C271193"
    },
    {
      "label": "EVM.NOW",
      "url": "https://evm.now"
    },
    {
      "label": "GitHub",
      "url": "https://github.com/1001-digital/support"
    }
  ],
  "theme": {
    "accent": "#484848"
  },
  "groups": {
    "subscription": {
      "label": "Subscription",
      "order": 1
    },
    "info": {
      "label": "Info",
      "order": 2
    },
    "admin": {
      "label": "Admin",
      "order": 3
    }
  },
  "actions": {
    "support": {
      "title": "Support",
      "description": "Subscribe or extend a subscription at a given tier, paid in ETH; only the recipient can change tiers.",
      "intent": "Support {recipient} at tier {tier} for {duration} months",
      "group": "subscription",
      "featured": true,
      "warning": "Sends ETH. The Partner tier (3) is blocked for direct purchase. Excess ETH is refunded to your address.",
      "params": {
        "recipient": {
          "label": "recipient",
          "description": "Address to receive the subscription",
          "type": "address"
        },
        "tier": {
          "label": "tier",
          "description": "Subscription tier: 0 Supporter ($10/mo), 1 Gold ($69/mo), 2 Platinum ($250/mo), 3 Partner ($1,000/mo, grant-only).",
          "type": {
            "type": "enum",
            "values": {
              "0": "Supporter",
              "1": "Gold",
              "2": "Platinum",
              "3": "Partner (grant-only)"
            }
          }
        },
        "duration": {
          "label": "months",
          "description": "Number of months to subscribe (12+ months for 20% discount)",
          "type": "duration"
        }
      },
      "related": [
        "estimate",
        "isActive",
        "currentTier"
      ]
    },
    "estimate": {
      "title": "Estimate Cost",
      "description": "Calculate the ETH cost and adjusted duration for a tier, including discounts; call before support().",
      "stateMutability": "view",
      "group": "subscription",
      "params": {
        "tier": {
          "label": "tier",
          "type": {
            "type": "enum",
            "values": {
              "0": "Supporter",
              "1": "Gold",
              "2": "Platinum"
            }
          }
        },
        "duration": {
          "label": "months",
          "description": "Number of months",
          "type": "duration"
        },
        "supporter": {
          "label": "supporter",
          "description": "Address to check (affects cost if upgrading/downgrading)",
          "type": "address"
        }
      },
      "returns": {
        "ethCost": {
          "label": "ETH cost",
          "type": "eth"
        },
        "adjustedDuration": {
          "label": "adjusted duration",
          "description": "Duration after any hook adjustments"
        }
      },
      "examples": [
        {
          "label": "Supporter for 1 month",
          "params": {
            "tier": "0",
            "duration": "1",
            "supporter": "0x0000000000000000000000000000000000000000"
          }
        },
        {
          "label": "Gold for 12 months (20% off)",
          "params": {
            "tier": "1",
            "duration": "12",
            "supporter": "0x0000000000000000000000000000000000000000"
          }
        }
      ],
      "related": [
        "support",
        "tierPrices"
      ]
    },
    "grant": {
      "title": "Grant Subscription",
      "description": "Grant a free subscription to an address; owner-only, used for Partner tier and honorary subscriptions.",
      "group": "admin",
      "params": {
        "recipient": {
          "label": "recipient",
          "description": "Address to receive the subscription",
          "type": "address"
        },
        "tier": {
          "label": "tier",
          "type": {
            "type": "enum",
            "values": {
              "0": "Supporter",
              "1": "Gold",
              "2": "Platinum",
              "3": "Partner"
            }
          }
        },
        "duration": {
          "label": "months",
          "description": "Number of months to grant"
        },
        "startAt": {
          "label": "start time",
          "description": "Custom start timestamp (0 to start immediately)",
          "type": "timestamp"
        }
      },
      "related": [
        "support"
      ]
    },
    "isActive": {
      "title": "Is Active",
      "description": "Check whether an address has an active subscription.",
      "stateMutability": "view",
      "group": "info",
      "params": {
        "supporter": {
          "label": "supporter",
          "type": "address"
        }
      },
      "related": [
        "subscription",
        "currentTier"
      ]
    },
    "subscription": {
      "title": "Subscription ID",
      "description": "Get the subscription ID for an address. Returns 0 if the address has never subscribed.",
      "stateMutability": "view",
      "group": "info",
      "params": {
        "_0": {
          "label": "supporter",
          "type": "address"
        }
      },
      "returns": {
        "_0": {
          "label": "subscription ID",
          "type": "token-id"
        }
      },
      "related": [
        "subscriptions",
        "isActive",
        "currentTier"
      ]
    },
    "subscriptions": {
      "title": "Subscription Data",
      "description": "Get a subscription's full data by ID: when it was created, when the current period started, and when it expires.",
      "stateMutability": "view",
      "group": "info",
      "params": {
        "_0": {
          "label": "subscription ID",
          "type": "token-id"
        }
      },
      "returns": {
        "createdAt": {
          "label": "created",
          "type": "timestamp"
        },
        "startedAt": {
          "label": "current period start",
          "type": "timestamp"
        },
        "expiresAt": {
          "label": "expires",
          "type": "timestamp"
        }
      },
      "related": [
        "subscription",
        "currentTier",
        "tierPeriods"
      ]
    },
    "currentTier": {
      "title": "Current Tier",
      "description": "Get the current tier and active status for a subscription ID.",
      "stateMutability": "view",
      "group": "info",
      "params": {
        "subscriptionId": {
          "label": "subscription ID",
          "type": "token-id"
        }
      },
      "returns": {
        "_0": {
          "label": "tier",
          "type": {
            "type": "enum",
            "values": {
              "0": "Supporter",
              "1": "Gold",
              "2": "Platinum",
              "3": "Partner"
            }
          }
        },
        "_1": {
          "label": "active"
        }
      },
      "related": [
        "subscription",
        "isActive"
      ]
    },
    "tierPeriods": {
      "title": "Tier History",
      "description": "Get the full tier change history for a subscription. Each entry records when the subscriber moved to a new tier.",
      "stateMutability": "view",
      "group": "info",
      "params": {
        "subscriptionId": {
          "label": "subscription ID",
          "type": "token-id"
        }
      },
      "related": [
        "currentTier",
        "subscriptions"
      ]
    },
    "tierPrices": {
      "title": "Tier Price",
      "description": "Get the monthly USD price for a tier (8 decimal places). Tier 0: $10, Tier 1: $69, Tier 2: $250, Tier 3: $1,000.",
      "stateMutability": "view",
      "group": "info",
      "params": {
        "_0": {
          "label": "tier",
          "type": {
            "type": "enum",
            "values": {
              "0": "Supporter",
              "1": "Gold",
              "2": "Platinum",
              "3": "Partner"
            }
          }
        }
      }
    },
    "totalTiers": {
      "title": "Total Tiers",
      "description": "The number of available subscription tiers (4).",
      "stateMutability": "view",
      "group": "info"
    },
    "totalSupply": {
      "title": "Total Subscriptions",
      "description": "Total number of subscriptions ever created (each represented as an NFT).",
      "stateMutability": "view",
      "group": "info"
    },
    "tokenURI": {
      "title": "Token Metadata",
      "description": "Returns the fully onchain metadata and SVG card for a subscription NFT, showing address, tier, dates, and status.",
      "stateMutability": "view",
      "group": "info",
      "params": {
        "tokenId": {
          "label": "subscription ID",
          "type": "token-id"
        }
      },
      "related": [
        "subscriptions",
        "currentTier"
      ]
    },
    "hook": {
      "title": "Hook Contract",
      "description": "The subscription hook contract that applies custom business logic (discounts, tier restrictions).",
      "stateMutability": "view",
      "group": "info",
      "returns": {
        "_0": {
          "label": "hook address",
          "type": "address"
        }
      }
    },
    "renderer": {
      "title": "Renderer Contract",
      "description": "The contract that generates onchain SVG metadata for subscription NFTs.",
      "stateMutability": "view",
      "group": "info",
      "returns": {
        "_0": {
          "label": "renderer address",
          "type": "address"
        }
      }
    },
    "logo": {
      "title": "Logo",
      "description": "The SVG logo content used in NFT artwork.",
      "stateMutability": "view",
      "group": "info"
    },
    "setTierPrice": {
      "title": "Set Tier Price",
      "description": "Update the monthly USD price for a tier. Only callable by the contract owner.",
      "group": "admin",
      "params": {
        "tier": {
          "label": "tier",
          "type": {
            "type": "enum",
            "values": {
              "0": "Supporter",
              "1": "Gold",
              "2": "Platinum",
              "3": "Partner"
            }
          }
        },
        "priceUSD": {
          "label": "price",
          "description": "Monthly price in USD (e.g. 1000000000 = $10).",
          "type": {
            "type": "amount",
            "decimals": 8,
            "symbol": "USD"
          }
        }
      }
    },
    "addTier": {
      "title": "Add Tier",
      "description": "Add a new subscription tier with a monthly USD price. Only callable by the contract owner.",
      "group": "admin",
      "params": {
        "priceUSD": {
          "label": "price",
          "description": "Monthly price in USD.",
          "type": {
            "type": "amount",
            "decimals": 8,
            "symbol": "USD"
          }
        }
      }
    },
    "setHook": {
      "title": "Set Hook",
      "description": "Set or remove the subscription hook contract. Only callable by the contract owner.",
      "group": "admin",
      "params": {
        "_hook": {
          "label": "hook address",
          "description": "Hook contract address (address(0) to disable)",
          "type": "address"
        }
      }
    },
    "setLogo": {
      "title": "Set Logo",
      "description": "Update the SVG logo used in NFT artwork. Only callable by the contract owner.",
      "group": "admin"
    },
    "setRenderer": {
      "title": "Set Renderer",
      "description": "Update the renderer contract for NFT metadata generation. Only callable by the contract owner.",
      "group": "admin",
      "params": {
        "_renderer": {
          "label": "renderer address",
          "type": "address"
        }
      }
    },
    "withdraw": {
      "title": "Withdraw",
      "description": "Withdraw all collected ETH to the contract owner. Only callable by the contract owner.",
      "group": "admin"
    },
    "owner": {
      "title": "Owner",
      "description": "The address that controls admin functions.",
      "stateMutability": "view",
      "group": "admin",
      "returns": {
        "_0": {
          "type": "address"
        }
      }
    },
    "pendingOwner": {
      "title": "Pending Owner",
      "description": "The address nominated to become the new owner (two-step transfer). Must call acceptOwnership() to complete.",
      "stateMutability": "view",
      "group": "admin",
      "returns": {
        "_0": {
          "type": "address"
        }
      }
    },
    "transferOwnership": {
      "title": "Transfer Ownership",
      "description": "Nominate a new owner, who must call acceptOwnership() to complete the transfer; owner only.",
      "group": "admin",
      "params": {
        "newOwner": {
          "label": "new owner",
          "type": "address"
        }
      }
    },
    "acceptOwnership": {
      "title": "Accept Ownership",
      "description": "Accept a pending ownership transfer. Only callable by the nominated address.",
      "group": "admin"
    },
    "saleStart": {
      "title": "Sale Start",
      "description": "The timestamp when subscriptions become available for purchase.",
      "stateMutability": "view",
      "group": "info",
      "returns": {
        "_0": {
          "type": "timestamp"
        }
      }
    },
    "setSaleStart": {
      "title": "Set Sale Start",
      "description": "Update when subscriptions become available. Only callable by the contract owner.",
      "group": "admin",
      "params": {
        "_saleStart": {
          "label": "sale start",
          "type": "timestamp"
        }
      }
    },
    "supportsInterface": {
      "title": "Supports Interface",
      "description": "Check whether this contract implements a specific interface (EIP-165). Supports ERC-721 and ERC-4906.",
      "stateMutability": "view",
      "group": "info",
      "hidden": true
    }
  },
  "events": {
    "Supported": {
      "title": "Subscription Created/Extended",
      "description": "Emitted when a subscription is created, extended, or tier-changed.",
      "params": {
        "supporter": {
          "label": "supporter",
          "type": "address"
        },
        "tier": {
          "label": "tier",
          "type": {
            "type": "enum",
            "values": {
              "0": "Supporter",
              "1": "Gold",
              "2": "Platinum",
              "3": "Partner"
            }
          }
        },
        "subscriptionId": {
          "label": "subscription ID",
          "type": "token-id"
        },
        "duration": {
          "label": "months"
        },
        "paid": {
          "label": "ETH paid",
          "type": "eth"
        },
        "startedAt": {
          "label": "started",
          "type": "timestamp"
        },
        "expiresAt": {
          "label": "expires",
          "type": "timestamp"
        }
      }
    },
    "TierPriceUpdated": {
      "description": "Emitted when a tier's monthly USD price is updated.",
      "params": {
        "tier": {
          "label": "tier",
          "type": {
            "type": "enum",
            "values": {
              "0": "Supporter",
              "1": "Gold",
              "2": "Platinum",
              "3": "Partner"
            }
          }
        },
        "priceUSD": {
          "label": "price",
          "type": {
            "type": "amount",
            "decimals": 8,
            "symbol": "USD"
          }
        }
      }
    },
    "HookUpdated": {
      "description": "Emitted when the subscription hook contract is changed.",
      "params": {
        "hook": {
          "label": "hook address",
          "type": "address"
        }
      }
    },
    "Withdrawal": {
      "description": "Emitted when collected ETH is withdrawn by the owner.",
      "params": {
        "to": {
          "label": "recipient",
          "type": "address"
        },
        "amount": {
          "label": "amount",
          "type": "eth"
        }
      }
    },
    "MetadataUpdate": {
      "description": "Emitted when a subscription NFT's metadata changes (ERC-4906). Signals marketplaces to refresh the token.",
      "params": {
        "tokenId": {
          "label": "subscription ID",
          "type": "token-id"
        }
      }
    },
    "LogoUpdated": {
      "description": "Emitted when the SVG logo is updated."
    },
    "RendererUpdated": {
      "description": "Emitted when the renderer contract is updated.",
      "params": {
        "renderer": {
          "label": "renderer address",
          "type": "address"
        }
      }
    }
  },
  "errors": {
    "InvalidTier": {
      "title": "Invalid Tier",
      "description": "The specified tier does not exist."
    },
    "InvalidDuration": {
      "title": "Invalid Duration",
      "description": "Duration must be at least 1 month for new subscriptions or reactivations."
    },
    "InvalidRecipient": {
      "title": "Invalid Recipient",
      "description": "Cannot subscribe the zero address."
    },
    "InsufficientPayment": {
      "title": "Insufficient Payment",
      "description": "The ETH sent is less than the required amount. Use estimate() to check the cost first."
    },
    "TransferFailed": {
      "title": "Transfer Failed",
      "description": "ETH refund or withdrawal transfer failed. Ensure the recipient can receive ETH."
    },
    "NothingToWithdraw": {
      "title": "Nothing to Withdraw",
      "description": "The contract has no ETH balance to withdraw."
    },
    "TierChangeForbidden": {
      "title": "Tier Change Forbidden",
      "description": "Only the subscription holder or contract owner can change tiers. Third parties can only extend at the current tier."
    },
    "InvalidPrice": {
      "title": "Invalid Price",
      "description": "Tier price cannot be zero."
    }
  }
}
