1import {ApiPromise, WsProvider} from '@polkadot/api';2import type {IKeyringPair} from '@polkadot/types/types';3import {ChainHelperBase, EthereumBalanceGroup, HelperGroup, SubstrateBalanceGroup, UniqueHelper} from '@unique-nft/playgrounds/unique.js';4import type {ILogger, TSigner} from '@unique-nft/playgrounds/types.js';5import type {AcalaAssetMetadata, DemocracyStandardAccountVote, MoonbeamAssetInfo} from './types.js';678export class XcmChainHelper extends ChainHelperBase {9 override async connect(wsEndpoint: string, _listeners?: any): Promise<void> {10 const wsProvider = new WsProvider(wsEndpoint);11 this.api = new ApiPromise({12 provider: wsProvider,13 });14 await this.api.isReadyOrError;15 this.network = await UniqueHelper.detectNetwork(this.api);16 }17}1819class AcalaAssetRegistryGroup extends HelperGroup<AcalaHelper> {20 async registerForeignAsset(signer: TSigner, destination: any, metadata: AcalaAssetMetadata) {21 await this.helper.executeExtrinsic(signer, 'api.tx.assetRegistry.registerForeignAsset', [destination, metadata], true);22 }23}2425class MoonbeamAssetManagerGroup extends HelperGroup<MoonbeamHelper> {26 makeRegisterForeignAssetProposal(assetInfo: MoonbeamAssetInfo) {27 const apiPrefix = 'api.tx.assetManager.';2829 const registerTx = this.helper.constructApiCall(30 apiPrefix + 'registerForeignAsset',31 [assetInfo.location, assetInfo.metadata, assetInfo.existentialDeposit, assetInfo.isSufficient],32 );3334 const setUnitsTx = this.helper.constructApiCall(35 apiPrefix + 'setAssetUnitsPerSecond',36 [assetInfo.location, assetInfo.unitsPerSecond, assetInfo.numAssetsWeightHint],37 );3839 const batchCall = this.helper.getApi().tx.utility.batchAll([registerTx, setUnitsTx]);40 const encodedProposal = batchCall?.method.toHex() || '';41 return encodedProposal;42 }4344 async assetTypeId(location: any) {45 return await this.helper.callRpc('api.query.assetManager.assetTypeId', [location]);46 }47}4849class MoonbeamDemocracyGroup extends HelperGroup<MoonbeamHelper> {50 notePreimagePallet: string;5152 constructor(helper: MoonbeamHelper, options: { [key: string]: any } = {}) {53 super(helper);54 this.notePreimagePallet = options.notePreimagePallet;55 }5657 async notePreimage(signer: TSigner, encodedProposal: string) {58 await this.helper.executeExtrinsic(signer, `api.tx.${this.notePreimagePallet}.notePreimage`, [encodedProposal], true);59 }6061 externalProposeMajority(proposal: any) {62 return this.helper.constructApiCall('api.tx.democracy.externalProposeMajority', [proposal]);63 }6465 fastTrack(proposalHash: string, votingPeriod: number, delayPeriod: number) {66 return this.helper.constructApiCall('api.tx.democracy.fastTrack', [proposalHash, votingPeriod, delayPeriod]);67 }6869 async referendumVote(signer: TSigner, referendumIndex: number, accountVote: DemocracyStandardAccountVote) {70 await this.helper.executeExtrinsic(signer, 'api.tx.democracy.vote', [referendumIndex, {Standard: accountVote}], true);71 }72}7374class DemocracyGroup<T extends ChainHelperBase> extends HelperGroup<T> {75 notePreimagePallet: string;7677 constructor(helper: T, options: { [key: string]: any } = {}) {78 super(helper);79 this.notePreimagePallet = options.notePreimagePallet;80 }8182 async notePreimage(signer: TSigner, encodedProposal: string) {83 await this.helper.executeExtrinsic(signer, `api.tx.${this.notePreimagePallet}.notePreimage`, [encodedProposal], true);84 }8586 externalProposeMajority(proposal: any) {87 return this.helper.constructApiCall('api.tx.democracy.externalProposeMajority', [proposal]);88 }8990 fastTrack(proposalHash: string, votingPeriod: number, delayPeriod: number) {91 return this.helper.constructApiCall('api.tx.democracy.fastTrack', [proposalHash, votingPeriod, delayPeriod]);92 }9394 async referendumVote(signer: TSigner, referendumIndex: number, accountVote: DemocracyStandardAccountVote) {95 await this.helper.executeExtrinsic(signer, 'api.tx.democracy.vote', [referendumIndex, {Standard: accountVote}], true);96 }97}9899class MoonbeamCollectiveGroup extends HelperGroup<MoonbeamHelper> {100 collective: string;101102 constructor(helper: MoonbeamHelper, collective: string) {103 super(helper);104105 this.collective = collective;106 }107108 async propose(signer: TSigner, threshold: number, proposalHash: string, lengthBound: number) {109 await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.propose`, [threshold, proposalHash, lengthBound], true);110 }111112 async vote(signer: TSigner, proposalHash: string, proposalIndex: number, approve: boolean) {113 await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.vote`, [proposalHash, proposalIndex, approve], true);114 }115116 async close(signer: TSigner, proposalHash: string, proposalIndex: number, weightBound: any, lengthBound: number) {117 await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.close`, [proposalHash, proposalIndex, weightBound, lengthBound], true);118 }119120 async proposalCount() {121 return Number(await this.helper.callRpc(`api.query.${this.collective}.proposalCount`, []));122 }123}124125class CollectiveGroup<T extends ChainHelperBase> extends HelperGroup<T> {126 collective: string;127128 constructor(helper: T, palletName: string) {129 super(helper);130131 this.collective = palletName;132 }133134 async propose(signer: TSigner, threshold: number, proposalHash: string, lengthBound: number) {135 await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.propose`, [threshold, proposalHash, lengthBound], true);136 }137138 async vote(signer: TSigner, proposalHash: string, proposalIndex: number, approve: boolean) {139 await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.vote`, [proposalHash, proposalIndex, approve], true);140 }141142 async close(signer: TSigner, proposalHash: string, proposalIndex: number, weightBound: any, lengthBound: number) {143 await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.close`, [proposalHash, proposalIndex, weightBound, lengthBound], true);144 }145146 async proposalCount() {147 return Number(await this.helper.callRpc(`api.query.${this.collective}.proposalCount`, []));148 }149}150class PolkadexXcmHelperGroup<T extends ChainHelperBase> extends HelperGroup<T> {151 async whitelistToken(signer: TSigner, assetId: any) {152 await this.helper.executeExtrinsic(signer, 'api.tx.xcmHelper.whitelistToken', [assetId], true);153 }154}155156export class ForeignAssetsGroup extends HelperGroup<UniqueHelper> {157 async register(signer: TSigner, assetId: any, name: string, tokenPrefix: string, mode: 'NFT' | { Fungible: number }) {158 await this.helper.executeExtrinsic(159 signer,160 'api.tx.foreignAssets.forceRegisterForeignAsset',161 [{V3: assetId}, this.helper.util.str2vec(name), tokenPrefix, mode],162 true,163 );164 }165166 async foreignCollectionId(assetId: any) {167 return (await this.helper.callRpc('api.query.foreignAssets.foreignAssetToCollection', [assetId])).toJSON();168 }169}170171export class XcmGroup<T extends ChainHelperBase> extends HelperGroup<T> {172 palletName: string;173174 constructor(helper: T, palletName: string) {175 super(helper);176177 this.palletName = palletName;178 }179180 async limitedReserveTransferAssets(signer: TSigner, destination: any, beneficiary: any, assets: any, feeAssetItem: number, weightLimit: any) {181 await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.limitedReserveTransferAssets`, [destination, beneficiary, assets, feeAssetItem, weightLimit], true);182 }183184 async setSafeXcmVersion(signer: TSigner, version: number) {185 await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.forceDefaultXcmVersion`, [version], true);186 }187188 async teleportAssets(signer: TSigner, destination: any, beneficiary: any, assets: any, feeAssetItem: number) {189 await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.teleportAssets`, [destination, beneficiary, assets, feeAssetItem], true);190 }191192 async teleportNativeAsset(signer: TSigner, destinationParaId: number, targetAccount: Uint8Array, amount: bigint, xcmVersion = 3) {193 const destinationContent = {194 parents: 0,195 interior: {196 X1: {197 Parachain: destinationParaId,198 },199 },200 };201202 const beneficiaryContent = {203 parents: 0,204 interior: {205 X1: {206 AccountId32: {207 network: 'Any',208 id: targetAccount,209 },210 },211 },212 };213214 const assetsContent = [215 {216 id: {217 Concrete: {218 parents: 0,219 interior: 'Here',220 },221 },222 fun: {223 Fungible: amount,224 },225 },226 ];227228 let destination;229 let beneficiary;230 let assets;231232 if(xcmVersion == 2) {233 destination = {V1: destinationContent};234 beneficiary = {V1: beneficiaryContent};235 assets = {V1: assetsContent};236237 } else if(xcmVersion == 3) {238 destination = {V2: destinationContent};239 beneficiary = {V2: beneficiaryContent};240 assets = {V2: assetsContent};241242 } else {243 throw Error('Unknown XCM version: ' + xcmVersion);244 }245246 const feeAssetItem = 0;247248 await this.teleportAssets(signer, destination, beneficiary, assets, feeAssetItem);249 }250251 async send(signer: IKeyringPair, destination: any, message: any) {252 await this.helper.executeExtrinsic(253 signer,254 `api.tx.${this.palletName}.send`,255 [256 destination,257 message,258 ],259 true,260 );261 }262}263264export class XTokensGroup<T extends ChainHelperBase> extends HelperGroup<T> {265 async transfer(signer: TSigner, currencyId: any, amount: bigint, destination: any, destWeight: any) {266 await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transfer', [currencyId, amount, destination, destWeight], true);267 }268269 async transferMultiasset(signer: TSigner, asset: any, destination: any, destWeight: any) {270 await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transferMultiasset', [asset, destination, destWeight], true);271 }272273 async transferMulticurrencies(signer: TSigner, currencies: any[], feeItem: number, destLocation: any, destWeight: any) {274 await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transferMulticurrencies', [currencies, feeItem, destLocation, destWeight], true);275 }276}277278279280export class TokensGroup<T extends ChainHelperBase> extends HelperGroup<T> {281 async accounts(address: string, currencyId: any) {282 const {free} = (await this.helper.callRpc('api.query.tokens.accounts', [address, currencyId])).toJSON() as any;283 return BigInt(free);284 }285}286287export class AssetsGroup<T extends ChainHelperBase> extends HelperGroup<T> {288 async create(signer: TSigner, assetId: number | bigint, admin: string, minimalBalance: bigint) {289 await this.helper.executeExtrinsic(signer, 'api.tx.assets.create', [assetId, admin, minimalBalance], true);290 }291292 async forceCreate(signer: TSigner, assetId: number | bigint, admin: string, minimalBalance: bigint, isSufficient = true) {293 await this.helper.executeExtrinsic(signer, 'api.tx.assets.forceCreate', [assetId, admin, isSufficient, minimalBalance], true);294 }295296 async setMetadata(signer: TSigner, assetId: number | bigint, name: string, symbol: string, decimals: number) {297 await this.helper.executeExtrinsic(signer, 'api.tx.assets.setMetadata', [assetId, name, symbol, decimals], true);298 }299300 async mint(signer: TSigner, assetId: number | bigint, beneficiary: string, amount: bigint) {301 await this.helper.executeExtrinsic(signer, 'api.tx.assets.mint', [assetId, beneficiary, amount], true);302 }303304 async assetInfo(assetId: number | bigint) {305 return (await this.helper.callRpc('api.query.assets.asset', [assetId])).toJSON();306 }307308 async account(assetId: string | number | bigint, address: string) {309 const accountAsset = (310 await this.helper.callRpc('api.query.assets.account', [assetId, address])311 ).toJSON()! as any;312313 if(accountAsset !== null) {314 return BigInt(accountAsset['balance']);315 } else {316 return null;317 }318 }319}320321export class RelayHelper extends XcmChainHelper {322 balance: SubstrateBalanceGroup<RelayHelper>;323 xcm: XcmGroup<RelayHelper>;324325 constructor(logger?: ILogger, options: { [key: string]: any } = {}) {326 super(logger, options.helperBase ?? RelayHelper);327328 this.balance = new SubstrateBalanceGroup(this);329 this.xcm = new XcmGroup(this, 'xcmPallet');330 }331}332333export class WestmintHelper extends XcmChainHelper {334 balance: SubstrateBalanceGroup<WestmintHelper>;335 xcm: XcmGroup<WestmintHelper>;336 assets: AssetsGroup<WestmintHelper>;337 xTokens: XTokensGroup<WestmintHelper>;338339 constructor(logger?: ILogger, options: { [key: string]: any } = {}) {340 super(logger, options.helperBase ?? WestmintHelper);341342 this.balance = new SubstrateBalanceGroup(this);343 this.xcm = new XcmGroup(this, 'polkadotXcm');344 this.assets = new AssetsGroup(this);345 this.xTokens = new XTokensGroup(this);346 }347}348349export class MoonbeamHelper extends XcmChainHelper {350 balance: EthereumBalanceGroup<MoonbeamHelper>;351 assetManager: MoonbeamAssetManagerGroup;352 assets: AssetsGroup<MoonbeamHelper>;353 xTokens: XTokensGroup<MoonbeamHelper>;354 democracy: MoonbeamDemocracyGroup;355 collective: {356 council: MoonbeamCollectiveGroup,357 techCommittee: MoonbeamCollectiveGroup,358 };359360 constructor(logger?: ILogger, options: { [key: string]: any } = {}) {361 super(logger, options.helperBase ?? MoonbeamHelper);362363 this.balance = new EthereumBalanceGroup(this);364 this.assetManager = new MoonbeamAssetManagerGroup(this);365 this.assets = new AssetsGroup(this);366 this.xTokens = new XTokensGroup(this);367 this.democracy = new MoonbeamDemocracyGroup(this, options);368 this.collective = {369 council: new MoonbeamCollectiveGroup(this, 'councilCollective'),370 techCommittee: new MoonbeamCollectiveGroup(this, 'techCommitteeCollective'),371 };372 }373}374375export class AstarHelper extends XcmChainHelper {376 balance: SubstrateBalanceGroup<AstarHelper>;377 assets: AssetsGroup<AstarHelper>;378 xcm: XcmGroup<AstarHelper>;379380 constructor(logger?: ILogger, options: { [key: string]: any } = {}) {381 super(logger, options.helperBase ?? AstarHelper);382383 this.balance = new SubstrateBalanceGroup(this);384 this.assets = new AssetsGroup(this);385 this.xcm = new XcmGroup(this, 'polkadotXcm');386 }387}388389export class AcalaHelper extends XcmChainHelper {390 balance: SubstrateBalanceGroup<AcalaHelper>;391 assetRegistry: AcalaAssetRegistryGroup;392 xTokens: XTokensGroup<AcalaHelper>;393 tokens: TokensGroup<AcalaHelper>;394 xcm: XcmGroup<AcalaHelper>;395396 constructor(logger?: ILogger, options: { [key: string]: any } = {}) {397 super(logger, options.helperBase ?? AcalaHelper);398399 this.balance = new SubstrateBalanceGroup(this);400 this.assetRegistry = new AcalaAssetRegistryGroup(this);401 this.xTokens = new XTokensGroup(this);402 this.tokens = new TokensGroup(this);403 this.xcm = new XcmGroup(this, 'polkadotXcm');404 }405}406407export class PolkadexHelper extends XcmChainHelper {408 assets: AssetsGroup<PolkadexHelper>;409 balance: SubstrateBalanceGroup<PolkadexHelper>;410 xTokens: XTokensGroup<PolkadexHelper>;411 xcm: XcmGroup<PolkadexHelper>;412 xcmHelper: PolkadexXcmHelperGroup<PolkadexHelper>;413414 constructor(logger?: ILogger, options: { [key: string]: any } = {}) {415 super(logger, options.helperBase ?? PolkadexHelper);416417 this.assets = new AssetsGroup(this);418 this.balance = new SubstrateBalanceGroup(this);419 this.xTokens = new XTokensGroup(this);420 this.xcm = new XcmGroup(this, 'polkadotXcm');421 this.xcmHelper = new PolkadexXcmHelperGroup(this);422 }423}424425export class HydraDxHelper extends XcmChainHelper {426 balance: SubstrateBalanceGroup<HydraDxHelper>;427 xcm: XcmGroup<HydraDxHelper>;428 xTokens: XTokensGroup<HydraDxHelper>;429 democracy: DemocracyGroup<HydraDxHelper>;430 collective: {431 council: CollectiveGroup<HydraDxHelper>,432 techCommittee: CollectiveGroup<HydraDxHelper>,433 };434435 constructor(logger?: ILogger, options: { [key: string]: any } = {}) {436 super(logger, options.helperBase ?? HydraDxHelper);437 options.notePreimagePallet = options.notePreimagePallet ?? 'preimage';438439 this.balance = new SubstrateBalanceGroup(this);440 this.xcm = new XcmGroup(this, 'polkadotXcm');441 this.xTokens = new XTokensGroup(this);442 this.democracy = new DemocracyGroup(this, options);443 this.collective = {444 council: new CollectiveGroup(this, 'council'),445 techCommittee: new CollectiveGroup(this, 'technicalCommittee'),446 };447 }448}449