diff --git a/apps/playground/src/components/assets/AssetsForm.tsx b/apps/playground/src/components/assets/AssetsForm.tsx index 44bbaed8..523cfd31 100644 --- a/apps/playground/src/components/assets/AssetsForm.tsx +++ b/apps/playground/src/components/assets/AssetsForm.tsx @@ -47,15 +47,26 @@ const AssetsForm: FC = ({ onSubmit, loading }) => { funcVal === "DECIMALS" || funcVal == "HAS_SUPPORT" || funcVal === "BALANCE_FOREIGN" || - funcVal === "ASSET_BALANCE"; + funcVal === "ASSET_BALANCE" || + funcVal === "MAX_FOREIGN_TRANSFERABLE_AMOUNT" || + funcVal === "TRANSFERABLE_AMOUNT" || + funcVal === "EXISTENTIAL_DEPOSIT"; const supportsCurrencyType = - funcVal === "BALANCE_FOREIGN" || funcVal === "ASSET_BALANCE"; + funcVal === "BALANCE_FOREIGN" || + funcVal === "ASSET_BALANCE" || + funcVal === "MAX_NATIVE_TRANSFERABLE_AMOUNT" || + funcVal === "MAX_FOREIGN_TRANSFERABLE_AMOUNT" || + funcVal === "TRANSFERABLE_AMOUNT" || + funcVal === "EXISTENTIAL_DEPOSIT"; const showAddressInput = funcVal === "BALANCE_FOREIGN" || funcVal === "BALANCE_NATIVE" || - funcVal === "ASSET_BALANCE"; + funcVal === "ASSET_BALANCE" || + funcVal === "MAX_NATIVE_TRANSFERABLE_AMOUNT" || + funcVal === "MAX_FOREIGN_TRANSFERABLE_AMOUNT" || + funcVal === "TRANSFERABLE_AMOUNT"; const onSubmitInternal = (formValues: FormValues) => { const { func } = formValues; @@ -71,7 +82,9 @@ const AssetsForm: FC = ({ onSubmit, loading }) => { funcVal === "PARA_ID" || funcVal === "BALANCE_NATIVE" || funcVal === "BALANCE_FOREIGN" || - funcVal === "ASSET_BALANCE"; + funcVal === "ASSET_BALANCE" || + funcVal === "MAX_NATIVE_TRANSFERABLE_AMOUNT" || + funcVal === "MAX_FOREIGN_TRANSFERABLE_AMOUNT"; const nodeList = notSupportsEthereum ? NODE_NAMES_DOT_KSM : NODE_NAMES; diff --git a/apps/playground/src/components/assets/AssetsQueries.tsx b/apps/playground/src/components/assets/AssetsQueries.tsx index 00f51963..2518e79e 100644 --- a/apps/playground/src/components/assets/AssetsQueries.tsx +++ b/apps/playground/src/components/assets/AssetsQueries.tsx @@ -8,7 +8,9 @@ import AssetsForm from "./AssetsForm"; import type { TCurrencyCore, TMultiLocation, + TNodeDotKsmWithRelayChains, TNodePolkadotKusama, + TNodeWithRelayChains, } from "@paraspell/sdk"; import { getAllAssetsSymbols, @@ -94,6 +96,28 @@ const AssetsQueries = () => { node: node as TNodePolkadotKusama, currency: resolvedCurrency, }); + case "MAX_NATIVE_TRANSFERABLE_AMOUNT": + return Sdk.getMaxNativeTransferableAmount({ + address, + node: node as TNodeDotKsmWithRelayChains, + }); + case "MAX_FOREIGN_TRANSFERABLE_AMOUNT": + return Sdk.getMaxForeignTransferableAmount({ + address, + node: node as TNodePolkadotKusama, + currency: resolvedCurrency, + }); + case "TRANSFERABLE_AMOUNT": + return Sdk.getTransferableAmount({ + address, + node: node as TNodePolkadotKusama, + currency: resolvedCurrency, + }); + case "EXISTENTIAL_DEPOSIT": + return Sdk.getExistentialDeposit( + node as TNodeWithRelayChains, + resolvedCurrency, + ); } }; @@ -129,6 +153,20 @@ const AssetsQueries = () => { return apiType === "PAPI" ? `/balance/${node}/asset-papi` : `/balance/${node}/asset`; + case "MAX_NATIVE_TRANSFERABLE_AMOUNT": + return apiType === "PAPI" + ? `/balance/${node}/max-native-transferable-amount-papi` + : `/balance/${node}/max-native-transferable-amount`; + case "MAX_FOREIGN_TRANSFERABLE_AMOUNT": + return apiType === "PAPI" + ? `/balance/${node}/max-foreign-transferable-amount-papi` + : `/balance/${node}/max-foreign-transferable-amount`; + case "TRANSFERABLE_AMOUNT": + return apiType === "PAPI" + ? `/balance/${node}/transferable-amount-papi` + : `/balance/${node}/transferable`; + case "EXISTENTIAL_DEPOSIT": + return `/balance/${node}/existential-deposit`; } }; @@ -146,22 +184,26 @@ const AssetsQueries = () => { const getQueryResult = async (formValues: FormValues): Promise => { const { useApi, func, address } = formValues; - const isBalanceQuery = + const shouldUsePost = func === "BALANCE_FOREIGN" || func === "BALANCE_NATIVE" || - func === "ASSET_BALANCE"; + func === "ASSET_BALANCE" || + func === "MAX_NATIVE_TRANSFERABLE_AMOUNT" || + func === "MAX_FOREIGN_TRANSFERABLE_AMOUNT" || + func === "TRANSFERABLE_AMOUNT" || + func === "EXISTENTIAL_DEPOSIT"; const resolvedCurrency = resolveCurrency(formValues); if (useApi) { return fetchFromApi( - isBalanceQuery + shouldUsePost ? { address, currency: resolvedCurrency, } : formValues, `${getEndpoint(formValues)}`, - isBalanceQuery ? "POST" : "GET", - isBalanceQuery, + shouldUsePost ? "POST" : "GET", + shouldUsePost, ); } else { return submitUsingSdk(formValues); diff --git a/apps/playground/src/consts.ts b/apps/playground/src/consts.ts index 969ff7a4..ef3ce0aa 100644 --- a/apps/playground/src/consts.ts +++ b/apps/playground/src/consts.ts @@ -13,6 +13,10 @@ export const ASSET_QUERIES = [ "BALANCE_NATIVE", "BALANCE_FOREIGN", "ASSET_BALANCE", + "MAX_NATIVE_TRANSFERABLE_AMOUNT", + "MAX_FOREIGN_TRANSFERABLE_AMOUNT", + "TRANSFERABLE_AMOUNT", + "EXISTENTIAL_DEPOSIT", ] as const; export const PALLETS_QUERIES = ["ALL_PALLETS", "DEFAULT_PALLET"] as const; diff --git a/apps/xcm-api/src/analytics/EventName.ts b/apps/xcm-api/src/analytics/EventName.ts index 0f154811..d7b82565 100644 --- a/apps/xcm-api/src/analytics/EventName.ts +++ b/apps/xcm-api/src/analytics/EventName.ts @@ -17,6 +17,10 @@ export enum EventName { GET_BALANCE_NATIVE = 'Get Balance Native', GET_BALANCE_NATIVE_PAPI = 'Get Balance Native Papi', GET_BALANCE_FOREIGN = 'Get Balance Foreign', + GET_MAX_NATIVE_TRANSFERABLE_AMOUNT = 'Get Max Native Transferable Amount', + GET_MAX_FOREIGN_TRANSFERABLE_AMOUNT = 'Get Max Foreign Transferable Amount', + GET_TRANSFERABLE_AMOUNT = 'Get Transferable Amount', + GET_EXISTENTIAL_DEPOSIT = 'Get Existential Deposit', GENERATE_XCM_CALL = 'Generate XCM Call', GENERATE_XCM_CALL_BATCH = 'Generate XCM Call Batch', GENERATE_XCM_CALL_BATCH_PAPI = 'Generate XCM Call Batch Papi', diff --git a/apps/xcm-api/src/balance/balance.controller.test.ts b/apps/xcm-api/src/balance/balance.controller.test.ts index 1e8c9a30..9e876576 100644 --- a/apps/xcm-api/src/balance/balance.controller.test.ts +++ b/apps/xcm-api/src/balance/balance.controller.test.ts @@ -7,6 +7,7 @@ import { AnalyticsService } from '../analytics/analytics.service.js'; import { EventName } from '../analytics/EventName.js'; import type { BalanceNativeDto } from './dto/BalanceNativeDto.js'; import type { BalanceForeignDto } from './dto/BalanceForeignDto.js'; +import type { ExistentialDepositDto } from './dto/ExistentialDepositDto.js'; describe('BalanceController', () => { let balanceController: BalanceController; @@ -23,6 +24,10 @@ describe('BalanceController', () => { getBalanceNative: vi.fn(), getBalanceForeign: vi.fn(), getAssetBalance: vi.fn(), + getMaxForeignTransferableAmount: vi.fn(), + getMaxNativeTransferableAmount: vi.fn(), + getTransferableAmount: vi.fn(), + getExistentialDeposit: vi.fn(), }, }, { @@ -183,4 +188,215 @@ describe('BalanceController', () => { expect(result).toEqual(balanceForeignMock); }); }); + + describe('getMaxForeignTransferableAmount', () => { + it('should track analytics and call BalanceService for max foreign transferable amount PAPI', async () => { + const node = 'Acala'; + const params: BalanceForeignDto = { + address: '0x1234567890', + currency: { symbol: 'UNQ' }, + }; + const req = {} as Request; + + const maxForeignAmountMock = BigInt('10000'); + const balanceServiceSpy = vi + .spyOn(balanceService, 'getMaxForeignTransferableAmount') + .mockResolvedValue(maxForeignAmountMock); + const analyticsServiceSpy = vi.spyOn(analyticsService, 'track'); + + const result = + await balanceController.getMaxForeignTransferableAmountPapi( + node, + params, + req, + ); + + expect(analyticsServiceSpy).toHaveBeenCalledWith( + EventName.GET_MAX_FOREIGN_TRANSFERABLE_AMOUNT, + req, + { node }, + ); + expect(balanceServiceSpy).toHaveBeenCalledWith(node, params, true); + expect(result).toEqual(maxForeignAmountMock); + }); + + it('should track analytics and call BalanceService for max foreign transferable amount PJS', async () => { + const node = 'Acala'; + const params: BalanceForeignDto = { + address: '0x1234567890', + currency: { symbol: 'UNQ' }, + }; + const req = {} as Request; + + const maxForeignAmountMock = BigInt('10000'); + const balanceServiceSpy = vi + .spyOn(balanceService, 'getMaxForeignTransferableAmount') + .mockResolvedValue(maxForeignAmountMock); + const analyticsServiceSpy = vi.spyOn(analyticsService, 'track'); + + const result = await balanceController.getMaxForeignTransferableAmount( + node, + params, + req, + ); + + expect(analyticsServiceSpy).toHaveBeenCalledWith( + EventName.GET_MAX_FOREIGN_TRANSFERABLE_AMOUNT, + req, + { node }, + ); + expect(balanceServiceSpy).toHaveBeenCalledWith(node, params); + expect(result).toEqual(maxForeignAmountMock); + }); + }); + + describe('getMaxNativeTransferableAmount', () => { + it('should track analytics and call BalanceService for max native transferable amount PAPI', async () => { + const node = 'Acala'; + const params: BalanceForeignDto = { + address: '0x1234567890', + currency: { symbol: 'UNQ' }, + }; + const req = {} as Request; + + const maxNativeAmountMock = BigInt('20000'); + const balanceServiceSpy = vi + .spyOn(balanceService, 'getMaxNativeTransferableAmount') + .mockResolvedValue(maxNativeAmountMock); + const analyticsServiceSpy = vi.spyOn(analyticsService, 'track'); + + const result = await balanceController.getMaxNativeTransferableAmountPapi( + node, + params, + req, + ); + + expect(analyticsServiceSpy).toHaveBeenCalledWith( + EventName.GET_MAX_FOREIGN_TRANSFERABLE_AMOUNT, // event name matches the code snippet + req, + { node }, + ); + expect(balanceServiceSpy).toHaveBeenCalledWith(node, params, true); + expect(result).toEqual(maxNativeAmountMock); + }); + + it('should track analytics and call BalanceService for max native transferable amount PJS', async () => { + const node = 'Acala'; + const params: BalanceForeignDto = { + address: '0x1234567890', + currency: { symbol: 'UNQ' }, + }; + const req = {} as Request; + + const maxNativeAmountMock = BigInt('20000'); + const balanceServiceSpy = vi + .spyOn(balanceService, 'getMaxNativeTransferableAmount') + .mockResolvedValue(maxNativeAmountMock); + const analyticsServiceSpy = vi.spyOn(analyticsService, 'track'); + + const result = await balanceController.getMaxNativeTransferableAmount( + node, + params, + req, + ); + + expect(analyticsServiceSpy).toHaveBeenCalledWith( + EventName.GET_MAX_FOREIGN_TRANSFERABLE_AMOUNT, // event name matches the code snippet + req, + { node }, + ); + expect(balanceServiceSpy).toHaveBeenCalledWith(node, params); + expect(result).toEqual(maxNativeAmountMock); + }); + }); + + describe('getTransferableAmount', () => { + it('should track analytics and call BalanceService for transferable amount PAPI', async () => { + const node = 'Acala'; + const params: BalanceForeignDto = { + address: '0x1234567890', + currency: { symbol: 'UNQ' }, + }; + const req = {} as Request; + + const amountMock = BigInt('20000'); + const balanceServiceSpy = vi + .spyOn(balanceService, 'getTransferableAmount') + .mockResolvedValue(amountMock); + const analyticsServiceSpy = vi.spyOn(analyticsService, 'track'); + + const result = await balanceController.getTransferableAmountPapi( + node, + params, + req, + ); + + expect(analyticsServiceSpy).toHaveBeenCalledWith( + EventName.GET_TRANSFERABLE_AMOUNT, + req, + { node }, + ); + expect(balanceServiceSpy).toHaveBeenCalledWith(node, params, true); + expect(result).toEqual(amountMock); + }); + + it('should track analytics and call BalanceService for transferable amount PJS', async () => { + const node = 'Acala'; + const params: BalanceForeignDto = { + address: '0x1234567890', + currency: { symbol: 'UNQ' }, + }; + const req = {} as Request; + + const amountMock = BigInt('20000'); + const balanceServiceSpy = vi + .spyOn(balanceService, 'getTransferableAmount') + .mockResolvedValue(amountMock); + const analyticsServiceSpy = vi.spyOn(analyticsService, 'track'); + + const result = await balanceController.getTransferableAmount( + node, + params, + req, + ); + + expect(analyticsServiceSpy).toHaveBeenCalledWith( + EventName.GET_TRANSFERABLE_AMOUNT, + req, + { node }, + ); + expect(balanceServiceSpy).toHaveBeenCalledWith(node, params); + expect(result).toEqual(amountMock); + }); + }); + + describe('getExistentialDeposit', () => { + it('should track analytics and call BalanceService for existential deposit PJS', async () => { + const node = 'Acala'; + const params: ExistentialDepositDto = { + currency: { symbol: 'DOT' }, + }; + const req = {} as Request; + + const edMock = '1000000000'; + const balanceServiceSpy = vi + .spyOn(balanceService, 'getExistentialDeposit') + .mockResolvedValue(edMock); + const analyticsServiceSpy = vi.spyOn(analyticsService, 'track'); + + const result = await balanceController.getExistentialDeposit( + node, + params, + req, + ); + + expect(analyticsServiceSpy).toHaveBeenCalledWith( + EventName.GET_EXISTENTIAL_DEPOSIT, + req, + { node }, + ); + expect(balanceServiceSpy).toHaveBeenCalledWith(node, params); + expect(result).toEqual(edMock); + }); + }); }); diff --git a/apps/xcm-api/src/balance/balance.controller.ts b/apps/xcm-api/src/balance/balance.controller.ts index b0ee945d..cda4e640 100644 --- a/apps/xcm-api/src/balance/balance.controller.ts +++ b/apps/xcm-api/src/balance/balance.controller.ts @@ -11,6 +11,10 @@ import { BalanceForeignDto, BalanceForeignDtoSchema, } from './dto/BalanceForeignDto.js'; +import { + ExistentialDepositDto, + ExistentialDepositDtoSchema, +} from './dto/ExistentialDepositDto.js'; @Controller('balance') export class BalanceController { @@ -83,4 +87,119 @@ export class BalanceController { }); return this.balanceService.getAssetBalance(node, params); } + + @Post(':node/max-foreign-transferable-amount-papi') + getMaxForeignTransferableAmountPapi( + @Param('node') node: string, + @Body(new ZodValidationPipe(BalanceForeignDtoSchema)) + params: BalanceForeignDto, + @Req() req: Request, + ) { + this.analyticsService.track( + EventName.GET_MAX_FOREIGN_TRANSFERABLE_AMOUNT, + req, + { + node, + }, + ); + return this.balanceService.getMaxForeignTransferableAmount( + node, + params, + true, + ); + } + + @Post(':node/max-foreign-transferable-amount') + getMaxForeignTransferableAmount( + @Param('node') node: string, + @Body(new ZodValidationPipe(BalanceForeignDtoSchema)) + params: BalanceForeignDto, + @Req() req: Request, + ) { + this.analyticsService.track( + EventName.GET_MAX_FOREIGN_TRANSFERABLE_AMOUNT, + req, + { + node, + }, + ); + return this.balanceService.getMaxForeignTransferableAmount(node, params); + } + + @Post(':node/max-native-transferable-amount-papi') + getMaxNativeTransferableAmountPapi( + @Param('node') node: string, + @Body(new ZodValidationPipe(BalanceForeignDtoSchema)) + params: BalanceForeignDto, + @Req() req: Request, + ) { + this.analyticsService.track( + EventName.GET_MAX_FOREIGN_TRANSFERABLE_AMOUNT, + req, + { + node, + }, + ); + return this.balanceService.getMaxNativeTransferableAmount( + node, + params, + true, + ); + } + + @Post(':node/max-native-transferable-amount') + getMaxNativeTransferableAmount( + @Param('node') node: string, + @Body(new ZodValidationPipe(BalanceForeignDtoSchema)) + params: BalanceForeignDto, + @Req() req: Request, + ) { + this.analyticsService.track( + EventName.GET_MAX_FOREIGN_TRANSFERABLE_AMOUNT, + req, + { + node, + }, + ); + return this.balanceService.getMaxNativeTransferableAmount(node, params); + } + + @Post(':node/transferable-amount') + getTransferableAmount( + @Param('node') node: string, + @Body(new ZodValidationPipe(BalanceForeignDtoSchema)) + params: BalanceForeignDto, + @Req() req: Request, + ) { + this.analyticsService.track(EventName.GET_TRANSFERABLE_AMOUNT, req, { + node, + }); + return this.balanceService.getTransferableAmount(node, params); + } + + @Post(':node/transferable-amount-papi') + getTransferableAmountPapi( + @Param('node') node: string, + @Body(new ZodValidationPipe(BalanceForeignDtoSchema)) + params: BalanceForeignDto, + @Req() req: Request, + ) { + this.analyticsService.track(EventName.GET_TRANSFERABLE_AMOUNT, req, { + node, + }); + return this.balanceService.getTransferableAmount(node, params, true); + } + + @Post(':node/existential-deposit') + getExistentialDeposit( + @Param('node') node: string, + @Body(new ZodValidationPipe(ExistentialDepositDtoSchema)) + params: ExistentialDepositDto, + @Req() req: Request, + ) { + this.analyticsService.track(EventName.GET_EXISTENTIAL_DEPOSIT, req, { + node, + }); + return this.balanceService.getExistentialDeposit(node, params); + } } diff --git a/apps/xcm-api/src/balance/balance.service.test.ts b/apps/xcm-api/src/balance/balance.service.test.ts index 6e427ae6..4b626985 100644 --- a/apps/xcm-api/src/balance/balance.service.test.ts +++ b/apps/xcm-api/src/balance/balance.service.test.ts @@ -5,21 +5,34 @@ import { createApiInstanceForNode, getBalanceForeign, getBalanceNative, + getExistentialDeposit, + getMaxForeignTransferableAmount, + getMaxNativeTransferableAmount, + getTransferableAmount, } from '@paraspell/sdk'; import { createApiInstanceForNode as createApiInstanceForNodePapi, getBalanceNative as getBalanceNativePapi, getBalanceForeign as getBalanceForeignPapi, + getMaxForeignTransferableAmount as getMaxForeignTransferableAmountPapi, + getMaxNativeTransferableAmount as getMaxNativeTransferableAmountPapi, + getTransferableAmount as getTransferableAmountPapi, + getExistentialDeposit as getExistentialDepositPapi, } from '@paraspell/sdk/papi'; import type { BalanceNativeDto } from './dto/BalanceNativeDto.js'; import type { BalanceForeignDto } from './dto/BalanceForeignDto.js'; import type { ApiPromise } from '@polkadot/api'; import type { PolkadotClient } from 'polkadot-api'; +import type { ExistentialDepositDto } from './dto/ExistentialDepositDto.js'; vi.mock('@paraspell/sdk', () => ({ createApiInstanceForNode: vi.fn(), getBalanceForeign: vi.fn(), getBalanceNative: vi.fn(), + getMaxForeignTransferableAmount: vi.fn(), + getMaxNativeTransferableAmount: vi.fn(), + getTransferableAmount: vi.fn(), + getExistentialDeposit: vi.fn(), NODE_NAMES_DOT_KSM: ['valid-node'], NODES_WITH_RELAY_CHAINS: ['valid-node'], NODES_WITH_RELAY_CHAINS_DOT_KSM: ['valid-node'], @@ -29,6 +42,10 @@ vi.mock('@paraspell/sdk/papi', () => ({ createApiInstanceForNode: vi.fn(), getBalanceForeign: vi.fn(), getBalanceNative: vi.fn(), + getMaxForeignTransferableAmount: vi.fn(), + getMaxNativeTransferableAmount: vi.fn(), + getTransferableAmount: vi.fn(), + getExistentialDeposit: vi.fn(), NODE_NAMES_DOT_KSM: ['valid-node'], NODES_WITH_RELAY_CHAINS: ['valid-node'], NODES_WITH_RELAY_CHAINS_DOT_KSM: ['valid-node'], @@ -286,4 +303,296 @@ describe('BalanceService', () => { expect(result).toEqual('0'); }); }); + + describe('getMaxNativeTransferableAmount', () => { + it('should throw BadRequestException for an invalid node', async () => { + const invalidNode = 'invalid-node'; + const params: BalanceNativeDto = { address: '0x1234567890' }; + + await expect( + balanceService.getMaxNativeTransferableAmount(invalidNode, params), + ).rejects.toThrow(BadRequestException); + }); + + it('should return max native transferable amount for a valid node', async () => { + const validNode = 'valid-node'; + const params: BalanceNativeDto = { address: '0x1234567890' }; + const mockApiInstance = { + disconnect: vi.fn(), + } as unknown as ApiPromise; + const mockAmount = 2000n; + + vi.mocked(createApiInstanceForNode).mockResolvedValue(mockApiInstance); + vi.mocked(getMaxNativeTransferableAmount).mockResolvedValue(mockAmount); + + const disconnectSpy = vi.spyOn(mockApiInstance, 'disconnect'); + + const result = await balanceService.getMaxNativeTransferableAmount( + validNode, + params, + ); + + expect(createApiInstanceForNode).toHaveBeenCalledWith(validNode); + expect(getMaxNativeTransferableAmount).toHaveBeenCalledWith({ + address: params.address, + node: validNode, + api: mockApiInstance, + }); + expect(disconnectSpy).toHaveBeenCalled(); + expect(result).toEqual(mockAmount); + }); + + it('should use papi for max native transferable amount if usePapi is true', async () => { + const validNode = 'valid-node'; + const params: BalanceNativeDto = { address: '0x1234567890' }; + const mockApiInstance = { + destroy: vi.fn(), + } as unknown as PolkadotClient; + const mockAmount = 2000n; + + vi.mocked(createApiInstanceForNodePapi).mockResolvedValue( + mockApiInstance, + ); + vi.mocked(getMaxNativeTransferableAmountPapi).mockResolvedValue( + mockAmount, + ); + + const destroySpy = vi.spyOn(mockApiInstance, 'destroy'); + + const result = await balanceService.getMaxNativeTransferableAmount( + validNode, + params, + true, + ); + + expect(createApiInstanceForNodePapi).toHaveBeenCalledWith(validNode); + expect(getMaxNativeTransferableAmountPapi).toHaveBeenCalledWith({ + address: params.address, + node: validNode, + api: mockApiInstance, + }); + expect(destroySpy).toHaveBeenCalled(); + expect(result).toEqual(mockAmount); + }); + }); + + describe('getMaxForeignTransferableAmount', () => { + it('should throw BadRequestException for an invalid node', async () => { + const invalidNode = 'invalid-node'; + const params: BalanceForeignDto = { + address: '0x1234567890', + currency: { symbol: 'UNQ' }, + }; + + await expect( + balanceService.getMaxForeignTransferableAmount(invalidNode, params), + ).rejects.toThrow(BadRequestException); + }); + + it('should return max foreign transferable amount for a valid node', async () => { + const validNode = 'valid-node'; + const params: BalanceForeignDto = { + address: '0x1234567890', + currency: { symbol: 'UNQ' }, + }; + const mockApiInstance = { + disconnect: vi.fn(), + } as unknown as ApiPromise; + const mockAmount = 3000n; + + vi.mocked(createApiInstanceForNode).mockResolvedValue(mockApiInstance); + vi.mocked(getMaxForeignTransferableAmount).mockResolvedValue(mockAmount); + + const disconnectSpy = vi.spyOn(mockApiInstance, 'disconnect'); + + const result = await balanceService.getMaxForeignTransferableAmount( + validNode, + params, + ); + + expect(createApiInstanceForNode).toHaveBeenCalledWith(validNode); + expect(getMaxForeignTransferableAmount).toHaveBeenCalledWith({ + address: params.address, + currency: params.currency, + node: validNode, + api: mockApiInstance, + }); + expect(disconnectSpy).toHaveBeenCalled(); + expect(result).toEqual(mockAmount); + }); + + it('should use papi for max foreign transferable amount if usePapi is true', async () => { + const validNode = 'valid-node'; + const params: BalanceForeignDto = { + address: '0x1234567890', + currency: { symbol: 'UNQ' }, + }; + const mockApiInstance = { + destroy: vi.fn(), + } as unknown as PolkadotClient; + const mockAmount = 3000n; + + vi.mocked(createApiInstanceForNodePapi).mockResolvedValue( + mockApiInstance, + ); + vi.mocked(getMaxForeignTransferableAmountPapi).mockResolvedValue( + mockAmount, + ); + + const destroySpy = vi.spyOn(mockApiInstance, 'destroy'); + + const result = await balanceService.getMaxForeignTransferableAmount( + validNode, + params, + true, + ); + + expect(createApiInstanceForNodePapi).toHaveBeenCalledWith(validNode); + expect(getMaxForeignTransferableAmountPapi).toHaveBeenCalledWith({ + address: params.address, + currency: params.currency, + node: validNode, + api: mockApiInstance, + }); + expect(destroySpy).toHaveBeenCalled(); + expect(result).toEqual(mockAmount); + }); + }); + + describe('getTransferableAmount', () => { + it('should throw BadRequestException for an invalid node', async () => { + const invalidNode = 'invalid-node'; + const params: BalanceForeignDto = { + address: '0x1234567890', + currency: { symbol: 'UNQ' }, + }; + + await expect( + balanceService.getTransferableAmount(invalidNode, params), + ).rejects.toThrow(BadRequestException); + }); + + it('should return transferable amount for a valid node', async () => { + const validNode = 'valid-node'; + const params: BalanceForeignDto = { + address: '0x1234567890', + currency: { symbol: 'UNQ' }, + }; + const mockApiInstance = { + disconnect: vi.fn(), + } as unknown as ApiPromise; + const mockAmount = 4000n; + + vi.mocked(createApiInstanceForNode).mockResolvedValue(mockApiInstance); + vi.mocked(getTransferableAmount).mockResolvedValue(mockAmount); + + const disconnectSpy = vi.spyOn(mockApiInstance, 'disconnect'); + + const result = await balanceService.getTransferableAmount( + validNode, + params, + ); + + expect(createApiInstanceForNode).toHaveBeenCalledWith(validNode); + expect(getTransferableAmount).toHaveBeenCalledWith({ + address: params.address, + currency: params.currency, + node: validNode, + api: mockApiInstance, + }); + expect(disconnectSpy).toHaveBeenCalled(); + expect(result).toEqual(mockAmount); + }); + + it('should use papi for transferable amount if usePapi is true', async () => { + const validNode = 'valid-node'; + const params: BalanceForeignDto = { + address: '0x1234567890', + currency: { symbol: 'UNQ' }, + }; + const mockApiInstance = { + destroy: vi.fn(), + } as unknown as PolkadotClient; + const mockAmount = 4000n; + + vi.mocked(createApiInstanceForNodePapi).mockResolvedValue( + mockApiInstance, + ); + vi.mocked(getTransferableAmountPapi).mockResolvedValue(mockAmount); + + const destroySpy = vi.spyOn(mockApiInstance, 'destroy'); + + const result = await balanceService.getTransferableAmount( + validNode, + params, + true, + ); + + expect(createApiInstanceForNodePapi).toHaveBeenCalledWith(validNode); + expect(getTransferableAmountPapi).toHaveBeenCalledWith({ + address: params.address, + currency: params.currency, + node: validNode, + api: mockApiInstance, + }); + expect(destroySpy).toHaveBeenCalled(); + expect(result).toEqual(mockAmount); + }); + }); + + describe('getExistentialDeposit', () => { + it('should throw BadRequestException for an invalid node', async () => { + const invalidNode = 'invalid-node'; + const params: ExistentialDepositDto = { + currency: { symbol: 'DOT' }, + }; + + await expect( + balanceService.getExistentialDeposit(invalidNode, params), + ).rejects.toThrow(BadRequestException); + }); + + it('should return existential deposit for a valid node using PJS', async () => { + const validNode = 'valid-node'; + const params: ExistentialDepositDto = { + currency: { symbol: 'DOT' }, + }; + const edMock = '1000000000'; + + vi.mocked(getExistentialDeposit).mockReturnValue(edMock); + + const result = await balanceService.getExistentialDeposit( + validNode, + params, + ); + + expect(getExistentialDeposit).toHaveBeenCalledWith( + validNode, + params.currency, + ); + expect(result).toEqual(edMock); + }); + + it('should return existential deposit for a valid node using PAPI', async () => { + const validNode = 'valid-node'; + const params: ExistentialDepositDto = { + currency: { symbol: 'DOT' }, + }; + const edMock = '1000000000'; + + vi.mocked(getExistentialDepositPapi).mockReturnValue(edMock); + + const result = await balanceService.getExistentialDeposit( + validNode, + params, + true, + ); + + expect(getExistentialDepositPapi).toHaveBeenCalledWith( + validNode, + params.currency, + ); + expect(result).toEqual(edMock); + }); + }); }); diff --git a/apps/xcm-api/src/balance/balance.service.ts b/apps/xcm-api/src/balance/balance.service.ts index 8a3db202..9182e0f6 100644 --- a/apps/xcm-api/src/balance/balance.service.ts +++ b/apps/xcm-api/src/balance/balance.service.ts @@ -1,14 +1,17 @@ import { BadRequestException, Injectable } from '@nestjs/common'; import { NODE_NAMES_DOT_KSM, + NODES_WITH_RELAY_CHAINS, NODES_WITH_RELAY_CHAINS_DOT_KSM, TNodeDotKsmWithRelayChains, TNodePolkadotKusama, + TNodeWithRelayChains, } from '@paraspell/sdk'; import { BalanceNativeDto } from './dto/BalanceNativeDto.js'; import { BalanceForeignDto } from './dto/BalanceForeignDto.js'; import { ApiPromise } from '@polkadot/api'; import { PolkadotClient } from 'polkadot-api'; +import { ExistentialDepositDto } from './dto/ExistentialDepositDto.js'; @Injectable() export class BalanceService { @@ -94,4 +97,106 @@ export class BalanceService { else api.destroy(); return balance === null ? 'null' : balance.toString(); } + + async getMaxNativeTransferableAmount( + node: string, + { address }: BalanceNativeDto, + usePapi = false, + ) { + const nodeTyped = node as TNodeDotKsmWithRelayChains; + if (!NODES_WITH_RELAY_CHAINS_DOT_KSM.includes(nodeTyped)) { + throw new BadRequestException( + `Node ${node} is not valid. Check docs for valid nodes.`, + ); + } + + const Sdk = usePapi + ? await import('@paraspell/sdk/papi') + : await import('@paraspell/sdk'); + + const api = await Sdk.createApiInstanceForNode(nodeTyped); + const balance = await Sdk.getMaxNativeTransferableAmount({ + address, + node: nodeTyped, + api: api as ApiPromise & PolkadotClient, + }); + if ('disconnect' in api) await api.disconnect(); + else api.destroy(); + return balance; + } + + async getMaxForeignTransferableAmount( + node: string, + { address, currency }: BalanceForeignDto, + usePapi = false, + ) { + const nodeTyped = node as TNodePolkadotKusama; + if (!NODE_NAMES_DOT_KSM.includes(nodeTyped)) { + throw new BadRequestException( + `Node ${node} is not valid. Check docs for valid nodes.`, + ); + } + + const Sdk = usePapi + ? await import('@paraspell/sdk/papi') + : await import('@paraspell/sdk'); + + const api = await Sdk.createApiInstanceForNode(nodeTyped); + const balance = await Sdk.getMaxForeignTransferableAmount({ + address, + currency, + node: nodeTyped, + api: api as ApiPromise & PolkadotClient, + }); + if ('disconnect' in api) await api.disconnect(); + else api.destroy(); + return balance; + } + + async getTransferableAmount( + node: string, + { address, currency }: BalanceForeignDto, + usePapi = false, + ) { + const nodeTyped = node as TNodeDotKsmWithRelayChains; + if (!NODES_WITH_RELAY_CHAINS_DOT_KSM.includes(nodeTyped)) { + throw new BadRequestException( + `Node ${node} is not valid. Check docs for valid nodes.`, + ); + } + + const Sdk = usePapi + ? await import('@paraspell/sdk/papi') + : await import('@paraspell/sdk'); + + const api = await Sdk.createApiInstanceForNode(nodeTyped); + const balance = await Sdk.getTransferableAmount({ + address, + currency, + node: nodeTyped, + api: api as ApiPromise & PolkadotClient, + }); + if ('disconnect' in api) await api.disconnect(); + else api.destroy(); + return balance; + } + + async getExistentialDeposit( + node: string, + { currency }: ExistentialDepositDto, + usePapi = false, + ) { + const nodeTyped = node as TNodeWithRelayChains; + if (!NODES_WITH_RELAY_CHAINS.includes(nodeTyped)) { + throw new BadRequestException( + `Node ${node} is not valid. Check docs for valid nodes.`, + ); + } + + const Sdk = usePapi + ? await import('@paraspell/sdk/papi') + : await import('@paraspell/sdk'); + + return Sdk.getExistentialDeposit(nodeTyped, currency); + } } diff --git a/apps/xcm-api/src/balance/dto/ExistentialDepositDto.ts b/apps/xcm-api/src/balance/dto/ExistentialDepositDto.ts new file mode 100644 index 00000000..fa4d6a43 --- /dev/null +++ b/apps/xcm-api/src/balance/dto/ExistentialDepositDto.ts @@ -0,0 +1,8 @@ +import { z } from 'zod'; +import { CurrencyCoreSchema } from '../../x-transfer/dto/XTransferDto.js'; + +export const ExistentialDepositDtoSchema = z.object({ + currency: CurrencyCoreSchema, +}); + +export type ExistentialDepositDto = z.infer; diff --git a/packages/sdk/scripts/assets/fetchAcalaAssets.ts b/packages/sdk/scripts/assets/fetchAcalaAssets.ts new file mode 100644 index 00000000..3af7ccb1 --- /dev/null +++ b/packages/sdk/scripts/assets/fetchAcalaAssets.ts @@ -0,0 +1,62 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +import type { ApiPromise } from '@polkadot/api' +import type { TForeignAsset, TNativeAsset } from '../../src/types' + +const fetchAssets = async ( + api: ApiPromise, + query: string, + isNative: boolean +): Promise => { + const [module, section] = query.split('.') + const res = await api.query[module][section].entries() + + return res + .filter( + ([ + { + args: [era] + } + ]) => { + const hasNativeAssetId = Object.prototype.hasOwnProperty.call( + era.toHuman(), + 'NativeAssetId' + ) + return isNative ? hasNativeAssetId : !hasNativeAssetId + } + ) + .map( + ([ + { + args: [era] + }, + value + ]) => { + const { symbol, decimals, existentialDeposit, minimalBalance } = value.toHuman() as any + return { + assetId: Object.values(era.toHuman() ?? {})[0], + symbol, + decimals: +decimals, + existentialDeposit: minimalBalance ?? existentialDeposit + } + } + ) +} + +export const fetchAcalaNativeAssets = async ( + api: ApiPromise, + query: string +): Promise => { + return (await fetchAssets(api, query, true)).map(asset => ({ + symbol: asset.symbol, + decimals: asset.decimals, + existentialDeposit: asset.existentialDeposit + })) +} + +export const fetchAcalaForeignAssets = async ( + api: ApiPromise, + query: string +): Promise => { + return fetchAssets(api, query, false) +} diff --git a/packages/sdk/scripts/assets/fetchAssets.ts b/packages/sdk/scripts/assets/fetchAssets.ts index 5e034743..908b99a9 100644 --- a/packages/sdk/scripts/assets/fetchAssets.ts +++ b/packages/sdk/scripts/assets/fetchAssets.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-prototype-builtins */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-explicit-any */ @@ -19,39 +20,102 @@ import { fetchEthereumAssets } from './fetchEthereumAssets' import { addAliasesToDuplicateSymbols } from './addAliases' import { capitalizeMultiLocation, fetchOtherAssetsRegistry } from './fetchOtherAssetsRegistry' import { isNodeEvm } from './isNodeEvm' - -const fetchNativeAssets = async (api: ApiPromise): Promise => { +import { fetchBifrostForeignAssets, fetchBifrostNativeAssets } from './fetchBifrostAssets' +import { fetchOtherAssetsCentrifuge } from './fetchAssetsCentrifuge' +import { fetchExistentialDeposit } from './fetchEd' +import { fetchAcalaForeignAssets, fetchAcalaNativeAssets } from './fetchAcalaAssets' +import { getNativeAssetSymbol } from '../../src/pallets/assets' +import { fetchComposableAssets } from './fetchComposableAssets' +import { fetchPendulumForeignAssets } from './fetchPendulumAssets' + +const fetchNativeAssetsDefault = async (api: ApiPromise): Promise => { const propertiesRes = await api.rpc.system.properties() const json = propertiesRes.toHuman() const symbols = json.tokenSymbol as string[] const decimals = json.tokenDecimals as string[] return symbols.map((symbol, i) => ({ symbol, - decimals: decimals[i] ? +decimals[i] : +decimals[0] + decimals: decimals[i] ? +decimals[i] : +decimals[0], + existentialDeposit: fetchExistentialDeposit(api) ?? '0' })) } -const fetchOtherAssets = async (api: ApiPromise, query: string): Promise => { +const fetchNativeAssets = async ( + node: TNodePolkadotKusama, + api: ApiPromise, + query: string +): Promise => { + let nativeAssets: TNativeAsset[] = [] + + if (node === 'Curio') { + nativeAssets = await fetchNativeAssetsCurio(api, query) + } + + if (node === 'BifrostPolkadot' || node === 'BifrostKusama') { + nativeAssets = await fetchBifrostNativeAssets(api, query) + } + + if (node === 'Acala' || node === 'Karura') { + nativeAssets = await fetchAcalaNativeAssets(api, query) + } + + const transformed = nativeAssets.length > 0 ? nativeAssets : await fetchNativeAssetsDefault(api) + + const nativeSymbol = getNativeAssetSymbol(node) + + const reordered = transformed.sort((a, b) => { + if (a.symbol === nativeSymbol) return -1 + if (b.symbol === nativeSymbol) return 1 + return 0 + }) + + return reordered.map(asset => ({ + ...asset, + existentialDeposit: asset.existentialDeposit?.replace(/,/g, '') + })) +} + +const fetchOtherAssetsDefault = async ( + node: TNodePolkadotKusama, + api: ApiPromise, + query: string +): Promise => { const [module, section] = query.split('.') + const res = await api.query[module][section].entries() - return res - .map( - ([ + const results = await Promise.all( + res.map( + async ([ { args: [era] }, value ]) => { - const { symbol, decimals } = value.toHuman() as any + const valueHuman = value.toHuman() as any + const resDetail = + api.query[module] && api.query[module].hasOwnProperty('asset') + ? await api.query[module].asset(era) + : undefined + const resDetail2 = + node === 'Basilisk' ? await api.query.assetRegistry.assets(era) : undefined + return { assetId: era.toString(), - symbol, - decimals: +decimals + symbol: valueHuman.symbol, + decimals: +valueHuman.decimals, + existentialDeposit: + valueHuman.existentialDeposit ?? + valueHuman.minimalBalance ?? + (resDetail?.toHuman() as any)?.existentialDeposit ?? + (resDetail?.toHuman() as any)?.minBalance ?? + (resDetail?.toHuman() as any)?.minimalBalance ?? + (resDetail2?.toHuman() as any)?.existentialDeposit } } ) - .filter(asset => asset.symbol !== null) + ) + return results.filter(asset => asset.symbol !== null) } const fetchNativeAssetsCurio = async (api: ApiPromise, query: string) => { @@ -65,18 +129,20 @@ const fetchNativeAssetsCurio = async (api: ApiPromise, query: string) => { }, value ]) => { - const { symbol, decimals } = value.toHuman() as any + const { symbol, decimals, existentialDeposit } = value.toHuman() as any return { assetId: era.toHuman(), symbol, - decimals: +decimals + decimals: +decimals, + existentialDeposit } } ) .filter(asset => Object.keys(asset.assetId ?? {})[0] === 'Token') .map(asset => ({ symbol: asset.symbol, - decimals: asset.decimals + decimals: asset.decimals, + existentialDeposit: asset.existentialDeposit })) } @@ -91,11 +157,12 @@ const fetchOtherAssetsCurio = async (api: ApiPromise, query: string) => { }, value ]) => { - const { symbol, decimals } = value.toHuman() as any + const { symbol, decimals, existentialDeposit } = value.toHuman() as any return { assetId: era.toHuman(), symbol, - decimals: +decimals + decimals: +decimals, + existentialDeposit } } ) @@ -103,7 +170,8 @@ const fetchOtherAssetsCurio = async (api: ApiPromise, query: string) => { .map(asset => ({ assetId: Object.values(asset.assetId ?? {})[0], symbol: asset.symbol, - decimals: asset.decimals + decimals: asset.decimals, + existentialDeposit: asset.existentialDeposit })) } @@ -125,217 +193,176 @@ const fetchOtherAssetsAmplitude = async (api: ApiPromise, query: string) => { }, value ]) => { - const { symbol, decimals } = value.toHuman() as any + const { symbol, decimals, existentialDeposit } = value.toHuman() as any return { assetId: Object.values(era.toHuman() ?? {})[0].replaceAll(',', ''), symbol, - decimals: +decimals + decimals: +decimals, + existentialDeposit } } ) } -const fetchOtherAssetsInnerType = async (api: ApiPromise, query: string) => { - const [module, section] = query.split('.') - const symbolsResponse = await api.query[module][section].entries() - const assetsWithoutDecimals = symbolsResponse.map( - ([ - { - args: [era] - }, - value - ]) => { - const { inner: symbol } = value.toHuman() as any - const assetId = era.toHuman() as string - const numberAssetId = assetId.replace(/[,]/g, '') - return { - assetId: numberAssetId, - symbol - } - } - ) - const decimalsResponse = await api.query[module].assetDecimals.entries() - const assetsWithoutSymbols = decimalsResponse.map( - ([ - { - args: [era] - }, - value - ]) => { - const assetId = era.toHuman() as string - const numberAssetId = assetId.replace(/[,]/g, '') - return { assetId: numberAssetId, decimals: +(value.toHuman() as number) } - } - ) - - return assetsWithoutDecimals - .map(assetWithoutDecimals => { - const matchingAsset = assetsWithoutSymbols.find( - assetWithoutSymbols => assetWithoutSymbols.assetId === assetWithoutDecimals.assetId - ) - return matchingAsset ? { ...assetWithoutDecimals, decimals: matchingAsset.decimals } : null - }) - .filter(asset => asset !== null) as unknown as TForeignAsset[] +const fetchNativeAsset = async (api: ApiPromise): Promise => { + const propertiesRes = await api.rpc.system.properties() + const json = propertiesRes.toHuman() + const symbols = json.tokenSymbol as string[] + return symbols[0] } -const fetchAssetsType2 = async (api: ApiPromise, query: string): Promise> => { - const [module, section] = query.split('.') - const res = await api.query[module][section].entries() - - const nativeAssets = res - .filter( - ([ - { - args: [era] - } - ]) => Object.prototype.hasOwnProperty.call(era.toHuman(), 'NativeAssetId') - ) - .map(([, value]) => { - const { symbol, decimals } = value.toHuman() as any - return { symbol, decimals: +decimals } - }) +const fetchMultiLocations = async (api: ApiPromise): Promise => { + const res = await api.query.foreignAssets.metadata.entries() - const otherAssets = res - .filter( - ([ - { - args: [era] - } - ]) => !Object.prototype.hasOwnProperty.call(era.toHuman(), 'NativeAssetId') - ) - .map( - ([ + const results = await Promise.all( + res.map( + async ([ { args: [era] }, value ]) => { + const multiLocation = era.toJSON() ?? {} + const resDetail = await api.query.foreignAssets.asset(era) const { symbol, decimals } = value.toHuman() as any + return { - assetId: Object.values(era.toHuman() ?? {})[0], symbol, - decimals: +decimals + decimals: +decimals, + multiLocation: multiLocation as object, + existentialDeposit: (resDetail.toHuman() as any).minBalance.replace(/,/g, '') } } ) + ) - return { nativeAssets, otherAssets } + return results } -const fetchNativeAsset = async (api: ApiPromise): Promise => { - const propertiesRes = await api.rpc.system.properties() - const json = propertiesRes.toHuman() - const symbols = json.tokenSymbol as string[] - return symbols[0] -} +const fetchOtherAssets = async ( + node: TNodePolkadotKusama, + api: ApiPromise, + query: string +): Promise => { + let otherAssets: TForeignAsset[] = [] + if (node === 'Zeitgeist' || node === 'Acala' || node === 'Karura') { + otherAssets = await fetchAcalaForeignAssets(api, query) + } -const fetchMultiLocations = async (api: ApiPromise): Promise => { - const res = await api.query.foreignAssets.metadata.entries() - return res.map( - ([ - { - args: [era] - }, - value - ]) => { - const multiLocation = era.toJSON() ?? {} - const { symbol, decimals } = value.toHuman() as any - return { - symbol, - decimals: +decimals, - multiLocation: multiLocation as object - } - } - ) + if (node === 'Amplitude') { + otherAssets = await fetchOtherAssetsAmplitude(api, query) + } + + if (node === 'Curio') { + otherAssets = await fetchOtherAssetsCurio(api, query) + } + + if (node === 'Picasso' || node === 'ComposableFinance') { + otherAssets = await fetchComposableAssets(api, query) + } + + if (node === 'BifrostPolkadot' || node === 'BifrostKusama') { + otherAssets = await fetchBifrostForeignAssets(api, query) + } + + if (node === 'Centrifuge' || node === 'Altair') { + otherAssets = await fetchOtherAssetsCentrifuge(api, query) + } + + if (node === 'Pendulum') { + otherAssets = await fetchPendulumForeignAssets(api, query) + } + + return otherAssets.length > 0 ? otherAssets : fetchOtherAssetsDefault(node, api, query) } const fetchNodeAssets = async ( node: TNodePolkadotKusama, api: ApiPromise, - query: string | null + query: string[] ): Promise> => { const nativeAssetSymbol = await fetchNativeAsset(api) - if (node === 'Zeitgeist') { - const nativeAssets = (await fetchNativeAssets(api)) ?? [] - const { otherAssets } = (await fetchAssetsType2(api, query!)) ?? [] - await api.disconnect() - return { - nativeAssets, - otherAssets, - nativeAssetSymbol - } - } - if (node === 'Amplitude') { - const nativeAssets = (await fetchNativeAssets(api)) ?? [] - const otherAssets = query ? await fetchOtherAssetsAmplitude(api, query) : [] - await api.disconnect() - return { - nativeAssets, - otherAssets, - nativeAssetSymbol - } - } + const hasGlobal = query.includes(GLOBAL) + const queryPath = hasGlobal ? query[1] : query[0] - // Different format of data - if (node === 'Curio') { - const nativeAssets = query ? await fetchNativeAssetsCurio(api, query) : [] - const otherAssets = query ? await fetchOtherAssetsCurio(api, query) : [] - await api.disconnect() - return { - nativeAssets, - otherAssets, - nativeAssetSymbol - } - } + let globalOtherAssets: TForeignAsset[] = [] + let queryOtherAssets: TForeignAsset[] = [] - if (node === 'Picasso' || node === 'ComposableFinance') { - const nativeAssets = (await fetchNativeAssets(api)) ?? [] - const otherAssets = query ? await fetchOtherAssetsInnerType(api, query) : [] - await api.disconnect() - return { - nativeAssets, - otherAssets, - nativeAssetSymbol - } + if (hasGlobal) { + globalOtherAssets = await fetchOtherAssetsRegistry(node) } - const nativeAssets = (await fetchNativeAssets(api)) ?? [] + if (queryPath) { + queryOtherAssets = await fetchOtherAssets(node, api, queryPath) + } - let otherAssets: TForeignAsset[] + let mergedAssets = globalOtherAssets.map(globalAsset => { + const matchingQueryAsset = queryOtherAssets.find( + queryAsset => queryAsset.assetId === globalAsset.assetId + ) + return matchingQueryAsset + ? { + ...globalAsset, + existentialDeposit: matchingQueryAsset.existentialDeposit?.replace(/,/g, '') + } + : globalAsset + }) - try { - otherAssets = - query === GLOBAL - ? await fetchOtherAssetsRegistry(node) - : typeof query === 'string' - ? await fetchOtherAssets(api, query) - : [] - } catch (e) { - console.warn(`Failed to fetch other assets for ${node}: ${e.message}`) - otherAssets = [] + if (mergedAssets.length === 0 && queryOtherAssets.length > 0) { + mergedAssets.push( + ...queryOtherAssets.map(asset => ({ + ...asset, + existentialDeposit: asset.existentialDeposit?.replace(/,/g, '') + })) + ) } + const nativeAssets = (await fetchNativeAssets(node, api, queryPath)) ?? [] + const isAssetHub = node === 'AssetHubPolkadot' || node === 'AssetHubKusama' if (isAssetHub) { const foreignAssets = await fetchMultiLocations(api) - const transformedForeignAssets = foreignAssets.map(asset => { - return { - ...asset, - multiLocation: asset.multiLocation - ? (capitalizeMultiLocation(asset.multiLocation) as TMultiLocation) - : undefined - } as TForeignAsset - }) - otherAssets.push(...transformedForeignAssets) + + const transformedForeignAssets = foreignAssets.map(asset => ({ + ...asset, + multiLocation: asset.multiLocation + ? (capitalizeMultiLocation(asset.multiLocation) as TMultiLocation) + : undefined + })) as TForeignAsset[] + + // Add transformed foreign assets to the merged list + mergedAssets.push(...transformedForeignAssets) + + // Check for unmatched assets by ID and attempt to match by symbol + const unmatchedAssets = queryOtherAssets.filter( + queryAsset => !mergedAssets.some(asset => asset.assetId === queryAsset.assetId) + ) + + if (unmatchedAssets.length > 0) { + const symbolMatches = unmatchedAssets.filter(queryAsset => + mergedAssets.some(asset => asset.symbol === queryAsset.symbol) + ) + + mergedAssets.push( + ...symbolMatches.map(asset => ({ + ...asset, + existentialDeposit: asset.existentialDeposit?.replace(/,/g, '') + })) + ) + } + + mergedAssets = mergedAssets.filter(asset => asset.multiLocation || asset.xcmInterior) } + mergedAssets = mergedAssets.filter(asset => asset.assetId !== 'Native') + await api.disconnect() return { nativeAssets, - otherAssets, + otherAssets: mergedAssets, nativeAssetSymbol, isEVM: isNodeEvm(api) } diff --git a/packages/sdk/scripts/assets/fetchAssetsCentrifuge.ts b/packages/sdk/scripts/assets/fetchAssetsCentrifuge.ts new file mode 100644 index 00000000..70a019a7 --- /dev/null +++ b/packages/sdk/scripts/assets/fetchAssetsCentrifuge.ts @@ -0,0 +1,38 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +import type { ApiPromise } from '@polkadot/api' + +export const fetchOtherAssetsCentrifuge = async (api: ApiPromise, query: string) => { + const [module, section] = query.split('.') + const res = await api.query[module][section].entries() + return res + .filter( + ([ + { + args: [era] + } + ]) => era.toHuman() !== 'Native' + ) + .map( + ([ + { + args: [era] + }, + value + ]) => { + const { symbol, decimals, existentialDeposit } = value.toHuman() as any + const eraObj = era as any + return { + assetId: + eraObj.type === 'Tranche' + ? Object.values(era.toHuman() ?? {})[0][0].replaceAll(',', '') + : Object.values(era.toHuman() ?? {})[0].replaceAll(',', ''), + symbol, + decimals: +decimals, + existentialDeposit: existentialDeposit + } + } + ) +} diff --git a/packages/sdk/scripts/assets/fetchBifrostAssets.ts b/packages/sdk/scripts/assets/fetchBifrostAssets.ts new file mode 100644 index 00000000..475e2927 --- /dev/null +++ b/packages/sdk/scripts/assets/fetchBifrostAssets.ts @@ -0,0 +1,73 @@ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +import type { ApiPromise } from '@polkadot/api' +import type { TForeignAsset, TNativeAsset } from '../../src/types' +import type { StorageKey } from '@polkadot/types' +import type { AnyTuple, Codec } from '@polkadot/types/types' + +export const fetchBifrostNativeAssets = async ( + api: ApiPromise, + query: string +): Promise => { + return fetchBifrostAssets(api, query).then(({ nativeAssets }) => nativeAssets) +} + +export const fetchBifrostForeignAssets = async ( + api: ApiPromise, + query: string +): Promise => { + return fetchBifrostAssets(api, query).then(({ otherAssets }) => otherAssets) +} + +const fetchBifrostAssets = async ( + api: ApiPromise, + query: string +): Promise<{ + nativeAssets: TNativeAsset[] + otherAssets: TForeignAsset[] +}> => { + const [module, section] = query.split('.') + const res = await api.query[module][section].entries() + + const filterAssets = (tokenTypes: string[]) => + res.filter( + ([ + { + args: [era] + } + ]) => { + const tokenType = Object.keys(era.toHuman() ?? {})[0].toLowerCase() + return tokenTypes.includes(tokenType) + } + ) + + const mapAssets = (assets: [StorageKey, Codec][], isNative: boolean) => + assets.map(([_key, value]) => { + const val = value.toHuman() as any + + return isNative + ? { symbol: val.symbol, decimals: +val.decimals, existentialDeposit: val.minimalBalance } + : { + assetId: Object.values(_key.args[0].toHuman() ?? {})[0], + symbol: val.symbol, + decimals: +val.decimals, + existentialDeposit: val.minimalBalance + } + }) + + const nativeAssets = mapAssets( + filterAssets(['token', 'vtoken', 'native']), + true + ) as TNativeAsset[] + + const otherAssets = mapAssets( + filterAssets(['token2', 'vtoken2', 'vstoken2']), + false + ) as TForeignAsset[] + + return { + nativeAssets, + otherAssets + } +} diff --git a/packages/sdk/scripts/assets/fetchComposableAssets.ts b/packages/sdk/scripts/assets/fetchComposableAssets.ts new file mode 100644 index 00000000..2d886355 --- /dev/null +++ b/packages/sdk/scripts/assets/fetchComposableAssets.ts @@ -0,0 +1,39 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +import type { ApiPromise } from '@polkadot/api' +import type { TForeignAsset } from '../../src/types' + +export const fetchComposableAssets = async ( + api: ApiPromise, + query: string +): Promise => { + const [module, section] = query.split('.') + const symbolsResponse = await api.query[module][section].entries() + + const assets = await Promise.all( + symbolsResponse.map( + async ([ + { + args: [era] + }, + value + ]) => { + const { inner: symbol } = value.toHuman() as any + const assetId = era.toHuman() as string + const numberAssetId = assetId.replace(/[,]/g, '') + + const decimals = await api.query[module].assetDecimals(era) + const existentialDeposit = await api.query[module].existentialDeposit(era) + + return { + assetId: numberAssetId, + symbol, + decimals: +decimals, + existentialDeposit: existentialDeposit.toHuman() as string + } + } + ) + ) + + return assets +} diff --git a/packages/sdk/scripts/assets/fetchEd.ts b/packages/sdk/scripts/assets/fetchEd.ts new file mode 100644 index 00000000..19c6157e --- /dev/null +++ b/packages/sdk/scripts/assets/fetchEd.ts @@ -0,0 +1,6 @@ +import type { ApiPromise } from '@polkadot/api' + +export const fetchExistentialDeposit = (api: ApiPromise): string | null => { + const balances = api.consts.balances + return balances !== undefined ? balances.existentialDeposit.toString() : null +} diff --git a/packages/sdk/scripts/assets/fetchEthereumAssets.ts b/packages/sdk/scripts/assets/fetchEthereumAssets.ts index 0572cba8..3e1a8690 100644 --- a/packages/sdk/scripts/assets/fetchEthereumAssets.ts +++ b/packages/sdk/scripts/assets/fetchEthereumAssets.ts @@ -35,11 +35,6 @@ export const fetchEthereumAssets = async (): Promise => { SyntaxKind.ArrayLiteralExpression ) - // remove property minimumTransferAmount from each token object - tokenArray.forEachChild(token => { - token.getLastChildByKindOrThrow(SyntaxKind.PropertyAssignment).remove() - }) - const assets: TForeignAsset[] = [] tokenArray.forEachChild(token => { @@ -54,9 +49,17 @@ export const fetchEthereumAssets = async (): Promise => { .getFirstChildByKindOrThrow(SyntaxKind.StringLiteral) .getText() + const ed = item + .getChildAtIndexIfKindOrThrow(4, SyntaxKind.PropertyAssignment) + .getFirstChildByKindOrThrow(SyntaxKind.BigIntLiteral) + .getText() + + const edTransformed = ed.replace(/_/g, '').replace('n', '') + assets.push({ symbol: JSON.parse(symbol), assetId: JSON.parse(assetId), + existentialDeposit: edTransformed.toString(), multiLocation: { parents: 2, interior: { diff --git a/packages/sdk/scripts/assets/fetchPendulumAssets.ts b/packages/sdk/scripts/assets/fetchPendulumAssets.ts new file mode 100644 index 00000000..718dd841 --- /dev/null +++ b/packages/sdk/scripts/assets/fetchPendulumAssets.ts @@ -0,0 +1,39 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +import type { ApiPromise } from '@polkadot/api' +import type { TForeignAsset } from '../../src/types' + +export const fetchPendulumForeignAssets = async ( + api: ApiPromise, + query: string +): Promise => { + const [module, section] = query.split('.') + const res = await api.query[module][section].entries() + + return res + .filter( + ([ + { + args: [era] + } + ]) => { + return Object.prototype.hasOwnProperty.call(era.toHuman(), 'XCM') + } + ) + .map( + ([ + { + args: [era] + }, + value + ]) => { + const { symbol, decimals, existentialDeposit } = value.toHuman() as any + return { + assetId: Object.values(era.toHuman() ?? {})[0], + symbol, + decimals: +decimals, + existentialDeposit: existentialDeposit + } + } + ) +} diff --git a/packages/sdk/scripts/assets/nodeToQueryMap.ts b/packages/sdk/scripts/assets/nodeToQueryMap.ts index dde7cf97..4d70aef2 100644 --- a/packages/sdk/scripts/assets/nodeToQueryMap.ts +++ b/packages/sdk/scripts/assets/nodeToQueryMap.ts @@ -2,65 +2,65 @@ import type { TNode } from '../../src/types' export const GLOBAL = 'GLOBAL_XCM_REGISTRY' -export const nodeToQuery: Record = { +export const nodeToQuery: Record = { // Chain state query: .
for assets metadata // Or GLOBAL flag to use global XCM registry - Acala: GLOBAL, - Astar: GLOBAL, - BifrostPolkadot: GLOBAL, - Bitgreen: null, // No assets metadata query - Centrifuge: GLOBAL, - ComposableFinance: 'assetsRegistry.assetSymbol', - Darwinia: GLOBAL, - Hydration: GLOBAL, - Interlay: GLOBAL, - Litentry: GLOBAL, - Moonbeam: GLOBAL, - Parallel: GLOBAL, - AssetHubPolkadot: GLOBAL, - Altair: GLOBAL, - Amplitude: 'assetRegistry.metadata', - Bajun: GLOBAL, - Basilisk: GLOBAL, - BifrostKusama: GLOBAL, - Calamari: GLOBAL, - Crab: 'assets.metadata', - CrustShadow: 'assets.metadata', - Encointer: null, // No assets metadata query - Imbue: GLOBAL, - InvArchTinker: null, // Assets query returns empty array - Karura: GLOBAL, - Kintsugi: GLOBAL, - Moonriver: GLOBAL, - ParallelHeiko: GLOBAL, - Picasso: 'assetsRegistry.assetSymbol', - Quartz: GLOBAL, - RobonomicsKusama: GLOBAL, - RobonomicsPolkadot: 'assets.metadata', - PeopleKusama: null, // Does not support ParaToPara transfers - PeoplePolkadot: null, // Does not support ParaToPara transfers - Shiden: GLOBAL, - AssetHubKusama: GLOBAL, - Turing: GLOBAL, - Unique: GLOBAL, - Crust: 'assets.metadata', - Manta: 'assets.metadata', - Nodle: GLOBAL, - NeuroWeb: 'assets.metadata', - Pendulum: GLOBAL, - Zeitgeist: 'assetRegistry.metadata', - Collectives: null, - Phala: GLOBAL, - Khala: GLOBAL, - CoretimeKusama: null, - CoretimePolkadot: null, - Subsocial: null, // No assets metadata query - KiltSpiritnet: null, // No assets metadata query - Curio: 'assetRegistry.metadata', - BridgeHubPolkadot: null, - BridgeHubKusama: null, - Mythos: null, // No assets metadata query - Peaq: 'assets.metadata', - Polimec: 'foreignAssets.metadata', - Ethereum: null + Acala: [GLOBAL, 'assetRegistry.assetMetadatas'], + Astar: [GLOBAL, 'assets.metadata'], + BifrostPolkadot: [GLOBAL, 'assetRegistry.currencyMetadatas'], + Bitgreen: [], // No assets metadata query + Centrifuge: [GLOBAL, 'ormlAssetRegistry.metadata'], + ComposableFinance: ['assetsRegistry.assetSymbol'], + Darwinia: [GLOBAL, 'assets.metadata'], + Hydration: [GLOBAL, 'assetRegistry.assets'], + Interlay: [GLOBAL, 'assetRegistry.metadata'], // !!! PROBLEM native assets eds + Litentry: ['assets.metadata'], + Moonbeam: [GLOBAL, 'assets.metadata'], + Parallel: [GLOBAL, 'assets.metadata'], + AssetHubPolkadot: [GLOBAL, 'assets.metadata'], + Altair: [GLOBAL, 'ormlAssetRegistry.metadata'], + Amplitude: ['assetRegistry.metadata'], + Bajun: ['assets.metadata'], + Basilisk: [GLOBAL, 'assetRegistry.assetMetadataMap'], + BifrostKusama: [GLOBAL, 'assetRegistry.currencyMetadatas'], + Calamari: [GLOBAL, 'assets.metadata'], + Crab: ['assets.metadata'], + CrustShadow: ['assets.metadata'], + Encointer: [], // No assets metadata query + Imbue: [], + InvArchTinker: [], // Assets query returns empty array + Karura: [GLOBAL, 'assetRegistry.assetMetadatas'], + Kintsugi: [GLOBAL, 'assetRegistry.metadata'], // !!! PROBLEM native assets eds + Moonriver: [GLOBAL, 'assets.metadata'], + ParallelHeiko: [GLOBAL, 'assets.metadata'], + Picasso: ['assetsRegistry.assetSymbol'], + Quartz: [], + RobonomicsKusama: ['assets.metadata'], + RobonomicsPolkadot: ['assets.metadata'], + PeopleKusama: [], // Does not support ParaToPara transfers + PeoplePolkadot: [], // Does not support ParaToPara transfers + Shiden: [GLOBAL, 'assets.metadata'], + AssetHubKusama: [GLOBAL, 'assets.metadata'], + Turing: [GLOBAL, 'assetRegistry.metadata'], + Unique: [], + Crust: ['assets.metadata'], + Manta: ['assets.metadata'], + Nodle: [], + NeuroWeb: ['assets.metadata'], + Pendulum: [GLOBAL, 'assetRegistry.metadata'], + Zeitgeist: ['assetRegistry.metadata'], + Collectives: [], + Phala: [GLOBAL, 'assets.metadata'], + Khala: [GLOBAL, 'assets.metadata'], + CoretimeKusama: [], + CoretimePolkadot: [], + Subsocial: [], // No assets metadata query + KiltSpiritnet: [], // No assets metadata query + Curio: ['assetRegistry.metadata'], + BridgeHubPolkadot: [], + BridgeHubKusama: [], + Mythos: [], // No assets metadata query + Peaq: ['assets.metadata'], + Polimec: ['foreignAssets.metadata'], + Ethereum: [] } diff --git a/packages/sdk/scripts/eds/fetchEds.ts b/packages/sdk/scripts/eds/fetchEds.ts deleted file mode 100644 index 8a0655f9..00000000 --- a/packages/sdk/scripts/eds/fetchEds.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { ApiPromise } from '@polkadot/api' -import { NODES_WITH_RELAY_CHAINS_DOT_KSM } from '../../src/maps/consts' -import type { TEdJsonMap } from '../../src/types' -import { fetchTryMultipleProvidersWithTimeout } from '../scriptUtils' -import { createApiInstanceForNode } from '../../src/pjs' - -const fetchExistentialDeposit = (api: ApiPromise): string | null => { - const balances = api.consts.balances - return balances !== undefined ? balances.existentialDeposit.toString() : null -} - -export const fetchAllExistentialDeposits = async (assetsMapJson: unknown) => { - const output = JSON.parse(JSON.stringify(assetsMapJson)) as TEdJsonMap - for (const node of NODES_WITH_RELAY_CHAINS_DOT_KSM) { - console.log(`Fetching existential deposits for ${node}...`) - - let newData: string | null - if (node === 'Polkadot' || node === 'Kusama') { - const api = await createApiInstanceForNode(node) - newData = fetchExistentialDeposit(api) - } else { - newData = await fetchTryMultipleProvidersWithTimeout(node, api => - fetchExistentialDeposit(api) - ) - } - - const oldData = Object.prototype.hasOwnProperty.call(output, node) ? output[node] : null - - output[node] = newData ?? oldData - } - return output -} diff --git a/packages/sdk/scripts/eds/updateEds.ts b/packages/sdk/scripts/eds/updateEds.ts deleted file mode 100644 index 4b5eeda2..00000000 --- a/packages/sdk/scripts/eds/updateEds.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { checkForNodeJsEnvironment, handleDataFetching } from '../scriptUtils' -import { fetchAllExistentialDeposits } from './fetchEds' - -const JSON_FILE_PATH = './src/maps/existential-deposits.json' - -void (async () => { - checkForNodeJsEnvironment() - await handleDataFetching( - JSON_FILE_PATH, - fetchAllExistentialDeposits, - 'Successfuly updated existential deposits.' - ) -})() diff --git a/packages/sdk/scripts/scriptUtils.ts b/packages/sdk/scripts/scriptUtils.ts index 65b3d074..e62a6e5c 100644 --- a/packages/sdk/scripts/scriptUtils.ts +++ b/packages/sdk/scripts/scriptUtils.ts @@ -2,7 +2,7 @@ import * as fs from 'fs' import { ApiPromise, WsProvider } from '@polkadot/api' -import { type TNodePolkadotKusama } from '../src/types' +import type { TNodeDotKsmWithRelayChains } from '../src/types' import { getNodeProvider, getNodeProviders } from '../src/nodes/config' export const readJsonOrReturnEmptyObject = (path: string) => { @@ -21,7 +21,7 @@ export const checkForNodeJsEnvironment = () => { } export const fetchTryMultipleProviders = ( - node: TNodePolkadotKusama, + node: TNodeDotKsmWithRelayChains, fetcher: (wsUrl: string) => T ): T | null => { const providers = (() => { @@ -73,7 +73,7 @@ export const fetchWithTimeout = async ( } export const fetchTryMultipleProvidersWithTimeout = async ( - node: TNodePolkadotKusama, + node: TNodeDotKsmWithRelayChains, fetcher: (api: ApiPromise) => T ) => { return fetchTryMultipleProviders(node, async wsUrl => { diff --git a/packages/sdk/src/api/IPolkadotApi.ts b/packages/sdk/src/api/IPolkadotApi.ts index 8ea092e4..d188868f 100644 --- a/packages/sdk/src/api/IPolkadotApi.ts +++ b/packages/sdk/src/api/IPolkadotApi.ts @@ -17,6 +17,7 @@ export interface IPolkadotApi { callTxMethod(serializedCall: TSerializedApiCall): TRes calculateTransactionFee(tx: TRes, address: string): Promise getBalanceNative(address: string): Promise + getBalanceNativeAcala(address: string, symbol: string): Promise getBalanceForeignPolkadotXcm(address: string, id?: string): Promise getMythosForeignBalance(address: string): Promise getAssetHubForeignBalance(address: string, multiLocation: TMultiLocation): Promise diff --git a/packages/sdk/src/maps/assets.json b/packages/sdk/src/maps/assets.json index 36a1dcc9..93a0fd3a 100644 --- a/packages/sdk/src/maps/assets.json +++ b/packages/sdk/src/maps/assets.json @@ -6,7 +6,8 @@ "nativeAssets": [ { "symbol": "DOT", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "10000000000" } ], "otherAssets": [] @@ -18,7 +19,8 @@ "nativeAssets": [ { "symbol": "KSM", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "333333333" } ], "otherAssets": [] @@ -30,14 +32,16 @@ "nativeAssets": [ { "symbol": "PLMC", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "100000000" } ], "otherAssets": [ { "assetId": "10", "symbol": "DOT", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "100000000" }, { "assetId": "1984", @@ -58,7 +62,8 @@ } ] } - } + }, + "existentialDeposit": "70000" }, { "assetId": "1337", @@ -79,7 +84,8 @@ } ] } - } + }, + "existentialDeposit": "70000" } ] }, @@ -90,19 +96,33 @@ "nativeAssets": [ { "symbol": "ACA", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100000000000" }, { - "symbol": "AUSD", - "decimals": 12 + "symbol": "aSEED", + "decimals": 12, + "existentialDeposit": "100000000000" }, { - "symbol": "DOT", - "decimals": 10 + "symbol": "TAP", + "decimals": 12, + "existentialDeposit": "1000000000000" + }, + { + "symbol": "LcDOT", + "decimals": 10, + "existentialDeposit": "100000000" }, { "symbol": "LDOT", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "500000000" + }, + { + "symbol": "DOT", + "decimals": 10, + "existentialDeposit": "100000000" } ], "otherAssets": [ @@ -125,7 +145,8 @@ } ] } - } + }, + "existentialDeposit": "10000" }, { "assetId": "12", @@ -146,7 +167,8 @@ } ] } - } + }, + "existentialDeposit": "10000" }, { "assetId": "13", @@ -167,7 +189,8 @@ } ] } - } + }, + "existentialDeposit": "1000000000" }, { "assetId": "6", @@ -188,7 +211,8 @@ } ] } - } + }, + "existentialDeposit": "500000000000000" }, { "assetId": "5", @@ -209,7 +233,8 @@ } ] } - } + }, + "existentialDeposit": "3000" }, { "assetId": "0", @@ -227,7 +252,8 @@ } ] } - } + }, + "existentialDeposit": "100000000" }, { "assetId": "2", @@ -240,7 +266,8 @@ "Parachain": 2006 } } - } + }, + "existentialDeposit": "100000000000000000" }, { "assetId": "11", @@ -253,7 +280,8 @@ "Parachain": 2008 } } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "8", @@ -274,7 +302,8 @@ } ] } - } + }, + "existentialDeposit": "1000000000" }, { "assetId": "7", @@ -287,7 +316,8 @@ "Parachain": 2011 } } - } + }, + "existentialDeposit": "1000000000" }, { "assetId": "1", @@ -308,7 +338,8 @@ } ] } - } + }, + "existentialDeposit": "100000000000" }, { "assetId": "15", @@ -329,7 +360,8 @@ } ] } - } + }, + "existentialDeposit": "1346900000000000000" }, { "assetId": "3", @@ -350,7 +382,8 @@ } ] } - } + }, + "existentialDeposit": "100" }, { "assetId": "4", @@ -371,7 +404,8 @@ } ] } - } + }, + "existentialDeposit": "1000000000" }, { "assetId": "17", @@ -389,7 +423,8 @@ } ] } - } + }, + "existentialDeposit": "78438200000000" }, { "assetId": "9", @@ -402,7 +437,8 @@ "Parachain": 2035 } } - } + }, + "existentialDeposit": "100000000000" }, { "assetId": "10", @@ -415,7 +451,8 @@ "Parachain": 2037 } } - } + }, + "existentialDeposit": "1250000000000000000" }, { "assetId": "16", @@ -428,7 +465,8 @@ "Parachain": 2040 } } - } + }, + "existentialDeposit": "3202800000000" } ] }, @@ -439,7 +477,8 @@ "nativeAssets": [ { "symbol": "DOT", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "1000000000" } ], "otherAssets": [] @@ -451,7 +490,8 @@ "nativeAssets": [ { "symbol": "KSM", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "33333333" } ], "otherAssets": [] @@ -463,7 +503,8 @@ "nativeAssets": [ { "symbol": "ASTR", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "1000000" } ], "otherAssets": [ @@ -476,7 +517,8 @@ "interior": { "Here": null } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551641", @@ -497,7 +539,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "4294969281", @@ -518,7 +561,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "4294969280", @@ -539,7 +583,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551633", @@ -560,7 +605,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551618", @@ -581,7 +627,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551616", @@ -602,7 +649,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551617", @@ -623,7 +671,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551625", @@ -636,7 +685,8 @@ "Parachain": 2002 } } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551619", @@ -654,7 +704,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551629", @@ -675,7 +726,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551628", @@ -688,7 +740,8 @@ "Parachain": 2011 } } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551639", @@ -709,7 +762,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551626", @@ -730,7 +784,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551638", @@ -751,7 +806,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551624", @@ -772,7 +828,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551640", @@ -793,7 +850,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551632", @@ -814,7 +872,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551623", @@ -835,7 +894,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551637", @@ -856,7 +916,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551620", @@ -877,7 +938,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551621", @@ -898,7 +960,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551630", @@ -916,7 +979,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551622", @@ -929,7 +993,8 @@ "Parachain": 2035 } } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551631", @@ -942,7 +1007,8 @@ "Parachain": 2037 } } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551627", @@ -960,7 +1026,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551636", @@ -993,7 +1060,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551634", @@ -1011,7 +1079,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551635", @@ -1032,7 +1101,8 @@ } ] } - } + }, + "existentialDeposit": "1" } ] }, @@ -1043,7 +1113,13 @@ "nativeAssets": [ { "symbol": "BNC", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "10000000000" + }, + { + "symbol": "vBNC", + "decimals": 12, + "existentialDeposit": "10000000000" } ], "otherAssets": [ @@ -1066,7 +1142,8 @@ } ] } - } + }, + "existentialDeposit": "100" }, { "assetId": "8", @@ -1079,7 +1156,8 @@ "Parachain": 2104 } } - } + }, + "existentialDeposit": "10000000000000" }, { "assetId": "13", @@ -1104,7 +1182,8 @@ } ] } - } + }, + "existentialDeposit": "15000000000000" }, { "assetId": "0", @@ -1115,7 +1194,8 @@ "interior": { "Here": null } - } + }, + "existentialDeposit": "1000000" }, { "assetId": "2", @@ -1136,7 +1216,8 @@ } ] } - } + }, + "existentialDeposit": "1000" }, { "assetId": "5", @@ -1157,7 +1238,8 @@ } ] } - } + }, + "existentialDeposit": "1000" }, { "assetId": "11", @@ -1178,7 +1260,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "10", @@ -1199,7 +1282,8 @@ } ] } - } + }, + "existentialDeposit": "100000000" }, { "assetId": "1", @@ -1217,7 +1301,8 @@ } ] } - } + }, + "existentialDeposit": "1000000000000" }, { "assetId": "1", @@ -1238,7 +1323,8 @@ } ] } - } + }, + "existentialDeposit": "1000000000000" }, { "assetId": "4", @@ -1259,7 +1345,8 @@ } ] } - } + }, + "existentialDeposit": "1000000000000" }, { "assetId": "9", @@ -1280,7 +1367,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "4", @@ -1301,7 +1389,8 @@ } ] } - } + }, + "existentialDeposit": "1000000000000" }, { "assetId": "8", @@ -1322,7 +1411,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000000" }, { "assetId": "12", @@ -1340,7 +1430,8 @@ } ] } - } + }, + "existentialDeposit": "100000000" }, { "assetId": "3", @@ -1361,7 +1452,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000000000" }, { "assetId": "0", @@ -1382,7 +1474,8 @@ } ] } - } + }, + "existentialDeposit": "1000000" }, { "assetId": "0", @@ -1403,7 +1496,8 @@ } ] } - } + }, + "existentialDeposit": "1000000" }, { "assetId": "7", @@ -1424,7 +1518,8 @@ } ] } - } + }, + "existentialDeposit": "10000000" }, { "assetId": "3", @@ -1437,7 +1532,8 @@ "Parachain": 2006 } } - } + }, + "existentialDeposit": "10000000000000000" } ] }, @@ -1448,7 +1544,8 @@ "nativeAssets": [ { "symbol": "BBB", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "1000000000" } ], "otherAssets": [] @@ -1460,7 +1557,8 @@ "nativeAssets": [ { "symbol": "CFG", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "1000000000000" } ], "otherAssets": [ @@ -1473,7 +1571,8 @@ "interior": { "Here": null } - } + }, + "existentialDeposit": "100000" }, { "assetId": "6", @@ -1494,7 +1593,8 @@ } ] } - } + }, + "existentialDeposit": "1000" }, { "assetId": "1", @@ -1515,7 +1615,8 @@ } ] } - } + }, + "existentialDeposit": "1000" }, { "assetId": "3", @@ -1536,7 +1637,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "4", @@ -1554,7 +1656,8 @@ } ] } - } + }, + "existentialDeposit": "1000000000000000" }, { "assetId": "100003", @@ -1585,7 +1688,8 @@ } ] } - } + }, + "existentialDeposit": "1000" }, { "assetId": "100005", @@ -1616,7 +1720,8 @@ } ] } - } + }, + "existentialDeposit": "1000000000000000" }, { "assetId": "100006", @@ -1647,28 +1752,8 @@ } ] } - } - }, - { - "assetId": "Native", - "symbol": "CFG", - "decimals": 18, - "multiLocation": { - "parents": 1, - "interior": { - "X2": [ - { - "Parachain": 2031 - }, - { - "GeneralKey": { - "length": 2, - "data": "0x0001000000000000000000000000000000000000000000000000000000000000" - } - } - ] - } - } + }, + "existentialDeposit": "1000" }, { "assetId": "100002", @@ -1699,7 +1784,8 @@ } ] } - } + }, + "existentialDeposit": "1000" }, { "assetId": "100001", @@ -1730,7 +1816,8 @@ } ] } - } + }, + "existentialDeposit": "1000" }, { "assetId": "100004", @@ -1761,7 +1848,8 @@ } ] } - } + }, + "existentialDeposit": "1000" } ] }, @@ -1772,7 +1860,8 @@ "nativeAssets": [ { "symbol": "SUB", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "100000000" } ], "otherAssets": [] @@ -1784,7 +1873,8 @@ "nativeAssets": [ { "symbol": "LAYR", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100000000000" } ], "otherAssets": [ @@ -1792,128 +1882,153 @@ "assetId": "79228162514264337593543950466", "symbol": "USDT", "decimals": 6, + "existentialDeposit": "1500", "alias": "USDT1" }, { "assetId": "79228162514264337593543950370", "symbol": "vDOT", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "100000000" }, { "assetId": "79228162514264337593543950351", "symbol": "lsDOT", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "21430000" }, { "assetId": "79228162514264337593543952342", "symbol": "ASTR", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "4700000000000000" }, { "assetId": "79228162514264337593543950346", "symbol": "stATOM", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "2000" }, { "assetId": "79228162514264337593543950343", "symbol": "ATOM", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "2000" }, { "assetId": "79228162514264337593543952343", "symbol": "SDN", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "1000000000000000" }, { "assetId": "79228162514264337593543950367", "symbol": "BNC Kusama", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "11000000000" }, { "assetId": "79228162514264337593543950355", "symbol": "TIA", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "9000" }, { "assetId": "79228162514264337593543950338", "symbol": "LAYR", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100000000000" }, { "assetId": "79228162514264337593543952347", "symbol": "EQ", - "decimals": 9 + "decimals": 9, + "existentialDeposit": "700000000" }, { "assetId": "79228162514264337593543950340", "symbol": "KSM", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "375000000" }, { "assetId": "79228162514264337593543950344", "symbol": "OSMO", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "40000" }, { "assetId": "79228162514264337593543950376", "symbol": "GLMR", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "40000000000000000" }, { "assetId": "79228162514264337593543950359", "symbol": "MOVR", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "4100000000000000" }, { "assetId": "79228162514264337593543950361", "symbol": "IST", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "20000" }, { "assetId": "79228162514264337593543950463", "symbol": "EQD", - "decimals": 9 + "decimals": 9, + "existentialDeposit": "200000" }, { "assetId": "79228162514264337593543950352", "symbol": "SILK", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "100000" }, { "assetId": "79228162514264337593543950485", "symbol": "USDT", "decimals": 6, + "existentialDeposit": "200000", "alias": "USDT2" }, { "assetId": "79228162514264337593543950368", "symbol": "vKSM", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "1000000000" }, { "assetId": "79228162514264337593543950342", "symbol": "DOT", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "21430000" }, { "assetId": "79228162514264337593543950337", "symbol": "PICA", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "1000000000" }, { "assetId": "79228162514264337593543950486", "symbol": "USDC", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "200000" }, { "assetId": "79228162514264337593543950369", "symbol": "BNC Polkadot", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "1100000000" }, { "assetId": "79228162514264337593543950354", "symbol": "BLD", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "120000" } ] }, @@ -1924,7 +2039,8 @@ "nativeAssets": [ { "symbol": "RING", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "0" } ], "otherAssets": [ @@ -1937,7 +2053,8 @@ "interior": { "Here": null } - } + }, + "existentialDeposit": "1" }, { "assetId": "1027", @@ -1958,7 +2075,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "1028", @@ -1979,7 +2097,8 @@ } ] } - } + }, + "existentialDeposit": "1" } ] }, @@ -1990,7 +2109,8 @@ "nativeAssets": [ { "symbol": "HDX", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "1000000000000" } ], "otherAssets": [ @@ -2017,7 +2137,8 @@ } ] } - } + }, + "existentialDeposit": "8928571428571430" }, { "assetId": "5", @@ -2028,7 +2149,8 @@ "interior": { "Here": null } - } + }, + "existentialDeposit": "17540000" }, { "assetId": "1000624", @@ -2053,7 +2175,8 @@ } ] } - } + }, + "existentialDeposit": "59084194977843" }, { "assetId": "1000190", @@ -2079,6 +2202,7 @@ ] } }, + "existentialDeposit": "23", "alias": "WBTC1" }, { @@ -2104,7 +2228,9 @@ } ] } - } + }, + "existentialDeposit": "9910802775024780", + "alias": "sUSDS1" }, { "assetId": "1000189", @@ -2130,6 +2256,7 @@ ] } }, + "existentialDeposit": "6009615384615", "alias": "WETH1" }, { @@ -2152,6 +2279,7 @@ ] } }, + "existentialDeposit": "10000", "alias": "USDT1" }, { @@ -2173,7 +2301,8 @@ } ] } - } + }, + "existentialDeposit": "200000000000000" }, { "assetId": "22", @@ -2195,6 +2324,7 @@ ] } }, + "existentialDeposit": "10000", "alias": "USDC2" }, { @@ -2217,6 +2347,7 @@ ] } }, + "existentialDeposit": "5000000000000", "alias": "WETH3" }, { @@ -2238,7 +2369,8 @@ } ] } - } + }, + "existentialDeposit": "90744101633" }, { "assetId": "6", @@ -2259,7 +2391,8 @@ } ] } - } + }, + "existentialDeposit": "2518891687657430" }, { "assetId": "2", @@ -2281,6 +2414,7 @@ ] } }, + "existentialDeposit": "10000000000000000", "alias": "DAI2" }, { @@ -2303,6 +2437,7 @@ ] } }, + "existentialDeposit": "10000", "alias": "USDC3" }, { @@ -2324,7 +2459,8 @@ } ] } - } + }, + "existentialDeposit": "100200401" }, { "assetId": "3", @@ -2346,6 +2482,7 @@ ] } }, + "existentialDeposit": "44", "alias": "WBTC3" }, { @@ -2371,6 +2508,7 @@ ] } }, + "existentialDeposit": "10000", "alias": "USDC1" }, { @@ -2396,6 +2534,7 @@ ] } }, + "existentialDeposit": "5390835579515", "alias": "WETH2" }, { @@ -2414,7 +2553,8 @@ } ] } - } + }, + "existentialDeposit": "34854864344868000" }, { "assetId": "19", @@ -2439,8 +2579,35 @@ ] } }, + "existentialDeposit": "34", "alias": "WBTC2" }, + { + "assetId": "1000745", + "symbol": "sUSDS", + "decimals": 18, + "multiLocation": { + "parents": 1, + "interior": { + "X3": [ + { + "Parachain": 2004 + }, + { + "PalletInstance": 110 + }, + { + "AccountKey20": { + "network": null, + "key": "0xda430218862d3db25de9f61458645dde49a9e9c1" + } + } + ] + } + }, + "existentialDeposit": "9910802775024780", + "alias": "sUSDS2" + }, { "assetId": "18", "symbol": "DAI", @@ -2464,6 +2631,7 @@ ] } }, + "existentialDeposit": "10000000000000000", "alias": "DAI1" }, { @@ -2489,6 +2657,7 @@ ] } }, + "existentialDeposit": "10000", "alias": "USDT2" }, { @@ -2502,7 +2671,8 @@ "Parachain": 2006 } } - } + }, + "existentialDeposit": "147058823529412000" }, { "assetId": "27", @@ -2515,7 +2685,8 @@ "Parachain": 2008 } } - } + }, + "existentialDeposit": "7874015748" }, { "assetId": "26", @@ -2533,7 +2704,8 @@ } ] } - } + }, + "existentialDeposit": "109890109890" }, { "assetId": "14", @@ -2554,7 +2726,8 @@ } ] } - } + }, + "existentialDeposit": "68795189840" }, { "assetId": "33", @@ -2575,7 +2748,8 @@ } ] } - } + }, + "existentialDeposit": "133689839572193000" }, { "assetId": "15", @@ -2596,7 +2770,8 @@ } ] } - } + }, + "existentialDeposit": "18761726" }, { "assetId": "13", @@ -2617,7 +2792,8 @@ } ] } - } + }, + "existentialDeposit": "32467532467532500" }, { "assetId": "11", @@ -2638,7 +2814,8 @@ } ] } - } + }, + "existentialDeposit": "36" }, { "assetId": "17", @@ -2659,7 +2836,8 @@ } ] } - } + }, + "existentialDeposit": "6164274209" }, { "assetId": "1001", @@ -2680,7 +2858,8 @@ } ] } - } + }, + "existentialDeposit": "0" }, { "assetId": "1002", @@ -2701,7 +2880,8 @@ } ] } - } + }, + "existentialDeposit": "0" }, { "assetId": "1003", @@ -2722,7 +2902,8 @@ } ] } - } + }, + "existentialDeposit": "0" }, { "assetId": "1004", @@ -2743,7 +2924,8 @@ } ] } - } + }, + "existentialDeposit": "0" }, { "assetId": "8", @@ -2756,7 +2938,8 @@ "Parachain": 2035 } } - } + }, + "existentialDeposit": "54945054945" }, { "assetId": "25", @@ -2769,7 +2952,8 @@ "Parachain": 2037 } } - } + }, + "existentialDeposit": "1224384348939740000" }, { "assetId": "31", @@ -2787,7 +2971,8 @@ } ] } - } + }, + "existentialDeposit": "1000000000000000000" }, { "assetId": "32", @@ -2808,7 +2993,8 @@ } ] } - } + }, + "existentialDeposit": "100786131828" }, { "assetId": "28", @@ -2821,7 +3007,8 @@ "Parachain": 2086 } } - } + }, + "existentialDeposit": "21358393848783" }, { "assetId": "12", @@ -2842,7 +3029,30 @@ } ] } - } + }, + "existentialDeposit": "1204151916" + }, + { + "assetId": "1000198", + "symbol": "XLM.s", + "decimals": 12, + "multiLocation": { + "parents": 1, + "interior": { + "X3": [ + { + "Parachain": 2094 + }, + { + "PalletInstance": 53 + }, + { + "GeneralIndex": 2 + } + ] + } + }, + "existentialDeposit": "19500780031" }, { "assetId": "1000081", @@ -2860,7 +3070,42 @@ } ] } - } + }, + "existentialDeposit": "153256704981" + }, + { + "assetId": "1000746", + "symbol": "EURC.s", + "decimals": 12, + "multiLocation": { + "parents": 1, + "interior": { + "X5": [ + { + "Parachain": 2094 + }, + { + "PalletInstance": 53 + }, + { + "GeneralIndex": 2 + }, + { + "GeneralKey": { + "length": 4, + "data": "0x4555524300000000000000000000000000000000000000000000000000000000" + } + }, + { + "GeneralKey": { + "length": 32, + "data": "0xcf4f5a26e2090bb3adcf02c7a9d73dbfe6659cc690461475b86437fa49c71136" + } + } + ] + } + }, + "existentialDeposit": "9523809524" }, { "assetId": "24", @@ -2873,7 +3118,8 @@ "Parachain": 2101 } } - } + }, + "existentialDeposit": "20000000" }, { "assetId": "29", @@ -2886,7 +3132,8 @@ "Parachain": 3344 } } - } + }, + "existentialDeposit": "205888408" }, { "assetId": "30", @@ -2899,7 +3146,8 @@ "Parachain": 3369 } } - } + }, + "existentialDeposit": "21367521367521400" } ] }, @@ -2910,27 +3158,33 @@ "nativeAssets": [ { "symbol": "INTR", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "0" }, { "symbol": "IBTC", - "decimals": 8 + "decimals": 8, + "existentialDeposit": "0" }, { "symbol": "DOT", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "0" }, { "symbol": "KINT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "0" }, { "symbol": "KBTC", - "decimals": 8 + "decimals": 8, + "existentialDeposit": "0" }, { "symbol": "KSM", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "0" } ], "otherAssets": [ @@ -2953,7 +3207,8 @@ } ] } - } + }, + "existentialDeposit": "0" }, { "assetId": "12", @@ -2974,7 +3229,8 @@ } ] } - } + }, + "existentialDeposit": "0" }, { "assetId": "1", @@ -2995,7 +3251,8 @@ } ] } - } + }, + "existentialDeposit": "0" }, { "assetId": "7", @@ -3019,7 +3276,8 @@ } ] } - } + }, + "existentialDeposit": "0" }, { "assetId": "5", @@ -3043,7 +3301,8 @@ } ] } - } + }, + "existentialDeposit": "0" }, { "assetId": "8", @@ -3067,7 +3326,8 @@ } ] } - } + }, + "existentialDeposit": "0" }, { "assetId": "9", @@ -3091,7 +3351,8 @@ } ] } - } + }, + "existentialDeposit": "0" }, { "assetId": "15", @@ -3115,7 +3376,8 @@ } ] } - } + }, + "existentialDeposit": "0" }, { "assetId": "10", @@ -3133,7 +3395,8 @@ } ] } - } + }, + "existentialDeposit": "0" }, { "assetId": "6", @@ -3157,7 +3420,8 @@ } ] } - } + }, + "existentialDeposit": "0" }, { "assetId": "4", @@ -3181,7 +3445,8 @@ } ] } - } + }, + "existentialDeposit": "0" }, { "assetId": "11", @@ -3202,7 +3467,8 @@ } ] } - } + }, + "existentialDeposit": "0" }, { "assetId": "3", @@ -3223,7 +3489,8 @@ } ] } - } + }, + "existentialDeposit": "0" }, { "assetId": "13", @@ -3241,7 +3508,8 @@ } ] } - } + }, + "existentialDeposit": "0" }, { "assetId": "14", @@ -3254,7 +3522,8 @@ "Parachain": 2035 } } - } + }, + "existentialDeposit": "10000000000" } ] }, @@ -3265,7 +3534,8 @@ "nativeAssets": [ { "symbol": "LIT", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "100000000000000000" } ], "otherAssets": [] @@ -3277,7 +3547,8 @@ "nativeAssets": [ { "symbol": "GLMR", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "0" } ], "otherAssets": [ @@ -3304,7 +3575,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "124105859028862849477017063633156007283", @@ -3329,7 +3601,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "36282181791341254438422467838694599751", @@ -3354,7 +3627,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "42259045809535163221576417993425387648", @@ -3365,7 +3639,8 @@ "interior": { "Here": null } - } + }, + "existentialDeposit": "1" }, { "assetId": "61295607754960722617854661686514597014", @@ -3386,7 +3661,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "124463719055550872076363892993240202694", @@ -3407,7 +3683,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "166377000701797186346254371275954761085", @@ -3428,7 +3705,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "184218609779515850660274730699350567246", @@ -3449,7 +3727,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "311091173110107856861649819128533077277", @@ -3470,7 +3749,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "64174511183114006009298114091987195453", @@ -3491,7 +3771,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "112679793397406599376365943185137098326", @@ -3512,7 +3793,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "225719522181998468294117309041779353812", @@ -3533,7 +3815,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "110021739665376159354538090254163045594", @@ -3554,7 +3837,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "224821240862170613278369189818311486111", @@ -3575,7 +3859,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "224077081838586484055667086558292981199", @@ -3588,7 +3873,8 @@ "Parachain": 2006 } } - } + }, + "existentialDeposit": "1" }, { "assetId": "187224307232923873519830480073807488153", @@ -3609,7 +3895,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "190590555344745888270686124937537713878", @@ -3622,7 +3909,8 @@ "Parachain": 2011 } } - } + }, + "existentialDeposit": "1" }, { "assetId": "32615670524745285411807346420584982855", @@ -3643,7 +3931,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "78407957940239408223554844611219482002", @@ -3664,7 +3953,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "133307414193833606001516599592873928539", @@ -3685,7 +3975,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "141196559012917796508928734717797136690", @@ -3706,7 +3997,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "199907282886248358976504623107230837230", @@ -3727,7 +4019,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "138280378441551394289980644963240827219", @@ -3748,7 +4041,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "228510780171552721666262089780561563481", @@ -3769,7 +4063,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "309163521958167876851250718453738106865", @@ -3787,7 +4082,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "144012926827374458669278577633504620722", @@ -3808,7 +4104,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "29085784439601774464560083082574142143", @@ -3829,7 +4126,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "142155548796783636521833385094843759961", @@ -3850,7 +4148,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "204507659831918931608354793288110796652", @@ -3871,7 +4170,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "289989900872525819559124583375550296953", @@ -3892,7 +4192,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "165823357460190568952172802245839421906", @@ -3913,7 +4214,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "272547899416482196831721420898811311297", @@ -3934,7 +4236,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "114018676402354620972806895487280206446", @@ -3955,7 +4258,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "91372035960551235635465443179559840483", @@ -3976,7 +4280,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "120637696315203257380661607956669368914", @@ -3997,7 +4302,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "101170542313601871197860408087030232491", @@ -4018,7 +4324,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "69606720909260275826784788104880799692", @@ -4036,7 +4343,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "132685552157663328694213725410064821485", @@ -4049,7 +4357,8 @@ "Parachain": 2035 } } - } + }, + "existentialDeposit": "1" }, { "assetId": "283870493414747423842723289889816153538", @@ -4062,7 +4371,8 @@ "Parachain": 2037 } } - } + }, + "existentialDeposit": "1" }, { "assetId": "90225766094594282577230355136633846906", @@ -4075,7 +4385,8 @@ "Parachain": 2040 } } - } + }, + "existentialDeposit": "1" }, { "assetId": "238111524681612888331172110363070489924", @@ -4093,7 +4404,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "125699734534028342599692732320197985871", @@ -4111,7 +4423,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "150874409661081770150564009349448205842", @@ -4132,7 +4445,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "45647473099451451833602657905356404688", @@ -4150,7 +4464,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "89994634370519791027168048838578580624", @@ -4163,7 +4478,8 @@ "Parachain": 2101 } } - } + }, + "existentialDeposit": "1" }, { "assetId": "166446646689194205559791995948102903873", @@ -4176,7 +4492,8 @@ "Parachain": 2104 } } - } + }, + "existentialDeposit": "1" }, { "assetId": "314077021455772878282433861213184736939", @@ -4189,7 +4506,8 @@ "Parachain": 3338 } } - } + }, + "existentialDeposit": "1" } ] }, @@ -4200,7 +4518,8 @@ "nativeAssets": [ { "symbol": "PARA", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100000000000" } ], "otherAssets": [ @@ -4213,7 +4532,8 @@ "interior": { "Here": null } - } + }, + "existentialDeposit": "1" }, { "assetId": "102", @@ -4234,7 +4554,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "110", @@ -4255,7 +4576,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "108", @@ -4276,7 +4598,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "106", @@ -4297,7 +4620,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "130", @@ -4310,7 +4634,8 @@ "Parachain": 2002 } } - } + }, + "existentialDeposit": "1" }, { "assetId": "114", @@ -4328,7 +4653,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "1001", @@ -4349,7 +4675,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "200070014", @@ -4370,7 +4697,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "200080015", @@ -4391,7 +4719,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "200100017", @@ -4412,7 +4741,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "200060013", @@ -4433,7 +4763,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "200090016", @@ -4454,7 +4785,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "120", @@ -4475,7 +4807,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "122", @@ -4496,7 +4829,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "115", @@ -4509,7 +4843,8 @@ "Parachain": 2035 } } - } + }, + "existentialDeposit": "1" } ] }, @@ -4520,7 +4855,8 @@ "nativeAssets": [ { "symbol": "DOT", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "100000000" }, { "symbol": "KSM", @@ -4546,7 +4882,8 @@ { "GeneralIndex": 1024 } - ] + ], + "existentialDeposit": "100000000" }, { "assetId": "1337", @@ -4565,7 +4902,8 @@ { "GeneralIndex": 1337 } - ] + ], + "existentialDeposit": "10000" }, { "assetId": "17", @@ -4584,7 +4922,8 @@ { "GeneralIndex": 17 } - ] + ], + "existentialDeposit": "1" }, { "assetId": "1984", @@ -4603,7 +4942,8 @@ { "GeneralIndex": 1984 } - ] + ], + "existentialDeposit": "10000" }, { "assetId": "21", @@ -4622,7 +4962,8 @@ { "GeneralIndex": 21 } - ] + ], + "existentialDeposit": "3000" }, { "assetId": "23", @@ -4641,7 +4982,8 @@ { "GeneralIndex": 23 } - ] + ], + "existentialDeposit": "1" }, { "assetId": "30", @@ -4660,7 +5002,8 @@ { "GeneralIndex": 30 } - ] + ], + "existentialDeposit": "1" }, { "assetId": "31337", @@ -4679,7 +5022,8 @@ { "GeneralIndex": 31337 } - ] + ], + "existentialDeposit": "10000000" }, { "assetId": "42069", @@ -4698,7 +5042,8 @@ { "GeneralIndex": 42069 } - ] + ], + "existentialDeposit": "1000000" }, { "assetId": "555", @@ -4717,7 +5062,8 @@ { "GeneralIndex": 555 } - ] + ], + "existentialDeposit": "100000" }, { "symbol": "EQ", @@ -4731,7 +5077,8 @@ } ] } - } + }, + "existentialDeposit": "100000000000" }, { "symbol": "WETH", @@ -4755,7 +5102,8 @@ } ] } - } + }, + "existentialDeposit": "15000000000000" }, { "symbol": "KSM", @@ -4771,7 +5119,8 @@ } ] } - } + }, + "existentialDeposit": "1000000000" }, { "symbol": "TEER", @@ -4785,7 +5134,8 @@ } ] } - } + }, + "existentialDeposit": "1000000000" }, { "symbol": "BNC", @@ -4805,7 +5155,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "symbol": "EQD", @@ -4825,7 +5176,8 @@ } ] } - } + }, + "existentialDeposit": "1000000000" }, { "symbol": "GLMR", @@ -4842,7 +5194,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "symbol": "MYTH", @@ -4856,7 +5209,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000000000" }, { "symbol": "vDOT", @@ -4876,7 +5230,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "symbol": "HDX", @@ -4893,7 +5248,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "symbol": "AJUN", @@ -4907,7 +5263,8 @@ } ] } - } + }, + "existentialDeposit": "1000000000" } ] }, @@ -4918,7 +5275,8 @@ "nativeAssets": [ { "symbol": "AIR", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "1000000000000" } ], "otherAssets": [ @@ -4931,7 +5289,8 @@ "interior": { "Here": null } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "1", @@ -4952,7 +5311,8 @@ } ] } - } + }, + "existentialDeposit": "10000" }, { "assetId": "2", @@ -4973,28 +5333,8 @@ } ] } - } - }, - { - "assetId": "Native", - "symbol": "AIR", - "decimals": 18, - "multiLocation": { - "parents": 1, - "interior": { - "X2": [ - { - "Parachain": 2088 - }, - { - "GeneralKey": { - "length": 2, - "data": "0x0001000000000000000000000000000000000000000000000000000000000000" - } - } - ] - } - } + }, + "existentialDeposit": "10000000000" } ] }, @@ -5005,24 +5345,28 @@ "nativeAssets": [ { "symbol": "AMPE", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "1000000000" } ], "otherAssets": [ { "assetId": "2", "symbol": "PICA", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "1000" }, { "assetId": "1", "symbol": "USDT", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "1000" }, { "assetId": "0", "symbol": "KSM", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "1000" } ] }, @@ -5033,7 +5377,8 @@ "nativeAssets": [ { "symbol": "BAJU", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "1000000000" } ], "otherAssets": [] @@ -5045,7 +5390,8 @@ "nativeAssets": [ { "symbol": "BSX", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "1000000000000" } ], "otherAssets": [ @@ -5058,7 +5404,8 @@ "interior": { "Here": null } - } + }, + "existentialDeposit": "297441999" }, { "assetId": "14", @@ -5079,7 +5426,8 @@ } ] } - } + }, + "existentialDeposit": "10000" }, { "assetId": "13", @@ -5100,7 +5448,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "9", @@ -5121,7 +5470,8 @@ } ] } - } + }, + "existentialDeposit": "10000" }, { "assetId": "2", @@ -5142,7 +5492,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "10", @@ -5163,7 +5514,8 @@ } ] } - } + }, + "existentialDeposit": "6230529595016" }, { "assetId": "11", @@ -5184,7 +5536,8 @@ } ] } - } + }, + "existentialDeposit": "33" }, { "assetId": "12", @@ -5205,7 +5558,8 @@ } ] } - } + }, + "existentialDeposit": "10000" }, { "assetId": "16", @@ -5218,7 +5572,8 @@ "Parachain": 2048 } } - } + }, + "existentialDeposit": "1683502" }, { "assetId": "6", @@ -5236,7 +5591,8 @@ } ] } - } + }, + "existentialDeposit": "43591979076" } ] }, @@ -5247,39 +5603,53 @@ "nativeAssets": [ { "symbol": "BNC", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "10000000000" }, { - "symbol": "KUSD", - "decimals": 12 + "symbol": "KSM", + "decimals": 12, + "existentialDeposit": "100000000" }, { - "symbol": "DOT", - "decimals": 10 + "symbol": "RMRK", + "decimals": 10, + "existentialDeposit": "10000" }, { - "symbol": "KSM", - "decimals": 12 + "symbol": "vBNC", + "decimals": 12, + "existentialDeposit": "10000000000" }, { - "symbol": "KAR", - "decimals": 12 + "symbol": "vMOVR", + "decimals": 18, + "existentialDeposit": "1000000000000" }, { - "symbol": "ZLK", - "decimals": 18 + "symbol": "vKSM", + "decimals": 12, + "existentialDeposit": "100000000" }, { - "symbol": "PHA", - "decimals": 12 + "symbol": "MOVR", + "decimals": 18, + "existentialDeposit": "1000000000000" }, { - "symbol": "RMRK", - "decimals": 10 + "symbol": "ZLK", + "decimals": 18, + "existentialDeposit": "1000000000000" }, { - "symbol": "MOVR", - "decimals": 18 + "symbol": "PHA", + "decimals": 12, + "existentialDeposit": "40000000000" + }, + { + "symbol": "KAR", + "decimals": 12, + "existentialDeposit": "100000000" } ], "otherAssets": [ @@ -5302,7 +5672,8 @@ } ] } - } + }, + "existentialDeposit": "1000" }, { "assetId": "2", @@ -5323,7 +5694,8 @@ } ] } - } + }, + "existentialDeposit": "100" }, { "assetId": "1", @@ -5344,7 +5716,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "4", @@ -5365,7 +5738,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000000" }, { "assetId": "3", @@ -5378,7 +5752,8 @@ "Parachain": 2007 } } - } + }, + "existentialDeposit": "10000000000000000" } ] }, @@ -5389,7 +5764,8 @@ "nativeAssets": [ { "symbol": "KMA", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100000000000" } ], "otherAssets": [ @@ -5402,7 +5778,8 @@ "interior": { "Here": null } - } + }, + "existentialDeposit": "33333333" }, { "assetId": "14", @@ -5423,7 +5800,8 @@ } ] } - } + }, + "existentialDeposit": "1000" }, { "assetId": "21", @@ -5444,7 +5822,8 @@ } ] } - } + }, + "existentialDeposit": "40000000000000" }, { "assetId": "26", @@ -5465,7 +5844,8 @@ } ] } - } + }, + "existentialDeposit": "35" }, { "assetId": "16", @@ -5486,7 +5866,8 @@ } ] } - } + }, + "existentialDeposit": "10000" }, { "assetId": "23", @@ -5507,7 +5888,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000000000" }, { "assetId": "9", @@ -5528,7 +5910,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "18", @@ -5549,7 +5932,8 @@ } ] } - } + }, + "existentialDeposit": "5000000000000000" }, { "assetId": "20", @@ -5570,7 +5954,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000000000" }, { "assetId": "8", @@ -5591,7 +5976,8 @@ } ] } - } + }, + "existentialDeposit": "100000000000" }, { "assetId": "10", @@ -5612,7 +5998,8 @@ } ] } - } + }, + "existentialDeposit": "500000000" }, { "assetId": "17", @@ -5633,7 +6020,8 @@ } ] } - } + }, + "existentialDeposit": "9000000000000000" }, { "assetId": "25", @@ -5654,7 +6042,8 @@ } ] } - } + }, + "existentialDeposit": "3000000000000000" }, { "assetId": "22", @@ -5675,7 +6064,8 @@ } ] } - } + }, + "existentialDeposit": "2000000000000000" }, { "assetId": "24", @@ -5696,7 +6086,8 @@ } ] } - } + }, + "existentialDeposit": "2000000000000000" }, { "assetId": "19", @@ -5717,7 +6108,8 @@ } ] } - } + }, + "existentialDeposit": "1000000000000000000000" }, { "assetId": "27", @@ -5738,7 +6130,8 @@ } ] } - } + }, + "existentialDeposit": "5555555555555" }, { "assetId": "15", @@ -5759,7 +6152,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000000000" }, { "assetId": "13", @@ -5772,7 +6166,8 @@ "Parachain": 2004 } } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "11", @@ -5790,7 +6185,8 @@ } ] } - } + }, + "existentialDeposit": "100000000000000000" } ] }, @@ -5801,14 +6197,16 @@ "nativeAssets": [ { "symbol": "CRAB", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "0" } ], "otherAssets": [ { "assetId": "1026", "symbol": "CKTON", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "1" } ] }, @@ -5819,44 +6217,52 @@ "nativeAssets": [ { "symbol": "CSM", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100000000000" } ], "otherAssets": [ { "assetId": "16797826370226091782818345603793389938", "symbol": "SDN", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "1000000" }, { "assetId": "108036400430056508975016746969135344601", "symbol": "XRT", - "decimals": 9 + "decimals": 9, + "existentialDeposit": "1" }, { "assetId": "173481220575862801646329923366065693029", "symbol": "CRAB", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "1" }, { "assetId": "214920334981412447805621250067209749032", "symbol": "AUSD", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "1" }, { "assetId": "232263652204149413431520870009560565298", "symbol": "MOVR", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "1000000" }, { "assetId": "10810581592933651521121702237638664357", "symbol": "KAR", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "1" }, { "assetId": "319623561105283008236062145480775032445", "symbol": "BNC", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "1" } ] }, @@ -5867,7 +6273,8 @@ "nativeAssets": [ { "symbol": "KSM", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "33333333" } ], "otherAssets": [] @@ -5879,7 +6286,8 @@ "nativeAssets": [ { "symbol": "IMBU", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "1000000" } ], "otherAssets": [] @@ -5891,7 +6299,8 @@ "nativeAssets": [ { "symbol": "KILT", - "decimals": 15 + "decimals": 15, + "existentialDeposit": "10000000000000" } ], "otherAssets": [] @@ -5903,7 +6312,8 @@ "nativeAssets": [ { "symbol": "TNKR", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "1000000000" } ], "otherAssets": [] @@ -5915,33 +6325,39 @@ "nativeAssets": [ { "symbol": "CGT", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "10000000000000000" }, { "symbol": "KSM", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "333333333" } ], "otherAssets": [ { "assetId": "0", "symbol": "BSX", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "1000000000000" }, { "assetId": "2", "symbol": "VAL", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "1000000000000000" }, { "assetId": "3", "symbol": "PSWAP", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "1000000000000000000" }, { "assetId": "1", "symbol": "XOR", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "1000000000000000" } ] }, @@ -5952,43 +6368,53 @@ "nativeAssets": [ { "symbol": "KAR", - "decimals": 12 - }, - { - "symbol": "KUSD", - "decimals": 12 - }, - { - "symbol": "KSM", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100000000000" }, { "symbol": "LKSM", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "500000000" }, { "symbol": "BNC", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "8000000000" }, { - "symbol": "VSKSM", - "decimals": 12 + "symbol": "TAI", + "decimals": 12, + "existentialDeposit": "1000000000000" }, { "symbol": "PHA", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "40000000000" }, { "symbol": "KINT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "133330000" }, { - "symbol": "KBTC", - "decimals": 8 + "symbol": "VSKSM", + "decimals": 12, + "existentialDeposit": "100000000" }, { - "symbol": "TAI", - "decimals": 12 + "symbol": "KSM", + "decimals": 12, + "existentialDeposit": "100000000" + }, + { + "symbol": "aSEED", + "decimals": 12, + "existentialDeposit": "10000000000" + }, + { + "symbol": "KBTC", + "decimals": 8, + "existentialDeposit": "66" } ], "otherAssets": [ @@ -6011,7 +6437,8 @@ } ] } - } + }, + "existentialDeposit": "100000000" }, { "assetId": "7", @@ -6032,7 +6459,8 @@ } ] } - } + }, + "existentialDeposit": "10000" }, { "assetId": "1", @@ -6053,7 +6481,8 @@ } ] } - } + }, + "existentialDeposit": "1000000000000" }, { "assetId": "18", @@ -6066,7 +6495,8 @@ "Parachain": 2007 } } - } + }, + "existentialDeposit": "10000000000000000" }, { "assetId": "5", @@ -6079,7 +6509,8 @@ "Parachain": 2012 } } - } + }, + "existentialDeposit": "1000000000000" }, { "assetId": "8", @@ -6100,7 +6531,8 @@ } ] } - } + }, + "existentialDeposit": "100000000000" }, { "assetId": "3", @@ -6118,7 +6550,8 @@ } ] } - } + }, + "existentialDeposit": "1000000000000000" }, { "assetId": "14", @@ -6131,7 +6564,8 @@ "Parachain": 2024 } } - } + }, + "existentialDeposit": "1000000000000" }, { "assetId": "15", @@ -6152,7 +6586,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "10", @@ -6165,7 +6600,8 @@ "Parachain": 2084 } } - } + }, + "existentialDeposit": "100000000000" }, { "assetId": "4", @@ -6186,7 +6622,8 @@ } ] } - } + }, + "existentialDeposit": "100000000000" }, { "assetId": "12", @@ -6207,7 +6644,8 @@ } ] } - } + }, + "existentialDeposit": "100000000000000000" }, { "assetId": "11", @@ -6225,7 +6663,8 @@ } ] } - } + }, + "existentialDeposit": "1000000000000" }, { "assetId": "2", @@ -6238,7 +6677,8 @@ "Parachain": 2095 } } - } + }, + "existentialDeposit": "1000000000000000000" }, { "assetId": "9", @@ -6259,7 +6699,8 @@ } ] } - } + }, + "existentialDeposit": "100000000000000000" }, { "assetId": "17", @@ -6280,7 +6721,8 @@ } ] } - } + }, + "existentialDeposit": "100000000000000000" }, { "assetId": "13", @@ -6298,7 +6740,8 @@ } ] } - } + }, + "existentialDeposit": "1000000000000000000" }, { "assetId": "20", @@ -6316,7 +6759,8 @@ } ] } - } + }, + "existentialDeposit": "100000000000" }, { "assetId": "6", @@ -6337,7 +6781,8 @@ } ] } - } + }, + "existentialDeposit": "100000000000000" }, { "assetId": "16", @@ -6350,7 +6795,8 @@ "Parachain": 2114 } } - } + }, + "existentialDeposit": "40000000000" }, { "assetId": "19", @@ -6371,7 +6817,8 @@ } ] } - } + }, + "existentialDeposit": "1000000000000" } ] }, @@ -6382,27 +6829,33 @@ "nativeAssets": [ { "symbol": "KINT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "0" }, { "symbol": "KBTC", - "decimals": 8 + "decimals": 8, + "existentialDeposit": "0" }, { "symbol": "KSM", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "0" }, { "symbol": "INTR", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "0" }, { "symbol": "IBTC", - "decimals": 8 + "decimals": 8, + "existentialDeposit": "0" }, { "symbol": "DOT", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "0" } ], "otherAssets": [ @@ -6425,7 +6878,8 @@ } ] } - } + }, + "existentialDeposit": "0" }, { "assetId": "1", @@ -6446,7 +6900,8 @@ } ] } - } + }, + "existentialDeposit": "0" }, { "assetId": "2", @@ -6467,7 +6922,8 @@ } ] } - } + }, + "existentialDeposit": "0" }, { "assetId": "5", @@ -6488,7 +6944,8 @@ } ] } - } + }, + "existentialDeposit": "0" }, { "assetId": "4", @@ -6506,7 +6963,8 @@ } ] } - } + }, + "existentialDeposit": "0" }, { "assetId": "6", @@ -6527,7 +6985,8 @@ } ] } - } + }, + "existentialDeposit": "0" } ] }, @@ -6549,7 +7008,8 @@ "nativeAssets": [ { "symbol": "MOVR", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "0" } ], "otherAssets": [ @@ -6562,7 +7022,8 @@ "interior": { "Here": null } - } + }, + "existentialDeposit": "1" }, { "assetId": "311091173110107856861649819128533077277", @@ -6583,7 +7044,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "182365888117048807484804376330534607370", @@ -6604,7 +7066,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "214920334981412447805621250067209749032", @@ -6625,7 +7088,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "10810581592933651521121702237638664357", @@ -6646,7 +7110,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "264344629840762281112027368930249420542", @@ -6667,7 +7132,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "72145018963825376852137222787619937732", @@ -6688,7 +7154,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "203223821023327994093278529517083736593", @@ -6709,7 +7176,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "319623561105283008236062145480775032445", @@ -6730,7 +7198,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "189307976387032586987344677431204943363", @@ -6743,7 +7212,8 @@ "Parachain": 2004 } } - } + }, + "existentialDeposit": "1" }, { "assetId": "16797826370226091782818345603793389938", @@ -6756,7 +7226,8 @@ "Parachain": 2007 } } - } + }, + "existentialDeposit": "1" }, { "assetId": "108457044225666871745333730479173774551", @@ -6769,7 +7240,8 @@ "Parachain": 2012 } } - } + }, + "existentialDeposit": "1" }, { "assetId": "105075627293246237499203909093923548958", @@ -6790,7 +7262,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "108036400430056508975016746969135344601", @@ -6803,7 +7276,8 @@ "Parachain": 2048 } } - } + }, + "existentialDeposit": "1" }, { "assetId": "213357169630950964874127107356898319277", @@ -6816,7 +7290,8 @@ "Parachain": 2084 } } - } + }, + "existentialDeposit": "1" }, { "assetId": "76100021443485661246318545281171740067", @@ -6837,7 +7312,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "167283995827706324502761431814209211090", @@ -6850,7 +7326,8 @@ "Parachain": 2087 } } - } + }, + "existentialDeposit": "1" }, { "assetId": "328179947973504579459046439826496046832", @@ -6871,7 +7348,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "175400718394635817552109270754364440562", @@ -6892,7 +7370,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "173481220575862801646329923366065693029", @@ -6910,7 +7389,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "65216491554813189869575508812319036608", @@ -6928,7 +7408,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "118095707745084482624853002839493125353", @@ -6949,7 +7430,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "133300872918374599700079037156071917454", @@ -6962,7 +7444,8 @@ "Parachain": 2114 } } - } + }, + "existentialDeposit": "1" }, { "assetId": "138512078356357941985706694377215053953", @@ -6980,7 +7463,8 @@ } ] } - } + }, + "existentialDeposit": "1" } ] }, @@ -6991,7 +7475,8 @@ "nativeAssets": [ { "symbol": "HKO", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "10000000000" } ], "otherAssets": [ @@ -7004,7 +7489,8 @@ "interior": { "Here": null } - } + }, + "existentialDeposit": "1" }, { "assetId": "102", @@ -7025,7 +7511,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "109", @@ -7046,7 +7533,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "107", @@ -7067,7 +7555,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "115", @@ -7080,7 +7569,8 @@ "Parachain": 2004 } } - } + }, + "existentialDeposit": "1" }, { "assetId": "113", @@ -7098,7 +7588,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "1000", @@ -7119,7 +7610,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "121", @@ -7140,7 +7632,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "119", @@ -7161,7 +7654,8 @@ } ] } - } + }, + "existentialDeposit": "1" } ] }, @@ -7172,359 +7666,430 @@ "nativeAssets": [ { "symbol": "PICA", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100000000000" } ], "otherAssets": [ { "assetId": "1088357900348863545348", "symbol": "DOT_KSM_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" }, { "assetId": "1088357900348863545357", "symbol": "DOT_SCRT_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" }, { "assetId": "1088357900348863545350", "symbol": "KSM_OSMO_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" }, { "assetId": "149", "symbol": "USDT", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "200000" }, { "assetId": "1088357900348863545359", "symbol": "DOT_BLD_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" }, { "assetId": "26", "symbol": "USK", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "200000" }, { "assetId": "1088357900348863545360", "symbol": "ASTR_SDN_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" }, { "assetId": "35", "symbol": "SEI", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "1000000" }, { "assetId": "16", "symbol": "SILK", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "20000" }, { "assetId": "29", "symbol": "QCK", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "333300" }, { "assetId": "23", "symbol": "MOVR", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "4100000000000000" }, { "assetId": "130", "symbol": "USDT Kusama", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "1500" }, { "assetId": "9", "symbol": "STRD", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "20000" }, { "assetId": "1088357900348863545349", "symbol": "DOT_OSMO_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" }, { "assetId": "1", "symbol": "PICA", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100000000000" }, { "assetId": "1088357900348863545352", "symbol": "DOT_STARS_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" }, { "assetId": "31", "symbol": "BNC Kusama", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "11000000000" }, { "assetId": "1088357900348863545356", "symbol": "DOT_CRE_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" }, { "assetId": "2007", "symbol": "SDn", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "1000000000000000" }, { "assetId": "1088357900348863545363", "symbol": "DOT_SDN_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" }, { "assetId": "18", "symbol": "BLD", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "120000" }, { "assetId": "127", "symbol": "EQD", - "decimals": 9 + "decimals": 9, + "existentialDeposit": "200000" }, { "assetId": "20", "symbol": "lsKSM", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "375000000" }, { "assetId": "8", "symbol": "OSMO", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "40000" }, { "assetId": "33", "symbol": "BNC Polkadot", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "1100000000" }, { "assetId": "129", "symbol": "kUSD", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100000000000" }, { "assetId": "3", "symbol": "wSOL", - "decimals": 9 + "decimals": 9, + "existentialDeposit": "5620" }, { "assetId": "1088357900348863545351", "symbol": "USDT_OSMO_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" }, { "assetId": "1088357900348863545347", "symbol": "DOT_USDT_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" }, { "assetId": "1088357900348863545354", "symbol": "DOT_STATOM_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" }, { "assetId": "1088357900348863545362", "symbol": "DOT_ASTR_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" }, { "assetId": "1088357900348863545368", "symbol": "lsDOT_DOT_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" }, { "assetId": "2006", "symbol": "ASTR", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "4700000000000000" }, { "assetId": "10", "symbol": "stATOM", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "2000" }, { "assetId": "12", "symbol": "NTRN", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "60000" }, { "assetId": "1088357900348863545367", "symbol": "PICA_OSMO_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" }, { "assetId": "7", "symbol": "ATOM", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "2000" }, { "assetId": "17", "symbol": "UMEE", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "1000000" }, { "assetId": "1088357900348863545366", "symbol": "DOT_TIA_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" }, { "assetId": "2", "symbol": "ETH", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "200000000000" }, { "assetId": "2011", "symbol": "EQ", - "decimals": 9 + "decimals": 9, + "existentialDeposit": "700000000" }, { "assetId": "45", "symbol": "XLM", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "2000000000000" }, { "assetId": "25", "symbol": "IST", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "20000" }, { "assetId": "13", "symbol": "CRE", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "1000000" }, { "assetId": "40", "symbol": "GLMR", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "40000000000000000" }, { "assetId": "6", "symbol": "DOT", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "21430000" }, { "assetId": "1088357900348863545361", "symbol": "vKSM_vDOT_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" }, { "assetId": "1088357900348863545358", "symbol": "DOT_UMEE_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" }, { "assetId": "1088357900348863545346", "symbol": "DOT_PICA_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" }, { "assetId": "28", "symbol": "KUJI", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "6006" }, { "assetId": "4", "symbol": "KSM", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "375000000" }, { "assetId": "34", "symbol": "vDOT", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "100000000" }, { "assetId": "105", "symbol": "KSM_USDT_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" }, { "assetId": "24", "symbol": "INJ", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "1250000000000000" }, { "assetId": "19", "symbol": "TIA", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "9000" }, { "assetId": "1088357900348863545364", "symbol": "DOT_vKSM_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" }, { "assetId": "32", "symbol": "vKSM", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "1000000000" }, { "assetId": "27", "symbol": "lsDOT", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "21430000" }, { "assetId": "15", "symbol": "SCRT", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "70000" }, { "assetId": "1088357900348863545355", "symbol": "DOT_NTRN_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" }, { "assetId": "150", "symbol": "USDC", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "200000" }, { "assetId": "2125", "symbol": "TNKR", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "135000000000" }, { "assetId": "106", "symbol": "PICA_USDT_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" }, { "assetId": "11", "symbol": "STARS", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "2000000" }, { "assetId": "14", "symbol": "bCRE", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "1000000" }, { "assetId": "1088357900348863545353", "symbol": "DOT_ATOM_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" }, { "assetId": "420", "symbol": "HUAHUA", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "1000000" }, { "assetId": "44", "symbol": "AMPE", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "1000000000000000" }, { "assetId": "1088357900348863545365", "symbol": "DOT_vDOT_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" }, { "assetId": "107", "symbol": "PICA_KSM_LPT", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100" } ] }, @@ -7535,7 +8100,8 @@ "nativeAssets": [ { "symbol": "QTZ", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "0" } ], "otherAssets": [] @@ -7547,10 +8113,24 @@ "nativeAssets": [ { "symbol": "XRT", - "decimals": 9 + "decimals": 9, + "existentialDeposit": "1000" } ], - "otherAssets": [] + "otherAssets": [ + { + "assetId": "4294967295", + "symbol": "KSM", + "decimals": 12, + "existentialDeposit": "100" + }, + { + "assetId": "4294967291", + "symbol": "CSM", + "decimals": 12, + "existentialDeposit": "1000000000000" + } + ] }, "RobonomicsPolkadot": { "relayChainAssetSymbol": "DOT", @@ -7559,14 +8139,16 @@ "nativeAssets": [ { "symbol": "XRT", - "decimals": 9 + "decimals": 9, + "existentialDeposit": "1000" } ], "otherAssets": [ { "assetId": "4294967295", "symbol": "DOT", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "100" } ] }, @@ -7577,7 +8159,8 @@ "nativeAssets": [ { "symbol": "KSM", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "33333333" } ], "otherAssets": [] @@ -7589,7 +8172,8 @@ "nativeAssets": [ { "symbol": "DOT", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "1000000000" } ], "otherAssets": [] @@ -7601,7 +8185,8 @@ "nativeAssets": [ { "symbol": "SDN", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "1000000" } ], "otherAssets": [ @@ -7614,7 +8199,8 @@ "interior": { "Here": null } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551634", @@ -7635,7 +8221,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "4294969280", @@ -7656,7 +8243,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551618", @@ -7677,7 +8265,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551619", @@ -7698,7 +8287,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551616", @@ -7719,7 +8309,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551627", @@ -7740,7 +8331,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551629", @@ -7761,7 +8353,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551628", @@ -7782,7 +8375,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551623", @@ -7795,7 +8389,8 @@ "Parachain": 2004 } } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551624", @@ -7808,7 +8403,8 @@ "Parachain": 2012 } } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551626", @@ -7821,7 +8417,8 @@ "Parachain": 2016 } } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551620", @@ -7839,7 +8436,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551621", @@ -7860,7 +8458,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551622", @@ -7881,7 +8480,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551633", @@ -7894,7 +8494,8 @@ "Parachain": 2095 } } - } + }, + "existentialDeposit": "1" }, { "assetId": "18446744073709551625", @@ -7912,7 +8513,8 @@ } ] } - } + }, + "existentialDeposit": "1" } ] }, @@ -7923,7 +8525,8 @@ "nativeAssets": [ { "symbol": "KSM", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "3333333" }, { "symbol": "DOT", @@ -7949,7 +8552,8 @@ { "GeneralIndex": 16 } - ] + ], + "existentialDeposit": "10000000" }, { "assetId": "1984", @@ -7968,7 +8572,8 @@ { "GeneralIndex": 1984 } - ] + ], + "existentialDeposit": "100" }, { "assetId": "223", @@ -7987,7 +8592,8 @@ { "GeneralIndex": 223 } - ] + ], + "existentialDeposit": "10000" }, { "assetId": "8", @@ -8006,7 +8612,8 @@ { "GeneralIndex": 8 } - ] + ], + "existentialDeposit": "10000" }, { "symbol": "DOT", @@ -8022,7 +8629,8 @@ } ] } - } + }, + "existentialDeposit": "10000000" }, { "symbol": "TNKR", @@ -8039,7 +8647,8 @@ } ] } - } + }, + "existentialDeposit": "1000000000" }, { "symbol": "FREN", @@ -8053,7 +8662,8 @@ } ] } - } + }, + "existentialDeposit": "1000000000" }, { "symbol": "MOVR", @@ -8070,7 +8680,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "symbol": "TEER", @@ -8084,7 +8695,8 @@ } ] } - } + }, + "existentialDeposit": "1000000000" } ] }, @@ -8095,7 +8707,8 @@ "nativeAssets": [ { "symbol": "KSM", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "33333333" } ], "otherAssets": [] @@ -8107,7 +8720,8 @@ "nativeAssets": [ { "symbol": "DOT", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "1000000000" } ], "otherAssets": [] @@ -8119,7 +8733,8 @@ "nativeAssets": [ { "symbol": "TUR", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "100000000" } ], "otherAssets": [ @@ -8132,7 +8747,8 @@ "interior": { "Here": null } - } + }, + "existentialDeposit": "100000000" }, { "assetId": "2", @@ -8153,7 +8769,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "3", @@ -8174,7 +8791,8 @@ } ] } - } + }, + "existentialDeposit": "100000000000" }, { "assetId": "4", @@ -8195,7 +8813,8 @@ } ] } - } + }, + "existentialDeposit": "500000000" }, { "assetId": "7", @@ -8208,7 +8827,8 @@ "Parachain": 2004 } } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "8", @@ -8221,7 +8841,8 @@ "Parachain": 2007 } } - } + }, + "existentialDeposit": "10000000000000000" }, { "assetId": "9", @@ -8239,7 +8860,8 @@ } ] } - } + }, + "existentialDeposit": "0" }, { "assetId": "5", @@ -8260,7 +8882,8 @@ } ] } - } + }, + "existentialDeposit": "500000000000" }, { "assetId": "6", @@ -8281,7 +8904,8 @@ } ] } - } + }, + "existentialDeposit": "500000000" }, { "assetId": "10", @@ -8302,7 +8926,8 @@ } ] } - } + }, + "existentialDeposit": "0" }, { "assetId": "0", @@ -8315,7 +8940,8 @@ "Parachain": 2114 } } - } + }, + "existentialDeposit": "100000000" } ] }, @@ -8326,7 +8952,8 @@ "nativeAssets": [ { "symbol": "UNQ", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "0" } ], "otherAssets": [] @@ -8338,19 +8965,22 @@ "nativeAssets": [ { "symbol": "CRU", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100000000" } ], "otherAssets": [ { "assetId": "187224307232923873519830480073807488153", "symbol": "EQD", - "decimals": 9 + "decimals": 9, + "existentialDeposit": "1000" }, { "assetId": "64174511183114006009298114091987195453", "symbol": "PINK", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "1" } ] }, @@ -8361,169 +8991,202 @@ "nativeAssets": [ { "symbol": "MANTA", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "100000000000000000" } ], "otherAssets": [ { "assetId": "21", "symbol": "BUSD.aca.eth", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "10000000000000000" }, { "assetId": "26", "symbol": "WBTC.aca.eth", - "decimals": 8 + "decimals": 8, + "existentialDeposit": "35" }, { "assetId": "35", "symbol": "WBNB.MRL.BSC", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "40000000000000" }, { "assetId": "16", "symbol": "SHIB", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "1000000000000000000000" }, { "assetId": "29", "symbol": "WBNB", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "40000000000000" }, { "assetId": "23", "symbol": "DAI.aca.eth", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "10000000000000000" }, { "assetId": "9", "symbol": "USDT", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "1000" }, { "assetId": "37", "symbol": "LP-GLMR-MANTA", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "1" }, { "assetId": "31", "symbol": "DAI.MRL.ETH", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "10000000000000000" }, { "assetId": "18", "symbol": "LINK", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "2000000000000000" }, { "assetId": "20", "symbol": "ARB.aca.eth", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "9000000000000000" }, { "assetId": "8", "symbol": "DOT", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "1" }, { "assetId": "30", "symbol": "BNC", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "1" }, { "assetId": "33", "symbol": "USDC.MRL.ETH", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "10000" }, { "assetId": "10", "symbol": "GLMR", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "1" }, { "assetId": "12", "symbol": "LDOT", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "500000000" }, { "assetId": "36", "symbol": "LP-DOT-MANTA", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "1" }, { "assetId": "17", "symbol": "UNI", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "2000000000000000" }, { "assetId": "38", "symbol": "LP-USDT-MANTA", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "1" }, { "assetId": "1000000000", "symbol": "MANDEX", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "3000000000000" }, { "assetId": "25", "symbol": "MATIC.aca.poly", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "10000000000000000" }, { "assetId": "13", "symbol": "ARB.aca.arb", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "9000000000000000" }, { "assetId": "22", "symbol": "USDT.aca.eth", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "10000" }, { "assetId": "28", "symbol": "MATIC.aca.eth", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "10000000000000000" }, { "assetId": "34", "symbol": "TBTC.MRL.ETH", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "1" }, { "assetId": "24", "symbol": "USDC.aca.eth", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "10000" }, { "assetId": "19", "symbol": "APE", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "3000000000000000" }, { "assetId": "32", "symbol": "WETH.MRL.ETH", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "5555555555555" }, { "assetId": "27", "symbol": "WETH.aca.eth", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "5555555555555" }, { "assetId": "15", "symbol": "LDO", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "5000000000000000" }, { "assetId": "11", "symbol": "ACA", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "100000000000" }, { "assetId": "14", "symbol": "BUSD.aca.bsc", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "10000000000000000" } ] }, @@ -8534,7 +9197,8 @@ "nativeAssets": [ { "symbol": "NODL", - "decimals": 11 + "decimals": 11, + "existentialDeposit": "10000" } ], "otherAssets": [] @@ -8546,14 +9210,16 @@ "nativeAssets": [ { "symbol": "NEURO", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "1000000000000" } ], "otherAssets": [ { "assetId": "1", "symbol": "TRAC", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "1" } ] }, @@ -8564,7 +9230,8 @@ "nativeAssets": [ { "symbol": "PEN", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "1000000000" } ], "otherAssets": [ @@ -8577,7 +9244,8 @@ "interior": { "Here": null } - } + }, + "existentialDeposit": "1000" }, { "assetId": "2", @@ -8598,7 +9266,8 @@ } ] } - } + }, + "existentialDeposit": "1000" }, { "assetId": "7", @@ -8619,7 +9288,8 @@ } ] } - } + }, + "existentialDeposit": "1000" }, { "assetId": "1", @@ -8640,7 +9310,8 @@ } ] } - } + }, + "existentialDeposit": "1000" }, { "assetId": "6", @@ -8658,7 +9329,8 @@ } ] } - } + }, + "existentialDeposit": "1" }, { "assetId": "12", @@ -8682,7 +9354,8 @@ } ] } - } + }, + "existentialDeposit": "1000" }, { "assetId": "4", @@ -8706,7 +9379,8 @@ } ] } - } + }, + "existentialDeposit": "1000" }, { "assetId": "9", @@ -8719,7 +9393,8 @@ "Parachain": 2006 } } - } + }, + "existentialDeposit": "0" }, { "assetId": "11", @@ -8740,7 +9415,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "10", @@ -8761,7 +9437,8 @@ } ] } - } + }, + "existentialDeposit": "1000000" }, { "assetId": "8", @@ -8779,7 +9456,8 @@ } ] } - } + }, + "existentialDeposit": "1000" }, { "assetId": "5", @@ -8792,25 +9470,8 @@ "Parachain": 2040 } } - } - }, - { - "assetId": "Native", - "symbol": "PEN", - "decimals": 12, - "multiLocation": { - "parents": 1, - "interior": { - "X2": [ - { - "Parachain": 2094 - }, - { - "PalletInstance": 10 - } - ] - } - } + }, + "existentialDeposit": "1000" } ] }, @@ -8821,7 +9482,8 @@ "nativeAssets": [ { "symbol": "ZTG", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "50000000" } ], "otherAssets": [ @@ -8829,68 +9491,81 @@ "assetId": "1", "symbol": "USDC", "decimals": 6, + "existentialDeposit": "100000000", "alias": "USDC1" }, { "assetId": "11", "symbol": "vASTR", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "1295001295" }, { "assetId": "4", "symbol": "USDC", "decimals": 6, + "existentialDeposit": "100000000", "alias": "USDC2" }, { "assetId": "9", "symbol": "vDOT", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "15748031" }, { "assetId": "7", "symbol": "INTR", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "8403361345" }, { "assetId": "2", "symbol": "WSX", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "10000000000000" }, { "assetId": "3", "symbol": "GLMR", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "233481200" }, { "assetId": "0", "symbol": "DOT", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "10000000" }, { "assetId": "8", "symbol": "BNC", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "466853408" }, { "assetId": "5", "symbol": "USDT", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "100000000" }, { "assetId": "10", "symbol": "vGLMR", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "515729758" }, { "assetId": "12", "symbol": "vMANTA", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "116645282" }, { "assetId": "6", "symbol": "HDX", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "15830299193" } ] }, @@ -8901,7 +9576,8 @@ "nativeAssets": [ { "symbol": "DOT", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "1000000000" } ], "otherAssets": [] @@ -8913,7 +9589,8 @@ "nativeAssets": [ { "symbol": "PHA", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "10000000000" } ], "otherAssets": [ @@ -8926,7 +9603,8 @@ "interior": { "Here": null } - } + }, + "existentialDeposit": "10000000000000000" }, { "assetId": "12", @@ -8947,7 +9625,8 @@ } ] } - } + }, + "existentialDeposit": "100000000" }, { "assetId": "5", @@ -8968,7 +9647,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "3", @@ -8989,7 +9669,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "4", @@ -9010,7 +9691,8 @@ } ] } - } + }, + "existentialDeposit": "100000000" }, { "assetId": "1", @@ -9028,7 +9710,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000000000" }, { "assetId": "6", @@ -9041,7 +9724,8 @@ "Parachain": 2006 } } - } + }, + "existentialDeposit": "10000000000000000" }, { "assetId": "9", @@ -9054,7 +9738,8 @@ "Parachain": 2011 } } - } + }, + "existentialDeposit": "10000000" }, { "assetId": "10", @@ -9075,7 +9760,8 @@ } ] } - } + }, + "existentialDeposit": "10000000" }, { "assetId": "2", @@ -9096,7 +9782,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "8", @@ -9117,7 +9804,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "13", @@ -9138,7 +9826,8 @@ } ] } - } + }, + "existentialDeposit": "100000000" }, { "assetId": "14", @@ -9159,7 +9848,8 @@ } ] } - } + }, + "existentialDeposit": "1000000" }, { "assetId": "11", @@ -9177,7 +9867,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "7", @@ -9195,7 +9886,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000000000" } ] }, @@ -9213,6 +9905,7 @@ { "symbol": "WETH", "assetId": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "existentialDeposit": "15000000000000", "multiLocation": { "parents": 2, "interior": { @@ -9236,6 +9929,7 @@ { "symbol": "WBTC", "assetId": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", + "existentialDeposit": "1", "multiLocation": { "parents": 2, "interior": { @@ -9259,6 +9953,7 @@ { "symbol": "SHIB", "assetId": "0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce", + "existentialDeposit": "1", "multiLocation": { "parents": 2, "interior": { @@ -9282,6 +9977,7 @@ { "symbol": "PEPE", "assetId": "0x6982508145454ce325ddbe47a25d4ec3d2311933", + "existentialDeposit": "1", "multiLocation": { "parents": 2, "interior": { @@ -9305,6 +10001,7 @@ { "symbol": "TON", "assetId": "0x582d872a1b094fc48f5de31d3b73f2d9be47def1", + "existentialDeposit": "1", "multiLocation": { "parents": 2, "interior": { @@ -9328,6 +10025,7 @@ { "symbol": "wstETH", "assetId": "0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0", + "existentialDeposit": "1", "multiLocation": { "parents": 2, "interior": { @@ -9351,6 +10049,7 @@ { "symbol": "tBTC", "assetId": "0x18084fba666a33d37592fa2633fd49a74dd93a88", + "existentialDeposit": "1", "multiLocation": { "parents": 2, "interior": { @@ -9374,6 +10073,7 @@ { "symbol": "USDC", "assetId": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "existentialDeposit": "1", "multiLocation": { "parents": 2, "interior": { @@ -9397,6 +10097,7 @@ { "symbol": "USDT", "assetId": "0xdac17f958d2ee523a2206206994597c13d831ec7", + "existentialDeposit": "1", "multiLocation": { "parents": 2, "interior": { @@ -9420,6 +10121,7 @@ { "symbol": "DAI", "assetId": "0x6b175474e89094c44da98b954eedeac495271d0f", + "existentialDeposit": "1", "multiLocation": { "parents": 2, "interior": { @@ -9443,6 +10145,7 @@ { "symbol": "KILT", "assetId": "0x5d3d01fd6d2ad1169b17918eb4f153c6616288eb", + "existentialDeposit": "1", "multiLocation": { "parents": 2, "interior": { @@ -9472,7 +10175,8 @@ "nativeAssets": [ { "symbol": "PHA", - "decimals": 12 + "decimals": 12, + "existentialDeposit": "10000000000" } ], "otherAssets": [ @@ -9485,7 +10189,8 @@ "interior": { "Here": null } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "1", @@ -9506,7 +10211,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "4", @@ -9527,7 +10233,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "2", @@ -9548,7 +10255,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "3", @@ -9569,7 +10277,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "12", @@ -9582,7 +10291,8 @@ "Parachain": 2007 } } - } + }, + "existentialDeposit": "10000000000000000" }, { "assetId": "6", @@ -9600,7 +10310,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "8", @@ -9613,7 +10324,8 @@ "Parachain": 2084 } } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "7", @@ -9634,7 +10346,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "15", @@ -9647,7 +10360,8 @@ "Parachain": 2087 } } - } + }, + "existentialDeposit": "10000000000" }, { "assetId": "5", @@ -9669,6 +10383,7 @@ ] } }, + "existentialDeposit": "10000000000", "alias": "BSX1" }, { @@ -9688,6 +10403,7 @@ ] } }, + "existentialDeposit": "10000000000", "alias": "BSX2" }, { @@ -9709,7 +10425,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000000000" }, { "assetId": "14", @@ -9730,7 +10447,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000000000" }, { "assetId": "11", @@ -9748,7 +10466,8 @@ } ] } - } + }, + "existentialDeposit": "10000000000000000" }, { "assetId": "10", @@ -9761,7 +10480,8 @@ "Parachain": 2114 } } - } + }, + "existentialDeposit": "100000000" } ] }, @@ -9772,7 +10492,8 @@ "nativeAssets": [ { "symbol": "MYTH", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "10000000000000000" } ], "otherAssets": [] @@ -9784,44 +10505,52 @@ "nativeAssets": [ { "symbol": "PEAQ", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "0" } ], "otherAssets": [ { "assetId": "1005", "symbol": "USDT.wh", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "1000000" }, { "assetId": "1004", "symbol": "DAI.wh", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "1000000000000000000" }, { "assetId": "1000", "symbol": "GLMR", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "1000000000000000000" }, { "assetId": "1002", "symbol": "WETH.wh", - "decimals": 18 + "decimals": 18, + "existentialDeposit": "1000000" }, { "assetId": "1", "symbol": "DOT", - "decimals": 10 + "decimals": 10, + "existentialDeposit": "1000000" }, { "assetId": "1001", "symbol": "USDC.wh", - "decimals": 6 + "decimals": 6, + "existentialDeposit": "1000000" }, { "assetId": "1003", "symbol": "WBTC.wh", - "decimals": 8 + "decimals": 8, + "existentialDeposit": "1000" } ] } diff --git a/packages/sdk/src/maps/existential-deposits.json b/packages/sdk/src/maps/existential-deposits.json deleted file mode 100644 index 72ae97ef..00000000 --- a/packages/sdk/src/maps/existential-deposits.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "AssetHubPolkadot": "100000000", - "Acala": "100000000000", - "Astar": "1000000", - "BifrostPolkadot": "10000000000", - "Bitgreen": "1000000000", - "Centrifuge": "1000000000000", - "ComposableFinance": "100000000000", - "Darwinia": "0", - "Hydration": "1000000000000", - "Litentry": "100000000000000000", - "Moonbeam": "0", - "Parallel": "100000000000", - "AssetHubKusama": "3333333", - "CoretimeKusama": "33333333", - "Encointer": "33333333", - "Altair": "1000000000000", - "Amplitude": "1000000000", - "Bajun": "1000000000", - "Basilisk": "1000000000000", - "BifrostKusama": "10000000000", - "Calamari": "100000000000", - "CrustShadow": "100000000000", - "Crab": "0", - "Imbue": "1000000", - "InvArchTinker": "1000000000", - "Karura": "100000000000", - "Moonriver": "0", - "ParallelHeiko": "10000000000", - "Picasso": "100000000000", - "Quartz": "0", - "RobonomicsKusama": "1000", - "Shiden": "1000000", - "Turing": "100000000", - "Unique": "0", - "Crust": "100000000", - "Manta": "100000000000000000", - "Nodle": "10000", - "NeuroWeb": "1000000000000", - "Pendulum": "1000000000", - "Zeitgeist": "50000000", - "Polkadot": "10000000000", - "Kusama": "333333333", - "Interlay": "0", - "Kintsugi": "0", - "Collectives": "1000000000", - "Khala": "10000000000", - "Phala": "10000000000", - "Subsocial": "100000000", - "KiltSpiritnet": "10000000000000", - "Curio": "10000000000000000", - "BridgeHubPolkadot": "1000000000", - "BridgeHubKusama": "33333333", - "Mythos": "10000000000000000", - "Peaq": "0", - "CoretimePolkadot": "1000000000", - "Polimec": "100000000", - "RobonomicsPolkadot": "1000", - "PeoplePolkadot": "1000000000", - "PeopleKusama": "33333333" -} diff --git a/packages/sdk/src/nodes/supported/Centrifuge.ts b/packages/sdk/src/nodes/supported/Centrifuge.ts index b10d82a4..e021f672 100644 --- a/packages/sdk/src/nodes/supported/Centrifuge.ts +++ b/packages/sdk/src/nodes/supported/Centrifuge.ts @@ -4,6 +4,7 @@ import { InvalidCurrencyError } from '../../errors' import type { TAsset } from '../../types' import { type IXTokensTransfer, Version, type TXTokensTransferOptions } from '../../types' import { isForeignAsset } from '../../utils/assets' +import { getNodeProviders } from '../config' import ParachainNode from '../ParachainNode' import XTokensTransferImpl from '../xTokens' @@ -27,4 +28,9 @@ export class Centrifuge extends ParachainNode implements const currencySelection = this.getCurrencySelection(asset) return XTokensTransferImpl.transferXTokens(input, currencySelection) } + + getProvider(): string { + // Return the second WebSocket URL because the first one is sometimes unreliable. + return getNodeProviders(this.node)[1] + } } diff --git a/packages/sdk/src/pallets/assets/assets.ts b/packages/sdk/src/pallets/assets/assets.ts index 4110561d..e2aef24e 100644 --- a/packages/sdk/src/pallets/assets/assets.ts +++ b/packages/sdk/src/pallets/assets/assets.ts @@ -1,5 +1,6 @@ // Contains different useful asset query operations from compatible Parachains asset map +import { InvalidCurrencyError } from '../../errors' import assetsMapJson from '../../maps/assets.json' assert { type: 'json' } import { NODE_NAMES_DOT_KSM } from '../../maps/consts' import { getParaId } from '../../nodes/config' @@ -8,7 +9,8 @@ import type { TAsset, TRelayChainType, TNodeDotKsmWithRelayChains, - TForeignAsset + TForeignAsset, + TCurrencyCore } from '../../types' import { type TNodeAssets, @@ -18,6 +20,7 @@ import { type TNativeAsset } from '../../types' import { getNode } from '../../utils' +import { getAssetBySymbolOrId } from './getAssetBySymbolOrId' const assetsMap = assetsMapJson as TAssetJsonMap @@ -102,14 +105,8 @@ export const getAllAssetsSymbols = (node: TNodeWithRelayChains): string[] => { * @param node - The node for which to get the native asset symbol. * @returns The symbol of the native asset. */ -export const getNativeAssetSymbol = (node: TNodeWithRelayChains): string => { - if (node === 'Polkadot') { - return 'DOT' - } else if (node === 'Kusama') { - return 'KSM' - } - return getAssetsObject(node).nativeAssetSymbol -} +export const getNativeAssetSymbol = (node: TNodeWithRelayChains): string => + getAssetsObject(node).nativeAssetSymbol /** * Determines whether a specified node supports an asset with the given symbol. @@ -173,3 +170,29 @@ export const getTNode = ( ) ?? null ) } + +/** + * Retrieves the existential deposit value for a given node. + * + * @param node - The node for which to get the existential deposit. + * @returns The existential deposit as a string if available; otherwise, null. + */ +export const getExistentialDeposit = ( + node: TNodeWithRelayChains, + currency?: TCurrencyCore +): string | null => { + const assetsObject = getAssetsObject(node) + if (!currency) { + return assetsObject.nativeAssets[0].existentialDeposit ?? null + } + + const asset = + getAssetBySymbolOrId(node, currency, null) ?? + (node === 'AssetHubPolkadot' ? getAssetBySymbolOrId('Ethereum', currency, null) : null) + + if (!asset) { + throw new InvalidCurrencyError(`Asset ${JSON.stringify(currency)} not found on ${node}`) + } + + return asset.existentialDeposit ?? null +} diff --git a/packages/sdk/src/pallets/assets/balance/getAssetBalance.ts b/packages/sdk/src/pallets/assets/balance/getAssetBalance.ts index 7d1a0cbf..1d861fc1 100644 --- a/packages/sdk/src/pallets/assets/balance/getAssetBalance.ts +++ b/packages/sdk/src/pallets/assets/balance/getAssetBalance.ts @@ -15,7 +15,7 @@ export const getAssetBalanceInternal = async ({ const isNativeSymbol = 'symbol' in currency ? getNativeAssetSymbol(node) === currency.symbol : false - return isNativeSymbol && node !== 'Interlay' + return isNativeSymbol && node !== 'Interlay' && node !== 'Kintsugi' ? await getBalanceNativeInternal({ address, node, diff --git a/packages/sdk/src/pallets/assets/balance/getBalanceNative.ts b/packages/sdk/src/pallets/assets/balance/getBalanceNative.ts index 915add55..bd620d42 100644 --- a/packages/sdk/src/pallets/assets/balance/getBalanceNative.ts +++ b/packages/sdk/src/pallets/assets/balance/getBalanceNative.ts @@ -5,19 +5,24 @@ import { getBalanceForeignInternal } from './getBalanceForeign' export const getBalanceNativeInternal = async ({ address, node, - api + api, + currency }: TGetBalanceNativeOptions): Promise => { await api.init(node) - if (node === 'Interlay') { + if (node === 'Interlay' || node === 'Kintsugi') { return getBalanceForeignInternal({ address, node, api, - currency: { symbol: getAssetsObject(node).nativeAssetSymbol } + currency: { symbol: currency ? currency.symbol : getAssetsObject(node).nativeAssetSymbol } }) } + if (currency && (node === 'Acala' || node === 'Karura')) { + return api.getBalanceNativeAcala(address, currency.symbol) + } + return api.getBalanceNative(address) } diff --git a/packages/sdk/src/pallets/assets/eds.test.ts b/packages/sdk/src/pallets/assets/eds.test.ts deleted file mode 100644 index 1e3df1f2..00000000 --- a/packages/sdk/src/pallets/assets/eds.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { describe, it, expect, vi } from 'vitest' -import type { TNodeDotKsmWithRelayChains } from '../../types' -import { getExistentialDeposit } from './eds' - -vi.mock('../../maps/existential-deposits.json', () => ({ - Kusama: '0.01', - Polkadot: '1.00', - RelayChain1: '0.1', - NonExistentNode: null -})) - -describe('getExistentialDeposit', () => { - it('should return the correct existential deposit for a known node', () => { - const node = 'Kusama' as TNodeDotKsmWithRelayChains - const expectedEd = '0.01' - - const ed = getExistentialDeposit(node) - - expect(ed).toEqual(expectedEd) - }) - - it('should return null for a node without an existential deposit', () => { - const node = 'NonExistentNode' as TNodeDotKsmWithRelayChains - - const ed = getExistentialDeposit(node) - - expect(ed).toBeNull() - }) -}) diff --git a/packages/sdk/src/pallets/assets/eds.ts b/packages/sdk/src/pallets/assets/eds.ts deleted file mode 100644 index be23c934..00000000 --- a/packages/sdk/src/pallets/assets/eds.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { TEdJsonMap, TNodeDotKsmWithRelayChains } from '../../types' -import * as edMapJson from '../../maps/existential-deposits.json' assert { type: 'json' } - -const edMap = edMapJson as TEdJsonMap - -/** - * Retrieves the existential deposit value for a given node. - * - * @param node - The node for which to get the existential deposit. - * @returns The existential deposit as a string if available; otherwise, null. - */ -export const getExistentialDeposit = (node: TNodeDotKsmWithRelayChains): string | null => - edMap[node] diff --git a/packages/sdk/src/pallets/assets/getExistentialDeposit.test.ts b/packages/sdk/src/pallets/assets/getExistentialDeposit.test.ts deleted file mode 100644 index 922fd4d7..00000000 --- a/packages/sdk/src/pallets/assets/getExistentialDeposit.test.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { describe, it, expect, vi } from 'vitest' -import { - getExistentialDeposit, - getMinNativeTransferableAmount, - getMaxNativeTransferableAmount -} from './getExistentialDeposit' -import * as edsMapJson from '../../maps/existential-deposits.json' -import { getBalanceNativeInternal } from './balance/getBalanceNative' -import type { TNodeDotKsmWithRelayChains } from '../../types' -import type { IPolkadotApi } from '../../api/IPolkadotApi' -import type { ApiPromise } from '@polkadot/api' -import type { Extrinsic } from '../../pjs/types' - -vi.mock('./balance/getBalanceNative', () => ({ - getBalanceNativeInternal: vi.fn() -})) - -describe('Existential Deposit and Transferable Amounts', () => { - const apiMock = { - disconnect: vi.fn() - } as unknown as IPolkadotApi - const mockPalletsMap = edsMapJson as { [key: string]: string } - const mockNode: TNodeDotKsmWithRelayChains = 'Polkadot' - const mockAddress = '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa' - - it('should return the correct existential deposit', () => { - const ed = getExistentialDeposit(mockNode) - expect(ed).toBe(BigInt(mockPalletsMap[mockNode])) - }) - - it('should return the correct minimum native transferable amount', () => { - const ed = getExistentialDeposit(mockNode) - const expectedMinTransferableAmount = ed + ed / BigInt(10) - const result = getMinNativeTransferableAmount(mockNode) - - expect(result).toBe(expectedMinTransferableAmount) - }) - - it('should return the correct maximum native transferable amount', async () => { - const mockBalance = BigInt(1000000000000) - vi.mocked(getBalanceNativeInternal).mockResolvedValue(mockBalance) - - const ed = getExistentialDeposit(mockNode) - const expectedMaxTransferableAmount = mockBalance - ed - ed / BigInt(10) - - const result = await getMaxNativeTransferableAmount(apiMock, mockAddress, mockNode) - - expect(result).toBe( - expectedMaxTransferableAmount > BigInt(0) ? expectedMaxTransferableAmount : BigInt(0) - ) - }) - - it('should return 0 for maximum native transferable amount if balance is too low', async () => { - const mockBalance = BigInt(5000) - vi.mocked(getBalanceNativeInternal).mockResolvedValue(mockBalance) - - const result = await getMaxNativeTransferableAmount(apiMock, mockAddress, mockNode) - - expect(result).toBe(BigInt(0)) - }) -}) diff --git a/packages/sdk/src/pallets/assets/getExistentialDeposit.ts b/packages/sdk/src/pallets/assets/getExistentialDeposit.ts deleted file mode 100644 index d2adb0cd..00000000 --- a/packages/sdk/src/pallets/assets/getExistentialDeposit.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { type TNodeDotKsmWithRelayChains, type TEdJsonMap } from '../../types' -import * as edsMapJson from '../../maps/existential-deposits.json' assert { type: 'json' } -import { getBalanceNativeInternal } from './balance/getBalanceNative' -import type { IPolkadotApi } from '../../api/IPolkadotApi' -const palletsMap = edsMapJson as TEdJsonMap - -export const getExistentialDeposit = (node: TNodeDotKsmWithRelayChains): bigint => - BigInt(palletsMap[node] as string) - -export const getMinNativeTransferableAmount = (node: TNodeDotKsmWithRelayChains): bigint => { - const ed = getExistentialDeposit(node) - const tenPercent = ed / BigInt(10) - return ed + tenPercent -} - -export const getMaxNativeTransferableAmount = async ( - api: IPolkadotApi, - address: string, - node: TNodeDotKsmWithRelayChains -): Promise => { - const ed = getExistentialDeposit(node) - const nativeBalance = await getBalanceNativeInternal({ - address, - node, - api - }) - const maxTransferableAmount = nativeBalance - ed - ed / BigInt(10) - return maxTransferableAmount > BigInt(0) ? maxTransferableAmount : BigInt(0) -} diff --git a/packages/sdk/src/pallets/assets/getOriginFeeDetails.test.ts b/packages/sdk/src/pallets/assets/getOriginFeeDetails.test.ts index 59302c16..fc81380a 100644 --- a/packages/sdk/src/pallets/assets/getOriginFeeDetails.test.ts +++ b/packages/sdk/src/pallets/assets/getOriginFeeDetails.test.ts @@ -1,8 +1,8 @@ import { describe, it, expect, vi } from 'vitest' import * as balanceModule from './balance/getBalanceNative' -import * as depositModule from './getExistentialDeposit' import * as utilsModule from '../../utils' import * as BuilderModule from '../../builder' +import * as assetsModule from './assets' import type { ApiPromise } from '@polkadot/api' import type { TCurrencyCore } from '../../types' @@ -27,11 +27,11 @@ describe('getOriginFeeDetails', () => { const account = 'account-address' const nativeBalance = BigInt('1000000000000000') - const minTransferableAmount = BigInt('1000000000000') + const ed = '1000000000000' const xcmFee = '1000000000' vi.spyOn(balanceModule, 'getBalanceNativeInternal').mockResolvedValue(nativeBalance) - vi.spyOn(depositModule, 'getMinNativeTransferableAmount').mockReturnValue(minTransferableAmount) + vi.spyOn(assetsModule, 'getExistentialDeposit').mockReturnValue(ed) vi.spyOn(utilsModule, 'createApiInstanceForNode').mockResolvedValue({} as ApiPromise) const mockTx = { @@ -83,11 +83,11 @@ describe('getOriginFeeDetails', () => { const account = 'account-address' const nativeBalance = BigInt('1000000000000000') - const minTransferableAmount = BigInt('1000000000000') + const ed = '1000000000000' const xcmFee = '1000000000' vi.spyOn(balanceModule, 'getBalanceNativeInternal').mockResolvedValue(nativeBalance) - vi.spyOn(depositModule, 'getMinNativeTransferableAmount').mockReturnValue(minTransferableAmount) + vi.spyOn(assetsModule, 'getExistentialDeposit').mockReturnValue(ed) vi.spyOn(utilsModule, 'createApiInstanceForNode').mockResolvedValue({} as ApiPromise) const mockTx = { @@ -139,11 +139,11 @@ describe('getOriginFeeDetails', () => { const account = 'account-address' const nativeBalance = BigInt('1000000000000000') - const minTransferableAmount = BigInt('1000000000000') + const ed = '1000000000000' const xcmFee = '1000000000' vi.spyOn(balanceModule, 'getBalanceNativeInternal').mockResolvedValue(nativeBalance) - vi.spyOn(depositModule, 'getMinNativeTransferableAmount').mockReturnValue(minTransferableAmount) + vi.spyOn(assetsModule, 'getExistentialDeposit').mockReturnValue(ed) vi.spyOn(utilsModule, 'createApiInstanceForNode').mockResolvedValue({} as ApiPromise) const mockTx = { diff --git a/packages/sdk/src/pallets/assets/getOriginFeeDetails.ts b/packages/sdk/src/pallets/assets/getOriginFeeDetails.ts index 955539ef..ea491508 100644 --- a/packages/sdk/src/pallets/assets/getOriginFeeDetails.ts +++ b/packages/sdk/src/pallets/assets/getOriginFeeDetails.ts @@ -1,11 +1,11 @@ import type { TCurrencyCore, TNodePolkadotKusama, TOriginFeeDetails } from '../../types' import { type TNodeDotKsmWithRelayChains } from '../../types' import { getBalanceNativeInternal } from './balance/getBalanceNative' -import { getMinNativeTransferableAmount } from './getExistentialDeposit' import { isRelayChain } from '../../utils' import { Builder } from '../../builder' import type { IPolkadotApi } from '../../api/IPolkadotApi' import type { TGetOriginFeeDetailsOptions } from '../../types/TBalance' +import { getExistentialDeposit } from './assets' const createTx = async ( api: IPolkadotApi, @@ -61,8 +61,8 @@ export const getOriginFeeDetailsInternal = async ({ api }) - const minTransferableAmount = getMinNativeTransferableAmount(origin) - const sufficientForXCM = nativeBalance - minTransferableAmount - xcmFeeWithMargin > 0 + const existentialDeposit = BigInt(getExistentialDeposit(origin) ?? '0') + const sufficientForXCM = nativeBalance - existentialDeposit - xcmFeeWithMargin > 0 return { sufficientForXCM, diff --git a/packages/sdk/src/pallets/assets/getTransferableAmount.test.ts b/packages/sdk/src/pallets/assets/getTransferableAmount.test.ts new file mode 100644 index 00000000..376a0d6b --- /dev/null +++ b/packages/sdk/src/pallets/assets/getTransferableAmount.test.ts @@ -0,0 +1,265 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest' +import { + getMaxNativeTransferableAmount, + getMaxForeignTransferableAmount, + getTransferableAmount +} from './getTransferableAmount' +import { getBalanceNativeInternal } from './balance/getBalanceNative' +import { getBalanceForeignInternal } from './balance/getBalanceForeign' +import { getExistentialDeposit } from './assets' +import { getAssetBySymbolOrId } from './getAssetBySymbolOrId' +import { InvalidCurrencyError } from '../../errors' +import { isForeignAsset } from '../../utils' + +import type { TNodeDotKsmWithRelayChains } from '../../types' +import type { IPolkadotApi } from '../../api/IPolkadotApi' +import type { ApiPromise } from '@polkadot/api' +import type { Extrinsic } from '../../pjs/types' + +vi.mock('./balance/getBalanceNative', () => ({ + getBalanceNativeInternal: vi.fn() +})) + +vi.mock('./balance/getBalanceForeign', () => ({ + getBalanceForeignInternal: vi.fn() +})) + +vi.mock('./getAssetBySymbolOrId', () => ({ + getAssetBySymbolOrId: vi.fn() +})) + +vi.mock('./assets', () => ({ + getExistentialDeposit: vi.fn(), + isNodeEvm: vi.fn() +})) + +vi.mock('../../utils', async () => { + const actual = await vi.importActual('../../utils') + return { + ...actual, + isForeignAsset: vi.fn(), + validateAddress: vi.fn() + } +}) + +describe('Transferable Amounts', () => { + const apiMock = { + disconnect: vi.fn() + } as unknown as IPolkadotApi + const mockNode: TNodeDotKsmWithRelayChains = 'Acala' + const mockAddress = '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa' + + beforeEach(() => { + vi.clearAllMocks() + }) + + describe('getMaxNativeTransferableAmount', () => { + it('should return the correct maximum native transferable amount', async () => { + const mockBalance = BigInt(1000000000000) + vi.mocked(getBalanceNativeInternal).mockResolvedValue(mockBalance) + vi.mocked(getExistentialDeposit).mockReturnValue('1000000000') + + const ed = BigInt(getExistentialDeposit(mockNode) ?? '0') + const expectedMaxTransferableAmount = mockBalance - ed + + const result = await getMaxNativeTransferableAmount({ + api: apiMock, + address: mockAddress, + node: mockNode + }) + + expect(result).toBe( + expectedMaxTransferableAmount > BigInt(0) ? expectedMaxTransferableAmount : BigInt(0) + ) + }) + + it('should return 0 if native balance is too low', async () => { + const mockBalance = BigInt(5000) + vi.mocked(getBalanceNativeInternal).mockResolvedValue(mockBalance) + vi.mocked(getExistentialDeposit).mockReturnValue('1000000000') + + const result = await getMaxNativeTransferableAmount({ + api: apiMock, + address: mockAddress, + node: mockNode + }) + + expect(result).toBe(BigInt(0)) + }) + + it('should throw an error if existential deposit cannot be obtained', async () => { + vi.mocked(getExistentialDeposit).mockReturnValue(null) + + await expect( + getMaxNativeTransferableAmount({ + api: apiMock, + address: mockAddress, + node: mockNode + }) + ).rejects.toThrowError(`Cannot get existential deposit for node ${mockNode}`) + }) + }) + + describe('getMaxForeignTransferableAmount', () => { + const mockCurrency = { symbol: 'UNQ' } + const mockAsset = { + symbol: 'UNQ', + existentialDeposit: '1000000000' // 1,000,000,000 as string + } + + it('should return the correct max foreign transferable amount', async () => { + const mockBalance = BigInt('2000000000000') + const edBN = BigInt(mockAsset.existentialDeposit) + vi.mocked(getAssetBySymbolOrId).mockReturnValue(mockAsset) + vi.mocked(getBalanceForeignInternal).mockResolvedValue(mockBalance) + + const result = await getMaxForeignTransferableAmount({ + api: apiMock, + address: mockAddress, + node: mockNode, + currency: mockCurrency + }) + + const expected = mockBalance - edBN + expect(result).toBe(expected > BigInt(0) ? expected : BigInt(0)) + }) + + it('should return 0 if foreign balance is too low', async () => { + const mockBalance = BigInt('500000000') // less than the ED + vi.mocked(getAssetBySymbolOrId).mockReturnValue(mockAsset) + vi.mocked(getBalanceForeignInternal).mockResolvedValue(mockBalance) + + const result = await getMaxForeignTransferableAmount({ + api: apiMock, + address: mockAddress, + node: mockNode, + currency: mockCurrency + }) + + expect(result).toBe(BigInt(0)) + }) + + it('should throw InvalidCurrencyError if asset not found', async () => { + vi.mocked(getAssetBySymbolOrId).mockReturnValue(null) + + await expect( + getMaxForeignTransferableAmount({ + api: apiMock, + address: mockAddress, + node: mockNode, + currency: mockCurrency + }) + ).rejects.toThrowError(InvalidCurrencyError) + }) + + it('should throw an error if existential deposit cannot be obtained for the asset', async () => { + const noEDAsset = { symbol: 'UNQ' } // no existentialDeposit field + vi.mocked(getAssetBySymbolOrId).mockReturnValue(noEDAsset) + + await expect( + getMaxForeignTransferableAmount({ + api: apiMock, + address: mockAddress, + node: mockNode, + currency: mockCurrency + }) + ).rejects.toThrowError( + `Cannot get existential deposit for asset ${JSON.stringify(noEDAsset)}` + ) + }) + }) + + describe('getTransferableAmount', () => { + const mockCurrency = { symbol: 'UNQ' } + const nativeAsset = { + symbol: 'DOT' + // Suppose native asset's ED is directly from getExistentialDeposit + } + const foreignAsset = { + symbol: 'UNQ', + existentialDeposit: '1000000000' + } + + it('should call getMaxNativeTransferableAmount if asset is native', async () => { + vi.mocked(getAssetBySymbolOrId).mockReturnValue(nativeAsset) + vi.mocked(isForeignAsset).mockReturnValue(false) + vi.mocked(getBalanceNativeInternal).mockResolvedValue(BigInt(1000000000000)) + vi.mocked(getExistentialDeposit).mockReturnValue('1000000000') + + const result = await getTransferableAmount({ + api: apiMock, + address: mockAddress, + node: mockNode, + currency: { symbol: 'DOT' } // native + }) + + // Check that it didn't call foreign functions + expect(getBalanceForeignInternal).not.toHaveBeenCalled() + expect(getBalanceNativeInternal).toHaveBeenCalled() + expect(result).toBeGreaterThan(BigInt(0)) + }) + + it('should call getMaxForeignTransferableAmount if asset is foreign', async () => { + vi.mocked(getAssetBySymbolOrId).mockReturnValue(foreignAsset) + vi.mocked(isForeignAsset).mockReturnValue(true) + vi.mocked(getBalanceForeignInternal).mockResolvedValue(BigInt('2000000000000')) + + const result = await getTransferableAmount({ + api: apiMock, + address: mockAddress, + node: mockNode, + currency: mockCurrency + }) + + // Check that it didn't call native function + expect(getBalanceNativeInternal).not.toHaveBeenCalled() + expect(getBalanceForeignInternal).toHaveBeenCalled() + expect(result).toBeGreaterThan(BigInt(0)) + }) + + it('should throw InvalidCurrencyError if asset is not found', async () => { + vi.mocked(getAssetBySymbolOrId).mockReturnValue(null) + vi.mocked(isForeignAsset).mockReturnValue(false) + + await expect( + getTransferableAmount({ + api: apiMock, + address: mockAddress, + node: mockNode, + currency: mockCurrency + }) + ).rejects.toThrowError(InvalidCurrencyError) + }) + + it('should return 0 if native balance is lower than ED when calling getTransferableAmount', async () => { + vi.mocked(getAssetBySymbolOrId).mockReturnValue(nativeAsset) + vi.mocked(isForeignAsset).mockReturnValue(false) + vi.mocked(getBalanceNativeInternal).mockResolvedValue(BigInt(5000)) + vi.mocked(getExistentialDeposit).mockReturnValue('1000000000') + + const result = await getTransferableAmount({ + api: apiMock, + address: mockAddress, + node: mockNode, + currency: { symbol: 'DOT' } + }) + + expect(result).toBe(BigInt(0)) + }) + + it('should return 0 if foreign balance is lower than ED when calling getTransferableAmount', async () => { + vi.mocked(getAssetBySymbolOrId).mockReturnValue(foreignAsset) + vi.mocked(isForeignAsset).mockReturnValue(true) + vi.mocked(getBalanceForeignInternal).mockResolvedValue(BigInt('500000000')) // less than ED + + const result = await getTransferableAmount({ + api: apiMock, + address: mockAddress, + node: mockNode, + currency: mockCurrency + }) + + expect(result).toBe(BigInt(0)) + }) + }) +}) diff --git a/packages/sdk/src/pallets/assets/getTransferableAmount.ts b/packages/sdk/src/pallets/assets/getTransferableAmount.ts new file mode 100644 index 00000000..93064bdf --- /dev/null +++ b/packages/sdk/src/pallets/assets/getTransferableAmount.ts @@ -0,0 +1,99 @@ +import { getBalanceNativeInternal } from './balance/getBalanceNative' +import { getExistentialDeposit } from './assets' +import { getBalanceForeignInternal } from './balance/getBalanceForeign' +import type { + TGetMaxForeignTransferableAmountOptions, + TGetMaxNativeTransferableAmountOptions, + TGetTransferableAmountOptions +} from '../../types/TBalance' +import { getAssetBySymbolOrId } from './getAssetBySymbolOrId' +import { InvalidCurrencyError } from '../../errors' +import { isForeignAsset, isRelayChain } from '../../utils' +import { validateAddress } from '../../utils/validateAddress' + +export const getMaxNativeTransferableAmount = async ({ + api, + address, + node, + currency +}: TGetMaxNativeTransferableAmountOptions): Promise => { + validateAddress(address, node, false) + + const ed = getExistentialDeposit(node, currency) + + if (ed === null) { + throw new Error(`Cannot get existential deposit for node ${node}`) + } + const edBN = BigInt(ed) + const nativeBalance = await getBalanceNativeInternal({ + address, + node, + api, + currency + }) + const maxTransferableAmount = nativeBalance - edBN + return maxTransferableAmount > BigInt(0) ? maxTransferableAmount : BigInt(0) +} + +export const getMaxForeignTransferableAmount = async ({ + api, + address, + node, + currency +}: TGetMaxForeignTransferableAmountOptions): Promise => { + validateAddress(address, node, false) + + const asset = + getAssetBySymbolOrId(node, currency, null) ?? + (node === 'AssetHubPolkadot' ? getAssetBySymbolOrId('Ethereum', currency, null) : null) + + if (!asset) { + throw new InvalidCurrencyError(`Asset ${JSON.stringify(currency)} not found on ${node}`) + } + + const ed = asset.existentialDeposit + + if (!ed) { + throw new Error(`Cannot get existential deposit for asset ${JSON.stringify(asset)}`) + } + + const edBN = BigInt(ed) + const balance = await getBalanceForeignInternal({ + address, + node, + api, + currency + }) + const maxTransferableAmount = balance - edBN + return maxTransferableAmount > BigInt(0) ? maxTransferableAmount : BigInt(0) +} + +export const getTransferableAmount = async ({ + api, + address, + node, + currency +}: TGetTransferableAmountOptions): Promise => { + validateAddress(address, node, false) + + const asset = + getAssetBySymbolOrId(node, currency, null) ?? + (node === 'AssetHubPolkadot' ? getAssetBySymbolOrId('Ethereum', currency, null) : null) + + if (!asset) { + throw new InvalidCurrencyError(`Asset ${JSON.stringify(currency)} not found on ${node}`) + } + + if (isForeignAsset(asset) && !isRelayChain(node)) { + return getMaxForeignTransferableAmount({ api, address, node, currency }) + } else { + return getMaxNativeTransferableAmount({ + api, + address, + node, + currency: { + symbol: asset.symbol + } + }) + } +} diff --git a/packages/sdk/src/pallets/assets/index.ts b/packages/sdk/src/pallets/assets/index.ts index b12aa334..6753076c 100644 --- a/packages/sdk/src/pallets/assets/index.ts +++ b/packages/sdk/src/pallets/assets/index.ts @@ -1,5 +1,4 @@ export * from './assets' -export * from './eds' export * from './balance/getAssetBalance' export * from './balance/getBalanceNative' export * from './balance/getBalanceForeign' diff --git a/packages/sdk/src/pallets/assets/transfer-info/getTransferInfo.test.ts b/packages/sdk/src/pallets/assets/transfer-info/getTransferInfo.test.ts index d151cbed..27e09547 100644 --- a/packages/sdk/src/pallets/assets/transfer-info/getTransferInfo.test.ts +++ b/packages/sdk/src/pallets/assets/transfer-info/getTransferInfo.test.ts @@ -5,13 +5,9 @@ import { getBalanceNativeInternal } from '../balance/getBalanceNative' import { getOriginFeeDetailsInternal } from '../getOriginFeeDetails' import { getAssetBySymbolOrId } from '../getAssetBySymbolOrId' import { getAssetBalanceInternal } from '../balance/getAssetBalance' -import { - getExistentialDeposit, - getMaxNativeTransferableAmount, - getMinNativeTransferableAmount -} from '../getExistentialDeposit' +import { getMaxNativeTransferableAmount } from '../getTransferableAmount' import type { ApiPromise } from '@polkadot/api' -import { getNativeAssetSymbol } from '../assets' +import { getExistentialDeposit, getNativeAssetSymbol } from '../assets' import { InvalidCurrencyError } from '../../../errors' import type { IPolkadotApi } from '../../../api/IPolkadotApi' import type { Extrinsic } from '../../../pjs/types' @@ -22,14 +18,13 @@ vi.mock('../../../utils', () => ({ getNativeAssetSymbol: vi.fn() })) -vi.mock('../getExistentialDeposit', () => ({ - getExistentialDeposit: vi.fn(), - getMinNativeTransferableAmount: vi.fn(), +vi.mock('../getTransferableAmount', () => ({ getMaxNativeTransferableAmount: vi.fn() })) vi.mock('../assets', () => ({ - getNativeAssetSymbol: vi.fn() + getNativeAssetSymbol: vi.fn(), + getExistentialDeposit: vi.fn() })) vi.mock('../getAssetBySymbolOrId', () => ({ @@ -71,8 +66,7 @@ describe('getTransferInfo', () => { }) vi.mocked(getAssetBySymbolOrId).mockReturnValue({ symbol: 'DOT', assetId: '1' }) vi.mocked(getAssetBalanceInternal).mockResolvedValue(BigInt(2000)) - vi.mocked(getExistentialDeposit).mockReturnValue(BigInt('100')) - vi.mocked(getMinNativeTransferableAmount).mockReturnValue(BigInt('10')) + vi.mocked(getExistentialDeposit).mockReturnValue('100') vi.mocked(getMaxNativeTransferableAmount).mockResolvedValue(BigInt(4000)) }) @@ -105,7 +99,7 @@ describe('getTransferInfo', () => { }, existentialDeposit: BigInt(100), asset: getNativeAssetSymbol(origin), - minNativeTransferableAmount: BigInt(10), + minNativeTransferableAmount: BigInt(100), maxNativeTransferableAmount: BigInt(4000) }, destinationFeeBalance: { diff --git a/packages/sdk/src/pallets/assets/transfer-info/getTransferInfo.ts b/packages/sdk/src/pallets/assets/transfer-info/getTransferInfo.ts index 6248759f..463f8adc 100644 --- a/packages/sdk/src/pallets/assets/transfer-info/getTransferInfo.ts +++ b/packages/sdk/src/pallets/assets/transfer-info/getTransferInfo.ts @@ -1,15 +1,11 @@ import { InvalidCurrencyError } from '../../../errors' import type { TGetTransferInfoOptions, TTransferInfo } from '../../../types/TTransferInfo' import { determineRelayChainSymbol } from '../../../utils' -import { getNativeAssetSymbol } from '../assets' +import { getExistentialDeposit, getNativeAssetSymbol } from '../assets' import { getAssetBalanceInternal } from '../balance/getAssetBalance' import { getBalanceNativeInternal } from '../balance/getBalanceNative' import { getAssetBySymbolOrId } from '../getAssetBySymbolOrId' -import { - getExistentialDeposit, - getMaxNativeTransferableAmount, - getMinNativeTransferableAmount -} from '../getExistentialDeposit' +import { getMaxNativeTransferableAmount } from '../getTransferableAmount' import { getOriginFeeDetailsInternal } from '../getOriginFeeDetails' export const getTransferInfo = async ({ @@ -72,12 +68,12 @@ export const getTransferInfo = async ({ xcmFee: xcmFeeDetails, existentialDeposit: BigInt(getExistentialDeposit(origin) ?? 0), asset: getNativeAssetSymbol(origin), - minNativeTransferableAmount: getMinNativeTransferableAmount(origin), - maxNativeTransferableAmount: await getMaxNativeTransferableAmount( + minNativeTransferableAmount: BigInt(getExistentialDeposit(origin) ?? '0'), + maxNativeTransferableAmount: await getMaxNativeTransferableAmount({ api, - accountOrigin, - origin - ) + address: accountOrigin, + node: origin + }) }, destinationFeeBalance: { balance: await getBalanceNativeInternal({ @@ -86,7 +82,7 @@ export const getTransferInfo = async ({ api }), currency: getNativeAssetSymbol(destination), - existentialDeposit: getExistentialDeposit(destination) + existentialDeposit: BigInt(getExistentialDeposit(destination) ?? '0') } } } finally { diff --git a/packages/sdk/src/pallets/xcmPallet/keepAlive/checkKeepAlive.test.ts b/packages/sdk/src/pallets/xcmPallet/keepAlive/checkKeepAlive.test.ts index 0ec56dd7..689263ed 100644 --- a/packages/sdk/src/pallets/xcmPallet/keepAlive/checkKeepAlive.test.ts +++ b/packages/sdk/src/pallets/xcmPallet/keepAlive/checkKeepAlive.test.ts @@ -1,18 +1,22 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' import { checkKeepAlive } from './checkKeepAlive' import { KeepAliveError } from '../../../errors/KeepAliveError' -import { getExistentialDeposit } from '../../assets/eds' import type { IPolkadotApi } from '../../../api/IPolkadotApi' import type { Extrinsic } from '../../../pjs/types' import type { ApiPromise } from '@polkadot/api' +import { getExistentialDeposit } from '../../assets' vi.mock('../keepAlive/createTx', () => ({ createTx: vi.fn().mockResolvedValue({} as Extrinsic) })) -vi.mock('../../assets/eds', () => ({ - getExistentialDeposit: vi.fn().mockReturnValue('0') -})) +vi.mock(import('../../assets'), async importOriginal => { + const actual = await importOriginal() + return { + ...actual, + getExistentialDeposit: vi.fn().mockReturnValue('0') + } +}) describe('checkKeepAlive', () => { const ADDRESS = '23sxrMSmaUMqe2ufSJg8U3Y8kxHfKT67YbubwXWFazpYi7w6' diff --git a/packages/sdk/src/pallets/xcmPallet/keepAlive/checkKeepAlive.ts b/packages/sdk/src/pallets/xcmPallet/keepAlive/checkKeepAlive.ts index 3ee55a95..4051a7aa 100644 --- a/packages/sdk/src/pallets/xcmPallet/keepAlive/checkKeepAlive.ts +++ b/packages/sdk/src/pallets/xcmPallet/keepAlive/checkKeepAlive.ts @@ -1,8 +1,7 @@ import { KeepAliveError } from '../../../errors/KeepAliveError' import type { TCheckKeepAliveOptions, TNodePolkadotKusama } from '../../../types' -import { getAssetsObject } from '../../assets' +import { getAssetsObject, getExistentialDeposit } from '../../assets' import { determineRelayChain } from '../../../utils' -import { getExistentialDeposit } from '../../assets/eds' import { createTx } from './createTx' export const checkKeepAlive = async ({ diff --git a/packages/sdk/src/pallets/xcmPallet/transfer/validateDestinationAddress.test.ts b/packages/sdk/src/pallets/xcmPallet/transfer/validateDestinationAddress.test.ts index c7b437f1..1331aedd 100644 --- a/packages/sdk/src/pallets/xcmPallet/transfer/validateDestinationAddress.test.ts +++ b/packages/sdk/src/pallets/xcmPallet/transfer/validateDestinationAddress.test.ts @@ -1,46 +1,48 @@ import { describe, it, expect, vi, afterEach } from 'vitest' import { validateDestinationAddress } from './validateDestinationAddress' -import { ethers } from 'ethers' -import { isNodeEvm } from '../../assets' import { InvalidAddressError } from '../../../errors' -import { isTMultiLocation } from './../utils' import type { TAddress, TDestination } from '../../../types' -vi.mock('ethers') -vi.mock('../../assets') -vi.mock('../utils') +vi.mock('../../../utils/validateAddress', () => ({ + validateAddress: vi.fn() +})) +vi.mock('../utils', () => ({ + isTMultiLocation: vi.fn() +})) + +import { validateAddress } from '../../../utils/validateAddress' +import { isTMultiLocation } from '../utils' describe('validateDestinationAddress', () => { - const mockedIsAddress = vi.mocked(ethers.isAddress) - const mockedIsNodeEvm = vi.mocked(isNodeEvm) + const mockedValidateAddress = vi.mocked(validateAddress) const mockedIsTMultiLocation = vi.mocked(isTMultiLocation) afterEach(() => { vi.clearAllMocks() }) - it('should not throw an error when destination is EVM and address is a valid Ethereum address', () => { + it('should call validateAddress when destination is defined, not a TMultiLocation, and address is a string', () => { const address = '0x1234567890abcdef1234567890abcdef12345678' const destination: TDestination = 'Moonbeam' mockedIsTMultiLocation.mockReturnValue(false) - mockedIsNodeEvm.mockReturnValue(true) - mockedIsAddress.mockReturnValue(true) - expect(() => validateDestinationAddress(address, destination)).not.toThrow() + validateDestinationAddress(address, destination) expect(mockedIsTMultiLocation).toHaveBeenCalledWith(destination) - expect(mockedIsNodeEvm).toHaveBeenCalledWith(destination) - expect(mockedIsAddress).toHaveBeenCalledWith(address) + expect(mockedValidateAddress).toHaveBeenCalledWith(address, destination) }) - it('should throw an error when destination is EVM and address is not a valid Ethereum address', () => { + it('should propagate InvalidAddressError thrown by validateAddress', () => { const address = 'invalid-address' const destination: TDestination = 'Moonbeam' mockedIsTMultiLocation.mockReturnValue(false) - mockedIsNodeEvm.mockReturnValue(true) - mockedIsAddress.mockReturnValue(false) + mockedValidateAddress.mockImplementation(() => { + throw new InvalidAddressError( + 'Destination node is an EVM chain, but the address provided is not a valid Ethereum address.' + ) + }) expect(() => validateDestinationAddress(address, destination)).toThrow(InvalidAddressError) expect(() => validateDestinationAddress(address, destination)).toThrow( @@ -48,41 +50,41 @@ describe('validateDestinationAddress', () => { ) expect(mockedIsTMultiLocation).toHaveBeenCalledWith(destination) - expect(mockedIsNodeEvm).toHaveBeenCalledWith(destination) - expect(mockedIsAddress).toHaveBeenCalledWith(address) + expect(mockedValidateAddress).toHaveBeenCalledWith(address, destination) }) - it('should throw an error when destination is not EVM and address is a valid Ethereum address', () => { + it('should propagate InvalidAddressError when EVM address is provided but destination is not EVM', () => { const address = '0x1234567890abcdef1234567890abcdef12345678' const destination: TDestination = 'Acala' mockedIsTMultiLocation.mockReturnValue(false) - mockedIsNodeEvm.mockReturnValue(false) - mockedIsAddress.mockReturnValue(true) + mockedValidateAddress.mockImplementation(() => { + throw new InvalidAddressError( + 'EVM address provided but destination node is not an EVM chain.' + ) + }) expect(() => validateDestinationAddress(address, destination)).toThrow(InvalidAddressError) expect(() => validateDestinationAddress(address, destination)).toThrow( - 'EVM address provided but destination is not an EVM chain.' + 'EVM address provided but destination node is not an EVM chain.' ) expect(mockedIsTMultiLocation).toHaveBeenCalledWith(destination) - expect(mockedIsNodeEvm).toHaveBeenCalledWith(destination) - expect(mockedIsAddress).toHaveBeenCalledWith(address) + expect(mockedValidateAddress).toHaveBeenCalledWith(address, destination) }) - it('should not throw an error when destination is not EVM and address is not a valid Ethereum address', () => { + it('should not throw an error when validateAddress succeeds for a non-EVM chain and non-EVM address', () => { const address = 'some-non-ethereum-address' const destination: TDestination = 'Acala' mockedIsTMultiLocation.mockReturnValue(false) - mockedIsNodeEvm.mockReturnValue(false) - mockedIsAddress.mockReturnValue(false) + mockedValidateAddress.mockImplementation(() => { + // Assume success, no error thrown + }) expect(() => validateDestinationAddress(address, destination)).not.toThrow() - expect(mockedIsTMultiLocation).toHaveBeenCalledWith(destination) - expect(mockedIsNodeEvm).toHaveBeenCalledWith(destination) - expect(mockedIsAddress).toHaveBeenCalledWith(address) + expect(mockedValidateAddress).toHaveBeenCalledWith(address, destination) }) it('should not perform validation when address is not a string', () => { @@ -101,8 +103,7 @@ describe('validateDestinationAddress', () => { validateDestinationAddress(address, destination) expect(mockedIsTMultiLocation).not.toHaveBeenCalled() - expect(mockedIsNodeEvm).not.toHaveBeenCalled() - expect(mockedIsAddress).not.toHaveBeenCalled() + expect(mockedValidateAddress).not.toHaveBeenCalled() }) it('should not perform validation when destination is undefined', () => { @@ -112,8 +113,7 @@ describe('validateDestinationAddress', () => { validateDestinationAddress(address, destination) expect(mockedIsTMultiLocation).not.toHaveBeenCalled() - expect(mockedIsNodeEvm).not.toHaveBeenCalled() - expect(mockedIsAddress).not.toHaveBeenCalled() + expect(mockedValidateAddress).not.toHaveBeenCalled() }) it('should not perform validation when destination is a TMultiLocation', () => { @@ -134,7 +134,6 @@ describe('validateDestinationAddress', () => { validateDestinationAddress(address, destination) expect(mockedIsTMultiLocation).toHaveBeenCalledWith(destination) - expect(mockedIsNodeEvm).not.toHaveBeenCalled() - expect(mockedIsAddress).not.toHaveBeenCalled() + expect(mockedValidateAddress).not.toHaveBeenCalled() }) }) diff --git a/packages/sdk/src/pallets/xcmPallet/transfer/validateDestinationAddress.ts b/packages/sdk/src/pallets/xcmPallet/transfer/validateDestinationAddress.ts index d5b50fe9..657c0790 100644 --- a/packages/sdk/src/pallets/xcmPallet/transfer/validateDestinationAddress.ts +++ b/packages/sdk/src/pallets/xcmPallet/transfer/validateDestinationAddress.ts @@ -1,28 +1,12 @@ -import { ethers } from 'ethers' import type { TAddress, TDestination } from '../../../types' -import { isNodeEvm } from '../../assets' import { isTMultiLocation } from '../utils' -import { InvalidAddressError } from '../../../errors' +import { validateAddress } from '../../../utils/validateAddress' export const validateDestinationAddress = ( address: TAddress, destination: TDestination | undefined ) => { if (typeof address === 'string' && destination && !isTMultiLocation(destination)) { - const isDestinationEvm = isNodeEvm(destination) - - const isEthereumAddress = ethers.isAddress(address) - - if (isDestinationEvm) { - if (!isEthereumAddress) { - throw new InvalidAddressError( - 'Destination node is an EVM chain, but the address provided is not a valid Ethereum address.' - ) - } - } else { - if (isEthereumAddress) { - throw new InvalidAddressError('EVM address provided but destination is not an EVM chain.') - } - } + validateAddress(address, destination) } } diff --git a/packages/sdk/src/papi/PapiApi.ts b/packages/sdk/src/papi/PapiApi.ts index c6654e97..7b63f1e2 100644 --- a/packages/sdk/src/papi/PapiApi.ts +++ b/packages/sdk/src/papi/PapiApi.ts @@ -141,6 +141,15 @@ class PapiApi implements IPolkadotApi { return accountData ? BigInt(accountData.free.toString()) : BigInt(0) } + async getBalanceNativeAcala(address: string, symbol: string): Promise { + const response = await this.api + .getUnsafeApi() + .query.Tokens.Accounts.getValue(address, { Token: symbol }) + + const accountData = response ? response : null + return accountData ? BigInt(accountData.free.toString()) : BigInt(0) + } + async getBalanceForeignXTokens(address: string, asset: TAsset): Promise { const response = await this.api.getUnsafeApi().query.Tokens.Accounts.getEntries(address) diff --git a/packages/sdk/src/papi/assets.ts b/packages/sdk/src/papi/assets.ts index b843962c..7cdb73d9 100644 --- a/packages/sdk/src/papi/assets.ts +++ b/packages/sdk/src/papi/assets.ts @@ -3,6 +3,9 @@ import { getBalanceForeign as getBalanceForeignImpl } from '../pallets/assets/ba import { getTransferInfo as getTransferInfoImpl } from '../pallets/assets/transfer-info/getTransferInfo' import { getAssetBalance as getAssetBalanceImpl } from '../pallets/assets/balance/getAssetBalance' import { getOriginFeeDetails as getOriginFeeDetailsImpl } from '../pallets/assets/getOriginFeeDetails' +import { getMaxNativeTransferableAmount as getMaxNativeTransferableAmountImpl } from '../pallets/assets/getTransferableAmount' +import { getMaxForeignTransferableAmount as getMaxForeignTransferableAmountImpl } from '../pallets/assets/getTransferableAmount' +import { getTransferableAmount as getTransferableAmountImpl } from '../pallets/assets/getTransferableAmount' import { default as claimAssetsImpl } from '../pallets/assets/asset-claim' import { createPapiApiCall } from './utils' import type { TPapiApi, TPapiTransaction } from './types' @@ -48,8 +51,19 @@ export const getOriginFeeDetails = createPapiApiCall( getOriginFeeDetailsImpl ) +export const getMaxNativeTransferableAmount = createPapiApiCall( + getMaxNativeTransferableAmountImpl +) + +export const getMaxForeignTransferableAmount = createPapiApiCall( + getMaxForeignTransferableAmountImpl +) + +export const getTransferableAmount = createPapiApiCall( + getTransferableAmountImpl +) + export * from '../pallets/assets/assets' -export * from '../pallets/assets/eds' export * from '../pallets/assets/assetSelectors' export * from '../pallets/assets/multiLocationSelectors' export { getSupportedAssets } from '../pallets/assets/getSupportedAssets' diff --git a/packages/sdk/src/pjs/PolkadotJsApi.ts b/packages/sdk/src/pjs/PolkadotJsApi.ts index 8bc804cf..4caae74a 100644 --- a/packages/sdk/src/pjs/PolkadotJsApi.ts +++ b/packages/sdk/src/pjs/PolkadotJsApi.ts @@ -120,6 +120,15 @@ class PolkadotJsApi implements IPolkadotApi { return accountData ? BigInt(accountData.free.toString()) : BigInt(0) } + async getBalanceNativeAcala(address: string, symbol: string): Promise { + const response: Codec = await this.api.query.tokens.accounts(address, { + Token: symbol + }) + + const accountData = response ? (response as AccountData) : null + return accountData ? BigInt(accountData.free.toString()) : BigInt(0) + } + async getBalanceForeignXTokens(address: string, asset: TAsset): Promise { const response: Array<[StorageKey, Codec]> = await this.api.query.tokens.accounts.entries(address) diff --git a/packages/sdk/src/pjs/assets.ts b/packages/sdk/src/pjs/assets.ts index d4ac9b05..58ad0af5 100644 --- a/packages/sdk/src/pjs/assets.ts +++ b/packages/sdk/src/pjs/assets.ts @@ -3,6 +3,9 @@ import { getBalanceForeign as getBalanceForeignImpl } from '../pallets/assets/ba import { getTransferInfo as getTransferInfoImpl } from '../pallets/assets/transfer-info/getTransferInfo' import { getAssetBalance as getAssetBalanceImpl } from '../pallets/assets/balance/getAssetBalance' import { getOriginFeeDetails as getOriginFeeDetailsImpl } from '../pallets/assets/getOriginFeeDetails' +import { getMaxNativeTransferableAmount as getMaxNativeTransferableAmountImpl } from '../pallets/assets/getTransferableAmount' +import { getMaxForeignTransferableAmount as getMaxForeignTransferableAmountImpl } from '../pallets/assets/getTransferableAmount' +import { getTransferableAmount as getTransferableAmountImpl } from '../pallets/assets/getTransferableAmount' import { default as claimAssetsImpl } from '../pallets/assets/asset-claim' import type { Extrinsic, TPjsApi } from './types' import { createPolkadotJsApiCall } from './utils' @@ -46,8 +49,19 @@ export const getOriginFeeDetails = createPolkadotJsApiCall( getOriginFeeDetailsImpl ) +export const getMaxNativeTransferableAmount = createPolkadotJsApiCall( + getMaxNativeTransferableAmountImpl +) + +export const getMaxForeignTransferableAmount = createPolkadotJsApiCall( + getMaxForeignTransferableAmountImpl +) + +export const getTransferableAmount = createPolkadotJsApiCall( + getTransferableAmountImpl +) + export * from '../pallets/assets/assets' -export * from '../pallets/assets/eds' export * from '../pallets/assets/assetSelectors' export * from '../pallets/assets/multiLocationSelectors' export { getSupportedAssets } from '../pallets/assets/getSupportedAssets' diff --git a/packages/sdk/src/types/TAssets.ts b/packages/sdk/src/types/TAssets.ts index b8a1c9ef..c6ab0906 100644 --- a/packages/sdk/src/types/TAssets.ts +++ b/packages/sdk/src/types/TAssets.ts @@ -11,6 +11,7 @@ type TBaseAsset = { decimals?: number manuallyAdded?: boolean alias?: string + existentialDeposit?: string } export type TNativeAsset = TBaseAsset diff --git a/packages/sdk/src/types/TBalance.ts b/packages/sdk/src/types/TBalance.ts index 6c304feb..148eb8ff 100644 --- a/packages/sdk/src/types/TBalance.ts +++ b/packages/sdk/src/types/TBalance.ts @@ -18,6 +18,12 @@ export type TGetBalanceNativeOptionsBase = { * The node on which to query the balance. */ node: TNodeDotKsmWithRelayChains + /** + * The native currency to query. + */ + currency?: { + symbol: string + } } export type TGetBalanceNativeOptions = WithApi @@ -102,3 +108,68 @@ export type TGetOriginFeeDetailsOptions = WithApi< TApi, TRes > + +export type TGetMaxNativeTransferableAmountOptionsBase = { + /** + * The address of the account. + */ + address: string + /** + * The node on which to query the balance. + */ + node: TNodeDotKsmWithRelayChains + /** + * The currency to query. + */ + currency?: { + symbol: string + } +} + +export type TGetMaxNativeTransferableAmountOptions = WithApi< + TGetMaxNativeTransferableAmountOptionsBase, + TApi, + TRes +> + +export type TGetMaxForeignTransferableAmountOptionsBase = { + /** + * The address of the account. + */ + address: string + /** + * The node on which to query the balance. + */ + node: TNodePolkadotKusama + /** + * The currency to query. + */ + currency: TCurrencyCore +} + +export type TGetMaxForeignTransferableAmountOptions = WithApi< + TGetMaxForeignTransferableAmountOptionsBase, + TApi, + TRes +> + +export type TGetTransferableAmountOptionsBase = { + /** + * The address of the account. + */ + address: string + /** + * The node on which to query the balance. + */ + node: TNodeDotKsmWithRelayChains + /** + * The currency to query. + */ + currency: TCurrencyCore +} + +export type TGetTransferableAmountOptions = WithApi< + TGetTransferableAmountOptionsBase, + TApi, + TRes +> diff --git a/packages/sdk/src/utils/validateAddress.test.ts b/packages/sdk/src/utils/validateAddress.test.ts new file mode 100644 index 00000000..415a99bf --- /dev/null +++ b/packages/sdk/src/utils/validateAddress.test.ts @@ -0,0 +1,97 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest' +import { validateAddress } from './validateAddress' +import { InvalidAddressError } from '../errors' +import { ethers } from 'ethers' +import { isNodeEvm } from '../pallets/assets' +import type { TAddress, TNodeWithRelayChains } from '../types' + +vi.mock('ethers', () => ({ + ethers: { + isAddress: vi.fn() + } +})) + +vi.mock('../pallets/assets', () => ({ + isNodeEvm: vi.fn() +})) + +describe('validateAddress', () => { + const mockedIsAddress = vi.mocked(ethers.isAddress) + const mockedIsNodeEvm = vi.mocked(isNodeEvm) + + beforeEach(() => { + vi.clearAllMocks() + }) + + it('should not throw when node is EVM and address is a valid Ethereum address', () => { + const address: TAddress = '0x1234567890abcdef1234567890abcdef12345678' + const node: TNodeWithRelayChains = 'Moonbeam' + + mockedIsNodeEvm.mockReturnValue(true) + mockedIsAddress.mockReturnValue(true) + + expect(() => validateAddress(address, node)).not.toThrow() + }) + + it('should throw InvalidAddressError when node is EVM and address is not a valid Ethereum address', () => { + const address: TAddress = 'invalid-address' + const node: TNodeWithRelayChains = 'Moonbeam' + + mockedIsNodeEvm.mockReturnValue(true) + mockedIsAddress.mockReturnValue(false) + + expect(() => validateAddress(address, node)).toThrow(InvalidAddressError) + expect(() => validateAddress(address, node)).toThrow( + 'Destination node is an EVM chain, but the address provided is not a valid Ethereum address.' + ) + }) + + it('should not throw when node is non-EVM and address is not a valid Ethereum address', () => { + const address: TAddress = 'some-non-ethereum-address' + const node: TNodeWithRelayChains = 'Acala' + + mockedIsNodeEvm.mockReturnValue(false) + mockedIsAddress.mockReturnValue(false) + + expect(() => validateAddress(address, node)).not.toThrow() + }) + + it('should throw InvalidAddressError when node is non-EVM and address is a valid Ethereum address', () => { + const address: TAddress = '0x1234567890abcdef1234567890abcdef12345678' + const node: TNodeWithRelayChains = 'Polkadot' + + mockedIsNodeEvm.mockReturnValue(false) + mockedIsAddress.mockReturnValue(true) + + expect(() => validateAddress(address, node)).toThrow(InvalidAddressError) + expect(() => validateAddress(address, node)).toThrow( + 'EVM address provided but destination node is not an EVM chain.' + ) + }) + + it('should customize the error message when isDestination is false and node is EVM and address is invalid', () => { + const address: TAddress = 'invalid-address' + const node: TNodeWithRelayChains = 'Moonbeam' + + mockedIsNodeEvm.mockReturnValue(true) + mockedIsAddress.mockReturnValue(false) + + expect(() => validateAddress(address, node, false)).toThrow(InvalidAddressError) + expect(() => validateAddress(address, node, false)).toThrow( + 'Node is an EVM chain, but the address provided is not a valid Ethereum address.' + ) + }) + + it('should customize the error message when isDestination is false and node is non-EVM and address is valid', () => { + const address: TAddress = '0x1234567890abcdef1234567890abcdef12345678' + const node: TNodeWithRelayChains = 'Polkadot' + + mockedIsNodeEvm.mockReturnValue(false) + mockedIsAddress.mockReturnValue(true) + + expect(() => validateAddress(address, node, false)).toThrow(InvalidAddressError) + expect(() => validateAddress(address, node, false)).toThrow( + 'EVM address provided but node is not an EVM chain.' + ) + }) +}) diff --git a/packages/sdk/src/utils/validateAddress.ts b/packages/sdk/src/utils/validateAddress.ts new file mode 100644 index 00000000..94da3ffd --- /dev/null +++ b/packages/sdk/src/utils/validateAddress.ts @@ -0,0 +1,28 @@ +import { ethers } from 'ethers' +import { InvalidAddressError } from '../errors' +import { isNodeEvm } from '../pallets/assets' +import type { TAddress, TNodeWithRelayChains } from '../types' + +export const validateAddress = ( + address: TAddress, + node: TNodeWithRelayChains, + isDestination = true +) => { + const isEvm = isNodeEvm(node) + + const isEthereumAddress = ethers.isAddress(address) + + if (isEvm) { + if (!isEthereumAddress) { + throw new InvalidAddressError( + `${isDestination ? 'Destination node' : 'Node'} is an EVM chain, but the address provided is not a valid Ethereum address.` + ) + } + } else { + if (isEthereumAddress) { + throw new InvalidAddressError( + `EVM address provided but ${isDestination ? 'destination ' : ''}node is not an EVM chain.` + ) + } + } +}