UNPKG

@swaptoshi/dex-module

Version:

Klayr decentralized exchange (dex) on-chain module

361 lines 22.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DexModule = void 0; const klayr_framework_1 = require("klayr-framework"); const codec_1 = require("@klayr/codec"); const validator = require("@klayr/validator"); const cc_method_1 = require("./cc_method"); const burn_command_1 = require("./commands/burn_command"); const collect_command_1 = require("./commands/collect_command"); const collect_treasury_command_1 = require("./commands/collect_treasury_command"); const create_pool_command_1 = require("./commands/create_pool_command"); const decrease_liquidity_command_1 = require("./commands/decrease_liquidity_command"); const exact_input_command_1 = require("./commands/exact_input_command"); const exact_input_single_command_1 = require("./commands/exact_input_single_command"); const exact_output_command_1 = require("./commands/exact_output_command"); const exact_output_single_command_1 = require("./commands/exact_output_single_command"); const increase_liquidity_command_1 = require("./commands/increase_liquidity_command"); const mint_command_1 = require("./commands/mint_command"); const treasurify_command_1 = require("./commands/treasurify_command"); const config_1 = require("./config"); const endpoint_1 = require("./endpoint"); const burn_1 = require("./events/burn"); const collect_1 = require("./events/collect"); const collect_position_1 = require("./events/collect_position"); const collect_protocol_1 = require("./events/collect_protocol"); const decrease_liquidity_1 = require("./events/decrease_liquidity"); const flash_1 = require("./events/flash"); const increase_liquidity_1 = require("./events/increase_liquidity"); const increase_observation_cardinality_next_1 = require("./events/increase_observation_cardinality_next"); const mint_1 = require("./events/mint"); const pool_created_1 = require("./events/pool_created"); const pool_initialized_1 = require("./events/pool_initialized"); const swap_1 = require("./events/swap"); const tokenuri_created_1 = require("./events/tokenuri_created"); const tokenuri_destroyed_1 = require("./events/tokenuri_destroyed"); const token_registered_1 = require("./events/token_registered"); const treasurify_1 = require("./events/treasurify"); const hooks_1 = require("./hooks"); const method_1 = require("./method"); const schema_1 = require("./schema"); const observation_1 = require("./stores/observation"); const pool_1 = require("./stores/pool"); const position_info_1 = require("./stores/position_info"); const position_manager_1 = require("./stores/position_manager"); const supported_token_1 = require("./stores/supported_token"); const tick_bitmap_1 = require("./stores/tick_bitmap"); const tick_info_1 = require("./stores/tick_info"); const token_symbol_1 = require("./stores/token_symbol"); const constants_1 = require("./constants"); class DexModule extends klayr_framework_1.Modules.Interoperability.BaseInteroperableModule { constructor() { super(); this._config = new config_1.DexGovernableConfig(this.name, constants_1.STORE_INDEX_MODULE_CONFIG); this._dexInteroperableMethod = new cc_method_1.DexInteroperableMethod(this.stores, this.events); this.crossChainCommand = []; this.crossChainMethod = this._dexInteroperableMethod; this.endpoint = new endpoint_1.DexEndpoint(this.stores, this.offchainStores); this.method = new method_1.DexMethod(this.stores, this.events); this.commands = [ new create_pool_command_1.CreatePoolCommand(this.stores, this.events), new mint_command_1.MintCommand(this.stores, this.events), new increase_liquidity_command_1.IncreaseLiquidityCommand(this.stores, this.events), new decrease_liquidity_command_1.DecreaseLiquidityCommand(this.stores, this.events), new collect_command_1.CollectCommand(this.stores, this.events), new burn_command_1.BurnCommand(this.stores, this.events), new exact_input_command_1.ExactInputCommand(this.stores, this.events), new exact_input_single_command_1.ExactInputSingleCommand(this.stores, this.events), new exact_output_command_1.ExactOutputCommand(this.stores, this.events), new exact_output_single_command_1.ExactOutputSingleCommand(this.stores, this.events), new treasurify_command_1.TreasurifyCommand(this.stores, this.events), new collect_treasury_command_1.CollectTreasuryCommand(this.stores, this.events), ]; this.stores.register(pool_1.PoolStore, new pool_1.PoolStore(this.name, constants_1.STORE_INDEX_POOL, this.stores, this.events)); this.stores.register(position_manager_1.PositionManagerStore, new position_manager_1.PositionManagerStore(this.name, constants_1.STORE_INDEX_POSITION_MANAGER, this.stores, this.events)); this.stores.register(observation_1.ObservationStore, new observation_1.ObservationStore(this.name, constants_1.STORE_INDEX_OBSERVATION)); this.stores.register(position_info_1.PositionInfoStore, new position_info_1.PositionInfoStore(this.name, constants_1.STORE_INDEX_POSITION_INFO)); this.stores.register(tick_bitmap_1.TickBitmapStore, new tick_bitmap_1.TickBitmapStore(this.name, constants_1.STORE_INDEX_TICK_BITMAP)); this.stores.register(tick_info_1.TickInfoStore, new tick_info_1.TickInfoStore(this.name, constants_1.STORE_INDEX_TICK_INFO)); this.stores.register(token_symbol_1.TokenSymbolStore, new token_symbol_1.TokenSymbolStore(this.name, constants_1.STORE_INDEX_TOKEN_SYMBOL, this.events)); this.stores.register(supported_token_1.SupportedTokenStore, new supported_token_1.SupportedTokenStore(this.name, constants_1.STORE_INDEX_SUPPORTED_TOKEN)); this.stores.register(config_1.DexGovernableConfig, this._config); this.events.register(burn_1.BurnEvent, new burn_1.BurnEvent(this.name)); this.events.register(collect_position_1.CollectPositionEvent, new collect_position_1.CollectPositionEvent(this.name)); this.events.register(collect_protocol_1.CollectProtocolEvent, new collect_protocol_1.CollectProtocolEvent(this.name)); this.events.register(collect_1.CollectEvent, new collect_1.CollectEvent(this.name)); this.events.register(decrease_liquidity_1.DecreaseLiquidityEvent, new decrease_liquidity_1.DecreaseLiquidityEvent(this.name)); this.events.register(flash_1.FlashEvent, new flash_1.FlashEvent(this.name)); this.events.register(increase_liquidity_1.IncreaseLiquidityEvent, new increase_liquidity_1.IncreaseLiquidityEvent(this.name)); this.events.register(increase_observation_cardinality_next_1.IncreaseObservationCardinalityNextEvent, new increase_observation_cardinality_next_1.IncreaseObservationCardinalityNextEvent(this.name)); this.events.register(mint_1.MintEvent, new mint_1.MintEvent(this.name)); this.events.register(pool_created_1.PoolCreatedEvent, new pool_created_1.PoolCreatedEvent(this.name)); this.events.register(pool_initialized_1.PoolInitializedEvent, new pool_initialized_1.PoolInitializedEvent(this.name)); this.events.register(swap_1.SwapEvent, new swap_1.SwapEvent(this.name)); this.events.register(tokenuri_created_1.TokenURICreatedEvent, new tokenuri_created_1.TokenURICreatedEvent(this.name)); this.events.register(tokenuri_destroyed_1.TokenURIDestroyedEvent, new tokenuri_destroyed_1.TokenURIDestroyedEvent(this.name)); this.events.register(treasurify_1.TreasurifyEvent, new treasurify_1.TreasurifyEvent(this.name)); this.events.register(token_registered_1.TokenRegisteredEvent, new token_registered_1.TokenRegisteredEvent(this.name)); } get name() { return constants_1.MODULE_NAME_DEX; } addDependencies(dependencies) { const poolStore = this.stores.get(pool_1.PoolStore); const positionManagerStore = this.stores.get(position_manager_1.PositionManagerStore); const supportManagerStore = this.stores.get(supported_token_1.SupportedTokenStore); poolStore.addDependencies(dependencies.tokenMethod); positionManagerStore.addDependencies(dependencies.tokenMethod, dependencies.nftMethod); supportManagerStore.addDependencies(dependencies.tokenMethod); this._feeMethod = dependencies.feeMethod; this._tokenMethod = dependencies.tokenMethod; this._governanceMethod = dependencies.governanceMethod; this._dexInteroperableMethod.addDependencies(dependencies.interoperabilityMethod, dependencies.tokenMethod, dependencies.nftMethod); this._config.addDependencies(this.stores, dependencies.feeConversionMethod); if (dependencies.feeConversionMethod) { this._feeConversionMethod = dependencies.feeConversionMethod; this._feeConversionMethod.addDependencies(dependencies.tokenMethod, dependencies.feeMethod); } } metadata() { return { ...this.baseMetadata(), endpoints: [ { name: this.endpoint.getConfig.name, request: schema_1.getConfigEndpointRequestSchema, response: schema_1.getConfigEndpointResponseSchema, }, { name: this.endpoint.getPool.name, request: schema_1.getPoolEndpointRequestSchema, response: schema_1.getPoolEndpointResponseSchema, }, { name: this.endpoint.getPosition.name, request: schema_1.getPositionEndpointRequestSchema, response: schema_1.getPositionEndpointResponseSchema, }, { name: this.endpoint.getTokenURI.name, request: schema_1.getTokenURIEndpointRequestSchema, response: schema_1.getTokenURIEndpointResponseSchema, }, { name: this.endpoint.getPoolAddressFromCollectionId.name, request: schema_1.getPoolAddressFromCollectionIdEndpointRequestSchema, response: schema_1.getPoolAddressFromCollectionIdEndpointResponseSchema, }, { name: this.endpoint.getMetadata.name, request: schema_1.getMetadataEndpointRequestSchema, response: schema_1.getMetadataEndpointResponseSchema, }, { name: this.endpoint.observe.name, request: schema_1.observeEndpointRequestSchema, response: schema_1.observeEndpointResponseSchema, }, { name: this.endpoint.quoteExactInput.name, request: schema_1.quoteExactInputEndpointRequestSchema, response: schema_1.quoteExactInputEndpointResponseSchema, }, { name: this.endpoint.quoteExactInputSingle.name, request: schema_1.quoteExactInputSingleEndpointRequestSchema, response: schema_1.quoteExactInputSingleEndpointResponseSchema, }, { name: this.endpoint.quoteExactOutput.name, request: schema_1.quoteExactOutputEndpointRequestSchema, response: schema_1.quoteExactOutputEndpointResponseSchema, }, { name: this.endpoint.quoteExactOutputSingle.name, request: schema_1.quoteExactOutputSingleEndpointRequestSchema, response: schema_1.quoteExactOutputSingleEndpointResponseSchema, }, { name: this.endpoint.quotePrice.name, request: schema_1.quotePriceEndpointRequestSchema, response: schema_1.quotePriceEndpointResponseSchema, }, ], assets: [ { version: 0, data: schema_1.dexGenesisStoreSchema, }, ], }; } async init(_args) { const poolStore = this.stores.get(pool_1.PoolStore); const positionManagerStore = this.stores.get(position_manager_1.PositionManagerStore); const supportedTokenStore = this.stores.get(supported_token_1.SupportedTokenStore); const tokenSymbolStore = this.stores.get(token_symbol_1.TokenSymbolStore); poolStore.init(this._config); positionManagerStore.init(_args.genesisConfig, this._config); supportedTokenStore.init(this._config); tokenSymbolStore.init(_args.genesisConfig, this._config); if (this._governanceMethod) { this._governanceMethod.registerGovernableConfig(_args, this.name, this._config); } else { this._config.init(_args); } if (!this._tokenMethod || !this._feeMethod) { throw new Error('dex module dependencies is not configured, make sure DexModule.addDependencies() is called before module registration'); } } async verifyTransaction(_context) { try { await hooks_1.verifyMinimumFee.bind(this)(_context); await hooks_1.verifyBaseFee.bind(this)(_context); await hooks_1.verifyValidTransfer.bind(this)(_context); await hooks_1.verifySwapByTransfer.bind(this)(_context); } catch (error) { return { status: klayr_framework_1.StateMachine.VerifyStatus.FAIL, error: new Error(error.message), }; } return { status: klayr_framework_1.StateMachine.VerifyStatus.OK }; } async beforeCommandExecute(_context) { await hooks_1.verifyMinimumFee.bind(this)(_context); await hooks_1.verifyBaseFee.bind(this)(_context); await hooks_1.verifyValidTransfer.bind(this)(_context); await hooks_1.verifySwapByTransfer.bind(this)(_context); await hooks_1.executeBaseFee.bind(this)(_context); } async afterCommandExecute(_context) { await hooks_1.executeSwapByTransfer.bind(this)(_context); } async beforeTransactionsExecute(context) { await this.stores.get(supported_token_1.SupportedTokenStore).apply(context); } async initGenesisState(context) { const assetBytes = context.assets.getAsset(this.name); if (!assetBytes) return; const genesisStore = codec_1.codec.decode(schema_1.dexGenesisStoreSchema, assetBytes); validator.validator.validate(schema_1.dexGenesisStoreSchema, genesisStore); const observationStore = this.stores.get(observation_1.ObservationStore); const copiedObservationStore = [...genesisStore.observationSubstore]; copiedObservationStore.sort((a, b) => { if (!a.poolAddress.equals(b.poolAddress)) return a.poolAddress.compare(b.poolAddress); return parseInt(a.index, 10) - parseInt(b.index, 10); }); for (let i = 0; i < genesisStore.observationSubstore.length; i += 1) { const observationData = genesisStore.observationSubstore[i]; if (!observationData.poolAddress.equals(copiedObservationStore[i].poolAddress) || observationData.index !== copiedObservationStore[i].index) { throw new Error('observationSubstore must be sorted by poolAddress and index.'); } await observationStore.set(context, observationStore.getKey(observationData.poolAddress, observationData.index), observationData); } const poolStore = this.stores.get(pool_1.PoolStore); const copiedPoolStore = [...genesisStore.poolSubstore]; copiedPoolStore.sort((a, b) => { if (!a.token0.equals(b.token0)) return a.token0.compare(b.token0); if (!a.token1.equals(b.token1)) return a.token1.compare(b.token1); return parseInt(a.fee, 10) - parseInt(b.fee, 10); }); for (let i = 0; i < genesisStore.poolSubstore.length; i += 1) { const poolData = genesisStore.poolSubstore[i]; if (!poolData.token0.equals(copiedPoolStore[i].token0) || !poolData.token1.equals(copiedPoolStore[i].token1) || poolData.fee !== copiedPoolStore[i].fee) { throw new Error('poolSubstore must be sorted by token0, token1, and fee'); } const poolAddress = poolStore.getKey(poolData.token0, poolData.token1, poolData.fee); await poolStore.set(context, poolAddress, poolData); } const positionInfoStore = this.stores.get(position_info_1.PositionInfoStore); const copiedPositionInfoSubstore = [...genesisStore.positionInfoSubstore]; copiedPositionInfoSubstore.sort((a, b) => { if (!a.poolAddress.equals(b.poolAddress)) return a.poolAddress.compare(b.poolAddress); if (!a.key.equals(b.key)) return a.key.compare(b.key); return 0; }); for (let i = 0; i < genesisStore.positionInfoSubstore.length; i += 1) { const positionInfoData = genesisStore.positionInfoSubstore[i]; if (!positionInfoData.poolAddress.equals(copiedPositionInfoSubstore[i].poolAddress) || !positionInfoData.key.equals(copiedPositionInfoSubstore[i].key)) { throw new Error('positionInfoSubstore must be sorted by poolAddress and key.'); } await positionInfoStore.set(context, positionInfoStore.getKey(positionInfoData.poolAddress, positionInfoData.key), positionInfoData); } const positionManagerStore = this.stores.get(position_manager_1.PositionManagerStore); const copiedPositionManagerSubstore = [...genesisStore.positionManagerSubstore]; copiedPositionManagerSubstore.sort((a, b) => a.poolAddress.compare(b.poolAddress)); for (let i = 0; i < genesisStore.positionManagerSubstore.length; i += 1) { const positionManagerData = genesisStore.positionManagerSubstore[i]; if (!positionManagerData.poolAddress.equals(copiedPositionManagerSubstore[i].poolAddress)) { throw new Error('positionManagerSubstore must be sorted by poolAddress.'); } await positionManagerStore.set(context, positionManagerStore.getKey(positionManagerData.poolAddress), positionManagerData); } const supportedTokenStore = this.stores.get(supported_token_1.SupportedTokenStore); const { supportedTokenSubstore } = genesisStore; if (supportedTokenSubstore.length > 0 && supportedTokenSubstore.length !== 1) { throw new Error('supportedTokenSubstore must have one element, if specified'); } if (supportedTokenSubstore.length === 1) { const supportedTokenData = supportedTokenSubstore[0]; const copiedSupportedTokenList = [...supportedTokenData.supported]; copiedSupportedTokenList.sort((a, b) => a.compare(b)); for (let i = 0; i < supportedTokenData.supported.length; i += 1) { if (!supportedTokenData.supported[i].equals(copiedSupportedTokenList[i])) { throw new Error('supportedTokenSubstore.supported must be sorted'); } } await supportedTokenStore.set(context, Buffer.alloc(0), supportedTokenData); } const tickBitmapStore = this.stores.get(tick_bitmap_1.TickBitmapStore); const copiedTickBitmapSubstore = [...genesisStore.tickBitmapSubstore]; copiedTickBitmapSubstore.sort((a, b) => { if (!a.poolAddress.equals(b.poolAddress)) { return a.poolAddress.compare(b.poolAddress); } return parseInt(a.index, 10) - parseInt(b.index, 10); }); for (let i = 0; i < genesisStore.tickBitmapSubstore.length; i += 1) { const tickBitmapData = genesisStore.tickBitmapSubstore[i]; if (!tickBitmapData.poolAddress.equals(copiedTickBitmapSubstore[i].poolAddress) || tickBitmapData.index !== copiedTickBitmapSubstore[i].index) { throw new Error('tickBitmapSubstore must be sorted by poolAddress and index.'); } await tickBitmapStore.set(context, tickBitmapStore.getKey(tickBitmapData.poolAddress, tickBitmapData.index), tickBitmapData); } const tickInfoStore = this.stores.get(tick_info_1.TickInfoStore); const copiedTickInfoSubstore = [...genesisStore.tickInfoSubstore]; copiedTickInfoSubstore.sort((a, b) => { if (!a.poolAddress.equals(b.poolAddress)) { return a.poolAddress.compare(b.poolAddress); } return parseInt(a.tick, 10) - parseInt(b.tick, 10); }); for (let i = 0; i < genesisStore.tickInfoSubstore.length; i += 1) { const tickInfoData = genesisStore.tickInfoSubstore[i]; if (!tickInfoData.poolAddress.equals(copiedTickInfoSubstore[i].poolAddress) || tickInfoData.tick !== copiedTickInfoSubstore[i].tick) { throw new Error('tickInfoSubstore must be sorted by poolAddress and tick.'); } await tickInfoStore.set(context, tickInfoStore.getKey(tickInfoData.poolAddress, tickInfoData.tick), tickInfoData); } const tokenSymbolStore = this.stores.get(token_symbol_1.TokenSymbolStore); const copiedTokenSymbolSubstore = [...genesisStore.tokenSymbolSubstore]; copiedTokenSymbolSubstore.sort((a, b) => a.tokenId.compare(b.tokenId)); for (let i = 0; i < genesisStore.tokenSymbolSubstore.length; i += 1) { const tokenSymbolData = genesisStore.tokenSymbolSubstore[i]; if (!tokenSymbolData.tokenId.equals(copiedTokenSymbolSubstore[i].tokenId)) { throw new Error('tokenSymbolSubstore must be sorted by tokenId.'); } await tokenSymbolStore.set(context, tokenSymbolStore.getKey(tokenSymbolData.tokenId), tokenSymbolData); } } } exports.DexModule = DexModule; //# sourceMappingURL=module.js.map