Skip to content

Commit

Permalink
feat(sdk): Add asset search by multi-location ✨
Browse files Browse the repository at this point in the history
  • Loading branch information
michaeldev5 committed Nov 12, 2024
1 parent 7730776 commit 07b931c
Show file tree
Hide file tree
Showing 75 changed files with 7,635 additions and 5,839 deletions.
2 changes: 1 addition & 1 deletion apps/playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"@tabler/icons-react": "^3.21.0",
"axios": "^1.7.7",
"ethers": "^6.13.4",
"polkadot-api": "^1.6.5",
"polkadot-api": "^1.7.3",
"react": "^18.3.1",
"react-confetti": "^6.1.0",
"react-dom": "^18.3.1",
Expand Down
20 changes: 18 additions & 2 deletions apps/playground/src/components/CurrencySelection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,25 @@ const CurrencySelection: FC<Props> = ({ form, currencyOptions }) => {
{form.values.isCustomCurrency &&
form.values.customCurrencyType === "multilocation" && (
<JsonInput
placeholder="Enter Multi-Location JSON here"
placeholder="Input Multi-Location JSON or interior junctions JSON to search for and identify the asset"
formatOnBlur
autosize
minRows={10}
{...form.getInputProps("customCurrency")}
/>
)}

{form.values.isCustomCurrency &&
form.values.customCurrencyType === "overridenMultilocation" && (
<JsonInput
placeholder="Provide the XCM Multi-Location JSON to override the default configuration"
formatOnBlur
autosize
minRows={10}
{...form.getInputProps("customCurrency")}
/>
)}

{!form.values.isCustomCurrency && (
<Select
key={form.values.from + form.values.to}
Expand All @@ -71,7 +83,7 @@ const CurrencySelection: FC<Props> = ({ form, currencyOptions }) => {
<Group>
<Checkbox
size="xs"
label="Use Custom Currency"
label="Select custom asset"
{...form.getInputProps("isCustomCurrency", { type: "checkbox" })}
/>
{form.values.isCustomCurrency && (
Expand All @@ -81,6 +93,10 @@ const CurrencySelection: FC<Props> = ({ form, currencyOptions }) => {
{ label: "Asset ID", value: "id" },
{ label: "Symbol", value: "symbol" },
{ label: "Multi-location", value: "multilocation" },
{
label: "Override Multi-location",
value: "overridenMultilocation",
},
]}
{...form.getInputProps("customCurrencyType")}
/>
Expand Down
6 changes: 5 additions & 1 deletion apps/playground/src/components/TransferForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ export type FormValues = {
amount: string;
useApi: boolean;
isCustomCurrency: boolean;
customCurrencyType?: "id" | "symbol" | "multilocation";
customCurrencyType?:
| "id"
| "symbol"
| "multilocation"
| "overridenMultilocation";
};

export type FormValuesTransformed = FormValues & {
Expand Down
7 changes: 6 additions & 1 deletion apps/playground/src/components/XcmTransfer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import TransferForm from "./TransferForm";
import { useDisclosure, useScrollIntoView } from "@mantine/hooks";
import {
isForeignAsset,
Override,
type Extrinsic,
type TCurrencyInput,
type TMultiLocation,
Expand Down Expand Up @@ -58,6 +59,10 @@ const XcmTransfer = () => {
return {
symbol: customCurrency,
};
} else if (customCurrencyType === "overridenMultilocation") {
return {
multilocation: Override(JSON.parse(customCurrency) as TMultiLocation),
};
} else {
return {
multilocation: JSON.parse(customCurrency) as TMultiLocation,
Expand All @@ -80,7 +85,7 @@ const XcmTransfer = () => {
return hasDuplicateIds
? { symbol: currency.symbol ?? "" }
: {
id: currency.assetId,
id: currency.assetId ?? "",
};
} else {
throw Error("Currency is required");
Expand Down
2 changes: 1 addition & 1 deletion apps/playground/src/hooks/useCurrencyOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const useCurrencyOptions = (
() =>
Object.keys(currencyMap).map((key) => ({
value: key,
label: `${currencyMap[key].symbol} - ${isForeignAsset(currencyMap[key]) ? currencyMap[key].assetId : "Native"}`,
label: `${currencyMap[key].symbol} - ${isForeignAsset(currencyMap[key]) ? (currencyMap[key].assetId ?? "Multi-location") : "Native"}`,
})),
[currencyMap],
);
Expand Down
4 changes: 2 additions & 2 deletions apps/playground/src/routes/RouterTransferPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -173,12 +173,12 @@ const RouterTransferPage = () => {
.to(to)
.exchange(exchange)
.currencyFrom(
isForeignAsset(currencyFrom)
isForeignAsset(currencyFrom) && currencyFrom.assetId
? { id: currencyFrom.assetId }
: { symbol: currencyFrom.symbol ?? "" },
)
.currencyTo(
isForeignAsset(currencyTo)
isForeignAsset(currencyTo) && currencyTo.assetId
? { id: currencyTo.assetId }
: { symbol: currencyTo.symbol ?? "" },
)
Expand Down
2 changes: 1 addition & 1 deletion apps/xcm-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
"mixpanel": "^0.18.0",
"nodemailer": "^6.9.16",
"pg": "^8.13.1",
"polkadot-api": "^1.6.5",
"polkadot-api": "^1.7.3",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1",
"typeorm": "^0.3.20",
Expand Down
31 changes: 26 additions & 5 deletions apps/xcm-api/src/x-transfer/dto/XTransferDto.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { z } from 'zod';
import { Version } from '@paraspell/sdk';
import { MultiLocationSchema } from '@paraspell/xcm-analyser';
import { MultiLocationSchema, JunctionSchema } from '@paraspell/xcm-analyser';
import { validateAmount } from '../../utils/validateAmount.js';

const StringOrNumber = z
Expand Down Expand Up @@ -33,6 +33,29 @@ export const MultiAssetSchema = z.union([

export type TMultiAsset = z.infer<typeof MultiAssetSchema>;

export const SymbolSpecifierSchema = z.object({
type: z.enum(['Native', 'Foreign', 'ForeignAbstract']),
value: z.string(),
});

const OverrideMultiLocationSpecifierSchema = z.object({
type: z.literal('Override'),
value: MultiLocationSchema,
});

const MultiLocationValueSchema = z.union([
z.string(),
MultiLocationSchema,
z.array(JunctionSchema),
OverrideMultiLocationSpecifierSchema,
]);

const CurrencySymbolValueSchema = z.union([z.string(), SymbolSpecifierSchema]);

const CurrencySymbolSchema = z.object({
symbol: CurrencySymbolValueSchema,
});

export const CurrencyCoreSchema = z.union([
z
.object({
Expand All @@ -47,14 +70,12 @@ export const CurrencyCoreSchema = z.union([
]);

export const CurrencySchema = z.union([
z.object({
symbol: z.string(),
}),
CurrencySymbolSchema,
z.object({
id: z.union([z.string(), z.number(), z.bigint()]),
}),
z.object({
multilocation: MultiLocationSchema,
multilocation: MultiLocationValueSchema,
}),
z.object({
multiasset: z.array(MultiAssetSchema),
Expand Down
61 changes: 58 additions & 3 deletions apps/xcm-api/test/app.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ import { AppModule } from './../src/app.module';
import {
BatchMode,
Builder,
Foreign,
NODE_NAMES,
NODE_NAMES_DOT_KSM,
Native,
Override,
TMultiAsset,
TMultiLocation,
TNode,
Expand Down Expand Up @@ -115,7 +118,7 @@ describe('XCM API (e2e)', () => {
.get(assetIdUrl)
.query({ symbol })
.expect(200)
.expect(assetId);
.expect(assetId ?? '');
});

if (symbol) {
Expand Down Expand Up @@ -396,6 +399,58 @@ describe('XCM API (e2e)', () => {
.expect(serializedApiCall);
});

it(`Generate XCM call - Parachain to parachain Native() selector - ${xTransferUrl} (POST)`, async () => {
const from: TNode = 'Acala';
const to: TNode = 'Astar';
const currency = { symbol: Native('DOT') };
const api = await createApiInstanceForNode(from);
const tx = await Builder(api)
.from(from)
.to(to)
.currency(currency)
.amount(amount)
.address(address)
.build();
await api.disconnect();
return request(app.getHttpServer())
.post(xTransferHashUrl)
.send({
from,
to,
amount,
address,
currency,
})
.expect(201)
.expect(JSON.stringify(tx.toHex()));
});

it(`Generate XCM call - Parachain to parachain Foreign() selector - ${xTransferUrl} (POST)`, async () => {
const from: TNode = 'Astar';
const to: TNode = 'Acala';
const currency = { symbol: Foreign('HDX') };
const api = await createApiInstanceForNode(from);
const tx = await Builder(api)
.from(from)
.to(to)
.currency(currency)
.amount(amount)
.address(address)
.build();
await api.disconnect();
return request(app.getHttpServer())
.post(xTransferHashUrl)
.send({
from,
to,
amount,
address,
currency,
})
.expect(201)
.expect(JSON.stringify(tx.toHex()));
});

it(`Generate XCM call - Parachain to parachain invalid scenario - ${xTransferHashUrl} (POST)`, async () => {
const from: TNode = 'AssetHubKusama';
const to: TNode = 'Basilisk';
Expand Down Expand Up @@ -917,7 +972,7 @@ describe('XCM API (e2e)', () => {
const serializedApiCall = await Builder(api)
.from(from)
.to(to)
.currency({ multilocation: currency })
.currency({ multilocation: Override(currency) })
.amount(amount)
.address(address)
.buildSerializedApiCall();
Expand All @@ -929,7 +984,7 @@ describe('XCM API (e2e)', () => {
to,
amount,
address,
currency: { multilocation: currency },
currency: { multilocation: Override(currency) },
})
.expect(201)
.expect(serializedApiCall);
Expand Down
4 changes: 2 additions & 2 deletions packages/sdk/e2e/xcm-papi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ const filteredNodes = NODE_NAMES_DOT_KSM.filter(

const findTransferableNodeAndAsset = (
from: TNode
): { nodeTo: TNode | undefined; asset: string | undefined; assetId: string | null } => {
): { nodeTo: TNode | undefined; asset: string | undefined; assetId: string | null | undefined } => {
const allFromAssets = getAssetsForNode(from)

const nodeTo = NODE_NAMES_DOT_KSM.filter(
Expand All @@ -83,7 +83,7 @@ const findTransferableNodeAndAsset = (

const filteredNodes =
node === 'AssetHubPolkadot' || node === 'AssetHubKusama'
? nodeAssets.filter(symbol => symbol !== 'DOT' && symbol !== 'KSM')
? nodeAssets.filter(symbol => symbol !== 'DOT' && symbol !== 'KSM' && symbol !== 'GLMR')
: nodeAssets

const commonAsset = filteredNodes.filter(asset => allFromAssets.includes(asset))[0]
Expand Down
4 changes: 2 additions & 2 deletions packages/sdk/e2e/xcm.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const filteredNodes = NODE_NAMES_DOT_KSM.filter(

const findTransferableNodeAndAsset = (
from: TNode
): { nodeTo: TNode | undefined; asset: string | undefined; assetId: string | null } => {
): { nodeTo: TNode | undefined; asset: string | undefined; assetId: string | null | undefined } => {
const allFromAssets = getAssetsForNode(from)

const nodeTo = NODE_NAMES_DOT_KSM.filter(
Expand All @@ -62,7 +62,7 @@ const findTransferableNodeAndAsset = (

const filteredNodes =
node === 'AssetHubPolkadot' || node === 'AssetHubKusama'
? nodeAssets.filter(symbol => symbol !== 'DOT' && symbol !== 'KSM')
? nodeAssets.filter(symbol => symbol !== 'DOT' && symbol !== 'KSM' && symbol !== 'GLMR')
: nodeAssets

const commonAsset = filteredNodes.filter(asset => allFromAssets.includes(asset))[0]
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"@polkadot/apps-config": ">= 0.145",
"@polkadot/types": ">= 12.4 < 13",
"@polkadot/util": ">= 13",
"polkadot-api": ">= 1.6.5 < 2"
"polkadot-api": ">= 1.7.3 < 2"
},
"peerDependenciesMeta": {
"@polkadot/api": {
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/scripts/assets/addAliases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export function addAliasesToDuplicateSymbols(assetsMap: TAssetJsonMap): TAssetJs

for (const asset of allAssets) {
if (asset.symbol === symbol && isForeignAsset(asset)) {
const aliasNumber = aliasNumbers[asset.assetId]
const aliasNumber = asset.assetId ? aliasNumbers[asset.assetId] : undefined
if (aliasNumber !== undefined) {
asset.alias = `${symbol}${aliasNumber}`
}
Expand Down
Loading

0 comments on commit 07b931c

Please sign in to comment.