diff --git a/framework/src/modules/token/endpoint.ts b/framework/src/modules/token/endpoint.ts index 73214281e20..d9ae76e48d3 100644 --- a/framework/src/modules/token/endpoint.ts +++ b/framework/src/modules/token/endpoint.ts @@ -16,25 +16,27 @@ import { validator } from '@liskhq/lisk-validator'; import * as cryptography from '@liskhq/lisk-cryptography'; import { NotFoundError } from '../../state_machine'; import { JSONObject, ModuleEndpointContext } from '../../types'; +import { ModuleConfig } from './types'; import { BaseEndpoint } from '../base_endpoint'; -import { TokenMethod } from './method'; -import { LOCAL_ID_LENGTH, TOKEN_ID_LENGTH } from './constants'; +import { CHAIN_ID_LENGTH, TOKEN_ID_LENGTH } from './constants'; import { getBalanceRequestSchema, getBalancesRequestSchema, + isSupportedRequestSchema, SupplyStoreData, UserStoreData, } from './schemas'; import { EscrowStore, EscrowStoreData } from './stores/escrow'; import { SupplyStore } from './stores/supply'; import { UserStore } from './stores/user'; -import { splitTokenID } from './utils'; - -const CHAIN_ID_ALIAS_NATIVE = Buffer.from([0, 0, 0, 1]); +import { SupportedTokensStore } from './stores/supported_tokens'; export class TokenEndpoint extends BaseEndpoint { - // eslint-disable-next-line @typescript-eslint/no-empty-function - public init(_tokenMethod: TokenMethod) {} + private _moduleConfig!: ModuleConfig; + + public init(moduleConfig: ModuleConfig) { + this._moduleConfig = moduleConfig; + } public async getBalances( context: ModuleEndpointContext, @@ -93,30 +95,69 @@ export class TokenEndpoint extends BaseEndpoint { context: ModuleEndpointContext, ): Promise<{ totalSupply: JSONObject[] }> { const supplyStore = this.stores.get(SupplyStore); - const supplyData = await supplyStore.iterate(context, { - gte: Buffer.concat([Buffer.alloc(LOCAL_ID_LENGTH, 0)]), - lte: Buffer.concat([Buffer.alloc(LOCAL_ID_LENGTH, 255)]), - }); + const supplyData = await supplyStore.getAll(context); return { - totalSupply: supplyData.map(({ key: localID, value: supply }) => ({ - tokenID: Buffer.concat([CHAIN_ID_ALIAS_NATIVE, localID]).toString('hex'), + totalSupply: supplyData.map(({ key: tokenID, value: supply }) => ({ + tokenID: tokenID.toString('hex'), totalSupply: supply.totalSupply.toString(), })), }; } - // TODO: Update to use SupportedTokensStore #7579 - // eslint-disable-next-line @typescript-eslint/require-await public async getSupportedTokens( - _context: ModuleEndpointContext, - ): Promise<{ tokenIDs: string[] }> { - return { - tokenIDs: [], - }; + context: ModuleEndpointContext, + ): Promise<{ supportedTokens: string[] }> { + const supportedTokensStore = this.stores.get(SupportedTokensStore); + + if (await supportedTokensStore.allSupported(context)) { + return { + supportedTokens: ['*'], + }; + } + + const supportedTokens: string[] = []; + + // main chain token + const mainchainTokenID = Buffer.concat([ + context.chainID.slice(0, 1), + Buffer.alloc(TOKEN_ID_LENGTH - 1, 0), + ]); + supportedTokens.push(mainchainTokenID.toString('hex')); + + // native chain tokens + const supplyStore = this.stores.get(SupplyStore); + const supplyData = await supplyStore.getAll(context); + + for (const tokenSupply of supplyData) { + supportedTokens.push(tokenSupply.key.toString('hex')); + } + + // foreign chain tokens + const supportedTokensData = await supportedTokensStore.getAll(context); + + for (const supportedToken of supportedTokensData) { + if (!supportedToken.value.supportedTokenIDs.length) { + supportedTokens.push(`${supportedToken.key.toString('hex')}${'********'}`); // key in supported token store is 4-byte chain ID + } else { + for (const token of supportedToken.value.supportedTokenIDs) { + supportedTokens.push(token.toString('hex')); + } + } + } + + return { supportedTokens }; + } + + public async isSupported(context: ModuleEndpointContext) { + validator.validate<{ tokenID: string }>(isSupportedRequestSchema, context.params); + + const tokenID = Buffer.from(context.params.tokenID, 'hex'); + const supportedTokensStore = this.stores.get(SupportedTokensStore); + + return { supported: await supportedTokensStore.isSupported(context, tokenID) }; } - // eslint-disable-next-line @typescript-eslint/require-await public async getEscrowedAmounts( context: ModuleEndpointContext, ): Promise<{ @@ -129,13 +170,21 @@ export class TokenEndpoint extends BaseEndpoint { }); return { escrowedAmounts: escrowData.map(({ key, value: escrow }) => { - const [escrowChainID, localID] = splitTokenID(key); + const escrowChainID = key.slice(0, CHAIN_ID_LENGTH); + const tokenID = key.slice(CHAIN_ID_LENGTH); return { escrowChainID: escrowChainID.toString('hex'), amount: escrow.amount.toString(), - tokenID: Buffer.concat([CHAIN_ID_ALIAS_NATIVE, localID]).toString('hex'), + tokenID: tokenID.toString('hex'), }; }), }; } + + public getInitializationFees() { + return { + userAccount: this._moduleConfig.userAccountInitializationFee.toString(), + escrowAccount: this._moduleConfig.escrowAccountInitializationFee.toString(), + }; + } } diff --git a/framework/src/modules/token/module.ts b/framework/src/modules/token/module.ts index c405a63f341..277bcdcfb3d 100644 --- a/framework/src/modules/token/module.ts +++ b/framework/src/modules/token/module.ts @@ -25,13 +25,16 @@ import { getBalanceRequestSchema, getBalanceResponseSchema, getBalancesRequestSchema, + getBalancesResponseSchema, getEscrowedAmountsResponseSchema, getSupportedTokensResponseSchema, + isSupportedRequestSchema, + isSupportedResponseSchema, getTotalSupplyResponseSchema, } from './schemas'; import { TokenMethod } from './method'; import { TokenEndpoint } from './endpoint'; -import { GenesisTokenStore, InteroperabilityMethod, ModuleConfigJSON } from './types'; +import { GenesisTokenStore, InteroperabilityMethod, ModuleConfig, ModuleConfigJSON } from './types'; import { splitTokenID } from './utils'; import { CCTransferCommand } from './commands/cc_transfer'; import { BaseInteroperableModule } from '../interoperability/base_interoperable_module'; @@ -126,7 +129,7 @@ export class TokenModule extends BaseInteroperableModule { { name: this.endpoint.getBalances.name, request: getBalancesRequestSchema, - response: getBalancesRequestSchema, + response: getBalancesResponseSchema, }, { name: this.endpoint.getTotalSupply.name, @@ -136,6 +139,11 @@ export class TokenModule extends BaseInteroperableModule { name: this.endpoint.getSupportedTokens.name, response: getSupportedTokensResponseSchema, }, + { + name: this.endpoint.isSupported.name, + request: isSupportedRequestSchema, + response: isSupportedResponseSchema, + }, { name: this.endpoint.getEscrowedAmounts.name, response: getEscrowedAmountsResponseSchema, @@ -163,29 +171,30 @@ export class TokenModule extends BaseInteroperableModule { const { moduleConfig, genesisConfig } = args; this._ownChainID = Buffer.from(genesisConfig.chainID, 'hex'); - const config = objects.mergeDeep( + const rawConfig = objects.mergeDeep( {}, defaultConfig, { feeTokenID: Buffer.concat([this._ownChainID, Buffer.alloc(4, 0)]).toString('hex') }, moduleConfig, ) as ModuleConfigJSON; - validator.validate(configSchema, config); + validator.validate(configSchema, rawConfig); + + const config: ModuleConfig = { + userAccountInitializationFee: BigInt(rawConfig.userAccountInitializationFee), + escrowAccountInitializationFee: BigInt(rawConfig.escrowAccountInitializationFee), + feeTokenID: Buffer.from(rawConfig.feeTokenID, 'hex'), + }; this.stores.get(SupportedTokensStore).registerOwnChainID(this._ownChainID); this.crossChainTransferCommand.init({ ownChainID: this._ownChainID }); - this.method.init({ - ownChainID: this._ownChainID, - escrowAccountInitializationFee: BigInt('50000000'), - feeTokenID: Buffer.from(config.feeTokenID, 'hex'), - userAccountInitializationFee: BigInt('50000000'), - }); + this.method.init({ ...config, ownChainID: this._ownChainID }); this.crossChainMethod.init(this._ownChainID); - this.endpoint.init(this.method); + this.endpoint.init(config); this._transferCommand.init({ method: this.method, - accountInitializationFee: BigInt(config.userAccountInitializationFee), - feeTokenID: Buffer.from(config.feeTokenID, 'hex'), + accountInitializationFee: config.userAccountInitializationFee, + feeTokenID: config.feeTokenID, }); } diff --git a/framework/src/modules/token/schemas.ts b/framework/src/modules/token/schemas.ts index a7009c3135f..8b5372ec239 100644 --- a/framework/src/modules/token/schemas.ts +++ b/framework/src/modules/token/schemas.ts @@ -619,3 +619,28 @@ export const getEscrowedAmountsResponseSchema = { }, }, }; + +export const isSupportedRequestSchema = { + $id: '/token/endpoint/isSupportedRequest', + type: 'object', + properties: { + tokenID: { + type: 'string', + format: 'hex', + minLength: TOKEN_ID_LENGTH * 2, + maxLength: TOKEN_ID_LENGTH * 2, + }, + }, + required: ['tokenID'], +}; + +export const isSupportedResponseSchema = { + $id: '/token/endpoint/isSupportedResponse', + type: 'object', + properties: { + supported: { + dataType: 'boolean', + }, + }, + required: ['supported'], +}; diff --git a/framework/src/modules/token/stores/supported_tokens.ts b/framework/src/modules/token/stores/supported_tokens.ts index c0b6fcaaf41..528fba2e9cc 100644 --- a/framework/src/modules/token/stores/supported_tokens.ts +++ b/framework/src/modules/token/stores/supported_tokens.ts @@ -37,7 +37,7 @@ export const supportedTokensStoreSchema = { }, }; -export const ALL_SUPPORTED_TOKENS_KEY = Buffer.from([0, 0, 0, 0]); +export const ALL_SUPPORTED_TOKENS_KEY = Buffer.alloc(0); export class SupportedTokensStore extends BaseStore { public schema = supportedTokensStoreSchema; @@ -77,25 +77,25 @@ export class SupportedTokensStore extends BaseStore { return false; } - public async removeAll(context: StoreGetter): Promise { - // check if exist - const allSupportedTokens = await this.iterate(context, { - gte: Buffer.alloc(4, 0), - lte: Buffer.alloc(4, 255), + public async getAll( + context: ImmutableStoreGetter, + ): Promise<{ key: Buffer; value: SupportedTokensStoreData }[]> { + return this.iterate(context, { + gte: Buffer.alloc(TOKEN_ID_LENGTH, 0), + lte: Buffer.alloc(TOKEN_ID_LENGTH, 255), }); + } + + public async removeAll(context: StoreGetter): Promise { + const allSupportedTokens = await this.getAll(context); + for (const { key } of allSupportedTokens) { await this.del(context, key); } } public async supportAll(context: StoreGetter): Promise { - const allSupportedTokens = await this.iterate(context, { - gte: Buffer.alloc(4, 0), - lte: Buffer.alloc(4, 255), - }); - for (const { key } of allSupportedTokens) { - await this.del(context, key); - } + await this.removeAll(context); await this.set(context, ALL_SUPPORTED_TOKENS_KEY, { supportedTokenIDs: [] }); } diff --git a/framework/test/unit/modules/token/endpoint.spec.ts b/framework/test/unit/modules/token/endpoint.spec.ts index 3cf8d6a461f..794fb5c962d 100644 --- a/framework/test/unit/modules/token/endpoint.spec.ts +++ b/framework/test/unit/modules/token/endpoint.spec.ts @@ -13,11 +13,15 @@ */ import { address, utils } from '@liskhq/lisk-cryptography'; import { TokenMethod, TokenModule } from '../../../../src/modules/token'; -import { CHAIN_ID_LENGTH } from '../../../../src/modules/token/constants'; +import { + USER_SUBSTORE_INITIALIZATION_FEE, + ESCROW_SUBSTORE_INITIALIZATION_FEE, +} from '../../../../src/modules/token/constants'; import { TokenEndpoint } from '../../../../src/modules/token/endpoint'; import { EscrowStore } from '../../../../src/modules/token/stores/escrow'; import { SupplyStore } from '../../../../src/modules/token/stores/supply'; import { UserStore } from '../../../../src/modules/token/stores/user'; +import { SupportedTokensStore } from '../../../../src/modules/token/stores/supported_tokens'; import { MethodContext } from '../../../../src/state_machine'; import { PrefixedStateReadWriter } from '../../../../src/state_machine/prefixed_state_read_writer'; import { @@ -25,13 +29,18 @@ import { createTransientModuleEndpointContext, } from '../../../../src/testing'; import { InMemoryPrefixedStateDB } from '../../../../src/testing/in_memory_prefixed_state'; +import { ModuleConfig } from '../../../../src/modules/token/types'; describe('token endpoint', () => { const tokenModule = new TokenModule(); - const defaultAddress = utils.getRandomBytes(20); - const defaultTokenID = Buffer.from([0, 0, 0, 1, 0, 0, 0, 0]); - const defaultForeignTokenID = Buffer.from([1, 0, 0, 0, 0, 0, 0, 0]); - const defaultAccount = { + const addr = utils.getRandomBytes(20); + const mainChainID = Buffer.from([1, 0, 0, 0]); + const mainChainTokenID = Buffer.concat([mainChainID, Buffer.from([0, 0, 0, 0])]); + const nativeChainID = Buffer.from([1, 0, 0, 1]); + const nativeTokenID = Buffer.concat([nativeChainID, Buffer.from([0, 0, 0, 0])]); + const foreignChainID = Buffer.from([1, 0, 0, 8]); + const foreignTokenID = Buffer.concat([foreignChainID, Buffer.from([0, 0, 0, 0])]); + const account = { availableBalance: BigInt(10000000000), lockedBalances: [ { @@ -40,9 +49,13 @@ describe('token endpoint', () => { }, ], }; - const defaultTotalSupply = BigInt('100000000000000'); - const defaultEscrowAmount = BigInt('100000000000'); - // const supportedTokenIDs = ['0000000000000000', '0000000200000000']; + const totalSupply = BigInt('100000000000000'); + const escrowAmount = BigInt('100000000000'); + const supportedForeignChainTokenIDs = [ + Buffer.concat([foreignChainID, Buffer.from([0, 0, 0, 8])]), + Buffer.concat([foreignChainID, Buffer.from([0, 0, 0, 9])]), + ]; + let supportedTokensStore: SupportedTokensStore; let endpoint: TokenEndpoint; let stateStore: PrefixedStateReadWriter; @@ -51,12 +64,12 @@ describe('token endpoint', () => { beforeEach(async () => { const method = new TokenMethod(tokenModule.stores, tokenModule.events, tokenModule.name); endpoint = new TokenEndpoint(tokenModule.stores, tokenModule.offchainStores); - method.init({ - ownChainID: Buffer.from([0, 0, 0, 1]), - escrowAccountInitializationFee: BigInt(50000000), - userAccountInitializationFee: BigInt(50000000), - feeTokenID: defaultTokenID, - }); + const config: ModuleConfig = { + userAccountInitializationFee: USER_SUBSTORE_INITIALIZATION_FEE, + escrowAccountInitializationFee: ESCROW_SUBSTORE_INITIALIZATION_FEE, + feeTokenID: nativeTokenID, + }; + method.init(Object.assign(config, { ownChainID: Buffer.from([0, 0, 0, 1]) })); method.addDependencies({ getOwnChainAccount: jest.fn().mockResolvedValue({ id: Buffer.from([0, 0, 0, 1]) }), send: jest.fn().mockResolvedValue(true), @@ -64,27 +77,25 @@ describe('token endpoint', () => { terminateChain: jest.fn(), getChannel: jest.fn(), } as never); - endpoint.init(method); + endpoint.init(config); stateStore = new PrefixedStateReadWriter(new InMemoryPrefixedStateDB()); methodContext = createTransientMethodContext({ stateStore }); const userStore = tokenModule.stores.get(UserStore); - await userStore.save(methodContext, defaultAddress, defaultTokenID, defaultAccount); - await userStore.save(methodContext, defaultAddress, defaultForeignTokenID, defaultAccount); + await userStore.save(methodContext, addr, nativeTokenID, account); + await userStore.save(methodContext, addr, foreignTokenID, account); const supplyStore = tokenModule.stores.get(SupplyStore); - await supplyStore.set(methodContext, defaultTokenID.slice(CHAIN_ID_LENGTH), { - totalSupply: defaultTotalSupply, + await supplyStore.set(methodContext, nativeTokenID, { + totalSupply, }); const escrowStore = tokenModule.stores.get(EscrowStore); - await escrowStore.set( - methodContext, - Buffer.concat([ - defaultForeignTokenID.slice(0, CHAIN_ID_LENGTH), - defaultTokenID.slice(CHAIN_ID_LENGTH), - ]), - { amount: defaultEscrowAmount }, - ); + await escrowStore.set(methodContext, Buffer.concat([foreignChainID, nativeTokenID]), { + amount: escrowAmount, + }); + + supportedTokensStore = tokenModule.stores.get(SupportedTokensStore); + supportedTokensStore.registerOwnChainID(nativeChainID); }); describe('getBalances', () => { @@ -110,24 +121,24 @@ describe('token endpoint', () => { it('should return all the balances', async () => { const moduleEndpointContext = createTransientModuleEndpointContext({ stateStore, - params: { address: address.getLisk32AddressFromAddress(defaultAddress) }, + params: { address: address.getLisk32AddressFromAddress(addr) }, }); const resp = await endpoint.getBalances(moduleEndpointContext); expect(resp).toEqual({ balances: [ { - tokenID: '0000000100000000', - availableBalance: defaultAccount.availableBalance.toString(), - lockedBalances: defaultAccount.lockedBalances.map(lb => ({ + tokenID: nativeTokenID.toString('hex'), + availableBalance: account.availableBalance.toString(), + lockedBalances: account.lockedBalances.map(lb => ({ ...lb, module: lb.module, amount: lb.amount.toString(), })), }, { - tokenID: '0100000000000000', - availableBalance: defaultAccount.availableBalance.toString(), - lockedBalances: defaultAccount.lockedBalances.map(lb => ({ + tokenID: foreignTokenID.toString('hex'), + availableBalance: account.availableBalance.toString(), + lockedBalances: account.lockedBalances.map(lb => ({ ...lb, module: lb.module, amount: lb.amount.toString(), @@ -152,7 +163,7 @@ describe('token endpoint', () => { it('should reject when input has invalid tokenID', async () => { const moduleEndpointContext = createTransientModuleEndpointContext({ stateStore, - params: { address: address.getLisk32AddressFromAddress(defaultAddress), tokenID: '00' }, + params: { address: address.getLisk32AddressFromAddress(addr), tokenID: '00' }, }); await expect(endpoint.getBalance(moduleEndpointContext)).rejects.toThrow( ".tokenID' must NOT have fewer than 16 characters", @@ -164,7 +175,7 @@ describe('token endpoint', () => { stateStore, params: { address: address.getLisk32AddressFromAddress(utils.getRandomBytes(20)), - tokenID: defaultTokenID.toString('hex'), + tokenID: nativeTokenID.toString('hex'), }, }); const resp = await endpoint.getBalance(moduleEndpointContext); @@ -178,14 +189,14 @@ describe('token endpoint', () => { const moduleEndpointContext = createTransientModuleEndpointContext({ stateStore, params: { - address: address.getLisk32AddressFromAddress(defaultAddress), - tokenID: defaultTokenID.toString('hex'), + address: address.getLisk32AddressFromAddress(addr), + tokenID: nativeTokenID.toString('hex'), }, }); const resp = await endpoint.getBalance(moduleEndpointContext); expect(resp).toEqual({ - availableBalance: defaultAccount.availableBalance.toString(), - lockedBalances: defaultAccount.lockedBalances.map(lb => ({ + availableBalance: account.availableBalance.toString(), + lockedBalances: account.lockedBalances.map(lb => ({ ...lb, module: lb.module, amount: lb.amount.toString(), @@ -197,14 +208,14 @@ describe('token endpoint', () => { const moduleEndpointContext = createTransientModuleEndpointContext({ stateStore, params: { - address: address.getLisk32AddressFromAddress(defaultAddress), - tokenID: defaultTokenID.toString('hex'), + address: address.getLisk32AddressFromAddress(addr), + tokenID: nativeTokenID.toString('hex'), }, }); const resp = await endpoint.getBalance(moduleEndpointContext); expect(resp).toEqual({ - availableBalance: defaultAccount.availableBalance.toString(), - lockedBalances: defaultAccount.lockedBalances.map(lb => ({ + availableBalance: account.availableBalance.toString(), + lockedBalances: account.lockedBalances.map(lb => ({ ...lb, module: lb.module, amount: lb.amount.toString(), @@ -222,8 +233,8 @@ describe('token endpoint', () => { expect(resp).toEqual({ totalSupply: [ { - tokenID: defaultTokenID.toString('hex'), - totalSupply: defaultTotalSupply.toString(), + tokenID: nativeTokenID.toString('hex'), + totalSupply: totalSupply.toString(), }, ], }); @@ -231,7 +242,52 @@ describe('token endpoint', () => { }); describe('getSupportedTokens', () => { - it.todo('should return all supported tokens'); + it('should return * when ALL tokens are supported globally', async () => { + await supportedTokensStore.supportAll(methodContext); + const moduleEndpointContext = createTransientModuleEndpointContext({ stateStore }); + + expect(await endpoint.getSupportedTokens(moduleEndpointContext)).toEqual({ + supportedTokens: ['*'], + }); + }); + + it('should return the list of supported tokens when ALL the tokens from a foreign chain are supported', async () => { + await supportedTokensStore.set(methodContext, foreignChainID, { supportedTokenIDs: [] }); + + // const anotherForeignChainID = Buffer.from([0, 0, 0, 9]); + // await supportedTokensStore.set(methodContext, anotherForeignChainID, { supportedTokenIDs: [] }); + const moduleEndpointContext = createTransientModuleEndpointContext({ + stateStore, + chainID: nativeChainID, + }); + + expect(await endpoint.getSupportedTokens(moduleEndpointContext)).toEqual({ + supportedTokens: [ + mainChainTokenID.toString('hex'), + nativeTokenID.toString('hex'), + `${foreignChainID.toString('hex')}********`, + ], + }); + }); + + it('should return the list of supported tokens when NOT ALL the tokens from a foreign chain are supported', async () => { + await supportedTokensStore.set(methodContext, foreignChainID, { + supportedTokenIDs: supportedForeignChainTokenIDs, + }); + const moduleEndpointContext = createTransientModuleEndpointContext({ + stateStore, + chainID: nativeChainID, + }); + + expect(await endpoint.getSupportedTokens(moduleEndpointContext)).toEqual({ + supportedTokens: [ + mainChainTokenID.toString('hex'), + nativeTokenID.toString('hex'), + supportedForeignChainTokenIDs[0].toString('hex'), + supportedForeignChainTokenIDs[1].toString('hex'), + ], + }); + }); }); describe('getEscrowedAmounts', () => { @@ -243,12 +299,54 @@ describe('token endpoint', () => { expect(resp).toEqual({ escrowedAmounts: [ { - tokenID: defaultTokenID.toString('hex'), - escrowChainID: defaultForeignTokenID.slice(0, CHAIN_ID_LENGTH).toString('hex'), - amount: defaultEscrowAmount.toString(), + tokenID: nativeTokenID.toString('hex'), + escrowChainID: foreignChainID.toString('hex'), + amount: escrowAmount.toString(), }, ], }); }); }); + + describe('isSupported', () => { + it('should return true for a supported token', async () => { + await supportedTokensStore.set(methodContext, foreignChainID, { + supportedTokenIDs: supportedForeignChainTokenIDs, + }); + const moduleEndpointContext = createTransientModuleEndpointContext({ + stateStore, + params: { tokenID: supportedForeignChainTokenIDs[0].toString('hex') }, + }); + + expect(await endpoint.isSupported(moduleEndpointContext)).toEqual({ supported: true }); + }); + + it('should return false for a non-supported token', async () => { + const moduleEndpointContext = createTransientModuleEndpointContext({ + stateStore, + params: { tokenID: '8888888888888888' }, + }); + + expect(await endpoint.isSupported(moduleEndpointContext)).toEqual({ supported: false }); + }); + + it('should return true for a token from a foreign chain, when all tokens are supported', async () => { + await supportedTokensStore.supportAll(methodContext); + const moduleEndpointContext = createTransientModuleEndpointContext({ + stateStore, + params: { tokenID: '8888888888888888' }, + }); + + expect(await endpoint.isSupported(moduleEndpointContext)).toEqual({ supported: true }); + }); + }); + + describe('getInitializationFees', () => { + it('should return configured initialization fees for user account and escrow account', () => { + expect(endpoint.getInitializationFees()).toEqual({ + userAccount: USER_SUBSTORE_INITIALIZATION_FEE.toString(), + escrowAccount: ESCROW_SUBSTORE_INITIALIZATION_FEE.toString(), + }); + }); + }); });