Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Multi ZNS] New formula for Curve pricer #114

Open
wants to merge 18 commits into
base: zns-zchain-final
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ docker*.tgz

# We don't ever use the generated manifests
.openzeppelin
/.vscode
MichaelKorchagin marked this conversation as resolved.
Show resolved Hide resolved
34 changes: 12 additions & 22 deletions contracts/price/IZNSCurvePricer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,14 @@ interface IZNSCurvePricer is ICurvePriceConfig, IZNSPricer {
* @notice Reverted when multiplier passed by the domain owner
* is equal to 0 or more than 10^18, which is too large.
*/
error InvalidMultiplierPassed(uint256 multiplier);

/**
* @notice Reverted when `priceConfig` set by the owner does not result in a proper asymptotic curve
* and one of it's incorrect values causes the price spike at maxLength, meaning that the price
* for a domain label shorter than `baseLength` (the one before `minPrice`) becomes higher than `minPrice`.
*/
error InvalidConfigCausingPriceSpikes(
bytes32 configsDomainHash,
uint256 minPrice,
uint256 previousToMinPrice
);
error InvalidPrecisionMultiplierPassed(bytes32 domainHash);

/**
* @notice Emitted when the `maxPrice` is set in `CurvePriceConfig`
* @param price The new maxPrice value
*/
event MaxPriceSet(bytes32 domainHash, uint256 price);

/**
* @notice Emitted when the `minPrice` is set in `CurvePriceConfig`
* @param price The new minPrice value
*/
event MinPriceSet(bytes32 domainHash, uint256 price);

/**
* @notice Emitted when the `baseLength` is set in `CurvePriceConfig`
* @param length The new baseLength value
Expand All @@ -60,18 +43,25 @@ interface IZNSCurvePricer is ICurvePriceConfig, IZNSPricer {
*/
event FeePercentageSet(bytes32 domainHash, uint256 feePercentage);

/**
* @notice Emitted when the `curveMultiplier` is set in state
* @param curveMultiplier The new curveMultiplier value
*/
event CurveMultiplierSet(bytes32 domainHash, uint256 curveMultiplier);


/**
* @notice Emitted when the full `CurvePriceConfig` is set in state
* @param maxPrice The new `maxPrice` value
* @param minPrice The new `minPrice` value
* @param curveMultiplier The new `curveMultiplier` value
* @param maxLength The new `maxLength` value
* @param baseLength The new `baseLength` value
* @param precisionMultiplier The new `precisionMultiplier` value
*/
event PriceConfigSet(
bytes32 domainHash,
uint256 maxPrice,
uint256 minPrice,
uint256 curveMultiplier,
uint256 maxLength,
uint256 baseLength,
uint256 precisionMultiplier,
Expand Down Expand Up @@ -111,12 +101,12 @@ interface IZNSCurvePricer is ICurvePriceConfig, IZNSPricer {

function setMaxPrice(bytes32 domainHash, uint256 maxPrice) external;

function setMinPrice(bytes32 domainHash, uint256 minPrice) external;

function setBaseLength(bytes32 domainHash, uint256 length) external;

function setMaxLength(bytes32 domainHash, uint256 length) external;

function setCurveMultiplier(bytes32 domainHash, uint256 curveMultiplier) external;

function setPrecisionMultiplier(bytes32 domainHash, uint256 multiplier) external;

function setFeePercentage(bytes32 domainHash, uint256 feePercentage) external;
Expand Down
219 changes: 138 additions & 81 deletions contracts/price/ZNSCurvePricer.sol

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions contracts/registrar/IZNSSubRegistrar.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import { IZNSPricer } from "../types/IZNSPricer.sol";
*/
interface IZNSSubRegistrar is IDistributionConfig {
/**
* @notice Reverted when someone other than parent owner is trying to buy
a subdomain under the parent that is locked\
* @notice Reverted when someone other than parent owner is trying to buy a subdomain
* under the parent that is locked
* or when the parent provided does not exist.
*/
error ParentLockedOrDoesntExist(bytes32 parentHash);
Expand Down
10 changes: 5 additions & 5 deletions contracts/types/ICurvePriceConfig.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ pragma solidity 0.8.26;
* @dev **`CurvePriceConfig` struct properties:**
*
* - `maxPrice` (uint256): Maximum price for a domain returned at <= `baseLength`
* - `minPrice` (uint256): Minimum price for a domain returned at > `maxLength`
* - `maxLength` (uint256): Maximum length of a domain name. If the name is longer - we return the `minPrice`
* - `maxLength` (uint256): Maximum length of a domain name. If the name is longer -
* we return the price that was at the `maxLength`.
* - `baseLength` (uint256): Base length of a domain name. If the name is shorter or equal - we return the `maxPrice`
* - `precisionMultiplier` (uint256): The precision multiplier of the price. This multiplier
* should be picked based on the number of token decimals to calculate properly.
Expand All @@ -25,12 +25,12 @@ interface ICurvePriceConfig {
*/
uint256 maxPrice;
/**
* @notice Minimum price for a domain returned at > `maxLength`
* @notice Multiplier which we use to bend a curve of price on interval from `baseLength` to `maxLength`.
*/
uint256 minPrice;
uint256 curveMultiplier;
/**
* @notice Maximum length of a domain name. If the name is longer than this
* value we return the `minPrice`
* value we return the price that was at the `maxLength`
*/
uint256 maxLength;
/**
Expand Down
10 changes: 10 additions & 0 deletions contracts/types/IZNSPricer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ interface IZNSPricer {
*/
error FeePercentageValueTooLarge(uint256 feePercentage, uint256 maximum);

/**
* @notice Reverted when `maxLength` smaller than `baseLength`.
*/
error MaxLengthSmallerThanBaseLength(bytes32 domainHash);

/**
* @notice Reverted when `curveMultiplier` AND `baseLength` are 0.
*/
error DivisionByZero(bytes32 domainHash);

/**
* @dev `parentHash` param is here to allow pricer contracts
* to have different price configs for different subdomains
Expand Down
16 changes: 9 additions & 7 deletions src/deploy/campaign/environments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,12 @@ export const getConfig = async ({
domainToken: {
name: process.env.DOMAIN_TOKEN_NAME ? process.env.DOMAIN_TOKEN_NAME : ZNS_DOMAIN_TOKEN_NAME,
symbol: process.env.DOMAIN_TOKEN_SYMBOL ? process.env.DOMAIN_TOKEN_SYMBOL : ZNS_DOMAIN_TOKEN_SYMBOL,
defaultRoyaltyReceiver: royaltyReceiver,
defaultRoyaltyReceiver: royaltyReceiver!,
defaultRoyaltyFraction: royaltyFraction,
},
rootPriceConfig: priceConfig,
zeroVaultAddress: zeroVaultAddressConf,
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
zeroVaultAddress: zeroVaultAddressConf!,
mockMeowToken: process.env.MOCK_MEOW_TOKEN === "true",
stakingTokenAddress: process.env.STAKING_TOKEN_ADDRESS!,
postDeploy: {
Expand Down Expand Up @@ -211,10 +212,10 @@ const getValidateRootPriceConfig = () => {
? ethers.parseEther(process.env.MAX_PRICE)
: DEFAULT_PRICE_CONFIG.maxPrice;

const minPrice =
process.env.MIN_PRICE
? ethers.parseEther(process.env.MIN_PRICE)
: DEFAULT_PRICE_CONFIG.minPrice;
const curveMultiplier =
process.env.curveMultiplier
? process.env.curveMultiplier
: DEFAULT_PRICE_CONFIG.curveMultiplier;

const maxLength =
process.env.MAX_LENGTH
Expand All @@ -237,7 +238,7 @@ const getValidateRootPriceConfig = () => {

const priceConfig : ICurvePriceConfig = {
maxPrice,
minPrice,
curveMultiplier: BigInt(curveMultiplier),
maxLength,
baseLength,
precisionMultiplier,
Expand All @@ -257,6 +258,7 @@ const requires = (condition : boolean, message : string) => {
};

// No price spike before `minPrice` kicks in at `maxLength`
// TODO: do we still need this?
const validatePrice = (config : ICurvePriceConfig) => {
MichaelKorchagin marked this conversation as resolved.
Show resolved Hide resolved
const strA = "a".repeat(Number(config.maxLength));
const strB = "b".repeat(Number(config.maxLength + 1n));
Expand Down
2 changes: 1 addition & 1 deletion src/deploy/missions/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

export interface ICurvePriceConfig {
maxPrice : bigint;
minPrice : bigint;
curveMultiplier : bigint;
maxLength : bigint;
baseLength : bigint;
precisionMultiplier : bigint;
Expand Down
23 changes: 0 additions & 23 deletions test/DeployCampaignInt.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import {
INVALID_ENV_ERR,
NO_MOCK_PROD_ERR,
STAKING_TOKEN_ERR,
INVALID_CURVE_ERR,
MONGO_URI_ERR,
} from "./helpers";
import {
Expand Down Expand Up @@ -796,28 +795,6 @@ describe("Deploy Campaign Test", () => {
}
});

it("Fails to validate if invalid curve for pricing", async () => {
process.env.MOCK_MEOW_TOKEN = "false";
process.env.STAKING_TOKEN_ADDRESS = MeowMainnet.address;
process.env.BASE_LENGTH = "3";
process.env.MAX_LENGTH = "5";
process.env.MAX_PRICE = "0";
process.env.MIN_PRICE = ethers.parseEther("3").toString();

try {
await getConfig({
env: "prod",
deployer: deployAdmin,
zeroVaultAddress: zeroVault.address,
governors: [deployAdmin.address, governor.address],
admins: [deployAdmin.address, admin.address],
});
/* eslint-disable @typescript-eslint/no-explicit-any */
} catch (e : any) {
expect(e.message).includes(INVALID_CURVE_ERR);
}
});

it("Fails to validate if no mongo uri or local URI in prod", async () => {
process.env.MOCK_MEOW_TOKEN = "false";
process.env.STAKING_TOKEN_ADDRESS = MeowMainnet.address;
Expand Down
Loading