Skip to content
This repository has been archived by the owner on Jun 11, 2024. It is now read-only.

Commit

Permalink
Align the token support methods to the lip (#8631)
Browse files Browse the repository at this point in the history
* Align the token support methods to the lip

Cleanup the comments

Refactor the updates

Refactor the methods and tests

Update the tests

Add unit test

Add unit tests

* Refactor the token support methods to be aligned to the lip

* Refactor the check for chain supported tokens

Co-authored-by: shuse2 <[email protected]>

* Refactor the tests and align functions to LIP

* Refactor the removeSupport method

* Update the removeSupport function and tests
  • Loading branch information
mosmartin authored Aug 3, 2023
1 parent 566c7a6 commit e00fe09
Show file tree
Hide file tree
Showing 2 changed files with 248 additions and 11 deletions.
86 changes: 81 additions & 5 deletions framework/src/modules/token/method.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import { BurnEvent } from './events/burn';
import { LockEvent } from './events/lock';
import { UnlockEvent } from './events/unlock';
import { TransferCrossChainEvent } from './events/transfer_cross_chain';
import { SupportedTokensStore } from './stores/supported_tokens';
import { ALL_SUPPORTED_TOKENS_KEY, SupportedTokensStore } from './stores/supported_tokens';
import { AllTokensSupportedEvent } from './events/all_tokens_supported';
import { AllTokensSupportRemovedEvent } from './events/all_tokens_supported_removed';
import { TokenIDSupportedEvent } from './events/token_id_supported';
Expand Down Expand Up @@ -687,15 +687,53 @@ export class TokenMethod extends BaseMethod {
methodContext: MethodContext,
chainID: Buffer,
): Promise<void> {
await this.stores.get(SupportedTokensStore).supportChain(methodContext, chainID);
const allTokensSupported = await this.stores
.get(SupportedTokensStore)
.has(methodContext, ALL_SUPPORTED_TOKENS_KEY);

if (allTokensSupported) {
return;
}

if (chainID.equals(this._config.ownChainID)) {
return;
}

await this.stores
.get(SupportedTokensStore)
.set(methodContext, chainID, { supportedTokenIDs: [] });

this.events.get(AllTokensFromChainSupportedEvent).log(methodContext, chainID);
}

public async removeAllTokensSupportFromChainID(
methodContext: MethodContext,
chainID: Buffer,
): Promise<void> {
await this.stores.get(SupportedTokensStore).removeSupportForChain(methodContext, chainID);
const allTokensSupported = await this.stores
.get(SupportedTokensStore)
.has(methodContext, ALL_SUPPORTED_TOKENS_KEY);

if (allTokensSupported) {
throw new Error('Invalid operation. All tokens from all chains are supported.');
}

if (chainID.equals(this._config.ownChainID)) {
throw new Error(
'Invalid operation. All tokens from all the specified chain should be supported.',
);
}

const isChainSupported = await this.stores
.get(SupportedTokensStore)
.has(methodContext, chainID);

if (!isChainSupported) {
return;
}

await this.stores.get(SupportedTokensStore).del(methodContext, chainID);

this.events.get(AllTokensFromChainSupportRemovedEvent).log(methodContext, chainID);
}

Expand All @@ -704,8 +742,46 @@ export class TokenMethod extends BaseMethod {
this.events.get(TokenIDSupportedEvent).log(methodContext, tokenID);
}

public async removeSupportTokenID(methodContext: MethodContext, tokenID: Buffer): Promise<void> {
await this.stores.get(SupportedTokensStore).removeSupportForToken(methodContext, tokenID);
public async removeSupport(methodContext: MethodContext, tokenID: Buffer): Promise<void> {
const [chainID] = splitTokenID(tokenID);

const allTokensSupported = await this.stores
.get(SupportedTokensStore)
.has(methodContext, ALL_SUPPORTED_TOKENS_KEY);

if (allTokensSupported) {
throw new Error('All tokens are supported.');
}

if (tokenID.equals(this.getMainchainTokenID()) || chainID.equals(this._config.ownChainID)) {
throw new Error('Cannot remove support for the specified token.');
}

const isChainSupported = await this.stores
.get(SupportedTokensStore)
.has(methodContext, chainID);

if (!isChainSupported) {
this.events.get(TokenIDSupportRemovedEvent).log(methodContext, tokenID);
return;
}

const supportedTokens = await this.stores.get(SupportedTokensStore).get(methodContext, chainID);

if (supportedTokens.supportedTokenIDs.length === 0) {
throw new Error('All tokens from the specified chain are supported.');
}

const tokenIndex = supportedTokens.supportedTokenIDs.indexOf(tokenID);

if (tokenIndex !== -1) {
supportedTokens.supportedTokenIDs.splice(tokenIndex, 1);

if (supportedTokens.supportedTokenIDs.length === 0) {
await this.stores.get(SupportedTokensStore).del(methodContext, chainID);
}
}

this.events.get(TokenIDSupportRemovedEvent).log(methodContext, tokenID);
}

Expand Down
173 changes: 167 additions & 6 deletions framework/test/unit/modules/token/method.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ import { InternalMethod } from '../../../../src/modules/token/internal_method';
import { crossChainTransferMessageParams } from '../../../../src/modules/token/schemas';
import { EscrowStore } from '../../../../src/modules/token/stores/escrow';
import { SupplyStore } from '../../../../src/modules/token/stores/supply';
import { SupportedTokensStore } from '../../../../src/modules/token/stores/supported_tokens';
import {
ALL_SUPPORTED_TOKENS_KEY,
SupportedTokensStore,
} from '../../../../src/modules/token/stores/supported_tokens';
import { UserStore } from '../../../../src/modules/token/stores/user';
import { MethodContext, createMethodContext, EventQueue } from '../../../../src/state_machine';
import { PrefixedStateReadWriter } from '../../../../src/state_machine/prefixed_state_read_writer';
Expand Down Expand Up @@ -1223,7 +1226,48 @@ describe('token module', () => {
});

describe('supportAllTokensFromChainID', () => {
it('should call support chain', async () => {
it('should return early if all tokens are already supported', async () => {
await tokenModule.stores
.get(SupportedTokensStore)
.set(methodContext, ALL_SUPPORTED_TOKENS_KEY, { supportedTokenIDs: [] });

await expect(
method.supportAllTokensFromChainID(methodContext, Buffer.from([1, 2, 3, 4])),
).resolves.toBeUndefined();

expect(methodContext.eventQueue.getEvents()).toHaveLength(0);
});

it('should return early if the chain ID is the same as the own chain ID', async () => {
const chainID = Buffer.from([1, 2, 3, 4]);
method['_config'].ownChainID = chainID;

await method.supportAllTokensFromChainID(methodContext, chainID);

await expect(
method.supportAllTokensFromChainID(methodContext, chainID),
).resolves.toBeUndefined();

expect(methodContext.eventQueue.getEvents()).toHaveLength(0);
});

it('should set an empty array of supported token IDs for the chain ID', async () => {
await tokenModule.stores
.get(SupportedTokensStore)
.set(methodContext, ALL_SUPPORTED_TOKENS_KEY, { supportedTokenIDs: [] });

await expect(
method.supportAllTokensFromChainID(methodContext, Buffer.from([1, 2, 3, 4])),
).resolves.toBeUndefined();

const supportedTokens = await tokenModule.stores
.get(SupportedTokensStore)
.get(methodContext, ALL_SUPPORTED_TOKENS_KEY);

expect(supportedTokens.supportedTokenIDs).toHaveLength(0);
});

it('should log AllTokensFromChainSupportedEvent', async () => {
await expect(
method.supportAllTokensFromChainID(methodContext, Buffer.from([1, 2, 3, 4])),
).resolves.toBeUndefined();
Expand All @@ -1249,6 +1293,54 @@ describe('token module', () => {
new AllTokensFromChainSupportRemovedEvent('token').name,
);
});

it('should throw an error if all tokens from all chains are supported', async () => {
await tokenModule.stores
.get(SupportedTokensStore)
.set(methodContext, ALL_SUPPORTED_TOKENS_KEY, { supportedTokenIDs: [] });

await expect(
method.removeAllTokensSupportFromChainID(methodContext, Buffer.from([1, 2, 3, 4])),
).rejects.toThrow('Invalid operation. All tokens from all chains are supported.');

expect(methodContext.eventQueue.getEvents()).toHaveLength(0);
});

it('should throw an error if the chain ID is the same as the own chain ID', async () => {
const chainID = Buffer.from([1, 2, 3, 4]);
method['_config'].ownChainID = chainID;

await expect(
method.removeAllTokensSupportFromChainID(methodContext, chainID),
).rejects.toThrow(
'Invalid operation. All tokens from all the specified chain should be supported.',
);

expect(methodContext.eventQueue.getEvents()).toHaveLength(0);
});

it('should return early if there are no supportedTokens', async () => {
await expect(
method.removeAllTokensSupportFromChainID(methodContext, Buffer.from([1, 2, 3, 4])),
).resolves.toBeUndefined();

expect(methodContext.eventQueue.getEvents()).toHaveLength(0);
});

it('should remove the chain ID from the supported tokens store', async () => {
await tokenModule.stores
.get(SupportedTokensStore)
.supportChain(methodContext, Buffer.from([1, 2, 3, 4]));

await expect(
method.removeAllTokensSupportFromChainID(methodContext, Buffer.from([1, 2, 3, 4])),
).resolves.toBeUndefined();

expect(methodContext.eventQueue.getEvents()).toHaveLength(1);
expect(methodContext.eventQueue.getEvents()[0].toObject().name).toEqual(
new AllTokensFromChainSupportRemovedEvent('token').name,
);
});
});

describe('supportTokenID', () => {
Expand All @@ -1264,14 +1356,83 @@ describe('token module', () => {
});
});

describe('removeSupportTokenID', () => {
describe('removeSupport', () => {
it('should call remove support for token', async () => {
await expect(
method.removeSupport(methodContext, Buffer.from([1, 2, 3, 4, 0, 0, 0, 0])),
).resolves.toBeUndefined();

expect(methodContext.eventQueue.getEvents()).toHaveLength(1);
expect(methodContext.eventQueue.getEvents()[0].toObject().name).toEqual(
new TokenIDSupportRemovedEvent('token').name,
);
});

it('should throw an error if all tokens are supported', async () => {
await tokenModule.stores
.get(SupportedTokensStore)
.supportToken(methodContext, Buffer.from([1, 2, 3, 4, 0, 0, 0, 0]));
.set(methodContext, ALL_SUPPORTED_TOKENS_KEY, { supportedTokenIDs: [] });

await expect(
method.removeSupportTokenID(methodContext, Buffer.from([1, 2, 3, 4, 0, 0, 0, 0])),
).resolves.toBeUndefined();
method.removeSupport(methodContext, Buffer.from([1, 2, 3, 4, 0, 0, 0, 0])),
).rejects.toThrow('All tokens are supported.');

expect(methodContext.eventQueue.getEvents()).toHaveLength(0);
});

it('should throw an error if the specified token is the mainchain token or the own chain ID', async () => {
const tokenId = Buffer.from([1, 2, 3, 4, 0, 0, 0, 0]);
const chainID = Buffer.from([1, 2, 3, 4]);
method['_config'].ownChainID = chainID;

await expect(method.removeSupport(methodContext, tokenId)).rejects.toThrow(
'Cannot remove support for the specified token.',
);

expect(methodContext.eventQueue.getEvents()).toHaveLength(0);
});

it('should return early and log an event if the specified token is not supported', async () => {
const tokenId = Buffer.from([1, 2, 3, 4, 0, 0, 0, 0]);

await expect(method.removeSupport(methodContext, tokenId)).resolves.toBeUndefined();

expect(methodContext.eventQueue.getEvents()).toHaveLength(1);
expect(methodContext.eventQueue.getEvents()[0].toObject().name).toEqual(
new TokenIDSupportRemovedEvent('token').name,
);
});

it('should throw an error if all tokens from the specified chain are supported', async () => {
const tokenId = Buffer.from([1, 2, 3, 4, 0, 0, 0, 0]);
const chainID = Buffer.from([1, 2, 3, 4]);

await tokenModule.stores.get(SupportedTokensStore).supportChain(methodContext, chainID);

await expect(method.removeSupport(methodContext, tokenId)).rejects.toThrow(
'All tokens from the specified chain are supported.',
);

expect(methodContext.eventQueue.getEvents()).toHaveLength(0);
});

it('should remove the specified token from the supported tokens list', async () => {
const tokenId = Buffer.from([1, 2, 3, 4, 0, 0, 0, 0]);

await tokenModule.stores.get(SupportedTokensStore).supportToken(methodContext, tokenId);

await expect(method.removeSupport(methodContext, tokenId)).resolves.toBeUndefined();

expect(methodContext.eventQueue.getEvents()).toHaveLength(1);
expect(methodContext.eventQueue.getEvents()[0].toObject().name).toEqual(
new TokenIDSupportRemovedEvent('token').name,
);
});

it('should log an event when support is removed for token', async () => {
const tokenId = Buffer.from([1, 2, 3, 4, 0, 0, 0, 0]);

await expect(method.removeSupport(methodContext, tokenId)).resolves.toBeUndefined();

expect(methodContext.eventQueue.getEvents()).toHaveLength(1);
expect(methodContext.eventQueue.getEvents()[0].toObject().name).toEqual(
Expand Down

0 comments on commit e00fe09

Please sign in to comment.