@kadena/hardhat-chainweb
Version:
Hardhat plugin for Kadena's Chainweb network
154 lines • 7.26 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getChainIds = exports.deployContractOnChains = void 0;
exports.getNetworks = getNetworks;
exports.getChainIdContract = getChainIdContract;
exports.callChainIdContract = callChainIdContract;
exports.runOverChains = runOverChains;
exports.requestSpvProof = requestSpvProof;
exports.createTamperedProof = createTamperedProof;
require("./type.js");
const network_contracts_js_1 = require("./utils/network-contracts.js");
const hardhat_1 = __importDefault(require("hardhat"));
const pure_utils_js_1 = require("./pure-utils.js");
const networkStem = (0, pure_utils_js_1.getNetworkStem)(hardhat_1.default.config.defaultChainweb);
function getNetworks() {
return Object.keys(hardhat_1.default.config.networks).filter((net) => net.includes(networkStem));
}
function getChainIdContract() {
const chainweb = hardhat_1.default.config.chainweb[hardhat_1.default.config.defaultChainweb];
return new hardhat_1.default.ethers.Contract(chainweb.precompiles.chainwebChainId, network_contracts_js_1.CHAIN_ID_ABI, hardhat_1.default.ethers.provider);
}
async function callChainIdContract() {
const chainweb = hardhat_1.default.config.chainweb[hardhat_1.default.config.defaultChainweb];
const hex = await hardhat_1.default.ethers.provider.send('eth_call', [
{ to: chainweb.precompiles.chainwebChainId },
'latest',
{},
]);
return parseInt(hex, 16);
}
async function runOverChains(callback) {
const result = [];
const chainwebChainIds = await hardhat_1.default.chainweb.getChainIds();
for (const cid of chainwebChainIds) {
await hardhat_1.default.chainweb.switchChain(cid);
result.push(await callback(cid));
}
return result;
}
const deployContractOnChains = async ({ name, signer, factoryOptions, constructorArgs = [], overrides, }) => {
const deployments = await runOverChains(async (cwId) => {
try {
const signers = await hardhat_1.default.ethers.getSigners();
// Determine the appropriate signer for this chain
let contractDeployer;
// First check if custom signer was provided
if (signer) {
const signerAddress = await signer.getAddress();
contractDeployer = signers.find((account) => account.address === signerAddress);
if (!contractDeployer) {
throw new Error(`Can't find signer with address ${signerAddress} on chain ${cwId}`);
}
}
// Then check factory options signer
else if (factoryOptions === null || factoryOptions === void 0 ? void 0 : factoryOptions.signer) {
const optionsSignerAddress = await factoryOptions.signer.getAddress();
contractDeployer = signers.find((account) => account.address === optionsSignerAddress);
if (!contractDeployer) {
throw new Error(`Can't find factory options signer with address ${optionsSignerAddress} on chain ${cwId}`);
}
}
// Finally use default
else {
contractDeployer = signers[0];
}
const deployerAddress = await contractDeployer.getAddress();
console.log(`Deploying with signer: ${deployerAddress} on network ${cwId}`);
/* Deploy the contract */
const factory = await hardhat_1.default.ethers.getContractFactory(name, {
signer: contractDeployer,
...factoryOptions,
});
const contract = await factory.deploy(...(overrides ? [...constructorArgs, overrides] : constructorArgs));
const deploymentTx = contract.deploymentTransaction();
if (!deploymentTx) {
throw new Error('Deployment transaction failed');
}
await deploymentTx.wait();
const tokenAddress = await contract.getAddress();
// Store deployment info in both formats
return {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
contract: contract,
address: tokenAddress,
chain: cwId,
deployer: deployerAddress,
network: {
chainId: cwId,
name: `${networkStem}${cwId}`,
},
};
}
catch (error) {
console.error(`Failed to deploy to network ${cwId}:`, error);
return null;
}
});
return {
deployments: deployments.filter((d) => d !== null),
};
};
exports.deployContractOnChains = deployContractOnChains;
/* *************************************************************************** */
/* Off-Chain: SPV Proof Creation */
// Call our chainweb SPV api with the necesasry proof parameters
async function getProof(trgChain, origin) {
const chainweb = hardhat_1.default.config.chainweb[hardhat_1.default.config.defaultChainweb];
if (chainweb.type === 'in-process') {
throw new Error('call requestSpvProof for in-process chainweb');
}
if (!chainweb.externalHostUrl) {
throw new Error('You need to set chainweb.externalHostUrl in hardhat.config.js for external chainweb access');
}
const url = `${chainweb.externalHostUrl}/chain/${trgChain}/spv/chain/${origin.chain}/height/${origin.height}/transaction/${origin.txIdx}/event/${origin.eventIdx}`;
return fetch(url);
}
// Request cross-chain transfer SPV proof
async function requestSpvProof(targetChain, origin, chainwebNetwork) {
const chainweb = hardhat_1.default.config.chainweb[hardhat_1.default.config.defaultChainweb];
if (chainweb.type === 'in-process' && chainwebNetwork) {
const hexProof = await chainwebNetwork.getSpvProof(targetChain, origin);
console.log(`Hex proof: ${hexProof}`);
return hexProof;
}
else {
const spvCall = await getProof(targetChain, origin);
const proof = await spvCall.text();
if (proof.startsWith('0x'))
return proof;
const proofStr = proof;
const hexProof = '0x' + Buffer.from(proofStr, 'utf8').toString('hex');
return hexProof;
}
}
async function createTamperedProof(targetChain, origin, chainwebNetwork) {
const spvString = await requestSpvProof(targetChain, origin, chainwebNetwork);
const proofBytes = Buffer.from(spvString.replace(/^0x/, ''), 'hex').buffer;
const bytes = new Uint8Array(proofBytes);
// Corrupt middle of proof
const midPoint = Math.floor(bytes.length / 2);
bytes[midPoint] = 0xff; // Change single byte to invalid value
return '0x' + Buffer.from(bytes).toString('hex');
}
const getChainIds = async () => {
const chainweb = hardhat_1.default.config.chainweb[hardhat_1.default.config.defaultChainweb];
return Promise.resolve(new Array(chainweb.chains)
.fill(0)
.map((_, i) => i + chainweb.chainwebChainIdOffset));
};
exports.getChainIds = getChainIds;
//# sourceMappingURL=utils.js.map