Skip to main content

Since January 2026, we are unfortunately unable to actively maintain or develop ink! further.

We have written down the details in a Polkadot Forum post.

Version: v6

Deploy with Hardhat & Ethers.js

Hardhat is a popular Ethereum development framework. With @parity/hardhat-polkadot, you can use it to deploy and interact with ink! smart contracts on Polkadot-compatible environments.

This guide walks you through using Hardhat to deploy and interact with ink! smart contracts on Polkadot Hub.

Prerequisites​

Before starting, ensure you have:

Project Setup​

  1. Create a Hardhat Project
mkdir hardhat-example
cd hardhat-example
npm init -y
  1. Install Required Dependencies

To interact with Polkadot, Hardhat requires the following plugin to compile contracts to PolkaVM bytecode and to spawn a local node compatible with PolkaVM:

npm install --save-dev @parity/hardhat-polkadot
  1. Initialize the Project
npx hardhat-polkadot init
npm install
note

By default, this creates a basic project with a Solidity smart contract. Since we already have our ink! smart contract compiled, we'll skip the Solidity compilation step.

Configuration​

Network Configuration​

Update your hardhat.config.js with network settings for the Polkadot Hub Testnet:

require('@nomicfoundation/hardhat-toolbox');
require('@parity/hardhat-polkadot');

const { vars } = require('hardhat/config');

module.exports = {
// ... other config
networks: {
hardhat: {
// ... local config
},
polkadotHubTestnet: {
polkavm: true,
url: 'https://testnet-passet-hub-eth-rpc.polkadot.io',
accounts: [vars.get('PRIVATE_KEY')],
},
},
};

Private Key Setup​

Export your private key and save it in your Hardhat environment:

npx hardhat vars set PRIVATE_KEY "INSERT_PRIVATE_KEY"

Replace INSERT_PRIVATE_KEY with your actual private key. For details on private key exportation, refer to How to export an account's private key.

Get Test Tokens​

Use the Polkadot Hub Testnet faucet to fund your account with test PAS tokens.

Contract Deployment​

Understanding Contract Files​

After building your ink! smart contract with Solidity metadata, you'll find 3 key files in your contract's target directory:

  • <contract-name>.polkavm: Raw contract bytecode that will be deployed on-chain
  • <contract-name>.abi: Solidity ABI JSON format for contract interaction (used by ethers.js)
  • <contract-name>.json: Solidity contract metadata specification for verification

Deployment Script​

Create a file called scripts/deploy.js:

const hre = require('hardhat');
const { join } = require('path');
const { readFileSync } = require('fs');

// Import the ABI of the contract from the flipper_evm.json file.
const abi = require("../../target/ink/flipper_evm.json").output.abi;

async function main() {
const [deployer] = await hre.ethers.getSigners();

// Fetch the bytecode of the contract.
const bytecodePath = join(__dirname, "../../target/ink", "flipper_evm.polkavm");
const bytecode = `0x${readFileSync(bytecodePath).toString('hex')}`;

const flipper = new hre.ethers.ContractFactory(abi, bytecode, deployer);

// Deploy the contract with the constructor arguments.
const contract = await flipper.deploy(true);
await contract.waitForDeployment();

// Get the address of the deployed contract.
const address = await contract.getAddress();
console.log(`Contract deployed at: ${address}`);
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});

Run Deployment​

npx hardhat run scripts/deploy.js --network polkadotHubTestnet

This will print the smart contract address once deployment is complete:

Contract deployed at: YOUR_CONTRACT_ADDRESS
note

Save this address - you'll need it to interact with your deployed contract.

Contract Interaction​

Create a file called scripts/interact.js:

const hre = require('hardhat');

// Import the ABI of the contract from the flipper_evm.json file.
const abi = require("../../target/ink/flipper_evm.json").output.abi;

async function main() {
const [deployer] = await hre.ethers.getSigners();

// Replace with your deployed contract address
const contractAddress = 'INSERT_CONTRACT_ADDRESS';

const flipper = new hre.ethers.Contract(contractAddress, abi, deployer);

// Read contract state
const state = await flipper.get();
console.log(`State: ${state}`);

// Call the flip message
await flipper.flip();

// Read contract state again to see the change
const state_after = await flipper.get();
console.log(`State: ${state_after}`);
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});

Run the interaction script:

npx hardhat run scripts/interact.js --network polkadotHubTestnet

Local Development Environment​

For local testing, you can spin up a local testing environment:

Download Required Binaries​

Download the latest release from ink-node releases. The release includes:

  • ink-node binary (the PolkaVM-compatible node)
  • eth-rpc adapter binary (adapts the node to EVM-style JSON-RPC)

Configure Local Network​

Update your hardhat.config.js:

require('@nomicfoundation/hardhat-toolbox');
require('@parity/hardhat-polkadot');

module.exports = {
// ... other config
networks: {
hardhat: {
polkavm: true,
nodeConfig: {
nodeBinaryPath: 'INSERT_PATH_TO_INK_NODE',
rpcPort: 8000,
dev: true,
},
adapterConfig: {
adapterBinaryPath: 'INSERT_PATH_TO_ETH_RPC_ADAPTER',
dev: true,
},
},
localNode: {
polkavm: true,
url: `http://127.0.0.1:8545`,
},
},
};

Start Local Environment​

npx hardhat node

This launches the ink-node (on localhost:8000) and the eth-rpc adapter (on localhost:8545).

Interact with Local Network​

npx hardhat run scripts/interact.js --network localNode

Next Steps​

With your contract deployed via Hardhat, you can now: