Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get sovereign account balance in destination and KSM in Kusama Asset Hub #339

Merged
merged 20 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/config/src/configs/moonbeam.ts
Original file line number Diff line number Diff line change
Expand Up @@ -471,8 +471,9 @@ export const moonbeamConfig = new ChainConfig({
destination: polkadotAssetHub,
destinationFee: {
amount: 0.2,
asset: usdt,
asset: dot,
balance: BalanceBuilder().substrate().assets().account(),
destinationBalance: BalanceBuilder().substrate().system().account(),
},
fee: {
asset: glmr,
Expand Down
1 change: 1 addition & 0 deletions packages/config/src/types/AssetConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface AssetConfigConstructorParams {

export interface DestinationFeeConfig extends FeeAssetConfig {
amount: number | FeeConfigBuilder;
destinationBalance?: BalanceConfigBuilder;
}

export interface FeeAssetConfig {
Expand Down
66 changes: 64 additions & 2 deletions packages/sdk/src/getTransferData/getDestinationData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
import { FeeConfigBuilder } from '@moonbeam-network/xcm-builder';
import { TransferConfig } from '@moonbeam-network/xcm-config';
import { AssetAmount } from '@moonbeam-network/xcm-types';
import { toBigInt } from '@moonbeam-network/xcm-utils';
import {
getSovereignAccountAddresses,
toBigInt,
} from '@moonbeam-network/xcm-utils';
import { PolkadotService } from '../polkadot';
import { DestinationChainTransferData } from '../sdk.interfaces';
import { getBalance, getDecimals, getMin } from './getTransferData.utils';
Expand Down Expand Up @@ -35,11 +38,13 @@ export async function getDestinationData({

const balance = await getBalance({
address: destinationAddress,
asset: config.asset,
balanceBuilder: config.balance,
chain,
config,
decimals: zeroAmount.decimals,
polkadot,
});

const min = await getMin(config, polkadot);

const balanceAmount = zeroAmount.copyWith({ amount: balance });
Expand All @@ -51,12 +56,18 @@ export async function getDestinationData({
polkadot,
});
const minAmount = zeroAmount.copyWith({ amount: min });

return {
balance: balanceAmount,
chain,
existentialDeposit,
fee: feeAmount,
min: minAmount,
sovereignAccountBalances: await getSovereignAccountBalances({
mmaurello marked this conversation as resolved.
Show resolved Hide resolved
decimals: zeroAmount.decimals,
polkadot,
transferConfig,
}),
};
}

Expand Down Expand Up @@ -93,3 +104,54 @@ export async function getFee({
amount: await cfg.call(),
});
}

interface GetSovereignAccountBalancesProps {
transferConfig: TransferConfig;
decimals: number;
polkadot: PolkadotService;
}

async function getSovereignAccountBalances({
transferConfig,
decimals,
polkadot,
}: GetSovereignAccountBalancesProps) {
const {
destination: { chain, config },
source: { config: sourceConfig },
} = transferConfig;
const sovereignAccountAddresses = getSovereignAccountAddresses(
transferConfig.source.chain.parachainId,
);

const destinationFeeAssetBalance =
sourceConfig.destinationFee?.destinationBalance;

const sovereignAccountAddress = chain.isRelay()
? sovereignAccountAddresses.relay
: sovereignAccountAddresses.generic;

const sovereignAccountBalance = await getBalance({
address: sovereignAccountAddress,
asset: config.asset,
balanceBuilder: config.balance,
chain,
decimals,
polkadot,
});

const sovereignAccountFeeAssetBalance = destinationFeeAssetBalance
? await getBalance({
address: sovereignAccountAddress,
asset: sourceConfig.destinationFee.asset,
balanceBuilder: destinationFeeAssetBalance,
chain,
decimals, // TODO this is not correct but it doesn't affect us
polkadot,
})
: undefined;
return {
feeAssetBalance: sovereignAccountFeeAssetBalance,
transferAssetBalance: sovereignAccountBalance,
};
}
13 changes: 8 additions & 5 deletions packages/sdk/src/getTransferData/getSourceData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import {
import { PolkadotService } from '../polkadot';
import { EvmSigner, SourceChainTransferData } from '../sdk.interfaces';
import {
GetBalancesParams,
BaseParams,
getBalance,
getDecimals,
getMin,
Expand Down Expand Up @@ -112,8 +112,9 @@ export async function getSourceData({

const balance = await getBalance({
address: sourceAddress,
asset: config.asset,
balanceBuilder: config.balance,
chain,
config,
decimals: zeroAmount.decimals,
polkadot,
});
Expand Down Expand Up @@ -197,6 +198,7 @@ export async function getSourceData({
return {
balance: balanceAmount,
chain,
destinationFee,
destinationFeeBalance: destinationFeeBalanceAmount,
existentialDeposit,
fee: feeAmount,
Expand All @@ -206,10 +208,10 @@ export async function getSourceData({
};
}

export interface GetFeeBalanceParams
extends Omit<GetBalancesParams, 'config' | 'evmSigner'> {
export interface GetFeeBalanceParams extends BaseParams {
balance: bigint;
feeConfig: FeeAssetConfig | undefined;
decimals: number;
}

export async function getFeeBalance({
Expand Down Expand Up @@ -456,8 +458,9 @@ export async function getAssetsBalances({
// eslint-disable-next-line no-await-in-loop
const balance = await getBalance({
address,
asset: asset.asset,
balanceBuilder: asset.balance,
chain,
config: asset,
decimals,
polkadot,
});
Expand Down
9 changes: 9 additions & 0 deletions packages/sdk/src/getTransferData/getTransferData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
} from '../sdk.interfaces';
import { getDestinationData } from './getDestinationData';
import { getSourceData } from './getSourceData';
import { validateSovereignAccountBalances } from './getTransferData.utils';

export interface GetTransferDataParams extends Partial<Signers> {
configService: IConfigService;
Expand Down Expand Up @@ -53,13 +54,15 @@ export async function getTransferData({
sourceAddress,
transferConfig,
});
// console.log('sovereignAccountBalances', destination.sovereignAccountBalances);
mmaurello marked this conversation as resolved.
Show resolved Hide resolved

return {
destination,
getEstimate(amount: number | string) {
const bigAmount = Big(
toBigInt(amount, source.balance.decimals).toString(),
);

const result = bigAmount.minus(
source.balance.isSame(destinationFee) ? destinationFee.toBig() : Big(0),
);
Expand Down Expand Up @@ -93,6 +96,12 @@ export async function getTransferData({
},
async transfer(amount): Promise<string> {
const bigintAmount = toBigInt(amount, source.balance.decimals);
validateSovereignAccountBalances({
amount: bigintAmount,
destination,
source,
});

const {
asset,
source: { chain, config },
Expand Down
69 changes: 59 additions & 10 deletions packages/sdk/src/getTransferData/getTransferData.utils.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,55 @@
import {
BalanceConfigBuilder,
CallType,
ContractConfig,
SubstrateQueryConfig,
} from '@moonbeam-network/xcm-builder';
import { AssetConfig } from '@moonbeam-network/xcm-config';
import {
AssetConfig,
FeeAssetConfig,
polkadotAssetHub,
} from '@moonbeam-network/xcm-config';
import { AnyChain, Asset, EvmParachain } from '@moonbeam-network/xcm-types';
import { convertDecimals, toBigInt } from '@moonbeam-network/xcm-utils';
import {
BalanceContractInterface,
createContractWithoutSigner,
} from '../contract';
import { PolkadotService } from '../polkadot';
import {
DestinationChainTransferData,
SourceChainTransferData,
} from '../sdk.interfaces';

export interface GetBalancesParams {
export interface BaseParams {
address: string;
asset?: Asset;
chain: AnyChain;
config: AssetConfig;
decimals: number;
polkadot: PolkadotService;
}

export type GetDecimalsParams = Omit<GetBalancesParams, 'decimals'> & {
export interface GetBalancesParams extends BaseParams {
asset: Asset;
balanceBuilder: BalanceConfigBuilder;
decimals: number;
}

export interface GetDecimalsParams extends BaseParams {
asset?: Asset;
config: AssetConfig | FeeAssetConfig;
assetBuiltConfig?: SubstrateQueryConfig | ContractConfig;
};
}

export async function getBalance({
address,
chain,
config,
balanceBuilder,
asset,
decimals,
polkadot,
}: GetBalancesParams) {
const cfg = config.balance.build({
const cfg = balanceBuilder.build({
address,
asset: polkadot.chain.getBalanceAssetId(config.asset),
asset: polkadot.chain.getBalanceAssetId(asset),
});
if (cfg.type === CallType.Substrate) {
const balance = await polkadot.query(cfg as SubstrateQueryConfig);
Expand Down Expand Up @@ -97,3 +112,37 @@ export async function getMin(config: AssetConfig, polkadot: PolkadotService) {

return 0n;
}

interface ValidateSovereignAccountBalancesProps {
amount: bigint;
destination: DestinationChainTransferData;
source: SourceChainTransferData;
}

export function validateSovereignAccountBalances({
amount,
source,
destination,
}: ValidateSovereignAccountBalancesProps): void {
const { sovereignAccountBalances } = destination;
mmaurello marked this conversation as resolved.
Show resolved Hide resolved
if (!sovereignAccountBalances) return;

if (destination.chain.key !== polkadotAssetHub.key) {
// currently we want this only for this chain
return;
}
mmaurello marked this conversation as resolved.
Show resolved Hide resolved

if (amount > sovereignAccountBalances.transferAssetBalance) {
throw new Error(
`${source.chain.name} Sovereign account in ${destination.chain.name} does not have enough balance for this transaction`,
);
}
if (
sovereignAccountBalances.feeAssetBalance &&
source.destinationFee.amount > sovereignAccountBalances.feeAssetBalance
) {
throw new Error(
`${source.chain.name} Sovereign account in ${destination.chain.name} does not have enough balance to pay for fees for this transaction`,
);
}
}
10 changes: 9 additions & 1 deletion packages/sdk/src/sdk.interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,20 @@ export interface TransferData {
}

export interface SourceChainTransferData extends ChainTransferData {
destinationFee: AssetAmount;
destinationFeeBalance: AssetAmount;
feeBalance: AssetAmount;
max: AssetAmount;
}

export interface DestinationChainTransferData extends ChainTransferData {}
export interface SovereignAccountBalance {
feeAssetBalance: bigint | undefined;
transferAssetBalance: bigint;
}

export interface DestinationChainTransferData extends ChainTransferData {
sovereignAccountBalances: SovereignAccountBalance;
}

export interface ChainTransferData {
balance: AssetAmount;
Expand Down
4 changes: 4 additions & 0 deletions packages/types/src/chain/parachain/Parachain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,8 @@ export class Parachain extends Chain {
getAssetMin(asset: Asset): number {
return this.assetsData.get(asset.key)?.min ?? 0;
}

isRelay(): boolean {
mmaurello marked this conversation as resolved.
Show resolved Hide resolved
return this.parachainId === 0;
}
}
Loading