@swaptoshi/dex-module
Version:
Klayr decentralized exchange (dex) on-chain module
361 lines • 22.3 kB
JavaScript
"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