Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: improve error messages #416

Merged
merged 4 commits into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/AssetTransferApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1104,7 +1104,7 @@ export class AssetTransferApi {
);
}
} else {
checkLocalRelayInput(assetIds, amounts);
checkLocalRelayInput(assetIds, amounts, this.registry);
/**
* By default local transaction on a relay chain will always be from the balances pallet
*/
Expand Down
9 changes: 9 additions & 0 deletions src/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,12 @@ export const JS_ENV = detectJsEnv();
* Supported consensus system chain names
*/
export const KNOWN_GLOBAL_CONSENSUS_SYSTEM_NAMES = ['polkadot', 'kusama', 'westend', 'rococo', 'ethereum'];

/**
* The asset location of the native relay chain asset from the perspective of `System` and `Para` Chains
*/
export const SYSTEM_AND_PARACHAINS_RELAY_ASSET_LOCATION = '{"parents":"1","interior":{"Here":""}}';
/**
* The asset location of the native relay chain asset from the perspective of the Relay chain
*/
export const RELAY_CHAINS_NATIVE_ASSET_LOCATION = '{"parents":"0","interior":{"Here":""}}';
5 changes: 1 addition & 4 deletions src/createXcmTypes/SystemToBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,16 +262,13 @@ export const createSystemToBridgeAssets = async (
let multiAssets: FungibleStrAssetType[] = [];
let multiAsset: FungibleStrAssetType;
const palletId = fetchPalletInstanceId(api, isLiquidTokenTransfer, isForeignAssetsTransfer);
const systemChainId = registry.lookupChainIdBySpecName(specName);

for (let i = 0; i < assets.length; i++) {
let assetId: string = assets[i];
const amount = amounts[i];

const { tokens } = registry.currentRelayRegistry[systemChainId];

const isValidInt = validateNumber(assetId);
const isRelayNative = isRelayNativeAsset(tokens, assetId);
const isRelayNative = isRelayNativeAsset(registry, assetId);
if (!isRelayNative && !isValidInt) {
assetId = await getAssetId(api, registry, assetId, specName, xcmVersion, isForeignAssetsTransfer);
}
Expand Down
4 changes: 1 addition & 3 deletions src/createXcmTypes/SystemToPara.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,14 +279,12 @@ export const createSystemToParaMultiAssets = async (
);
}

const { tokens } = registry.currentRelayRegistry[systemChainId];

for (let i = 0; i < assets.length; i++) {
let assetId: string = assets[i];
const amount = amounts[i];

const isValidInt = validateNumber(assetId);
const isRelayNative = isRelayNativeAsset(tokens, assetId);
const isRelayNative = isRelayNativeAsset(registry, assetId);

if (!isRelayNative && !isValidInt) {
assetId = await getAssetId(api, registry, assetId, specName, xcmVersion, isForeignAssetsTransfer);
Expand Down
4 changes: 1 addition & 3 deletions src/createXcmTypes/SystemToSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,14 +260,12 @@ export const createSystemToSystemMultiAssets = async (
);
}

const { tokens } = registry.currentRelayRegistry[systemChainId];

for (let i = 0; i < assets.length; i++) {
let assetId: string = assets[i];
const amount = amounts[i];

const isValidInt = validateNumber(assetId);
const isRelayNative = isRelayNativeAsset(tokens, assetId);
const isRelayNative = isRelayNativeAsset(registry, assetId);

if (!isRelayNative && !isValidInt) {
assetId = await getAssetId(api, registry, assetId, specName, xcmVersion, isForeignAssetsTransfer);
Expand Down
3 changes: 1 addition & 2 deletions src/createXcmTypes/util/assetIdsContainsRelayAsset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@ export const assetIdsContainRelayAsset = (assetIds: string[], registry: Registry
return true;
}

const { tokens } = registry.currentRelayRegistry['0'];
const relayAssetMultiLocation = `{"parents": 1, "interior": { "Here": ''}}`;

for (const asset of assetIds) {
// check relay tokens and if matched it is the relay asset
if (isRelayNativeAsset(tokens, asset)) {
if (isRelayNativeAsset(registry, asset)) {
return true;
}

Expand Down
4 changes: 1 addition & 3 deletions src/createXcmTypes/util/createAssetLocations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import { ApiPromise } from '@polkadot/api';

import { ASSET_HUB_CHAIN_ID } from '../../consts';
import { Registry } from '../../registry';
import { RequireOnlyOne } from '../../types';
import { resolveMultiLocation } from '../../util/resolveMultiLocation';
Expand Down Expand Up @@ -37,7 +36,6 @@ export const createAssetLocations = async (
let multiAssets: FungibleStrAssetType[] = [];
let multiAsset: FungibleStrAssetType;

const { tokens } = registry.currentRelayRegistry[ASSET_HUB_CHAIN_ID];
const palletId = fetchPalletInstanceId(api, isLiquidTokenTransfer, assetIdsContainLocations);
const isRelayChain = originChainId === '0' ? true : false;

Expand All @@ -47,7 +45,7 @@ export const createAssetLocations = async (
let assetId = assetIds[i];

const isValidInt = validateNumber(assetId);
const isRelayNative = isRelayNativeAsset(tokens, assetId);
const isRelayNative = isRelayNativeAsset(registry, assetId);

if (!assetIdsContainLocations && !isRelayNative && !isValidInt) {
assetId = await getAssetId(api, registry, assetId, specName, xcmVersion, assetIdsContainLocations);
Expand Down
2 changes: 1 addition & 1 deletion src/createXcmTypes/util/getAssetId.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ describe('getAssetId', () => {
it('Should error when an asset id symbol is given that is not present in the registry or chain state', async () => {
await expect(async () => {
await getAssetId(systemAssetsApi.api, registry, 'hello', 'statemine', 2, false);
}).rejects.toThrow('assetId hello is not a valid symbol or integer asset id');
}).rejects.toThrow('assetId hello is not a valid symbol, integer asset id or location for statemine');
});

it('Should correctly return the foreign asset multilocation when given a valid foreign asset multilocation', async () => {
Expand Down
2 changes: 1 addition & 1 deletion src/createXcmTypes/util/getAssetId.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export const getAssetId = async (
}
} else {
throw new BaseError(
`assetId ${asset} is not a valid symbol or integer asset id for ${specName}`,
`assetId ${asset} is not a valid symbol, integer asset id or location for ${specName}`,
BaseErrorsEnum.InvalidAsset,
);
}
Expand Down
46 changes: 41 additions & 5 deletions src/createXcmTypes/util/isRelayNativeAsset.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,47 @@
// Copyright 2024 Parity Technologies (UK) Ltd.

import { Registry } from '../../registry';
import { isRelayNativeAsset } from './isRelayNativeAsset';

describe('isRelayNativeAsset', () => {
const tokens = ['KSM'];
it('Should return true', () => {
expect(isRelayNativeAsset(tokens, 'KSM')).toEqual(true);
describe('RelayToSystem', () => {
const specName = 'kusama';
const registry = new Registry(specName, {});

it('Should return true when an empty string is provided as the assetId', () => {
expect(isRelayNativeAsset(registry, '')).toEqual(true);
});
it('Should return true when a symbol assetId matches the relay assetId', () => {
expect(isRelayNativeAsset(registry, 'KSM')).toEqual(true);
});
it('Should return false when a symbol assetId does not match the relay assetId', () => {
expect(isRelayNativeAsset(registry, 'DOT')).toEqual(false);
});
it('Should return true when the relay chains asset location is given as input from the perspective of the relay chain', () => {
expect(isRelayNativeAsset(registry, '{"parents":"0","interior":{"Here":""}}')).toEqual(true);
});
it('Should return false when the relay chains asset location is given as input from the perspective of a child chain', () => {
expect(isRelayNativeAsset(registry, '{"parents":"1","interior":{"Here":""}}')).toEqual(false);
});
});
it('Should return false', () => {
expect(isRelayNativeAsset(tokens, 'DOT')).toEqual(false);
describe('SystemToRelay', () => {
const specName = 'statemint';
const registry = new Registry(specName, {});

it('Should return true when an empty string is provided as the assetId', () => {
expect(isRelayNativeAsset(registry, '')).toEqual(true);
});
it('Should return true when a symbol assetId matches the relay assetId', () => {
expect(isRelayNativeAsset(registry, 'DOT')).toEqual(true);
});
it('Should return false when a symbol assetId does not match the relay assetId', () => {
expect(isRelayNativeAsset(registry, 'KSM')).toEqual(false);
});
it('Should return true when the relay chains asset location is given as input from the persepect of AssetHub', () => {
expect(isRelayNativeAsset(registry, '{"parents":"1","interior":{"Here":""}}')).toEqual(true);
});
it('Should return false when the relay chains asset location is given as input from the perspective of the relay chain', () => {
expect(isRelayNativeAsset(registry, '{"parents":"0","interior":{"Here":""}}')).toEqual(false);
});
});
});
18 changes: 15 additions & 3 deletions src/createXcmTypes/util/isRelayNativeAsset.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
// Copyright 2023 Parity Technologies (UK) Ltd.
// Copyright 2024 Parity Technologies (UK) Ltd.

import { RELAY_CHAIN_IDS } from '../../consts';
import { Registry } from '../../registry';

export const isRelayNativeAsset = (registry: Registry, assetId: string): boolean => {
const relayChainId = RELAY_CHAIN_IDS[0];
const { tokens } = registry.currentRelayRegistry[relayChainId];
const originChainId = registry.lookupChainIdBySpecName(registry.specName);
const originIsRelayChain = originChainId === relayChainId;

export const isRelayNativeAsset = (tokens: string[], assetId: string): boolean => {
// if assetId is an empty string treat it as the relay asset
if (assetId === '') {
return true;
}

if (assetId === `{"parents":"0","interior":{"Here":""}}` || assetId === `{"parents":"1","interior":{"Here":""}}`) {
if (originIsRelayChain && assetId === `{"parents":"0","interior":{"Here":""}}`) {
return true;
}

if (!originIsRelayChain && assetId === `{"parents":"1","interior":{"Here":""}}`) {
return true;
}

Expand Down
4 changes: 2 additions & 2 deletions src/errors/checkBaseInputTypes.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ describe('checkBaseInputTypes', () => {
['10000000000'],
);

expect(err).toThrow(`'assetIds' must be a array. Received: string`);
expect(err).toThrow(`'assetIds' must be an array. Received: string`);
});
it('Should error when assetIds has the wrong types in the array', () => {
const err = () =>
Expand All @@ -48,7 +48,7 @@ describe('checkBaseInputTypes', () => {
10000000000 as unknown as string[],
);

expect(err).toThrow(`'amounts' must be a array. Received: number`);
expect(err).toThrow(`'amounts' must be an array. Received: number`);
});
it('Should error when amounts has the wrong types in the array', () => {
const err = () =>
Expand Down
4 changes: 2 additions & 2 deletions src/errors/checkBaseInputTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const checkBaseInputTypes = (destChainId: string, destAddr: string, asset
}

if (!Array.isArray(assetIds)) {
throw new BaseError(`'assetIds' must be a array. Received: ${typeof assetIds}`, BaseErrorsEnum.InvalidInput);
throw new BaseError(`'assetIds' must be an array. Received: ${typeof assetIds}`, BaseErrorsEnum.InvalidInput);
} else {
for (let i = 0; i < assetIds.length; i++) {
if (typeof assetIds[i] !== 'string') {
Expand All @@ -33,7 +33,7 @@ export const checkBaseInputTypes = (destChainId: string, destAddr: string, asset
}

if (!Array.isArray(amounts)) {
throw new BaseError(`'amounts' must be a array. Received: ${typeof amounts}`, BaseErrorsEnum.InvalidInput);
throw new BaseError(`'amounts' must be an array. Received: ${typeof amounts}`, BaseErrorsEnum.InvalidInput);
} else {
for (let i = 0; i < amounts.length; i++) {
if (typeof amounts[i] !== 'string') {
Expand Down
16 changes: 13 additions & 3 deletions src/errors/checkLocalTxInput/checkLocalRelayInput.spec.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
// Copyright 2023 Parity Technologies (UK) Ltd.
// Copyright 2024 Parity Technologies (UK) Ltd.

import { Registry } from '../../registry';
import { checkLocalRelayInput } from './checkLocalRelayInput';
import { LocalTxType } from './types';

describe('checkLocalRelayInput', () => {
const registry = new Registry('statemine', { chainName: 'rococo' });

it('Should return LocalTxType.Balances', () => {
const res = checkLocalRelayInput([], ['10000']);
const res = checkLocalRelayInput([], ['10000'], registry);
expect(res).toEqual(LocalTxType.Balances);
});
it('Should error with an invalid input', () => {
expect(() => checkLocalRelayInput(['dot', 'ksm'], ['100000'])).toThrow(
expect(() => checkLocalRelayInput(['roc', 'ksm'], ['100000'], registry)).toThrow(
'Local transactions must have the `assetIds` input be a length of 1 or 0, and the `amounts` input be a length of 1',
);
});
it('Should correctly error when a non native asset is passed in', () => {
expect(() =>
checkLocalRelayInput(['{"parents":"3","interior":{"X1":{"GlobalConsensus":"Westend"}}}'], ['100000'], registry),
).toThrow(
'AssetId {"parents":"3","interior":{"X1":{"GlobalConsensus":"Westend"}}} is not the native asset of rococo relay chain. Expected an assetId of ROC or asset location {"parents":"0","interior":{"Here":""}}',
);
});
});
17 changes: 15 additions & 2 deletions src/errors/checkLocalTxInput/checkLocalRelayInput.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
// Copyright 2023 Parity Technologies (UK) Ltd.
// Copyright 2024 Parity Technologies (UK) Ltd.

import { RELAY_CHAIN_IDS, RELAY_CHAINS_NATIVE_ASSET_LOCATION } from '../../consts';
import { isRelayNativeAsset } from '../../createXcmTypes/util/isRelayNativeAsset';
import { Registry } from '../../registry';
import { BaseError, BaseErrorsEnum } from '../BaseError';
import { LocalTxType } from './types';

export const checkLocalRelayInput = (assetIds: string[], amounts: string[]): LocalTxType => {
export const checkLocalRelayInput = (assetIds: string[], amounts: string[], registry: Registry): LocalTxType => {
if (assetIds.length > 1 || amounts.length !== 1) {
throw new BaseError(
'Local transactions must have the `assetIds` input be a length of 1 or 0, and the `amounts` input be a length of 1',
BaseErrorsEnum.InvalidInput,
);
}
const relayChainId = RELAY_CHAIN_IDS[0];
const relayChain = registry.currentRelayRegistry[relayChainId];
const relayChainNativeAsset = relayChain.tokens[0];

const assetIsRelayNativeAsset = assetIds.length === 0 ? true : isRelayNativeAsset(registry, assetIds[0]);
if (!assetIsRelayNativeAsset) {
throw new BaseError(
`AssetId ${assetIds[0]} is not the native asset of ${relayChain.specName} relay chain. Expected an assetId of ${relayChainNativeAsset} or asset location ${RELAY_CHAINS_NATIVE_ASSET_LOCATION}`,
);
}

return LocalTxType.Balances;
};
2 changes: 1 addition & 1 deletion src/errors/checkLocalTxInput/checkLocalTxInput.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ describe('checkLocalTxInput', () => {
it('Should correctly throw an error with an incorrect assetId', async () => {
await expect(async () => {
await checkLocalTxInput(systemAssetsApi.api, ['TST'], ['10000'], specName, registry, 2, false, false);
}).rejects.toThrow('assetId TST is not a valid symbol or integer asset id for statemine');
}).rejects.toThrow('assetId TST is not a valid symbol, integer asset id or location for statemine');
});
it("Should correctly throw an error when the integer assetId doesn't exist", async () => {
await expect(async () => {
Expand Down
32 changes: 24 additions & 8 deletions src/errors/checkXcmTxInputs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,19 +109,19 @@ describe('checkAssetIds', () => {
'Polkadot',
['1', 'DOT'],
Direction.RelayToSystem,
`(RelayToSystem) asset 1 is not polkadot's native asset. Expected DOT`,
`(RelayToSystem) assetId 1 is not the native asset of polkadot relay chain. Expected an assetId of DOT or asset location {"parents":"0","interior":{"Here":""}}`,
],
[
'Kusama',
['DOT', 'KSM'],
Direction.RelayToSystem,
`(RelayToSystem) asset DOT is not kusama's native asset. Expected KSM`,
`(RelayToSystem) assetId DOT is not the native asset of kusama relay chain. Expected an assetId of KSM or asset location {"parents":"0","interior":{"Here":""}}`,
],
[
'Westend',
['WND', '100000'],
Direction.RelayToSystem,
`(RelayToSystem) asset 100000 is not westend's native asset. Expected WND`,
`(RelayToSystem) assetId 100000 is not the native asset of westend relay chain. Expected an assetId of WND or asset location {"parents":"0","interior":{"Here":""}}`,
],
];

Expand All @@ -134,13 +134,13 @@ describe('checkAssetIds', () => {
'Polkadot',
['1', 'DOT'],
Direction.RelayToPara,
`(RelayToPara) asset 1 is not polkadot's native asset. Expected DOT`,
`(RelayToPara) assetId 1 is not the native asset of polkadot relay chain. Expected an assetId of DOT or asset location {"parents":"0","interior":{"Here":""}}`,
],
[
'Kusama',
['DOT', 'KSM'],
Direction.RelayToPara,
`(RelayToPara) asset DOT is not kusama's native asset. Expected KSM`,
`(RelayToPara) assetId DOT is not the native asset of kusama relay chain. Expected an assetId of KSM or asset location {"parents":"0","interior":{"Here":""}}`,
],
];

Expand All @@ -149,9 +149,24 @@ describe('checkAssetIds', () => {

it('Should error when direction is SystemToRelay and an assetId is not native to the relay chain', async () => {
const tests: Test[] = [
['Statemint', ['0'], Direction.SystemToRelay, `(SystemToRelay) assetId 0 not native to polkadot`],
['Statemine', ['MOVR', 'KSM'], Direction.SystemToRelay, `(SystemToRelay) assetId MOVR not native to kusama`],
['Westmint', ['WND', '250'], Direction.SystemToRelay, `(SystemToRelay) assetId 250 not native to westend`],
[
'Statemint',
['0'],
Direction.SystemToRelay,
`(SystemToRelay) assetId 0 is not the native asset of polkadot relay chain. Expected an assetId of DOT or asset location {"parents":"1","interior":{"Here":""}}`,
],
[
'Statemine',
['MOVR', 'KSM'],
Direction.SystemToRelay,
`(SystemToRelay) assetId MOVR is not the native asset of kusama relay chain. Expected an assetId of KSM or asset location {"parents":"1","interior":{"Here":""}}`,
],
[
'Westmint',
['WND', '250'],
Direction.SystemToRelay,
`(SystemToRelay) assetId 250 is not the native asset of westend relay chain. Expected an assetId of WND or asset location {"parents":"1","interior":{"Here":""}}`,
],
];

await runTests(tests);
Expand Down Expand Up @@ -855,6 +870,7 @@ describe('checkBridgeTxInputs', () => {
);
});
});

describe('checkPaysWithFeeDestAssetIdIsInAssets', () => {
it('Should correctly error when a paysWithFeeDestAsset is not found in the assetIds list', () => {
const assetIds = [`{"parents":"2","interior":{"X1":{"GlobalConsensus":"Rococo"}}}`];
Expand Down
Loading