Step 3: Deploy Blended Contracts
3.1 Create the Deployment Script
This deployment script is responsible for deploying both the Rust smart contract (compiled to Wasm) and the Solidity smart contract (GreetingWithWorld
).
deploy/01_deploy_contracts.ts
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { DeployFunction } from "hardhat-deploy/types";
import { ethers } from "ethers";
import fs from "fs";
import crypto from "crypto";
import path from "path";
require("dotenv").config();
const DEPLOYER_PRIVATE_KEY = process.env.DEPLOYER_PRIVATE_KEY || "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80";
const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const { deployments, getNamedAccounts, ethers, config, network } = hre;
const { deploy, save, getOrNull } = deployments;
const { deployer: deployerAddress } = await getNamedAccounts();
console.log("deployerAddress", deployerAddress);
// Deploy WASM Contract
console.log("Deploying WASM contract...");
const wasmBinaryPath = "./greeting/lib.wasm";
// @ts-ignore
const provider = new ethers.JsonRpcProvider(network.config.url);
const deployer = new ethers.Wallet(DEPLOYER_PRIVATE_KEY, provider);
const checkmateValidatorAddress = await deployWasmContract(wasmBinaryPath, deployer, provider, getOrNull, save);
//Deploy Solidity Contract
console.log("Deploying GreetingWithWorld contract...");
const fluentGreetingContractAddress = checkmateValidatorAddress;
const greetingWithWorld = await deploy("GreetingWithWorld", {
from: deployerAddress,
args: [fluentGreetingContractAddress],
log: true,
});
console.log(`GreetingWithWorld contract deployed at: ${greetingWithWorld.address}`);
};
async function deployWasmContract(
wasmBinaryPath: string,
deployer: ethers.Wallet,
provider: ethers.JsonRpcProvider,
getOrNull: any,
save: any
) {
const wasmBinary = fs.readFileSync(wasmBinaryPath);
const wasmBinaryHash = crypto.createHash("sha256").update(wasmBinary).digest("hex");
const artifactName = path.basename(wasmBinaryPath, ".wasm");
const existingDeployment = await getOrNull(artifactName);
if (existingDeployment && existingDeployment.metadata === wasmBinaryHash) {
console.log(`WASM contract bytecode has not changed. Skipping deployment.`);
console.log(`Existing contract address: ${existingDeployment.address}`);
return existingDeployment.address;
}
const gasPrice = (await provider.getFeeData()).gasPrice;
const transaction = {
data: "0x" + wasmBinary.toString("hex"),
gasLimit: 300_000_000,
gasPrice: gasPrice,
};
const tx = await deployer.sendTransaction(transaction);
const receipt = await tx.wait();
if (receipt && receipt.contractAddress) {
console.log(`WASM contract deployed at: ${receipt.contractAddress}`);
const artifact = {
abi: [],
bytecode: "0x" + wasmBinary.toString("hex"),
deployedBytecode: "0x" + wasmBinary.toString("hex"),
metadata: wasmBinaryHash,
};
const deploymentData = {
address: receipt.contractAddress,
...artifact,
};
await save(artifactName, deploymentData);
} else {
throw new Error("Failed to deploy WASM contract");
}
return receipt.contractAddress;
}
export default func;
func.tags = ["all"];
3.2 Create the Hardhat Task
tasks/get-greeting.ts
import { task } from "hardhat/config";
task("get-greeting", "Fetches the greeting from the deployed GreetingWithWorld contract")
.addParam("contract", "The address of the deployed GreetingWithWorld contract")
.setAction(async ({ contract }, hre) => {
const { ethers } = hre;
const GreetingWithWorld = await ethers.getContractAt("GreetingWithWorld", contract);
const greeting = await GreetingWithWorld.getGreeting();
console.log("Greeting:", greeting);
});
3.3 Compile and Deploy the Contracts
Run the following commands to compile and deploy your contracts:
pnpm hardhat compile
pnpm hardhat deploy
pnpm hardhat get-greeting --contract <CONTRACT_ADDRESS>