Skip to content

Commit

Permalink
feat(xcm-api): Add support for new currency input types ✨
Browse files Browse the repository at this point in the history
  • Loading branch information
michaeldev5 authored and dudo50 committed Sep 10, 2024
1 parent 3465e64 commit 5d8655a
Show file tree
Hide file tree
Showing 23 changed files with 440 additions and 110 deletions.
14 changes: 9 additions & 5 deletions apps/playground/src/components/TransferInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ const TransferInfo = () => {
const getQueryResult = async (formValues: FormValues) => {
const { useApi } = formValues;
const originAddress = selectedAccount?.address ?? "";
const currency =
formValues.customCurrencyType === "id"
? { id: formValues.currency }
: { symbol: formValues.currency };
if (useApi) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return await fetchFromApi(
Expand All @@ -45,20 +49,20 @@ const TransferInfo = () => {
destination: formValues.to,
accountOrigin: originAddress,
accountDestination: formValues.destinationAddress,
currency: formValues.currency,
currency,
amount: formValues.amount,
},
`/transfer-info`
`/transfer-info`,
"POST",
true
);
} else {
return await getTransferInfo(
formValues.from,
formValues.to,
originAddress,
formValues.destinationAddress,
formValues.customCurrencyType === "id"
? { id: formValues.currency }
: { symbol: formValues.currency },
currency,
formValues.amount
);
}
Expand Down
1 change: 1 addition & 0 deletions apps/playground/src/components/TransferInfoForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const TransferInfoForm: FC<Props> = ({ onSubmit, loading }) => {
amount: "10000000000000000000",
address: "5F5586mfsnM6durWRLptYt3jSUs55KEmahdodQ5tQMr9iY96",
destinationAddress: "5F5586mfsnM6durWRLptYt3jSUs55KEmahdodQ5tQMr9iY96",
customCurrencyType: "symbol",
useApi: false,
},

Expand Down
15 changes: 12 additions & 3 deletions apps/playground/src/components/XcmTransfer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,22 @@ const XcmTransfer = () => {
await submitTxUsingApi(
{
...formValues,
currency:
formValues.currency?.symbol ?? formValues.currency?.assetId,
from:
formValues.from === "Polkadot" || formValues.from === "Kusama"
? undefined
: formValues.from,
to:
formValues.to === "Polkadot" || formValues.to === "Kusama"
? undefined
: formValues.to,
currency: determineCurrency(formValues),
},
formValues.from,
"/x-transfer",
selectedAccount.address,
injector.signer
injector.signer,
"POST",
true
);
} else {
await submitUsingSdk(
Expand Down
50 changes: 41 additions & 9 deletions apps/playground/src/components/assets/AssetsForm.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
import { useForm } from "@mantine/form";
import { FC } from "react";
import { Button, Checkbox, Select, Stack, TextInput } from "@mantine/core";
import {
Button,
Checkbox,
Group,
SegmentedControl,
Select,
Stack,
TextInput,
} from "@mantine/core";
import { NODE_NAMES, TNodePolkadotKusama } from "@paraspell/sdk";
import { TAssetsQuery } from "../../types";
import { ASSET_QUERIES } from "../../consts";

export type FormValues = {
func: TAssetsQuery;
node: TNodePolkadotKusama;
symbol: string;
currency: string;
address: string;
useApi: boolean;
currencyType?: "id" | "symbol";
};

type Props = {
Expand All @@ -23,9 +32,10 @@ const AssetsForm: FC<Props> = ({ onSubmit, loading }) => {
initialValues: {
func: "ASSETS_OBJECT",
node: "Acala",
symbol: "GLMR",
currency: "GLMR",
address: "",
useApi: false,
currencyType: "symbol",
},
});

Expand All @@ -37,6 +47,8 @@ const AssetsForm: FC<Props> = ({ onSubmit, loading }) => {
funcVal == "HAS_SUPPORT" ||
funcVal === "BALANCE_FOREIGN";

const supportsCurrencyType = funcVal === "BALANCE_FOREIGN";

const showAddressInput =
funcVal === "BALANCE_FOREIGN" || funcVal === "BALANCE_NATIVE";

Expand All @@ -62,12 +74,32 @@ const AssetsForm: FC<Props> = ({ onSubmit, loading }) => {
/>

{showSymbolInput && (
<TextInput
label="Symbol"
placeholder="GLMR"
required
{...form.getInputProps("symbol")}
/>
<Group align="flex-end">
<TextInput
flex={1}
label={supportsCurrencyType ? "Currency" : "Symbol"}
placeholder={
supportsCurrencyType
? "GLMR"
: form.values.currencyType === "id"
? "Asset ID"
: "Symbol"
}
required
{...form.getInputProps("currency")}
/>
{supportsCurrencyType && (
<SegmentedControl
size="xs"
pb={8}
data={[
{ label: "Asset ID", value: "id" },
{ label: "Symbol", value: "symbol" },
]}
{...form.getInputProps("customCurrencyType")}
/>
)}
</Group>
)}

{showAddressInput && (
Expand Down
15 changes: 10 additions & 5 deletions apps/playground/src/components/assets/AssetsQueries.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,15 @@ const AssetsQueries = () => {
const submitUsingSdk = async ({
func,
node,
symbol,
currency,
currencyType,
address,
}: FormValues) => {
switch (func) {
case "ASSETS_OBJECT":
return getAssetsObject(node);
case "ASSET_ID":
return getAssetId(node, symbol);
return getAssetId(node, currency);
case "RELAYCHAIN_SYMBOL":
return getRelayChainSymbol(node);
case "NATIVE_ASSETS":
Expand All @@ -62,15 +63,19 @@ const AssetsQueries = () => {
case "ALL_SYMBOLS":
return getAllAssetsSymbols(node);
case "DECIMALS":
return getAssetDecimals(node, symbol);
return getAssetDecimals(node, currency);
case "HAS_SUPPORT":
return hasSupportForAsset(node, symbol);
return hasSupportForAsset(node, currency);
case "PARA_ID":
return getParaId(node);
case "BALANCE_NATIVE":
return getBalanceNative(address, node);
case "BALANCE_FOREIGN":
return getBalanceForeign(address, node, { symbol: symbol });
return getBalanceForeign(
address,
node,
currencyType === "id" ? { id: currency } : { symbol: currency }
);
}
};

Expand Down
2 changes: 1 addition & 1 deletion apps/playground/src/consts.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const API_URL = "https://api.lightspell.xyz";
export const API_URL = "http://localhost:3001";

export const ASSET_QUERIES = [
"ASSETS_OBJECT",
Expand Down
11 changes: 6 additions & 5 deletions apps/xcm-api/src/testUtils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Request } from '@nestjs/common';

export const mockRequestObject = () => {
return { headers: {}, body: {}, query: {}, params: {} } as unknown as Request;
};
export const mockRequestObject = {
headers: {},
body: {},
query: {},
params: {},
} as unknown as Request;
8 changes: 7 additions & 1 deletion apps/xcm-api/src/transfer-info/dto/transfer-info.dto.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { TCurrencyCore } from '@paraspell/sdk';
import { CurrencyCoreSchema } from '../../x-transfer/dto/XTransferDto.js';
import { z } from 'zod';

export const TransferInfoSchema = z.object({
Expand All @@ -7,7 +9,7 @@ export const TransferInfoSchema = z.object({
accountDestination: z
.string()
.min(1, { message: 'Destination address is required' }),
currency: z.string(),
currency: CurrencyCoreSchema,
amount: z.union([
z.string().refine(
(val) => {
Expand All @@ -23,3 +25,7 @@ export const TransferInfoSchema = z.object({
});

export type TransferInfoDto = z.infer<typeof TransferInfoSchema>;

export type PatchedTransferInfoDto = TransferInfoDto & {
currency: TCurrencyCore;
};
57 changes: 57 additions & 0 deletions apps/xcm-api/src/transfer-info/transfer-info.controller.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/* eslint-disable @typescript-eslint/unbound-method */
import { vi, describe, beforeEach, it, expect } from 'vitest';
import { Test, TestingModule } from '@nestjs/testing';
import { mockRequestObject } from '../testUtils.js';
import { AnalyticsService } from '../analytics/analytics.service.js';
import { TransferInfoController } from './transfer-info.controller.js';
import { TransferInfoService } from './transfer-info.service.js';
import { PatchedTransferInfoDto } from './dto/transfer-info.dto.js';
import { TTransferInfo } from '@paraspell/sdk';

describe('TransferInfoController', () => {
let controller: TransferInfoController;
let service: TransferInfoService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [TransferInfoController],
providers: [
TransferInfoService,
{
provide: AnalyticsService,
useValue: { get: () => '', track: vi.fn() },
},
],
}).compile();

controller = module.get<TransferInfoController>(TransferInfoController);
service = module.get<TransferInfoService>(TransferInfoService);
});

it('should be defined', () => {
expect(controller).toBeDefined();
});

describe('generateXcmCall', () => {
it('should call generateXcmCall service method with correct parameters and return result', async () => {
const queryParams: PatchedTransferInfoDto = {
origin: 'Acala',
destination: 'Basilisk',
accountOrigin: '5F5586mfsnM6durWRLptYt3jSUs55KEmahdodQ5tQMr9iY96',
accountDestination: '5F5586mfsnM6durWRLptYt3jSUs55KEmahdodQ5tQMr9iY96',
currency: { symbol: 'DOT' },
amount: 100,
};
const mockResult = {} as TTransferInfo;
vi.spyOn(service, 'getTransferInfo').mockResolvedValue(mockResult);

const result = await controller.getTransferInfo(
queryParams,
mockRequestObject,
);

expect(result).toBe(mockResult);
expect(service.getTransferInfo).toHaveBeenCalledWith(queryParams);
});
});
});
19 changes: 11 additions & 8 deletions apps/xcm-api/src/transfer-info/transfer-info.controller.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Controller, Get, Request, Query, Req, UsePipes } from '@nestjs/common';
import { Controller, Request, Req, UsePipes, Post, Body } from '@nestjs/common';
import { AnalyticsService } from '../analytics/analytics.service.js';
import { EventName } from '../analytics/EventName.js';
import { ZodValidationPipe } from '../zod-validation-pipe.js';
import { TransferInfoService } from './transfer-info.service.js';
import {
TransferInfoDto,
PatchedTransferInfoDto,
TransferInfoSchema,
} from './dto/transfer-info.dto.js';

Expand All @@ -18,21 +18,24 @@ export class TransferInfoController {
private trackAnalytics(
eventName: EventName,
req: Request,
params: TransferInfoDto,
params: PatchedTransferInfoDto,
) {
const { origin, destination, currency, amount } = params;
this.analyticsService.track(eventName, req, {
origin,
destination,
currency,
currency: JSON.stringify(currency),
amount,
});
}

@Get()
@Post()
@UsePipes(new ZodValidationPipe(TransferInfoSchema))
getTransferInfo(@Query() queryParams: TransferInfoDto, @Req() req: Request) {
this.trackAnalytics(EventName.GET_TRANSFER_INFO, req, queryParams);
return this.transferInfoService.getTransferInfo(queryParams);
async getTransferInfo(
@Body() params: PatchedTransferInfoDto,
@Req() req: Request,
) {
this.trackAnalytics(EventName.GET_TRANSFER_INFO, req, params);
return await this.transferInfoService.getTransferInfo(params);
}
}
Loading

0 comments on commit 5d8655a

Please sign in to comment.