difftreelog
feat skip-balance-check option
in: master
1 file changed
js-packages/scripts/hrmpchannel.tsdiffbeforeafterboth1import {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) => {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(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) => {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(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 if(process.argv.length != 6) {63 console.log('Usage: yarn hrmpChannel <RELAY_URL> <OUR_CHAIN_URL> <OTHER_CHAIN_URL> <open | accept>');64 process.exit(1);65 }6667 const relayUrl = process.argv[2];68 const uniqueParachainUrl = process.argv[3];69 const otherParachainUrl = process.argv[4];70 const op = process.argv[5];7172 const relayWsProvider = new WsProvider(relayUrl);73 const relayApi = await ApiPromise.create({provider: relayWsProvider});7475 const uniqueWsProvider = new WsProvider(uniqueParachainUrl);76 const uniqueApi = await ApiPromise.create({provider: uniqueWsProvider});7778 const otherWsProvider = new WsProvider(otherParachainUrl);79 const otherApi = await ApiPromise.create({provider: otherWsProvider});8081 const uniqueParaId = await uniqueApi.query.parachainInfo.parachainId()82 .then(data => data.toJSON() as number);8384 const otherParaId = await otherApi.query.parachainInfo.parachainId()85 .then(data => data.toJSON() as number);8687 const relayDecimals = await relayApi.rpc.system.properties()88 .then(data => data.tokenDecimals.unwrap()[0].toNumber());8990 const relayFee = 2n * BigInt(10 ** relayDecimals);9192 let encodedRelayCall: string;93 if(op == 'open') {94 encodedRelayCall = await proposeOpenChannel(relayApi, relayFee, uniqueParaId, otherParaId);95 } else if(op == 'accept') {96 encodedRelayCall = await proposeAcceptChannel(relayApi, relayFee, otherParaId, uniqueParaId);97 } else {98 throw Error(`Unknown hrmp channel operation: ${op}`);99 }100101 const proposal = uniqueApi.tx.polkadotXcm.send(102 {103 V3: {104 parents: 1,105 interior: 'Here',106 },107 },108 {109 V3: [110 {111 WithdrawAsset: [112 {113 id: {114 Concrete: {115 parents: 0,116 interior: 'Here',117 },118 },119 fun: {120 Fungible: relayFee,121 },122 },123 ],124 },125 {126 BuyExecution: {127 fees: {128 id: {129 Concrete: {130 parents: 0,131 interior: 'Here',132 },133 },134 fun: {135 Fungible: relayFee,136 },137 },138 weightLimit: 'Unlimited',139 },140 },141 {142 Transact: {143 originKind: 'Native',144 requireWeightAtMost: {145 refTime: 1000000000,146 proofSize: 65536,147 },148 call: {149 encoded: encodedRelayCall,150 },151 },152 },153 'RefundSurplus',154 {155 DepositAsset: {156 assets: {157 Wild: {158 AllCounted: 1,159 },160 },161 beneficiary: {162 parents: 0,163 interior: {164 X1: {165 Parachain: uniqueParaId,166 },167 },168 },169 },170 },171 ],172 },173 ).method.toHex();174175 const councilMembers = (await uniqueApi.query.council.members()).toJSON() as any[];176 const councilProposalThreshold = Math.floor(councilMembers.length / 2) + 1;177178 const democracyProposalHash = blake2AsHex(proposal, 256);179 const democracyProposalPreimage = uniqueApi.tx.preimage.notePreimage(proposal).method.toHex();180181 const democracyProposal = uniqueApi.tx.democracy.externalProposeDefault({182 Legacy: democracyProposalHash,183 });184185 const councilProposal = uniqueApi.tx.council.propose(186 councilProposalThreshold,187 democracyProposal,188 democracyProposal.method.encodedLength,189 ).method.toHex();190191 const proposeBatch = uniqueApi.tx.utility.batchAll([192 democracyProposalPreimage,193 councilProposal,194 ]);195196 const encodedCall = proposeBatch.method.toHex();197198 console.log('-----------------');199 console.log('Council Proposal: ', `https://polkadot.js.org/apps/?rpc=${uniqueParachainUrl}#/extrinsics/decode/${encodedCall}`);200 console.log('-----------------');201202 await relayApi.disconnect();203 await uniqueApi.disconnect();204 await otherApi.disconnect();205}206207await main();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();