diff --git a/framework/src/modules/token/cc_method.ts b/framework/src/modules/token/cc_method.ts index 5ceff2c38e..ae48543c88 100644 --- a/framework/src/modules/token/cc_method.ts +++ b/framework/src/modules/token/cc_method.ts @@ -12,6 +12,7 @@ * Removal or modification of this copyright notice is prohibited. */ +import { validator } from '@liskhq/lisk-validator'; import { codec } from '@liskhq/lisk-codec'; import { BaseCCMethod } from '../interoperability/base_cc_method'; import { @@ -200,6 +201,7 @@ export class TokenInteroperableMethod extends BaseCCMethod { try { account = codec.decode(userStoreSchema, ctx.storeValue); + validator.validate(userStoreSchema, account); } catch (error) { this.events .get(RecoverEvent) diff --git a/framework/test/unit/modules/token/cc_method.spec.ts b/framework/test/unit/modules/token/cc_method.spec.ts index 6f219684fb..e318c4867d 100644 --- a/framework/test/unit/modules/token/cc_method.spec.ts +++ b/framework/test/unit/modules/token/cc_method.spec.ts @@ -19,6 +19,8 @@ import { CCM_STATUS_OK, CHAIN_ID_LENGTH, CROSS_CHAIN_COMMAND_NAME_TRANSFER, + MIN_MODULE_NAME_LENGTH, + MAX_MODULE_NAME_LENGTH, TokenEventResult, } from '../../../../src/modules/token/constants'; import { TokenInteroperableMethod } from '../../../../src/modules/token/cc_method'; @@ -700,6 +702,50 @@ describe('TokenInteroperableMethod', () => { ); }); + it('should reject if module name length in lockedBalances is not valid', async () => { + await expect( + tokenInteropMethod.recover({ + ...createRecoverContext(stateStore), + storeKey: Buffer.concat([defaultAddress, defaultTokenID]), + substorePrefix: userStore.subStorePrefix, + storeValue: codec.encode(userStoreSchema, { + availableBalance: defaultAccount.availableBalance, + lockedBalances: [{ module: ''.repeat(MIN_MODULE_NAME_LENGTH - 1), amount: BigInt(10) }], + }), + terminatedChainID: sendingChainID, + }), + ).rejects.toThrow('Invalid arguments.'); + + checkEventResult( + methodContext.eventQueue, + RecoverEvent, + TokenEventResult.RECOVER_FAIL_INVALID_INPUTS, + ); + + await expect( + tokenInteropMethod.recover({ + ...createRecoverContext(stateStore), + storeKey: Buffer.concat([defaultAddress, defaultTokenID]), + substorePrefix: userStore.subStorePrefix, + storeValue: codec.encode(userStoreSchema, { + availableBalance: defaultAccount.availableBalance, + lockedBalances: [ + { module: '1'.repeat(MAX_MODULE_NAME_LENGTH + 1), amount: BigInt(10) }, + ], + }), + terminatedChainID: sendingChainID, + }), + ).rejects.toThrow('Invalid arguments.'); + + checkEventResult( + methodContext.eventQueue, + RecoverEvent, + TokenEventResult.RECOVER_FAIL_INVALID_INPUTS, + 2, + 1, + ); + }); + it('should reject if token is not native', async () => { jest .spyOn(tokenInteropMethod['_interopMethod'], 'getMessageFeeTokenIDFromCCM')