git.delta.rocks / unique-network / refs/commits / f29e16fd1f41

difftreelog

source

js-packages/scripts/hrmpchannel.ts6.7 KiBsourcehistory
1import {ApiPromise, WsProvider} from '@polkadot/api';2import {blake2AsHex, encodeAddress} from '@polkadot/util-crypto';34export const paraChildSovereignAccount = (relayApi: ApiPromise, paraid: number) => {5  // We are getting a *child* parachain sovereign account,6  // so we need a child prefix: encoded(b"para") == 0x706172617  const childPrefix = '70617261';89  const encodedParaId = relayApi10    .createType('u32', paraid)11    .toHex(true)12    .substring(2 /* skip 0x */);1314  const addrBytesLen = 32;15  const byteLenInHex = 2;16  return '0x' + (childPrefix + encodedParaId).padEnd(addrBytesLen * byteLenInHex, '0');17};1819const proposeOpenChannel = async (relayApi: ApiPromise, relayFee: bigint, senderParaId: number, receiverParaId: number, skipBalanceCheck: boolean) => {20  const conf: any = await relayApi.query.configuration.activeConfig()21    .then(data => data.toJSON());22  const maxCapacity = conf.hrmpChannelMaxCapacity;23  const maxSize = conf.hrmpChannelMaxMessageSize;2425  const senderDeposit = BigInt(conf.hrmpSenderDeposit);2627  const requiredBalance = relayFee + senderDeposit;28  const sovereignAccount = paraChildSovereignAccount(relayApi, senderParaId);29  const balance = await relayApi.query.system.account(sovereignAccount)30    .then(accountInfo => (accountInfo.toJSON() as any).data.free as bigint);3132  if(!skipBalanceCheck && balance < requiredBalance) {33    throw Error(`Not enough balance on the sender's sovereign account: balance(${balance}) < requiredBalance(${requiredBalance})`);34  }3536  return relayApi.tx.hrmp.hrmpInitOpenChannel(37    receiverParaId,38    maxCapacity,39    maxSize,40  ).method.toHex();41};4243const proposeAcceptChannel = async (relayApi: ApiPromise, relayFee: bigint, senderParaId: number, recipientParaId: number, skipBalanceCheck: boolean) => {44  const conf: any = await relayApi.query.configuration.activeConfig()45    .then(data => data.toJSON());46  const recipientDeposit = BigInt(conf.hrmpRecipientDeposit);4748  const requiredBalance = relayFee + recipientDeposit;4950  const sovereignAccount = paraChildSovereignAccount(relayApi, recipientParaId);51  const balance = await relayApi.query.system.account(sovereignAccount)52    .then(accountInfo => (accountInfo.toJSON() as any).data.free as bigint);5354  if(!skipBalanceCheck && balance < requiredBalance) {55    throw Error(`Not enough balance on the recipient's sovereign account: balance(${balance}) < requiredBalance(${requiredBalance})`);56  }5758  return relayApi.tx.hrmp.hrmpAcceptOpenChannel(senderParaId).method.toHex();59};6061async function main() {62  let skipBalanceCheck;63  if(process.argv.length == 6) {64    skipBalanceCheck = false;65  }66  else if(process.argv.length == 7 && process.argv[6] == 'skip-balance-check') {67    skipBalanceCheck = true;68  } else {69    console.log('Usage: yarn hrmpChannel <RELAY_URL> <OUR_CHAIN_URL> <OTHER_CHAIN_URL> <open | accept> [skip-balance-check]');70    process.exit(1);71  }7273  const relayUrl = process.argv[2];74  const uniqueParachainUrl = process.argv[3];75  const otherParachainUrl = process.argv[4];76  const op = process.argv[5];7778  const relayWsProvider = new WsProvider(relayUrl);79  const relayApi = await ApiPromise.create({provider: relayWsProvider});8081  const uniqueWsProvider = new WsProvider(uniqueParachainUrl);82  const uniqueApi = await ApiPromise.create({provider: uniqueWsProvider});8384  const otherWsProvider = new WsProvider(otherParachainUrl);85  const otherApi = await ApiPromise.create({provider: otherWsProvider});8687  const uniqueParaId = await uniqueApi.query.parachainInfo.parachainId()88    .then(data => data.toJSON() as number);8990  const otherParaId = await otherApi.query.parachainInfo.parachainId()91    .then(data => data.toJSON() as number);9293  const relayDecimals = await relayApi.rpc.system.properties()94    .then(data => data.tokenDecimals.unwrap()[0].toNumber());9596  const relayFee = 2n * BigInt(10 ** relayDecimals);9798  let encodedRelayCall: string;99100  if(op == 'open') {101    encodedRelayCall = await proposeOpenChannel(relayApi, relayFee, uniqueParaId, otherParaId, skipBalanceCheck);102  } else if(op == 'accept') {103    encodedRelayCall = await proposeAcceptChannel(relayApi, relayFee, otherParaId, uniqueParaId, skipBalanceCheck);104  } else {105    throw Error(`Unknown hrmp channel operation: ${op}`);106  }107108  const proposal = uniqueApi.tx.polkadotXcm.send(109    {110      V3: {111        parents: 1,112        interior: 'Here',113      },114    },115    {116      V3: [117        {118          WithdrawAsset: [119            {120              id: {121                Concrete: {122                  parents: 0,123                  interior: 'Here',124                },125              },126              fun: {127                Fungible: relayFee,128              },129            },130          ],131        },132        {133          BuyExecution: {134            fees: {135              id: {136                Concrete: {137                  parents: 0,138                  interior: 'Here',139                },140              },141              fun: {142                Fungible: relayFee,143              },144            },145            weightLimit: 'Unlimited',146          },147        },148        {149          Transact: {150            originKind: 'Native',151            requireWeightAtMost: {152              refTime: 1000000000,153              proofSize: 65536,154            },155            call: {156              encoded: encodedRelayCall,157            },158          },159        },160        'RefundSurplus',161        {162          DepositAsset: {163            assets: {164              Wild: {165                AllCounted: 1,166              },167            },168            beneficiary: {169              parents: 0,170              interior: {171                X1: {172                  Parachain: uniqueParaId,173                },174              },175            },176          },177        },178      ],179    },180  ).method.toHex();181182  const councilMembers = (await uniqueApi.query.council.members()).toJSON() as any[];183  const councilProposalThreshold = Math.floor(councilMembers.length / 2) + 1;184185  const democracyProposalHash = blake2AsHex(proposal, 256);186  const democracyProposalPreimage = uniqueApi.tx.preimage.notePreimage(proposal).method.toHex();187188  const democracyProposal = uniqueApi.tx.democracy.externalProposeDefault({189    Legacy: democracyProposalHash,190  });191192  const councilProposal = uniqueApi.tx.council.propose(193    councilProposalThreshold,194    democracyProposal,195    democracyProposal.method.encodedLength,196  ).method.toHex();197198  const proposeBatch = uniqueApi.tx.utility.batchAll([199    democracyProposalPreimage,200    councilProposal,201  ]);202203  const encodedCall = proposeBatch.method.toHex();204205  console.log('-----------------');206  console.log('Council Proposal: ', `https://polkadot.js.org/apps/?rpc=${uniqueParachainUrl}#/extrinsics/decode/${encodedCall}`);207  console.log('-----------------');208209  await relayApi.disconnect();210  await uniqueApi.disconnect();211  await otherApi.disconnect();212}213214await main();