-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: add
TokenStateManager
to manage token state (#325)
- Loading branch information
1 parent
fe8d810
commit 9ea5310
Showing
2 changed files
with
556 additions
and
0 deletions.
There are no files selected for viewing
311 changes: 311 additions & 0 deletions
311
packages/starknet-snap/src/state/token-state-manager.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,311 @@ | ||
import { constants } from 'starknet'; | ||
|
||
import type { Erc20Token } from '../types/snapState'; | ||
import { | ||
ETHER_MAINNET, | ||
ETHER_SEPOLIA_TESTNET, | ||
STRK_MAINNET, | ||
STRK_SEPOLIA_TESTNET, | ||
} from '../utils/constants'; | ||
import { mockState } from './__tests__/helper'; | ||
import { StateManagerError } from './state-manager'; | ||
import { TokenStateManager, ChainIdFilter } from './token-state-manager'; | ||
|
||
describe('TokenStateManager', () => { | ||
describe('findToken', () => { | ||
it('returns the token', async () => { | ||
const chainId = constants.StarknetChainId.SN_SEPOLIA; | ||
await mockState({ | ||
tokens: [ETHER_MAINNET, ETHER_SEPOLIA_TESTNET], | ||
}); | ||
|
||
const stateManager = new TokenStateManager(); | ||
const result = await stateManager.findToken({ | ||
chainId, | ||
address: ETHER_SEPOLIA_TESTNET.address, | ||
}); | ||
|
||
expect(result).toStrictEqual(ETHER_SEPOLIA_TESTNET); | ||
}); | ||
|
||
it('finds the token by symbol', async () => { | ||
const chainId = constants.StarknetChainId.SN_SEPOLIA; | ||
await mockState({ | ||
tokens: [ETHER_MAINNET, ETHER_SEPOLIA_TESTNET], | ||
}); | ||
|
||
const stateManager = new TokenStateManager(); | ||
const result = await stateManager.findToken({ | ||
chainId, | ||
address: ETHER_SEPOLIA_TESTNET.address, | ||
}); | ||
|
||
expect(result).toStrictEqual(ETHER_SEPOLIA_TESTNET); | ||
}); | ||
|
||
it('returns null if the token can not be found', async () => { | ||
const chainId = constants.StarknetChainId.SN_SEPOLIA; | ||
await mockState({ | ||
tokens: [ETHER_MAINNET], | ||
}); | ||
|
||
const stateManager = new TokenStateManager(); | ||
const result = await stateManager.findToken({ | ||
chainId, | ||
address: ETHER_SEPOLIA_TESTNET.address, | ||
}); | ||
|
||
expect(result).toBeNull(); | ||
}); | ||
}); | ||
|
||
describe('addDefaultTokens', () => { | ||
it("adds tokens if the given tokens don't exist", async () => { | ||
const { state } = await mockState({ | ||
tokens: [], | ||
}); | ||
|
||
const stateManager = new TokenStateManager(); | ||
await stateManager.addDefaultTokens([ | ||
ETHER_MAINNET, | ||
ETHER_SEPOLIA_TESTNET, | ||
]); | ||
|
||
expect(state.erc20Tokens).toStrictEqual([ | ||
ETHER_MAINNET, | ||
ETHER_SEPOLIA_TESTNET, | ||
]); | ||
}); | ||
|
||
it('updates the tokens if the given tokens found', async () => { | ||
const { state } = await mockState({ | ||
tokens: [ETHER_MAINNET], | ||
}); | ||
|
||
const stateManager = new TokenStateManager(); | ||
await stateManager.addDefaultTokens([ | ||
{ | ||
...ETHER_MAINNET, | ||
name: 'Updated Token', | ||
}, | ||
ETHER_SEPOLIA_TESTNET, | ||
]); | ||
|
||
expect(state.erc20Tokens[0]).toStrictEqual({ | ||
...ETHER_MAINNET, | ||
name: 'Updated Token', | ||
}); | ||
expect(state.erc20Tokens[1]).toStrictEqual(ETHER_SEPOLIA_TESTNET); | ||
}); | ||
|
||
it('throws a `StateManagerError` if an error was thrown', async () => { | ||
const { getDataSpy } = await mockState({ | ||
tokens: [ETHER_MAINNET], | ||
}); | ||
getDataSpy.mockRejectedValue(new Error('Error')); | ||
|
||
const stateManager = new TokenStateManager(); | ||
|
||
await expect( | ||
stateManager.addDefaultTokens([ | ||
{ | ||
...ETHER_MAINNET, | ||
name: 'Updated Token', | ||
}, | ||
ETHER_SEPOLIA_TESTNET, | ||
]), | ||
).rejects.toThrow(StateManagerError); | ||
}); | ||
}); | ||
|
||
describe('list', () => { | ||
it('returns the list of token by chainId', async () => { | ||
const chainId = constants.StarknetChainId.SN_SEPOLIA; | ||
await mockState({ | ||
tokens: [ETHER_MAINNET, ETHER_SEPOLIA_TESTNET], | ||
}); | ||
|
||
const stateManager = new TokenStateManager(); | ||
const result = await stateManager.list([new ChainIdFilter([chainId])]); | ||
|
||
expect(result).toStrictEqual([ETHER_SEPOLIA_TESTNET]); | ||
}); | ||
|
||
it('returns empty array if a token with the given chainId cannot be found', async () => { | ||
const chainId = constants.StarknetChainId.SN_SEPOLIA; | ||
await mockState({ | ||
tokens: [ETHER_MAINNET], | ||
}); | ||
|
||
const stateManager = new TokenStateManager(); | ||
const result = await stateManager.list([new ChainIdFilter([chainId])]); | ||
|
||
expect(result).toStrictEqual([]); | ||
}); | ||
}); | ||
|
||
describe('updateToken', () => { | ||
it('updates the token', async () => { | ||
const { state } = await mockState({ | ||
tokens: [ETHER_MAINNET], | ||
}); | ||
|
||
const stateManager = new TokenStateManager(); | ||
const updatedEntity = { | ||
...ETHER_MAINNET, | ||
name: 'Updated Token', | ||
}; | ||
await stateManager.updateToken(updatedEntity); | ||
|
||
expect(state.erc20Tokens[0]).toStrictEqual(updatedEntity); | ||
}); | ||
|
||
it('throws `Token does not exist` error if the update entity can not be found', async () => { | ||
await mockState({ | ||
tokens: [ETHER_MAINNET], | ||
}); | ||
|
||
const stateManager = new TokenStateManager(); | ||
const updatedEntity = { | ||
...ETHER_SEPOLIA_TESTNET, | ||
name: 'Updated Token', | ||
}; | ||
|
||
await expect(stateManager.updateToken(updatedEntity)).rejects.toThrow( | ||
'Token does not exist', | ||
); | ||
}); | ||
}); | ||
|
||
describe('getEthToken', () => { | ||
it.each([ | ||
{ | ||
chainId: constants.StarknetChainId.SN_MAIN, | ||
token: ETHER_MAINNET, | ||
}, | ||
{ | ||
chainId: constants.StarknetChainId.SN_SEPOLIA, | ||
token: ETHER_SEPOLIA_TESTNET, | ||
}, | ||
])( | ||
'returns the ETH token if the chain id is $chainId', | ||
async ({ chainId, token }: { chainId: string; token: Erc20Token }) => { | ||
await mockState({ | ||
tokens: [token], | ||
}); | ||
|
||
const stateManager = new TokenStateManager(); | ||
const result = await stateManager.getEthToken({ | ||
chainId, | ||
}); | ||
|
||
expect(result).toStrictEqual(token); | ||
}, | ||
); | ||
|
||
it('returns null if the ETH token is null or undefined', async () => { | ||
await mockState({ | ||
tokens: [ETHER_MAINNET], | ||
}); | ||
|
||
const stateManager = new TokenStateManager(); | ||
const result = await stateManager.getEthToken({ | ||
chainId: constants.StarknetChainId.SN_SEPOLIA, | ||
}); | ||
|
||
expect(result).toBeNull(); | ||
}); | ||
|
||
it('returns null if the chain id is not supported', async () => { | ||
await mockState({ | ||
tokens: [ETHER_MAINNET], | ||
}); | ||
|
||
const stateManager = new TokenStateManager(); | ||
const result = await stateManager.getEthToken({ | ||
chainId: 'invalid-chain-id', | ||
}); | ||
|
||
expect(result).toBeNull(); | ||
}); | ||
}); | ||
|
||
describe('getStrkToken', () => { | ||
it.each([ | ||
{ | ||
chainId: constants.StarknetChainId.SN_MAIN, | ||
token: STRK_MAINNET, | ||
}, | ||
{ | ||
chainId: constants.StarknetChainId.SN_SEPOLIA, | ||
token: STRK_SEPOLIA_TESTNET, | ||
}, | ||
])( | ||
'return the STRK token if the chain id is $chainId', | ||
async ({ chainId, token }: { chainId: string; token: Erc20Token }) => { | ||
await mockState({ | ||
tokens: [token], | ||
}); | ||
|
||
const stateManager = new TokenStateManager(); | ||
const result = await stateManager.getStrkToken({ | ||
chainId, | ||
}); | ||
|
||
expect(result).toStrictEqual(token); | ||
}, | ||
); | ||
|
||
it('returns null if the STRK token is null or undefined', async () => { | ||
await mockState({ | ||
tokens: [STRK_MAINNET], | ||
}); | ||
|
||
const stateManager = new TokenStateManager(); | ||
const result = await stateManager.getStrkToken({ | ||
chainId: constants.StarknetChainId.SN_SEPOLIA, | ||
}); | ||
|
||
expect(result).toBeNull(); | ||
}); | ||
|
||
it('returns null if the chain id is not supported', async () => { | ||
await mockState({ | ||
tokens: [STRK_SEPOLIA_TESTNET], | ||
}); | ||
|
||
const stateManager = new TokenStateManager(); | ||
const result = await stateManager.getStrkToken({ | ||
chainId: 'invalid-chain-id', | ||
}); | ||
|
||
expect(result).toBeNull(); | ||
}); | ||
}); | ||
|
||
describe('addToken', () => { | ||
it('adds the token', async () => { | ||
const { state } = await mockState({ | ||
tokens: [ETHER_MAINNET], | ||
}); | ||
|
||
const stateManager = new TokenStateManager(); | ||
await stateManager.addToken(ETHER_SEPOLIA_TESTNET); | ||
|
||
expect(state.erc20Tokens[1]).toStrictEqual(ETHER_SEPOLIA_TESTNET); | ||
}); | ||
|
||
it('throws a `Token already exist` error if the token is exist', async () => { | ||
const { setDataSpy } = await mockState({ | ||
tokens: [ETHER_MAINNET], | ||
}); | ||
setDataSpy.mockRejectedValue(new Error('Error')); | ||
|
||
const stateManager = new TokenStateManager(); | ||
|
||
await expect(stateManager.addToken(ETHER_MAINNET)).rejects.toThrow( | ||
StateManagerError, | ||
); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.