UNPKG

@anton-seriesfi/doppler-v3-sdk

Version:

SDK for interacting with Doppler v3 protocol

290 lines 11.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ReadWriteFactory = void 0; const drift_1 = require("@delvtech/drift"); const ReadFactory_1 = require("./ReadFactory"); const viem_1 = require("viem"); // Constants for default configuration values const ONE_YEAR_IN_SECONDS = 365 * 24 * 60 * 60; const DEFAULT_START_TICK = 167000; const DEFAULT_END_TICK = 200000; const DEFAULT_NUM_POSITIONS = 10; const DEFAULT_FEE = 10000; // 1% fee tier const DEFAULT_VESTING_DURATION = BigInt(ONE_YEAR_IN_SECONDS); const DEFAULT_INITIAL_SUPPLY_WAD = (0, viem_1.parseEther)("1000000000"); const DEFAULT_NUM_TOKENS_TO_SELL_WAD = (0, viem_1.parseEther)("900000000"); const DEFAULT_YEARLY_MINT_RATE_WAD = (0, viem_1.parseEther)("0.02"); const DEFAULT_PRE_MINT_WAD = (0, viem_1.parseEther)("9000000"); // 0.9% of the total supply const DEFAULT_MAX_SHARE_TO_BE_SOLD = (0, viem_1.parseEther)("0.35"); const DEFAULT_INITIAL_VOTING_DELAY = 7200; const DEFAULT_INITIAL_VOTING_PERIOD = 50400; const DEFAULT_INITIAL_PROPOSAL_THRESHOLD = BigInt(0); /** * Factory class for creating and managing Doppler V3 pools with read/write capabilities */ class ReadWriteFactory extends ReadFactory_1.ReadFactory { /** * Create a new ReadWriteFactory instance * @param address Contract address * @param drift Drift instance for blockchain interaction * @param defaultConfigs Optional default configurations */ constructor(address, drift = (0, drift_1.createDrift)(), defaultConfigs) { super(address, drift); /** * Generate a random salt using cryptographic random values * @param account User address to incorporate into salt * @returns Hex string of generated salt */ this.generateRandomSalt = (account) => { const array = new Uint8Array(32); // Cross-platform random generation if (typeof window !== "undefined" && window.crypto) { window.crypto.getRandomValues(array); } else { array.set(require("crypto").randomBytes(32)); } // Incorporate user address into salt if (account) { const addressBytes = account.slice(2).padStart(40, "0"); for (let i = 0; i < 20; i++) { const addressByte = parseInt(addressBytes.slice(i * 2, (i + 1) * 2), 16); array[i] ^= addressByte; } } return `0x${Array.from(array) .map((b) => b.toString(16).padStart(2, "0")) .join("")}`; }; // Initialize default configurations with fallback values this.defaultV3PoolConfig = defaultConfigs?.defaultV3PoolConfig ?? { startTick: DEFAULT_START_TICK, endTick: DEFAULT_END_TICK, numPositions: DEFAULT_NUM_POSITIONS, maxShareToBeSold: DEFAULT_MAX_SHARE_TO_BE_SOLD, fee: DEFAULT_FEE, }; this.defaultVestingConfig = defaultConfigs?.defaultVestingConfig ?? { yearlyMintRate: DEFAULT_YEARLY_MINT_RATE_WAD, vestingDuration: DEFAULT_VESTING_DURATION, recipients: [], amounts: [], }; this.defaultSaleConfig = defaultConfigs?.defaultSaleConfig ?? { initialSupply: DEFAULT_INITIAL_SUPPLY_WAD, numTokensToSell: DEFAULT_NUM_TOKENS_TO_SELL_WAD, }; this.defaultGovernanceConfig = defaultConfigs?.defaultGovernanceConfig ?? { initialVotingDelay: DEFAULT_INITIAL_VOTING_DELAY, initialVotingPeriod: DEFAULT_INITIAL_VOTING_PERIOD, initialProposalThreshold: DEFAULT_INITIAL_PROPOSAL_THRESHOLD, }; } /** * Merge user configuration with defaults * @param config User-provided partial configuration * @param defaults Full default configuration * @returns Merged configuration object */ mergeWithDefaults(config, defaults) { return { ...defaults, ...config }; } /** * Get merged sale configuration * @param saleConfig Optional partial sale config * @returns Complete SaleConfig */ getMergedSaleConfig(saleConfig) { return this.mergeWithDefaults(saleConfig, this.defaultSaleConfig); } /** * Get merged pool configuration * @param v3PoolConfig Optional partial pool config * @returns Complete V3PoolConfig */ getMergedV3PoolConfig(v3PoolConfig) { return this.mergeWithDefaults(v3PoolConfig, this.defaultV3PoolConfig); } /** * Get merged governance configuration * @param governanceConfig Optional partial governance config * @returns Complete GovernanceConfig */ getMergedGovernanceConfig(governanceConfig) { return this.mergeWithDefaults(governanceConfig, this.defaultGovernanceConfig); } /** * Get merged vesting configuration * @param config Vesting config or "default" preset * @param userAddress User address for default recipient * @returns Complete VestingConfig */ getMergedVestingConfig(config, userAddress) { const base = config === "default" ? this.defaultVestingConfig : config; return { ...base, recipients: config === "default" ? [userAddress] : [...base.recipients], amounts: config === "default" ? [DEFAULT_PRE_MINT_WAD] : [...base.amounts], }; } /** * Encode pool initialization data for contract calls * @param v3PoolConfig Complete pool configuration * @returns ABI-encoded initialization data */ encodePoolInitializerData(v3PoolConfig) { return (0, viem_1.encodeAbiParameters)([ { type: "uint24" }, { type: "int24" }, { type: "int24" }, { type: "uint16" }, { type: "uint256" }, ], [ v3PoolConfig.fee, v3PoolConfig.startTick, v3PoolConfig.endTick, v3PoolConfig.numPositions, v3PoolConfig.maxShareToBeSold, ]); } /** * Encode token factory initialization data * @param tokenConfig Token metadata * @param vestingConfig Vesting schedule * @returns ABI-encoded token factory data */ encodeTokenFactoryData(tokenConfig, vestingConfig) { return (0, viem_1.encodeAbiParameters)([ { type: "string" }, { type: "string" }, { type: "uint256" }, { type: "uint256" }, { type: "address[]" }, { type: "uint256[]" }, { type: "string" }, ], [ tokenConfig.name, tokenConfig.symbol, vestingConfig.yearlyMintRate, vestingConfig.vestingDuration, vestingConfig.recipients, vestingConfig.amounts, tokenConfig.tokenURI, ]); } /** * Encode governance factory initialization data * @param tokenConfig Token metadata * @returns ABI-encoded governance data */ encodeGovernanceFactoryData(tokenConfig, governanceConfig) { return (0, viem_1.encodeAbiParameters)([ { type: "string" }, { type: "uint48" }, { type: "uint32" }, { type: "uint256" }, ], [ tokenConfig.name, Number(governanceConfig.initialVotingDelay), Number(governanceConfig.initialVotingPeriod), governanceConfig.initialProposalThreshold, ]); } /** * Encode all parameters for pool creation * @param params CreateV3PoolParams input parameters * @returns Object containing create parameters and final pool config * @throws Error if user address is missing or invalid tick range */ encode(params) { const { userAddress, numeraire, integrator, contracts, tokenConfig } = params; if (!userAddress) { throw new Error("User address is required. Is a wallet connected?"); } // Merge configurations with defaults const vestingConfig = this.getMergedVestingConfig(params.vestingConfig, userAddress); const v3PoolConfig = this.getMergedV3PoolConfig(params.v3PoolConfig); const saleConfig = this.getMergedSaleConfig(params.saleConfig); const governanceConfig = this.getMergedGovernanceConfig(params.governanceConfig); // Validate tick configuration if (v3PoolConfig.startTick > v3PoolConfig.endTick) { throw new Error("Invalid start and end ticks. Start tick must be less than end tick."); } // Generate unique salt and encode contract data const salt = this.generateRandomSalt(userAddress); const governanceFactoryData = this.encodeGovernanceFactoryData(tokenConfig, governanceConfig); const tokenFactoryData = this.encodeTokenFactoryData(tokenConfig, vestingConfig); const poolInitializerData = this.encodePoolInitializerData(v3PoolConfig); const liquidityMigratorData = "0x"; // Prepare final arguments const { tokenFactory, governanceFactory, v3Initializer: poolInitializer, liquidityMigrator, } = contracts; const { initialSupply, numTokensToSell } = saleConfig; const args = { initialSupply, numTokensToSell, numeraire, tokenFactory, tokenFactoryData, governanceFactory, governanceFactoryData, poolInitializer, poolInitializerData, liquidityMigrator, liquidityMigratorData, integrator, salt, }; return { createParams: args, v3PoolConfig, }; } /** * Encode creation data with token order validation * @param params CreateV3PoolParams input parameters * @returns Finalized create parameters with adjusted ticks if needed */ async encodeCreateData(params) { let isToken0 = true; let createParams; let asset; while (isToken0) { const encoded = this.encode(params); createParams = encoded.createParams; const simulateResult = await this.simulateCreate(createParams); asset = simulateResult.asset; isToken0 = Number(asset) < Number(params.numeraire); } return createParams; } /** * Execute pool creation transaction * @param params Finalized create parameters * @param options Write options and mined handlers * @returns Transaction hash */ async create(params, options) { return this.airlock.write("create", { createData: params }, options); } /** * Simulate pool creation transaction * @param params Create parameters * @returns Simulation results */ async simulateCreate(params) { return this.airlock.simulateWrite("create", { createData: params }); } /** * Update default configurations * @param configs Partial configuration overrides */ updateDefaultConfigs(configs) { this.defaultV3PoolConfig = this.mergeWithDefaults(configs.defaultV3PoolConfig || {}, this.defaultV3PoolConfig); this.defaultVestingConfig = this.mergeWithDefaults(configs.defaultVestingConfig || {}, this.defaultVestingConfig); this.defaultSaleConfig = this.mergeWithDefaults(configs.defaultSaleConfig || {}, this.defaultSaleConfig); this.defaultGovernanceConfig = this.mergeWithDefaults(configs.defaultGovernanceConfig || {}, this.defaultGovernanceConfig); } } exports.ReadWriteFactory = ReadWriteFactory; //# sourceMappingURL=ReadWriteFactory.js.map