Skip to content

Commit

Permalink
fix(sdk): Add existential deposits for foreign assets ✨
Browse files Browse the repository at this point in the history
  • Loading branch information
michaeldev5 committed Dec 7, 2024
1 parent 73622dd commit 35dbc0a
Show file tree
Hide file tree
Showing 51 changed files with 3,540 additions and 1,325 deletions.
21 changes: 17 additions & 4 deletions apps/playground/src/components/assets/AssetsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,26 @@ const AssetsForm: FC<Props> = ({ 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;
Expand All @@ -71,7 +82,9 @@ const AssetsForm: FC<Props> = ({ 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;

Expand Down
52 changes: 47 additions & 5 deletions apps/playground/src/components/assets/AssetsQueries.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import AssetsForm from "./AssetsForm";
import type {
TCurrencyCore,
TMultiLocation,
TNodeDotKsmWithRelayChains,
TNodePolkadotKusama,
TNodeWithRelayChains,
} from "@paraspell/sdk";
import {
getAllAssetsSymbols,
Expand Down Expand Up @@ -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,
);
}
};

Expand Down Expand Up @@ -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`;
}
};

Expand All @@ -146,22 +184,26 @@ const AssetsQueries = () => {

const getQueryResult = async (formValues: FormValues): Promise<unknown> => {
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);
Expand Down
4 changes: 4 additions & 0 deletions apps/playground/src/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
4 changes: 4 additions & 0 deletions apps/xcm-api/src/analytics/EventName.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
216 changes: 216 additions & 0 deletions apps/xcm-api/src/balance/balance.controller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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(),
},
},
{
Expand Down Expand Up @@ -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);
});
});
});
Loading

0 comments on commit 35dbc0a

Please sign in to comment.