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 6, 2024
1 parent 73622dd commit ea38f8f
Show file tree
Hide file tree
Showing 38 changed files with 2,342 additions and 1,272 deletions.
11 changes: 8 additions & 3 deletions apps/playground/src/components/assets/AssetsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,20 @@ 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";

const supportsCurrencyType =
funcVal === "BALANCE_FOREIGN" || funcVal === "ASSET_BALANCE";
funcVal === "BALANCE_FOREIGN" ||
funcVal === "ASSET_BALANCE" ||
funcVal === "MAX_FOREIGN_TRANSFERABLE_AMOUNT";

const showAddressInput =
funcVal === "BALANCE_FOREIGN" ||
funcVal === "BALANCE_NATIVE" ||
funcVal === "ASSET_BALANCE";
funcVal === "ASSET_BALANCE" ||
funcVal === "MAX_NATIVE_TRANSFERABLE_AMOUNT" ||
funcVal === "MAX_FOREIGN_TRANSFERABLE_AMOUNT";

const onSubmitInternal = (formValues: FormValues) => {
const { func } = formValues;
Expand Down
22 changes: 21 additions & 1 deletion apps/playground/src/components/assets/AssetsQueries.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import AssetsForm from "./AssetsForm";
import type {
TCurrencyCore,
TMultiLocation,
TNodeDotKsmWithRelayChains,
TNodePolkadotKusama,
} from "@paraspell/sdk";
import {
Expand Down Expand Up @@ -94,6 +95,17 @@ 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,
});
}
};

Expand Down Expand Up @@ -129,6 +141,14 @@ 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`;
}
};

Expand Down Expand Up @@ -161,7 +181,7 @@ const AssetsQueries = () => {
: formValues,
`${getEndpoint(formValues)}`,
isBalanceQuery ? "POST" : "GET",
isBalanceQuery,
isBalanceQuery
);
} else {
return submitUsingSdk(formValues);
Expand Down
2 changes: 2 additions & 0 deletions apps/playground/src/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export const ASSET_QUERIES = [
"BALANCE_NATIVE",
"BALANCE_FOREIGN",
"ASSET_BALANCE",
"MAX_NATIVE_TRANSFERABLE_AMOUNT",
"MAX_FOREIGN_TRANSFERABLE_AMOUNT",
] as const;

export const PALLETS_QUERIES = ["ALL_PALLETS", "DEFAULT_PALLET"] as const;
2 changes: 2 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,8 @@ 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',
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
76 changes: 76 additions & 0 deletions apps/xcm-api/src/balance/balance.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,80 @@ 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-foreign-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-foreign-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);
}
}
55 changes: 55 additions & 0 deletions apps/xcm-api/src/balance/balance.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,59 @@ 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;
}
}
62 changes: 62 additions & 0 deletions packages/sdk/scripts/assets/fetchAcalaAssets.ts
Original file line number Diff line number Diff line change
@@ -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<TForeignAsset[]> => {
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<TNativeAsset[]> => {
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<TForeignAsset[]> => {
return fetchAssets(api, query, false)
}
Loading

0 comments on commit ea38f8f

Please sign in to comment.