From 0638be4c3bcaa80089e90b4a8ab0d61d2cbced02 Mon Sep 17 00:00:00 2001 From: nhussein11 Date: Mon, 17 Nov 2025 09:30:00 -0300 Subject: [PATCH 1/7] Add Solidity compiler and update contract scripts --- .../libraries/ethers-js/checkStorage.js | 10 ++- .../libraries/ethers-js/compile.js | 81 +++++++++++++------ .../libraries/ethers-js/deploy.js | 31 ++++--- .../libraries/ethers-js/Storage.sol | 17 ++++ smart-contracts/libraries/ethers-js.md | 49 ++++++----- text/smart-contracts/code-size.md | 2 + variables.yml | 3 + 7 files changed, 123 insertions(+), 70 deletions(-) create mode 100644 code/smart-contracts/libraries/ethers-js/Storage.sol create mode 100644 text/smart-contracts/code-size.md diff --git a/.snippets/code/smart-contracts/libraries/ethers-js/checkStorage.js b/.snippets/code/smart-contracts/libraries/ethers-js/checkStorage.js index d95379916..216bfd83a 100644 --- a/.snippets/code/smart-contracts/libraries/ethers-js/checkStorage.js +++ b/.snippets/code/smart-contracts/libraries/ethers-js/checkStorage.js @@ -2,6 +2,8 @@ const { ethers } = require('ethers'); const { readFileSync } = require('fs'); const { join } = require('path'); +const artifactsDir = join(__dirname, '../contracts'); + const createProvider = (providerConfig) => { return new ethers.JsonRpcProvider(providerConfig.rpc, { chainId: providerConfig.chainId, @@ -13,7 +15,7 @@ const createWallet = (mnemonic, provider) => { return ethers.Wallet.fromPhrase(mnemonic).connect(provider); }; -const loadContractAbi = (contractName, directory = __dirname) => { +const loadContractAbi = (contractName, directory = artifactsDir) => { const contractPath = join(directory, `${contractName}.json`); const contractJson = JSON.parse(readFileSync(contractPath, 'utf8')); return contractJson.abi || contractJson; // Depending on JSON structure @@ -69,9 +71,9 @@ const providerConfig = { chainId: 420420422, }; -const mnemonic = 'INSERT_MNEMONIC'; +const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon'; const contractName = 'Storage'; -const contractAddress = 'INSERT_CONTRACT_ADDRESS'; +const contractAddress = '0x83e43892a98f924706E9DB7917244897dC8b8126'; const newNumber = 42; interactWithStorageContract( @@ -80,4 +82,4 @@ interactWithStorageContract( mnemonic, providerConfig, newNumber, -); +); \ No newline at end of file diff --git a/.snippets/code/smart-contracts/libraries/ethers-js/compile.js b/.snippets/code/smart-contracts/libraries/ethers-js/compile.js index a02829666..ec13f81ba 100644 --- a/.snippets/code/smart-contracts/libraries/ethers-js/compile.js +++ b/.snippets/code/smart-contracts/libraries/ethers-js/compile.js @@ -1,37 +1,71 @@ -const { compile } = require('@parity/resolc'); -const { readFileSync, writeFileSync } = require('fs'); +const solc = require('solc'); +const { readFileSync, writeFileSync, mkdirSync, existsSync } = require('fs'); const { basename, join } = require('path'); -const compileContract = async (solidityFilePath, outputDir) => { +const ensureDir = (dirPath) => { + if (!existsSync(dirPath)) { + mkdirSync(dirPath, { recursive: true }); + } +}; + +const compileContract = (solidityFilePath, abiDir, artifactsDir) => { try { // Read the Solidity file const source = readFileSync(solidityFilePath, 'utf8'); - - // Construct the input object for the compiler + const fileName = basename(solidityFilePath); + + // Construct the input object for the Solidity compiler const input = { - [basename(solidityFilePath)]: { content: source }, + language: 'Solidity', + sources: { + [fileName]: { + content: source, + }, + }, + settings: { + outputSelection: { + '*': { + '*': ['abi', 'evm.bytecode'], + }, + }, + }, }; - - console.log(`Compiling contract: ${basename(solidityFilePath)}...`); - + + console.log(`Compiling contract: ${fileName}...`); + // Compile the contract - const out = await compile(input); - - for (const contracts of Object.values(out.contracts)) { - for (const [name, contract] of Object.entries(contracts)) { - console.log(`Compiled contract: ${name}`); + const output = JSON.parse(solc.compile(JSON.stringify(input))); + + // Check for errors + if (output.errors) { + const errors = output.errors.filter(error => error.severity === 'error'); + if (errors.length > 0) { + console.error('Compilation errors:'); + errors.forEach(err => console.error(err.formattedMessage)); + return; + } + // Show warnings + const warnings = output.errors.filter(error => error.severity === 'warning'); + warnings.forEach(warn => console.warn(warn.formattedMessage)); + } + + // Ensure output directories exist + ensureDir(abiDir); + ensureDir(artifactsDir); + // Process compiled contracts + for (const [sourceFile, contracts] of Object.entries(output.contracts)) { + for (const [contractName, contract] of Object.entries(contracts)) { + console.log(`Compiled contract: ${contractName}`); + // Write the ABI - const abiPath = join(outputDir, `${name}.json`); + const abiPath = join(abiDir, `${contractName}.json`); writeFileSync(abiPath, JSON.stringify(contract.abi, null, 2)); console.log(`ABI saved to ${abiPath}`); - + // Write the bytecode - const bytecodePath = join(outputDir, `${name}.polkavm`); - writeFileSync( - bytecodePath, - Buffer.from(contract.evm.bytecode.object, 'hex'), - ); + const bytecodePath = join(artifactsDir, `${contractName}.bin`); + writeFileSync(bytecodePath, contract.evm.bytecode.object); console.log(`Bytecode saved to ${bytecodePath}`); } } @@ -41,6 +75,7 @@ const compileContract = async (solidityFilePath, outputDir) => { }; const solidityFilePath = join(__dirname, '../contracts/Storage.sol'); -const outputDir = join(__dirname, '../contracts'); +const abiDir = join(__dirname, '../abis'); +const artifactsDir = join(__dirname, '../artifacts'); -compileContract(solidityFilePath, outputDir); +compileContract(solidityFilePath, abiDir, artifactsDir); \ No newline at end of file diff --git a/.snippets/code/smart-contracts/libraries/ethers-js/deploy.js b/.snippets/code/smart-contracts/libraries/ethers-js/deploy.js index 40c78e463..c2bc56b59 100644 --- a/.snippets/code/smart-contracts/libraries/ethers-js/deploy.js +++ b/.snippets/code/smart-contracts/libraries/ethers-js/deploy.js @@ -1,11 +1,11 @@ -// Deploy an EVM-compatible smart contract using ethers.js const { writeFileSync, existsSync, readFileSync } = require('fs'); const { join } = require('path'); const { ethers, JsonRpcProvider } = require('ethers'); -const codegenDir = join(__dirname); +const scriptsDir = __dirname; +const artifactsDir = join(__dirname, '../contracts'); -// Creates an Ethereum provider with specified RPC URL and chain details +// Creates a provider with specified RPC URL and chain details const createProvider = (rpcUrl, chainId, chainName) => { const provider = new JsonRpcProvider(rpcUrl, { chainId: chainId, @@ -17,9 +17,8 @@ const createProvider = (rpcUrl, chainId, chainName) => { // Reads and parses the ABI file for a given contract const getAbi = (contractName) => { try { - return JSON.parse( - readFileSync(join(codegenDir, `${contractName}.json`), 'utf8'), - ); + const abiPath = join(artifactsDir, `${contractName}.json`); + return JSON.parse(readFileSync(abiPath, 'utf8')); } catch (error) { console.error( `Could not find ABI for contract ${contractName}:`, @@ -32,12 +31,10 @@ const getAbi = (contractName) => { // Reads the compiled bytecode for a given contract const getByteCode = (contractName) => { try { - const bytecodePath = join( - codegenDir, - '../contracts', - `${contractName}.polkavm`, - ); - return `0x${readFileSync(bytecodePath).toString('hex')}`; + const bytecodePath = join(artifactsDir, `${contractName}.bin`); + const bytecode = readFileSync(bytecodePath, 'utf8').trim(); + // Add 0x prefix if not present + return bytecode.startsWith('0x') ? bytecode : `0x${bytecode}`; } catch (error) { console.error( `Could not find bytecode for contract ${contractName}:`, @@ -49,7 +46,6 @@ const getByteCode = (contractName) => { const deployContract = async (contractName, mnemonic, providerConfig) => { console.log(`Deploying ${contractName}...`); - try { // Step 1: Set up provider and wallet const provider = createProvider( @@ -73,10 +69,11 @@ const deployContract = async (contractName, mnemonic, providerConfig) => { const address = await contract.getAddress(); console.log(`Contract ${contractName} deployed at: ${address}`); - const addressesFile = join(codegenDir, 'contract-address.json'); + const addressesFile = join(scriptsDir, 'contract-address.json'); const addresses = existsSync(addressesFile) ? JSON.parse(readFileSync(addressesFile, 'utf8')) : {}; + addresses[contractName] = address; writeFileSync(addressesFile, JSON.stringify(addresses, null, 2), 'utf8'); } catch (error) { @@ -85,11 +82,11 @@ const deployContract = async (contractName, mnemonic, providerConfig) => { }; const providerConfig = { - rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', + rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', #TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready chainId: 420420422, name: 'polkadot-hub-testnet', }; -const mnemonic = 'INSERT_MNEMONIC'; +const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon'; -deployContract('Storage', mnemonic, providerConfig); +deployContract('Storage', mnemonic, providerConfig); \ No newline at end of file diff --git a/code/smart-contracts/libraries/ethers-js/Storage.sol b/code/smart-contracts/libraries/ethers-js/Storage.sol new file mode 100644 index 000000000..a306bb393 --- /dev/null +++ b/code/smart-contracts/libraries/ethers-js/Storage.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.9; + +contract Storage { + uint256 private storedNumber; + + event NumberUpdated(uint256 newValue); + + function store(uint256 num) public { + storedNumber = num; + emit NumberUpdated(num); + } + + function retrieve() public view returns (uint256) { + return storedNumber; + } +} diff --git a/smart-contracts/libraries/ethers-js.md b/smart-contracts/libraries/ethers-js.md index 0afab9ce6..9d4871414 100644 --- a/smart-contracts/libraries/ethers-js.md +++ b/smart-contracts/libraries/ethers-js.md @@ -6,8 +6,6 @@ categories: Smart Contracts, Tooling # Ethers.js ---8<-- 'text/smart-contracts/polkaVM-warning.md' - ## Introduction [Ethers.js](https://docs.ethers.org/v6/){target=\_blank} is a lightweight library that enables interaction with Ethereum Virtual Machine (EVM)-compatible blockchains through JavaScript. Ethers is widely used as a toolkit to establish connections and read and write blockchain data. This article demonstrates using Ethers.js to interact and deploy smart contracts to Polkadot Hub. @@ -39,7 +37,7 @@ ethers-project ├── abis │ ├── Storage.json ├── artifacts -│ ├── Storage.polkavm +│ ├── Storage.bin ├── contract-address.json ├── node_modules/ ├── package.json @@ -65,6 +63,17 @@ Next, run the following command to install the Ethers.js library: npm install ethers ``` +Add the Solidity compiler so you can generate standard EVM bytecode: + +```bash +npm install --save-dev solc +``` + +This guide uses `solc` version `{{ dependencies.javascript_packages.solc.version }}`. + +!!! tip + The sample scripts use ECMAScript modules. Add `"type": "module"` to your `package.json` (or rename the files to `.mjs`) so that `node` can run the `import` statements. + ## Set Up the Ethers.js Provider A [`Provider`](https://docs.ethers.org/v6/api/providers/#Provider){target=\_blank} is an abstraction of a connection to the Ethereum network, allowing you to query blockchain data and send transactions. It serves as a bridge between your application and the blockchain. @@ -89,7 +98,7 @@ To interact with Polkadot Hub, you must set up an Ethers.js provider. This provi To connect to the provider, execute: ```bash -node connectToProvider +node scripts/connectToProvider.js ``` With the provider set up, you can start querying the blockchain. For instance, to fetch the latest block number: @@ -102,19 +111,7 @@ With the provider set up, you can start querying the blockchain. For instance, t ## Compile Contracts ---8<-- 'text/smart-contracts/code-size.md' - -The `revive` compiler transforms Solidity smart contracts into [PolkaVM](/smart-contracts/overview/#native-smart-contracts){target=\_blank} bytecode for deployment on Polkadot Hub. Revive's Ethereum RPC interface allows you to use familiar tools like Ethers.js and MetaMask to interact with contracts. - -### Install the Revive Library - -The [`@parity/resolc`](https://www.npmjs.com/package/@parity/resolc){target=\_blank} library will compile your Solidity code for deployment on Polkadot Hub. Run the following command in your terminal to install the library: - -```bash -npm install --save-dev @parity/resolc -``` - -This guide uses `@parity/resolc` version `{{ dependencies.javascript_packages.resolc.version }}`. +Polkadot Hub exposes an Ethereum JSON-RPC endpoint, so you can compile Solidity contracts to familiar EVM bytecode with the upstream [`solc`](https://www.npmjs.com/package/solc){target=\_blank} compiler. The resulting artifacts work with any EVM-compatible toolchain and can be deployed through Ethers.js. ### Sample Storage Smart Contract @@ -140,10 +137,10 @@ The ABI (Application Binary Interface) is a JSON representation of your contract Execute the script above by running: ```bash -node compile +node scripts/compile.js ``` -After executing the script, the Solidity contract will be compiled into the required PolkaVM bytecode format. The ABI and bytecode will be saved into files with `.json` and `.polkavm` extensions, respectively. You can now proceed with deploying the contract to Polkadot Hub, as outlined in the next section. +After executing the script, the Solidity contract is compiled into standard EVM bytecode. The ABI and bytecode are saved into files with `.json` and `.bin` extensions, respectively. You can now proceed with deploying the contract to Polkadot Hub, as outlined in the next section. ## Deploy the Compiled Contract @@ -154,7 +151,7 @@ You can create a `deploy.js` script in the root of your project to achieve this. 1. Set up the required imports and utilities: ```js title="scripts/deploy.js" - --8<-- 'code/smart-contracts/libraries/ethers-js/deploy.js:1:6' + --8<-- 'code/smart-contracts/libraries/ethers-js/deploy.js:1:4' ``` 2. Create a provider to connect to Polkadot Hub: @@ -166,19 +163,19 @@ You can create a `deploy.js` script in the root of your project to achieve this. 3. Set up functions to read contract artifacts: ```js title="scripts/deploy.js" - --8<-- 'code/smart-contracts/libraries/ethers-js/deploy.js:17:48' + --8<-- 'code/smart-contracts/libraries/ethers-js/deploy.js:17:46' ``` 4. Create the main deployment function: ```js title="scripts/deploy.js" - --8<-- 'code/smart-contracts/libraries/ethers-js/deploy.js:49:85' + --8<-- 'code/smart-contracts/libraries/ethers-js/deploy.js:47:82' ``` 5. Configure and execute the deployment: ```js title="scripts/deploy.js" - --8<-- 'code/smart-contracts/libraries/ethers-js/deploy.js:87:95' + --8<-- 'code/smart-contracts/libraries/ethers-js/deploy.js4:92' ``` !!! note @@ -195,7 +192,7 @@ You can create a `deploy.js` script in the root of your project to achieve this. To run the script, execute the following command: ```bash -node deploy +node scripts/deploy.js ``` After running this script, your contract will be deployed to Polkadot Hub, and its address will be saved in `contract-address.json` within your project directory. You can use this address for future contract interactions. @@ -208,12 +205,12 @@ Once the contract is deployed, you can interact with it by calling its functions --8<-- 'code/smart-contracts/libraries/ethers-js/checkStorage.js' ``` -Ensure you replace the `INSERT_MNEMONIC`, `INSERT_CONTRACT_ADDRESS`, and `INSERT_ADDRESS_TO_CHECK` placeholders with actual values. Also, ensure the contract ABI file (`Storage.json`) is correctly referenced. +Ensure you replace the `INSERT_MNEMONIC`, `INSERT_CONTRACT_ADDRESS`, and `INSERT_ADDRESS_TO_CHECK` placeholders with actual values. Also, ensure the contract ABI file (`Storage.json`) is correctly referenced. The script prints the balance for `ADDRESS_TO_CHECK` before it writes and doubles the stored value, so pick any account you want to monitor. To interact with the contract, run: ```bash -node checkStorage +node scripts/checkStorage.js ``` ## Where to Go Next diff --git a/text/smart-contracts/code-size.md b/text/smart-contracts/code-size.md new file mode 100644 index 000000000..b004a7594 --- /dev/null +++ b/text/smart-contracts/code-size.md @@ -0,0 +1,2 @@ +!!! info "Mind the contract size" + Polkadot Hub enforces Ethereum's 24 KiB contract-size limit (EIP-170) for EVM deployments. Keep contracts modular, share logic through libraries, and make use of compiler optimizations so your bytecode stays within the limit. diff --git a/variables.yml b/variables.yml index 3886dd564..f173ee4cf 100644 --- a/variables.yml +++ b/variables.yml @@ -71,6 +71,9 @@ dependencies: resolc: name: '@resolc' version: 0.2.0 + solc: + name: 'solc' + version: 0.8.33 web3_js: name: '@web3js' version: 4.16.0 From 4009f7fe608b9db1f4c9a8b0a83c3349d5da3ed6 Mon Sep 17 00:00:00 2001 From: nhussein11 Date: Mon, 17 Nov 2025 09:33:28 -0300 Subject: [PATCH 2/7] fix: llms --- .ai/categories/smart-contracts.md | 202 ++++++++++-------- .ai/categories/tooling.md | 202 ++++++++++-------- .../smart-contracts-libraries-ethers-js.md | 202 ++++++++++-------- .ai/pages/text-smart-contracts-code-size.md | 6 + .ai/site-index.json | 37 +++- llms-full.jsonl | 25 ++- llms.txt | 3 +- 7 files changed, 367 insertions(+), 310 deletions(-) create mode 100644 .ai/pages/text-smart-contracts-code-size.md diff --git a/.ai/categories/smart-contracts.md b/.ai/categories/smart-contracts.md index 1e901e36e..0b9e7d40a 100644 --- a/.ai/categories/smart-contracts.md +++ b/.ai/categories/smart-contracts.md @@ -3074,8 +3074,6 @@ Page Title: Deploy Contracts to Polkadot Hub with Ethers.js # Ethers.js -!!! smartcontract "PolkaVM Preview Release" - PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. ## Introduction [Ethers.js](https://docs.ethers.org/v6/){target=\_blank} is a lightweight library that enables interaction with Ethereum Virtual Machine (EVM)-compatible blockchains through JavaScript. Ethers is widely used as a toolkit to establish connections and read and write blockchain data. This article demonstrates using Ethers.js to interact and deploy smart contracts to Polkadot Hub. @@ -3107,7 +3105,7 @@ ethers-project ├── abis │ ├── Storage.json ├── artifacts -│ ├── Storage.polkavm +│ ├── Storage.bin ├── contract-address.json ├── node_modules/ ├── package.json @@ -3133,6 +3131,17 @@ Next, run the following command to install the Ethers.js library: npm install ethers ``` +Add the Solidity compiler so you can generate standard EVM bytecode: + +```bash +npm install --save-dev solc +``` + +This guide uses `solc` version `0.8.33`. + +!!! tip + The sample scripts use ECMAScript modules. Add `"type": "module"` to your `package.json` (or rename the files to `.mjs`) so that `node` can run the `import` statements. + ## Set Up the Ethers.js Provider A [`Provider`](https://docs.ethers.org/v6/api/providers/#Provider){target=\_blank} is an abstraction of a connection to the Ethereum network, allowing you to query blockchain data and send transactions. It serves as a bridge between your application and the blockchain. @@ -3175,7 +3184,7 @@ createProvider(PROVIDER_RPC.rpc, PROVIDER_RPC.chainId, PROVIDER_RPC.name); To connect to the provider, execute: ```bash -node connectToProvider +node scripts/connectToProvider.js ``` With the provider set up, you can start querying the blockchain. For instance, to fetch the latest block number: @@ -3220,22 +3229,7 @@ With the provider set up, you can start querying the blockchain. For instance, t ## Compile Contracts -!!! note "Contracts Code Blob Size Disclaimer" - The maximum contract code blob size on Polkadot Hub networks is _100 kilobytes_, significantly larger than Ethereum’s EVM limit of 24 kilobytes. - - For detailed comparisons and migration guidelines, see the [EVM vs. PolkaVM](/polkadot-protocol/smart-contract-basics/evm-vs-polkavm/#current-memory-limits){target=\_blank} documentation page. - -The `revive` compiler transforms Solidity smart contracts into [PolkaVM](/smart-contracts/overview/#native-smart-contracts){target=\_blank} bytecode for deployment on Polkadot Hub. Revive's Ethereum RPC interface allows you to use familiar tools like Ethers.js and MetaMask to interact with contracts. - -### Install the Revive Library - -The [`@parity/resolc`](https://www.npmjs.com/package/@parity/resolc){target=\_blank} library will compile your Solidity code for deployment on Polkadot Hub. Run the following command in your terminal to install the library: - -```bash -npm install --save-dev @parity/resolc -``` - -This guide uses `@parity/resolc` version `0.2.0`. +Polkadot Hub exposes an Ethereum JSON-RPC endpoint, so you can compile Solidity contracts to familiar EVM bytecode with the upstream [`solc`](https://www.npmjs.com/package/solc){target=\_blank} compiler. The resulting artifacts work with any EVM-compatible toolchain and can be deployed through Ethers.js. ### Sample Storage Smart Contract @@ -3270,40 +3264,74 @@ contract Storage { To compile this contract, use the following script: ```js title="scripts/compile.js" -const { compile } = require('@parity/resolc'); -const { readFileSync, writeFileSync } = require('fs'); +const solc = require('solc'); +const { readFileSync, writeFileSync, mkdirSync, existsSync } = require('fs'); const { basename, join } = require('path'); -const compileContract = async (solidityFilePath, outputDir) => { +const ensureDir = (dirPath) => { + if (!existsSync(dirPath)) { + mkdirSync(dirPath, { recursive: true }); + } +}; + +const compileContract = (solidityFilePath, abiDir, artifactsDir) => { try { // Read the Solidity file const source = readFileSync(solidityFilePath, 'utf8'); - - // Construct the input object for the compiler + const fileName = basename(solidityFilePath); + + // Construct the input object for the Solidity compiler const input = { - [basename(solidityFilePath)]: { content: source }, + language: 'Solidity', + sources: { + [fileName]: { + content: source, + }, + }, + settings: { + outputSelection: { + '*': { + '*': ['abi', 'evm.bytecode'], + }, + }, + }, }; - - console.log(`Compiling contract: ${basename(solidityFilePath)}...`); - + + console.log(`Compiling contract: ${fileName}...`); + // Compile the contract - const out = await compile(input); - - for (const contracts of Object.values(out.contracts)) { - for (const [name, contract] of Object.entries(contracts)) { - console.log(`Compiled contract: ${name}`); - + const output = JSON.parse(solc.compile(JSON.stringify(input))); + + // Check for errors + if (output.errors) { + const errors = output.errors.filter(error => error.severity === 'error'); + if (errors.length > 0) { + console.error('Compilation errors:'); + errors.forEach(err => console.error(err.formattedMessage)); + return; + } + // Show warnings + const warnings = output.errors.filter(error => error.severity === 'warning'); + warnings.forEach(warn => console.warn(warn.formattedMessage)); + } + + // Ensure output directories exist + ensureDir(abiDir); + ensureDir(artifactsDir); + + // Process compiled contracts + for (const [sourceFile, contracts] of Object.entries(output.contracts)) { + for (const [contractName, contract] of Object.entries(contracts)) { + console.log(`Compiled contract: ${contractName}`); + // Write the ABI - const abiPath = join(outputDir, `${name}.json`); + const abiPath = join(abiDir, `${contractName}.json`); writeFileSync(abiPath, JSON.stringify(contract.abi, null, 2)); console.log(`ABI saved to ${abiPath}`); - + // Write the bytecode - const bytecodePath = join(outputDir, `${name}.polkavm`); - writeFileSync( - bytecodePath, - Buffer.from(contract.evm.bytecode.object, 'hex'), - ); + const bytecodePath = join(artifactsDir, `${contractName}.bin`); + writeFileSync(bytecodePath, contract.evm.bytecode.object); console.log(`Bytecode saved to ${bytecodePath}`); } } @@ -3313,10 +3341,10 @@ const compileContract = async (solidityFilePath, outputDir) => { }; const solidityFilePath = join(__dirname, '../contracts/Storage.sol'); -const outputDir = join(__dirname, '../contracts'); - -compileContract(solidityFilePath, outputDir); +const abiDir = join(__dirname, '../abis'); +const artifactsDir = join(__dirname, '../artifacts'); +compileContract(solidityFilePath, abiDir, artifactsDir); ``` !!! note @@ -3327,10 +3355,10 @@ The ABI (Application Binary Interface) is a JSON representation of your contract Execute the script above by running: ```bash -node compile +node scripts/compile.js ``` -After executing the script, the Solidity contract will be compiled into the required PolkaVM bytecode format. The ABI and bytecode will be saved into files with `.json` and `.polkavm` extensions, respectively. You can now proceed with deploying the contract to Polkadot Hub, as outlined in the next section. +After executing the script, the Solidity contract is compiled into standard EVM bytecode. The ABI and bytecode are saved into files with `.json` and `.bin` extensions, respectively. You can now proceed with deploying the contract to Polkadot Hub, as outlined in the next section. ## Deploy the Compiled Contract @@ -3341,19 +3369,17 @@ You can create a `deploy.js` script in the root of your project to achieve this. 1. Set up the required imports and utilities: ```js title="scripts/deploy.js" - // Deploy an EVM-compatible smart contract using ethers.js const { writeFileSync, existsSync, readFileSync } = require('fs'); const { join } = require('path'); const { ethers, JsonRpcProvider } = require('ethers'); - const codegenDir = join(__dirname); ``` 2. Create a provider to connect to Polkadot Hub: ```js title="scripts/deploy.js" - // Creates an Ethereum provider with specified RPC URL and chain details + // Creates a provider with specified RPC URL and chain details const createProvider = (rpcUrl, chainId, chainName) => { const provider = new JsonRpcProvider(rpcUrl, { chainId: chainId, @@ -3369,9 +3395,8 @@ You can create a `deploy.js` script in the root of your project to achieve this. // Reads and parses the ABI file for a given contract const getAbi = (contractName) => { try { - return JSON.parse( - readFileSync(join(codegenDir, `${contractName}.json`), 'utf8'), - ); + const abiPath = join(artifactsDir, `${contractName}.json`); + return JSON.parse(readFileSync(abiPath, 'utf8')); } catch (error) { console.error( `Could not find ABI for contract ${contractName}:`, @@ -3384,12 +3409,10 @@ You can create a `deploy.js` script in the root of your project to achieve this. // Reads the compiled bytecode for a given contract const getByteCode = (contractName) => { try { - const bytecodePath = join( - codegenDir, - '../contracts', - `${contractName}.polkavm`, - ); - return `0x${readFileSync(bytecodePath).toString('hex')}`; + const bytecodePath = join(artifactsDir, `${contractName}.bin`); + const bytecode = readFileSync(bytecodePath, 'utf8').trim(); + // Add 0x prefix if not present + return bytecode.startsWith('0x') ? bytecode : `0x${bytecode}`; } catch (error) { console.error( `Could not find bytecode for contract ${contractName}:`, @@ -3398,15 +3421,14 @@ You can create a `deploy.js` script in the root of your project to achieve this. throw error; } }; + ``` 4. Create the main deployment function: ```js title="scripts/deploy.js" - const deployContract = async (contractName, mnemonic, providerConfig) => { console.log(`Deploying ${contractName}...`); - try { // Step 1: Set up provider and wallet const provider = createProvider( @@ -3430,10 +3452,11 @@ You can create a `deploy.js` script in the root of your project to achieve this. const address = await contract.getAddress(); console.log(`Contract ${contractName} deployed at: ${address}`); - const addressesFile = join(codegenDir, 'contract-address.json'); + const addressesFile = join(scriptsDir, 'contract-address.json'); const addresses = existsSync(addressesFile) ? JSON.parse(readFileSync(addressesFile, 'utf8')) : {}; + addresses[contractName] = address; writeFileSync(addressesFile, JSON.stringify(addresses, null, 2), 'utf8'); } catch (error) { @@ -3445,15 +3468,7 @@ You can create a `deploy.js` script in the root of your project to achieve this. 5. Configure and execute the deployment: ```js title="scripts/deploy.js" - const providerConfig = { - rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', - chainId: 420420422, - name: 'polkadot-hub-testnet', - }; - - const mnemonic = 'INSERT_MNEMONIC'; - - deployContract('Storage', mnemonic, providerConfig); + ``` !!! note @@ -3464,14 +3479,14 @@ You can create a `deploy.js` script in the root of your project to achieve this. ??? code "View complete script" ```js title="scripts/deploy.js" - // Deploy an EVM-compatible smart contract using ethers.js const { writeFileSync, existsSync, readFileSync } = require('fs'); const { join } = require('path'); const { ethers, JsonRpcProvider } = require('ethers'); - const codegenDir = join(__dirname); + const scriptsDir = __dirname; + const artifactsDir = join(__dirname, '../contracts'); - // Creates an Ethereum provider with specified RPC URL and chain details + // Creates a provider with specified RPC URL and chain details const createProvider = (rpcUrl, chainId, chainName) => { const provider = new JsonRpcProvider(rpcUrl, { chainId: chainId, @@ -3483,9 +3498,8 @@ You can create a `deploy.js` script in the root of your project to achieve this. // Reads and parses the ABI file for a given contract const getAbi = (contractName) => { try { - return JSON.parse( - readFileSync(join(codegenDir, `${contractName}.json`), 'utf8'), - ); + const abiPath = join(artifactsDir, `${contractName}.json`); + return JSON.parse(readFileSync(abiPath, 'utf8')); } catch (error) { console.error( `Could not find ABI for contract ${contractName}:`, @@ -3498,12 +3512,10 @@ You can create a `deploy.js` script in the root of your project to achieve this. // Reads the compiled bytecode for a given contract const getByteCode = (contractName) => { try { - const bytecodePath = join( - codegenDir, - '../contracts', - `${contractName}.polkavm`, - ); - return `0x${readFileSync(bytecodePath).toString('hex')}`; + const bytecodePath = join(artifactsDir, `${contractName}.bin`); + const bytecode = readFileSync(bytecodePath, 'utf8').trim(); + // Add 0x prefix if not present + return bytecode.startsWith('0x') ? bytecode : `0x${bytecode}`; } catch (error) { console.error( `Could not find bytecode for contract ${contractName}:`, @@ -3515,7 +3527,6 @@ You can create a `deploy.js` script in the root of your project to achieve this. const deployContract = async (contractName, mnemonic, providerConfig) => { console.log(`Deploying ${contractName}...`); - try { // Step 1: Set up provider and wallet const provider = createProvider( @@ -3539,10 +3550,11 @@ You can create a `deploy.js` script in the root of your project to achieve this. const address = await contract.getAddress(); console.log(`Contract ${contractName} deployed at: ${address}`); - const addressesFile = join(codegenDir, 'contract-address.json'); + const addressesFile = join(scriptsDir, 'contract-address.json'); const addresses = existsSync(addressesFile) ? JSON.parse(readFileSync(addressesFile, 'utf8')) : {}; + addresses[contractName] = address; writeFileSync(addressesFile, JSON.stringify(addresses, null, 2), 'utf8'); } catch (error) { @@ -3551,21 +3563,20 @@ You can create a `deploy.js` script in the root of your project to achieve this. }; const providerConfig = { - rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', + rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', #TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready chainId: 420420422, name: 'polkadot-hub-testnet', }; - const mnemonic = 'INSERT_MNEMONIC'; + const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon'; deployContract('Storage', mnemonic, providerConfig); - ``` To run the script, execute the following command: ```bash -node deploy +node scripts/deploy.js ``` After running this script, your contract will be deployed to Polkadot Hub, and its address will be saved in `contract-address.json` within your project directory. You can use this address for future contract interactions. @@ -3579,6 +3590,8 @@ const { ethers } = require('ethers'); const { readFileSync } = require('fs'); const { join } = require('path'); +const artifactsDir = join(__dirname, '../contracts'); + const createProvider = (providerConfig) => { return new ethers.JsonRpcProvider(providerConfig.rpc, { chainId: providerConfig.chainId, @@ -3590,7 +3603,7 @@ const createWallet = (mnemonic, provider) => { return ethers.Wallet.fromPhrase(mnemonic).connect(provider); }; -const loadContractAbi = (contractName, directory = __dirname) => { +const loadContractAbi = (contractName, directory = artifactsDir) => { const contractPath = join(directory, `${contractName}.json`); const contractJson = JSON.parse(readFileSync(contractPath, 'utf8')); return contractJson.abi || contractJson; // Depending on JSON structure @@ -3646,9 +3659,9 @@ const providerConfig = { chainId: 420420422, }; -const mnemonic = 'INSERT_MNEMONIC'; +const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon'; const contractName = 'Storage'; -const contractAddress = 'INSERT_CONTRACT_ADDRESS'; +const contractAddress = '0x83e43892a98f924706E9DB7917244897dC8b8126'; const newNumber = 42; interactWithStorageContract( @@ -3658,15 +3671,14 @@ interactWithStorageContract( providerConfig, newNumber, ); - ``` -Ensure you replace the `INSERT_MNEMONIC`, `INSERT_CONTRACT_ADDRESS`, and `INSERT_ADDRESS_TO_CHECK` placeholders with actual values. Also, ensure the contract ABI file (`Storage.json`) is correctly referenced. +Ensure you replace the `INSERT_MNEMONIC`, `INSERT_CONTRACT_ADDRESS`, and `INSERT_ADDRESS_TO_CHECK` placeholders with actual values. Also, ensure the contract ABI file (`Storage.json`) is correctly referenced. The script prints the balance for `ADDRESS_TO_CHECK` before it writes and doubles the stored value, so pick any account you want to monitor. To interact with the contract, run: ```bash -node checkStorage +node scripts/checkStorage.js ``` ## Where to Go Next diff --git a/.ai/categories/tooling.md b/.ai/categories/tooling.md index d5f748831..5f743028f 100644 --- a/.ai/categories/tooling.md +++ b/.ai/categories/tooling.md @@ -2372,8 +2372,6 @@ Page Title: Deploy Contracts to Polkadot Hub with Ethers.js # Ethers.js -!!! smartcontract "PolkaVM Preview Release" - PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. ## Introduction [Ethers.js](https://docs.ethers.org/v6/){target=\_blank} is a lightweight library that enables interaction with Ethereum Virtual Machine (EVM)-compatible blockchains through JavaScript. Ethers is widely used as a toolkit to establish connections and read and write blockchain data. This article demonstrates using Ethers.js to interact and deploy smart contracts to Polkadot Hub. @@ -2405,7 +2403,7 @@ ethers-project ├── abis │ ├── Storage.json ├── artifacts -│ ├── Storage.polkavm +│ ├── Storage.bin ├── contract-address.json ├── node_modules/ ├── package.json @@ -2431,6 +2429,17 @@ Next, run the following command to install the Ethers.js library: npm install ethers ``` +Add the Solidity compiler so you can generate standard EVM bytecode: + +```bash +npm install --save-dev solc +``` + +This guide uses `solc` version `0.8.33`. + +!!! tip + The sample scripts use ECMAScript modules. Add `"type": "module"` to your `package.json` (or rename the files to `.mjs`) so that `node` can run the `import` statements. + ## Set Up the Ethers.js Provider A [`Provider`](https://docs.ethers.org/v6/api/providers/#Provider){target=\_blank} is an abstraction of a connection to the Ethereum network, allowing you to query blockchain data and send transactions. It serves as a bridge between your application and the blockchain. @@ -2473,7 +2482,7 @@ createProvider(PROVIDER_RPC.rpc, PROVIDER_RPC.chainId, PROVIDER_RPC.name); To connect to the provider, execute: ```bash -node connectToProvider +node scripts/connectToProvider.js ``` With the provider set up, you can start querying the blockchain. For instance, to fetch the latest block number: @@ -2518,22 +2527,7 @@ With the provider set up, you can start querying the blockchain. For instance, t ## Compile Contracts -!!! note "Contracts Code Blob Size Disclaimer" - The maximum contract code blob size on Polkadot Hub networks is _100 kilobytes_, significantly larger than Ethereum’s EVM limit of 24 kilobytes. - - For detailed comparisons and migration guidelines, see the [EVM vs. PolkaVM](/polkadot-protocol/smart-contract-basics/evm-vs-polkavm/#current-memory-limits){target=\_blank} documentation page. - -The `revive` compiler transforms Solidity smart contracts into [PolkaVM](/smart-contracts/overview/#native-smart-contracts){target=\_blank} bytecode for deployment on Polkadot Hub. Revive's Ethereum RPC interface allows you to use familiar tools like Ethers.js and MetaMask to interact with contracts. - -### Install the Revive Library - -The [`@parity/resolc`](https://www.npmjs.com/package/@parity/resolc){target=\_blank} library will compile your Solidity code for deployment on Polkadot Hub. Run the following command in your terminal to install the library: - -```bash -npm install --save-dev @parity/resolc -``` - -This guide uses `@parity/resolc` version `0.2.0`. +Polkadot Hub exposes an Ethereum JSON-RPC endpoint, so you can compile Solidity contracts to familiar EVM bytecode with the upstream [`solc`](https://www.npmjs.com/package/solc){target=\_blank} compiler. The resulting artifacts work with any EVM-compatible toolchain and can be deployed through Ethers.js. ### Sample Storage Smart Contract @@ -2568,40 +2562,74 @@ contract Storage { To compile this contract, use the following script: ```js title="scripts/compile.js" -const { compile } = require('@parity/resolc'); -const { readFileSync, writeFileSync } = require('fs'); +const solc = require('solc'); +const { readFileSync, writeFileSync, mkdirSync, existsSync } = require('fs'); const { basename, join } = require('path'); -const compileContract = async (solidityFilePath, outputDir) => { +const ensureDir = (dirPath) => { + if (!existsSync(dirPath)) { + mkdirSync(dirPath, { recursive: true }); + } +}; + +const compileContract = (solidityFilePath, abiDir, artifactsDir) => { try { // Read the Solidity file const source = readFileSync(solidityFilePath, 'utf8'); - - // Construct the input object for the compiler + const fileName = basename(solidityFilePath); + + // Construct the input object for the Solidity compiler const input = { - [basename(solidityFilePath)]: { content: source }, + language: 'Solidity', + sources: { + [fileName]: { + content: source, + }, + }, + settings: { + outputSelection: { + '*': { + '*': ['abi', 'evm.bytecode'], + }, + }, + }, }; - - console.log(`Compiling contract: ${basename(solidityFilePath)}...`); - + + console.log(`Compiling contract: ${fileName}...`); + // Compile the contract - const out = await compile(input); - - for (const contracts of Object.values(out.contracts)) { - for (const [name, contract] of Object.entries(contracts)) { - console.log(`Compiled contract: ${name}`); - + const output = JSON.parse(solc.compile(JSON.stringify(input))); + + // Check for errors + if (output.errors) { + const errors = output.errors.filter(error => error.severity === 'error'); + if (errors.length > 0) { + console.error('Compilation errors:'); + errors.forEach(err => console.error(err.formattedMessage)); + return; + } + // Show warnings + const warnings = output.errors.filter(error => error.severity === 'warning'); + warnings.forEach(warn => console.warn(warn.formattedMessage)); + } + + // Ensure output directories exist + ensureDir(abiDir); + ensureDir(artifactsDir); + + // Process compiled contracts + for (const [sourceFile, contracts] of Object.entries(output.contracts)) { + for (const [contractName, contract] of Object.entries(contracts)) { + console.log(`Compiled contract: ${contractName}`); + // Write the ABI - const abiPath = join(outputDir, `${name}.json`); + const abiPath = join(abiDir, `${contractName}.json`); writeFileSync(abiPath, JSON.stringify(contract.abi, null, 2)); console.log(`ABI saved to ${abiPath}`); - + // Write the bytecode - const bytecodePath = join(outputDir, `${name}.polkavm`); - writeFileSync( - bytecodePath, - Buffer.from(contract.evm.bytecode.object, 'hex'), - ); + const bytecodePath = join(artifactsDir, `${contractName}.bin`); + writeFileSync(bytecodePath, contract.evm.bytecode.object); console.log(`Bytecode saved to ${bytecodePath}`); } } @@ -2611,10 +2639,10 @@ const compileContract = async (solidityFilePath, outputDir) => { }; const solidityFilePath = join(__dirname, '../contracts/Storage.sol'); -const outputDir = join(__dirname, '../contracts'); - -compileContract(solidityFilePath, outputDir); +const abiDir = join(__dirname, '../abis'); +const artifactsDir = join(__dirname, '../artifacts'); +compileContract(solidityFilePath, abiDir, artifactsDir); ``` !!! note @@ -2625,10 +2653,10 @@ The ABI (Application Binary Interface) is a JSON representation of your contract Execute the script above by running: ```bash -node compile +node scripts/compile.js ``` -After executing the script, the Solidity contract will be compiled into the required PolkaVM bytecode format. The ABI and bytecode will be saved into files with `.json` and `.polkavm` extensions, respectively. You can now proceed with deploying the contract to Polkadot Hub, as outlined in the next section. +After executing the script, the Solidity contract is compiled into standard EVM bytecode. The ABI and bytecode are saved into files with `.json` and `.bin` extensions, respectively. You can now proceed with deploying the contract to Polkadot Hub, as outlined in the next section. ## Deploy the Compiled Contract @@ -2639,19 +2667,17 @@ You can create a `deploy.js` script in the root of your project to achieve this. 1. Set up the required imports and utilities: ```js title="scripts/deploy.js" - // Deploy an EVM-compatible smart contract using ethers.js const { writeFileSync, existsSync, readFileSync } = require('fs'); const { join } = require('path'); const { ethers, JsonRpcProvider } = require('ethers'); - const codegenDir = join(__dirname); ``` 2. Create a provider to connect to Polkadot Hub: ```js title="scripts/deploy.js" - // Creates an Ethereum provider with specified RPC URL and chain details + // Creates a provider with specified RPC URL and chain details const createProvider = (rpcUrl, chainId, chainName) => { const provider = new JsonRpcProvider(rpcUrl, { chainId: chainId, @@ -2667,9 +2693,8 @@ You can create a `deploy.js` script in the root of your project to achieve this. // Reads and parses the ABI file for a given contract const getAbi = (contractName) => { try { - return JSON.parse( - readFileSync(join(codegenDir, `${contractName}.json`), 'utf8'), - ); + const abiPath = join(artifactsDir, `${contractName}.json`); + return JSON.parse(readFileSync(abiPath, 'utf8')); } catch (error) { console.error( `Could not find ABI for contract ${contractName}:`, @@ -2682,12 +2707,10 @@ You can create a `deploy.js` script in the root of your project to achieve this. // Reads the compiled bytecode for a given contract const getByteCode = (contractName) => { try { - const bytecodePath = join( - codegenDir, - '../contracts', - `${contractName}.polkavm`, - ); - return `0x${readFileSync(bytecodePath).toString('hex')}`; + const bytecodePath = join(artifactsDir, `${contractName}.bin`); + const bytecode = readFileSync(bytecodePath, 'utf8').trim(); + // Add 0x prefix if not present + return bytecode.startsWith('0x') ? bytecode : `0x${bytecode}`; } catch (error) { console.error( `Could not find bytecode for contract ${contractName}:`, @@ -2696,15 +2719,14 @@ You can create a `deploy.js` script in the root of your project to achieve this. throw error; } }; + ``` 4. Create the main deployment function: ```js title="scripts/deploy.js" - const deployContract = async (contractName, mnemonic, providerConfig) => { console.log(`Deploying ${contractName}...`); - try { // Step 1: Set up provider and wallet const provider = createProvider( @@ -2728,10 +2750,11 @@ You can create a `deploy.js` script in the root of your project to achieve this. const address = await contract.getAddress(); console.log(`Contract ${contractName} deployed at: ${address}`); - const addressesFile = join(codegenDir, 'contract-address.json'); + const addressesFile = join(scriptsDir, 'contract-address.json'); const addresses = existsSync(addressesFile) ? JSON.parse(readFileSync(addressesFile, 'utf8')) : {}; + addresses[contractName] = address; writeFileSync(addressesFile, JSON.stringify(addresses, null, 2), 'utf8'); } catch (error) { @@ -2743,15 +2766,7 @@ You can create a `deploy.js` script in the root of your project to achieve this. 5. Configure and execute the deployment: ```js title="scripts/deploy.js" - const providerConfig = { - rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', - chainId: 420420422, - name: 'polkadot-hub-testnet', - }; - - const mnemonic = 'INSERT_MNEMONIC'; - - deployContract('Storage', mnemonic, providerConfig); + ``` !!! note @@ -2762,14 +2777,14 @@ You can create a `deploy.js` script in the root of your project to achieve this. ??? code "View complete script" ```js title="scripts/deploy.js" - // Deploy an EVM-compatible smart contract using ethers.js const { writeFileSync, existsSync, readFileSync } = require('fs'); const { join } = require('path'); const { ethers, JsonRpcProvider } = require('ethers'); - const codegenDir = join(__dirname); + const scriptsDir = __dirname; + const artifactsDir = join(__dirname, '../contracts'); - // Creates an Ethereum provider with specified RPC URL and chain details + // Creates a provider with specified RPC URL and chain details const createProvider = (rpcUrl, chainId, chainName) => { const provider = new JsonRpcProvider(rpcUrl, { chainId: chainId, @@ -2781,9 +2796,8 @@ You can create a `deploy.js` script in the root of your project to achieve this. // Reads and parses the ABI file for a given contract const getAbi = (contractName) => { try { - return JSON.parse( - readFileSync(join(codegenDir, `${contractName}.json`), 'utf8'), - ); + const abiPath = join(artifactsDir, `${contractName}.json`); + return JSON.parse(readFileSync(abiPath, 'utf8')); } catch (error) { console.error( `Could not find ABI for contract ${contractName}:`, @@ -2796,12 +2810,10 @@ You can create a `deploy.js` script in the root of your project to achieve this. // Reads the compiled bytecode for a given contract const getByteCode = (contractName) => { try { - const bytecodePath = join( - codegenDir, - '../contracts', - `${contractName}.polkavm`, - ); - return `0x${readFileSync(bytecodePath).toString('hex')}`; + const bytecodePath = join(artifactsDir, `${contractName}.bin`); + const bytecode = readFileSync(bytecodePath, 'utf8').trim(); + // Add 0x prefix if not present + return bytecode.startsWith('0x') ? bytecode : `0x${bytecode}`; } catch (error) { console.error( `Could not find bytecode for contract ${contractName}:`, @@ -2813,7 +2825,6 @@ You can create a `deploy.js` script in the root of your project to achieve this. const deployContract = async (contractName, mnemonic, providerConfig) => { console.log(`Deploying ${contractName}...`); - try { // Step 1: Set up provider and wallet const provider = createProvider( @@ -2837,10 +2848,11 @@ You can create a `deploy.js` script in the root of your project to achieve this. const address = await contract.getAddress(); console.log(`Contract ${contractName} deployed at: ${address}`); - const addressesFile = join(codegenDir, 'contract-address.json'); + const addressesFile = join(scriptsDir, 'contract-address.json'); const addresses = existsSync(addressesFile) ? JSON.parse(readFileSync(addressesFile, 'utf8')) : {}; + addresses[contractName] = address; writeFileSync(addressesFile, JSON.stringify(addresses, null, 2), 'utf8'); } catch (error) { @@ -2849,21 +2861,20 @@ You can create a `deploy.js` script in the root of your project to achieve this. }; const providerConfig = { - rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', + rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', #TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready chainId: 420420422, name: 'polkadot-hub-testnet', }; - const mnemonic = 'INSERT_MNEMONIC'; + const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon'; deployContract('Storage', mnemonic, providerConfig); - ``` To run the script, execute the following command: ```bash -node deploy +node scripts/deploy.js ``` After running this script, your contract will be deployed to Polkadot Hub, and its address will be saved in `contract-address.json` within your project directory. You can use this address for future contract interactions. @@ -2877,6 +2888,8 @@ const { ethers } = require('ethers'); const { readFileSync } = require('fs'); const { join } = require('path'); +const artifactsDir = join(__dirname, '../contracts'); + const createProvider = (providerConfig) => { return new ethers.JsonRpcProvider(providerConfig.rpc, { chainId: providerConfig.chainId, @@ -2888,7 +2901,7 @@ const createWallet = (mnemonic, provider) => { return ethers.Wallet.fromPhrase(mnemonic).connect(provider); }; -const loadContractAbi = (contractName, directory = __dirname) => { +const loadContractAbi = (contractName, directory = artifactsDir) => { const contractPath = join(directory, `${contractName}.json`); const contractJson = JSON.parse(readFileSync(contractPath, 'utf8')); return contractJson.abi || contractJson; // Depending on JSON structure @@ -2944,9 +2957,9 @@ const providerConfig = { chainId: 420420422, }; -const mnemonic = 'INSERT_MNEMONIC'; +const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon'; const contractName = 'Storage'; -const contractAddress = 'INSERT_CONTRACT_ADDRESS'; +const contractAddress = '0x83e43892a98f924706E9DB7917244897dC8b8126'; const newNumber = 42; interactWithStorageContract( @@ -2956,15 +2969,14 @@ interactWithStorageContract( providerConfig, newNumber, ); - ``` -Ensure you replace the `INSERT_MNEMONIC`, `INSERT_CONTRACT_ADDRESS`, and `INSERT_ADDRESS_TO_CHECK` placeholders with actual values. Also, ensure the contract ABI file (`Storage.json`) is correctly referenced. +Ensure you replace the `INSERT_MNEMONIC`, `INSERT_CONTRACT_ADDRESS`, and `INSERT_ADDRESS_TO_CHECK` placeholders with actual values. Also, ensure the contract ABI file (`Storage.json`) is correctly referenced. The script prints the balance for `ADDRESS_TO_CHECK` before it writes and doubles the stored value, so pick any account you want to monitor. To interact with the contract, run: ```bash -node checkStorage +node scripts/checkStorage.js ``` ## Where to Go Next diff --git a/.ai/pages/smart-contracts-libraries-ethers-js.md b/.ai/pages/smart-contracts-libraries-ethers-js.md index 5983b83be..b09d29c2c 100644 --- a/.ai/pages/smart-contracts-libraries-ethers-js.md +++ b/.ai/pages/smart-contracts-libraries-ethers-js.md @@ -7,8 +7,6 @@ url: https://docs.polkadot.com/smart-contracts/libraries/ethers-js/ # Ethers.js -!!! smartcontract "PolkaVM Preview Release" - PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. ## Introduction [Ethers.js](https://docs.ethers.org/v6/){target=\_blank} is a lightweight library that enables interaction with Ethereum Virtual Machine (EVM)-compatible blockchains through JavaScript. Ethers is widely used as a toolkit to establish connections and read and write blockchain data. This article demonstrates using Ethers.js to interact and deploy smart contracts to Polkadot Hub. @@ -40,7 +38,7 @@ ethers-project ├── abis │ ├── Storage.json ├── artifacts -│ ├── Storage.polkavm +│ ├── Storage.bin ├── contract-address.json ├── node_modules/ ├── package.json @@ -66,6 +64,17 @@ Next, run the following command to install the Ethers.js library: npm install ethers ``` +Add the Solidity compiler so you can generate standard EVM bytecode: + +```bash +npm install --save-dev solc +``` + +This guide uses `solc` version `0.8.33`. + +!!! tip + The sample scripts use ECMAScript modules. Add `"type": "module"` to your `package.json` (or rename the files to `.mjs`) so that `node` can run the `import` statements. + ## Set Up the Ethers.js Provider A [`Provider`](https://docs.ethers.org/v6/api/providers/#Provider){target=\_blank} is an abstraction of a connection to the Ethereum network, allowing you to query blockchain data and send transactions. It serves as a bridge between your application and the blockchain. @@ -108,7 +117,7 @@ createProvider(PROVIDER_RPC.rpc, PROVIDER_RPC.chainId, PROVIDER_RPC.name); To connect to the provider, execute: ```bash -node connectToProvider +node scripts/connectToProvider.js ``` With the provider set up, you can start querying the blockchain. For instance, to fetch the latest block number: @@ -153,22 +162,7 @@ With the provider set up, you can start querying the blockchain. For instance, t ## Compile Contracts -!!! note "Contracts Code Blob Size Disclaimer" - The maximum contract code blob size on Polkadot Hub networks is _100 kilobytes_, significantly larger than Ethereum’s EVM limit of 24 kilobytes. - - For detailed comparisons and migration guidelines, see the [EVM vs. PolkaVM](/polkadot-protocol/smart-contract-basics/evm-vs-polkavm/#current-memory-limits){target=\_blank} documentation page. - -The `revive` compiler transforms Solidity smart contracts into [PolkaVM](/smart-contracts/overview/#native-smart-contracts){target=\_blank} bytecode for deployment on Polkadot Hub. Revive's Ethereum RPC interface allows you to use familiar tools like Ethers.js and MetaMask to interact with contracts. - -### Install the Revive Library - -The [`@parity/resolc`](https://www.npmjs.com/package/@parity/resolc){target=\_blank} library will compile your Solidity code for deployment on Polkadot Hub. Run the following command in your terminal to install the library: - -```bash -npm install --save-dev @parity/resolc -``` - -This guide uses `@parity/resolc` version `0.2.0`. +Polkadot Hub exposes an Ethereum JSON-RPC endpoint, so you can compile Solidity contracts to familiar EVM bytecode with the upstream [`solc`](https://www.npmjs.com/package/solc){target=\_blank} compiler. The resulting artifacts work with any EVM-compatible toolchain and can be deployed through Ethers.js. ### Sample Storage Smart Contract @@ -203,40 +197,74 @@ contract Storage { To compile this contract, use the following script: ```js title="scripts/compile.js" -const { compile } = require('@parity/resolc'); -const { readFileSync, writeFileSync } = require('fs'); +const solc = require('solc'); +const { readFileSync, writeFileSync, mkdirSync, existsSync } = require('fs'); const { basename, join } = require('path'); -const compileContract = async (solidityFilePath, outputDir) => { +const ensureDir = (dirPath) => { + if (!existsSync(dirPath)) { + mkdirSync(dirPath, { recursive: true }); + } +}; + +const compileContract = (solidityFilePath, abiDir, artifactsDir) => { try { // Read the Solidity file const source = readFileSync(solidityFilePath, 'utf8'); - - // Construct the input object for the compiler + const fileName = basename(solidityFilePath); + + // Construct the input object for the Solidity compiler const input = { - [basename(solidityFilePath)]: { content: source }, + language: 'Solidity', + sources: { + [fileName]: { + content: source, + }, + }, + settings: { + outputSelection: { + '*': { + '*': ['abi', 'evm.bytecode'], + }, + }, + }, }; - - console.log(`Compiling contract: ${basename(solidityFilePath)}...`); - + + console.log(`Compiling contract: ${fileName}...`); + // Compile the contract - const out = await compile(input); - - for (const contracts of Object.values(out.contracts)) { - for (const [name, contract] of Object.entries(contracts)) { - console.log(`Compiled contract: ${name}`); - + const output = JSON.parse(solc.compile(JSON.stringify(input))); + + // Check for errors + if (output.errors) { + const errors = output.errors.filter(error => error.severity === 'error'); + if (errors.length > 0) { + console.error('Compilation errors:'); + errors.forEach(err => console.error(err.formattedMessage)); + return; + } + // Show warnings + const warnings = output.errors.filter(error => error.severity === 'warning'); + warnings.forEach(warn => console.warn(warn.formattedMessage)); + } + + // Ensure output directories exist + ensureDir(abiDir); + ensureDir(artifactsDir); + + // Process compiled contracts + for (const [sourceFile, contracts] of Object.entries(output.contracts)) { + for (const [contractName, contract] of Object.entries(contracts)) { + console.log(`Compiled contract: ${contractName}`); + // Write the ABI - const abiPath = join(outputDir, `${name}.json`); + const abiPath = join(abiDir, `${contractName}.json`); writeFileSync(abiPath, JSON.stringify(contract.abi, null, 2)); console.log(`ABI saved to ${abiPath}`); - + // Write the bytecode - const bytecodePath = join(outputDir, `${name}.polkavm`); - writeFileSync( - bytecodePath, - Buffer.from(contract.evm.bytecode.object, 'hex'), - ); + const bytecodePath = join(artifactsDir, `${contractName}.bin`); + writeFileSync(bytecodePath, contract.evm.bytecode.object); console.log(`Bytecode saved to ${bytecodePath}`); } } @@ -246,10 +274,10 @@ const compileContract = async (solidityFilePath, outputDir) => { }; const solidityFilePath = join(__dirname, '../contracts/Storage.sol'); -const outputDir = join(__dirname, '../contracts'); - -compileContract(solidityFilePath, outputDir); +const abiDir = join(__dirname, '../abis'); +const artifactsDir = join(__dirname, '../artifacts'); +compileContract(solidityFilePath, abiDir, artifactsDir); ``` !!! note @@ -260,10 +288,10 @@ The ABI (Application Binary Interface) is a JSON representation of your contract Execute the script above by running: ```bash -node compile +node scripts/compile.js ``` -After executing the script, the Solidity contract will be compiled into the required PolkaVM bytecode format. The ABI and bytecode will be saved into files with `.json` and `.polkavm` extensions, respectively. You can now proceed with deploying the contract to Polkadot Hub, as outlined in the next section. +After executing the script, the Solidity contract is compiled into standard EVM bytecode. The ABI and bytecode are saved into files with `.json` and `.bin` extensions, respectively. You can now proceed with deploying the contract to Polkadot Hub, as outlined in the next section. ## Deploy the Compiled Contract @@ -274,19 +302,17 @@ You can create a `deploy.js` script in the root of your project to achieve this. 1. Set up the required imports and utilities: ```js title="scripts/deploy.js" - // Deploy an EVM-compatible smart contract using ethers.js const { writeFileSync, existsSync, readFileSync } = require('fs'); const { join } = require('path'); const { ethers, JsonRpcProvider } = require('ethers'); - const codegenDir = join(__dirname); ``` 2. Create a provider to connect to Polkadot Hub: ```js title="scripts/deploy.js" - // Creates an Ethereum provider with specified RPC URL and chain details + // Creates a provider with specified RPC URL and chain details const createProvider = (rpcUrl, chainId, chainName) => { const provider = new JsonRpcProvider(rpcUrl, { chainId: chainId, @@ -302,9 +328,8 @@ You can create a `deploy.js` script in the root of your project to achieve this. // Reads and parses the ABI file for a given contract const getAbi = (contractName) => { try { - return JSON.parse( - readFileSync(join(codegenDir, `${contractName}.json`), 'utf8'), - ); + const abiPath = join(artifactsDir, `${contractName}.json`); + return JSON.parse(readFileSync(abiPath, 'utf8')); } catch (error) { console.error( `Could not find ABI for contract ${contractName}:`, @@ -317,12 +342,10 @@ You can create a `deploy.js` script in the root of your project to achieve this. // Reads the compiled bytecode for a given contract const getByteCode = (contractName) => { try { - const bytecodePath = join( - codegenDir, - '../contracts', - `${contractName}.polkavm`, - ); - return `0x${readFileSync(bytecodePath).toString('hex')}`; + const bytecodePath = join(artifactsDir, `${contractName}.bin`); + const bytecode = readFileSync(bytecodePath, 'utf8').trim(); + // Add 0x prefix if not present + return bytecode.startsWith('0x') ? bytecode : `0x${bytecode}`; } catch (error) { console.error( `Could not find bytecode for contract ${contractName}:`, @@ -331,15 +354,14 @@ You can create a `deploy.js` script in the root of your project to achieve this. throw error; } }; + ``` 4. Create the main deployment function: ```js title="scripts/deploy.js" - const deployContract = async (contractName, mnemonic, providerConfig) => { console.log(`Deploying ${contractName}...`); - try { // Step 1: Set up provider and wallet const provider = createProvider( @@ -363,10 +385,11 @@ You can create a `deploy.js` script in the root of your project to achieve this. const address = await contract.getAddress(); console.log(`Contract ${contractName} deployed at: ${address}`); - const addressesFile = join(codegenDir, 'contract-address.json'); + const addressesFile = join(scriptsDir, 'contract-address.json'); const addresses = existsSync(addressesFile) ? JSON.parse(readFileSync(addressesFile, 'utf8')) : {}; + addresses[contractName] = address; writeFileSync(addressesFile, JSON.stringify(addresses, null, 2), 'utf8'); } catch (error) { @@ -378,15 +401,7 @@ You can create a `deploy.js` script in the root of your project to achieve this. 5. Configure and execute the deployment: ```js title="scripts/deploy.js" - const providerConfig = { - rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', - chainId: 420420422, - name: 'polkadot-hub-testnet', - }; - - const mnemonic = 'INSERT_MNEMONIC'; - - deployContract('Storage', mnemonic, providerConfig); + ``` !!! note @@ -397,14 +412,14 @@ You can create a `deploy.js` script in the root of your project to achieve this. ??? code "View complete script" ```js title="scripts/deploy.js" - // Deploy an EVM-compatible smart contract using ethers.js const { writeFileSync, existsSync, readFileSync } = require('fs'); const { join } = require('path'); const { ethers, JsonRpcProvider } = require('ethers'); - const codegenDir = join(__dirname); + const scriptsDir = __dirname; + const artifactsDir = join(__dirname, '../contracts'); - // Creates an Ethereum provider with specified RPC URL and chain details + // Creates a provider with specified RPC URL and chain details const createProvider = (rpcUrl, chainId, chainName) => { const provider = new JsonRpcProvider(rpcUrl, { chainId: chainId, @@ -416,9 +431,8 @@ You can create a `deploy.js` script in the root of your project to achieve this. // Reads and parses the ABI file for a given contract const getAbi = (contractName) => { try { - return JSON.parse( - readFileSync(join(codegenDir, `${contractName}.json`), 'utf8'), - ); + const abiPath = join(artifactsDir, `${contractName}.json`); + return JSON.parse(readFileSync(abiPath, 'utf8')); } catch (error) { console.error( `Could not find ABI for contract ${contractName}:`, @@ -431,12 +445,10 @@ You can create a `deploy.js` script in the root of your project to achieve this. // Reads the compiled bytecode for a given contract const getByteCode = (contractName) => { try { - const bytecodePath = join( - codegenDir, - '../contracts', - `${contractName}.polkavm`, - ); - return `0x${readFileSync(bytecodePath).toString('hex')}`; + const bytecodePath = join(artifactsDir, `${contractName}.bin`); + const bytecode = readFileSync(bytecodePath, 'utf8').trim(); + // Add 0x prefix if not present + return bytecode.startsWith('0x') ? bytecode : `0x${bytecode}`; } catch (error) { console.error( `Could not find bytecode for contract ${contractName}:`, @@ -448,7 +460,6 @@ You can create a `deploy.js` script in the root of your project to achieve this. const deployContract = async (contractName, mnemonic, providerConfig) => { console.log(`Deploying ${contractName}...`); - try { // Step 1: Set up provider and wallet const provider = createProvider( @@ -472,10 +483,11 @@ You can create a `deploy.js` script in the root of your project to achieve this. const address = await contract.getAddress(); console.log(`Contract ${contractName} deployed at: ${address}`); - const addressesFile = join(codegenDir, 'contract-address.json'); + const addressesFile = join(scriptsDir, 'contract-address.json'); const addresses = existsSync(addressesFile) ? JSON.parse(readFileSync(addressesFile, 'utf8')) : {}; + addresses[contractName] = address; writeFileSync(addressesFile, JSON.stringify(addresses, null, 2), 'utf8'); } catch (error) { @@ -484,21 +496,20 @@ You can create a `deploy.js` script in the root of your project to achieve this. }; const providerConfig = { - rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', + rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', #TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready chainId: 420420422, name: 'polkadot-hub-testnet', }; - const mnemonic = 'INSERT_MNEMONIC'; + const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon'; deployContract('Storage', mnemonic, providerConfig); - ``` To run the script, execute the following command: ```bash -node deploy +node scripts/deploy.js ``` After running this script, your contract will be deployed to Polkadot Hub, and its address will be saved in `contract-address.json` within your project directory. You can use this address for future contract interactions. @@ -512,6 +523,8 @@ const { ethers } = require('ethers'); const { readFileSync } = require('fs'); const { join } = require('path'); +const artifactsDir = join(__dirname, '../contracts'); + const createProvider = (providerConfig) => { return new ethers.JsonRpcProvider(providerConfig.rpc, { chainId: providerConfig.chainId, @@ -523,7 +536,7 @@ const createWallet = (mnemonic, provider) => { return ethers.Wallet.fromPhrase(mnemonic).connect(provider); }; -const loadContractAbi = (contractName, directory = __dirname) => { +const loadContractAbi = (contractName, directory = artifactsDir) => { const contractPath = join(directory, `${contractName}.json`); const contractJson = JSON.parse(readFileSync(contractPath, 'utf8')); return contractJson.abi || contractJson; // Depending on JSON structure @@ -579,9 +592,9 @@ const providerConfig = { chainId: 420420422, }; -const mnemonic = 'INSERT_MNEMONIC'; +const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon'; const contractName = 'Storage'; -const contractAddress = 'INSERT_CONTRACT_ADDRESS'; +const contractAddress = '0x83e43892a98f924706E9DB7917244897dC8b8126'; const newNumber = 42; interactWithStorageContract( @@ -591,15 +604,14 @@ interactWithStorageContract( providerConfig, newNumber, ); - ``` -Ensure you replace the `INSERT_MNEMONIC`, `INSERT_CONTRACT_ADDRESS`, and `INSERT_ADDRESS_TO_CHECK` placeholders with actual values. Also, ensure the contract ABI file (`Storage.json`) is correctly referenced. +Ensure you replace the `INSERT_MNEMONIC`, `INSERT_CONTRACT_ADDRESS`, and `INSERT_ADDRESS_TO_CHECK` placeholders with actual values. Also, ensure the contract ABI file (`Storage.json`) is correctly referenced. The script prints the balance for `ADDRESS_TO_CHECK` before it writes and doubles the stored value, so pick any account you want to monitor. To interact with the contract, run: ```bash -node checkStorage +node scripts/checkStorage.js ``` ## Where to Go Next diff --git a/.ai/pages/text-smart-contracts-code-size.md b/.ai/pages/text-smart-contracts-code-size.md new file mode 100644 index 000000000..191ee473a --- /dev/null +++ b/.ai/pages/text-smart-contracts-code-size.md @@ -0,0 +1,6 @@ +--- +url: https://docs.polkadot.com/text/smart-contracts/code-size/ +--- + +!!! info "Mind the contract size" + Polkadot Hub enforces Ethereum's 24 KiB contract-size limit (EIP-170) for EVM deployments. Keep contracts modular, share logic through libraries, and make use of compiler optimizations so your bytecode stays within the limit. diff --git a/.ai/site-index.json b/.ai/site-index.json index 66fe0f3ff..b75b63f4c 100644 --- a/.ai/site-index.json +++ b/.ai/site-index.json @@ -8477,7 +8477,7 @@ ], "raw_md_url": "https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-libraries-ethers-js.md", "html_url": "https://docs.polkadot.com/smart-contracts/libraries/ethers-js/", - "preview": "!!! smartcontract \"PolkaVM Preview Release\" PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. ## Introduction", + "preview": "[Ethers.js](https://docs.ethers.org/v6/){target=\\_blank} is a lightweight library that enables interaction with Ethereum Virtual Machine (EVM)-compatible blockchains through JavaScript. Ethers is widely used as a toolkit to establish connections and read and write blockchain data. This article demonstrates using Ethers.js to interact and deploy smart contracts to Polkadot Hub.", "outline": [ { "depth": 2, @@ -8514,11 +8514,6 @@ "title": "Compile Contracts", "anchor": "compile-contracts" }, - { - "depth": 3, - "title": "Install the Revive Library", - "anchor": "install-the-revive-library" - }, { "depth": 3, "title": "Sample Storage Smart Contract", @@ -8546,12 +8541,12 @@ } ], "stats": { - "chars": 20457, - "words": 2333, - "headings": 13, - "estimated_token_count_total": 4474 + "chars": 21133, + "words": 2401, + "headings": 12, + "estimated_token_count_total": 4687 }, - "hash": "sha256:c74a28d8d62369591c5734535136508db3d1f7380e486fd214f98d433cafd6e7", + "hash": "sha256:ea39f6aab99e80c378fbf7c48030d274e13c340e23465d40d4cfb33c9f0d0f2f", "token_estimator": "heuristic-v1" }, { @@ -9056,5 +9051,25 @@ }, "hash": "sha256:a40e3f34f70db22bfe39e40d68dc5a53a726ce47cb73b602d8605355c61ffd22", "token_estimator": "heuristic-v1" + }, + { + "id": "text-smart-contracts-code-size", + "title": "text-smart-contracts-code-size", + "slug": "text-smart-contracts-code-size", + "categories": [ + "Uncategorized" + ], + "raw_md_url": "https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/text-smart-contracts-code-size.md", + "html_url": "https://docs.polkadot.com/text/smart-contracts/code-size/", + "preview": "!!! info \"Mind the contract size\" Polkadot Hub enforces Ethereum's 24 KiB contract-size limit (EIP-170) for EVM deployments. Keep contracts modular, share logic through libraries, and make use of compiler optimizations so your bytecode stays within the limit.", + "outline": [], + "stats": { + "chars": 264, + "words": 40, + "headings": 0, + "estimated_token_count_total": 0 + }, + "hash": "sha256:e6c2ffab1e1d9d06f6e209f37e1c829abd6be41fa7c5350d7dcc858745d4e011", + "token_estimator": "heuristic-v1" } ] \ No newline at end of file diff --git a/llms-full.jsonl b/llms-full.jsonl index 643cef3d9..8fb554bcc 100644 --- a/llms-full.jsonl +++ b/llms-full.jsonl @@ -1109,19 +1109,18 @@ {"page_id": "smart-contracts-integrations-wallets", "page_title": "Wallets for Polkadot Hub", "index": 3, "depth": 3, "title": "SubWallet", "anchor": "subwallet", "start_char": 2383, "end_char": 4969, "estimated_token_count": 613, "token_estimator": "heuristic-v1", "text": "### SubWallet\n\n[SubWallet](https://www.subwallet.app/){target=\\_blank} is a popular non-custodial wallet solution for Polkadot and Ethereum ecosystems. It offers seamless integration with Polkadot SDK-based networks while maintaining Ethereum compatibility, making the wallet an ideal choice for users and developers to interact with Polkadot Hub.\n\nSubWallet now fully supports the [Polkadot Hub TestNet](/polkadot-protocol/smart-contract-basics/networks/#test-networks){target=\\_blank} where developers can deploy and interact with Ethereum-compatible, Solidity smart contracts.\n\nYou can easily view and manage your Paseo native token (PAS) using the Ethereum RPC endpoint (Passet Hub EVM) or the Substrate node RPC endpoint (passet-hub).\n\n??? code \"Polkadot Hub TestNet\"\n You can see support here for Polkadot Hub's TestNet. The **Passet Hub EVM** network uses an ETH RPC endpoint, and the **passet-hub** uses a Substrate endpoint.\n The ETH RPC endpoint will let you send transactions that follow an ETH format, while the Substrate endpoint will follow a Substrate transaction format.\n Note the PAS token, which is the native token of the Polkadot Hub TestNet.\n\n ![](/images/smart-contracts/integrations/wallets/subwallet-PAS.webp){: .browser-extension}\n\nTo connect to Polkadot Hub TestNet using SubWallet, follow these steps:\n\n1. Install the [SubWallet browser extension](https://chromewebstore.google.com/detail/subwallet-polkadot-wallet/onhogfjeacnfoofkfgppdlbmlmnplgbn?hl=en){target=\\_blank} and set up your wallet by following the on-screen instructions, or refer to our [step-by-step guide](https://docs.subwallet.app/main/extension-user-guide/getting-started/install-subwallet){target=\\_blank} for assistance.\n\n2. After setting up your wallet, click the List icon at the top left corner of the extension window to open **Settings**.\n\n ![](/images/smart-contracts/integrations/wallets/subwallet-01.webp){: .browser-extension}\n\n3. Scroll down and select **Manage networks**.\n\n ![](/images/smart-contracts/integrations/wallets/subwallet-02.webp){: .browser-extension}\n\n4. In the Manage network screen, either scroll down or type in the search bar to find the networks. Once done, enable the toggle next to the network name.\n\n ![](/images/smart-contracts/integrations/wallets/subwallet-03.webp){: .browser-extension}\n\n You are now ready to use SubWallet to interact with [Polkadot Hub TestNet](/smart-contracts/connect/#networks-details){target=\\_blank} seamlessly!\n\n![](/images/smart-contracts/integrations/wallets/subwallet-04.webp){: .browser-extension}"} {"page_id": "smart-contracts-integrations-wallets", "page_title": "Wallets for Polkadot Hub", "index": 4, "depth": 3, "title": "Talisman", "anchor": "talisman", "start_char": 4969, "end_char": 6716, "estimated_token_count": 431, "token_estimator": "heuristic-v1", "text": "### Talisman\n\n[Talisman](https://talisman.xyz/){target=\\_blank} is a specialized wallet for the Polkadot ecosystem that supports both Substrate and EVM accounts, making it an excellent choice for Polkadot Hub interactions. Talisman offers a more integrated experience for Polkadot-based chains while still providing Ethereum compatibility.\n\nTo use Talisman with Polkadot Hub TestNet:\n\n1. Install the [Talisman extension](https://talisman.xyz/download){target=\\_blank} and set up your wallet by following the on-screen instructions.\n\n2. Once installed, click on the Talisman icon in your browser extensions and click on the **Settings** button.\n\n ![](/images/smart-contracts/integrations/wallets/wallets-5.webp){: .browser-extension}\n\n3. Click the button **All settings**.\n\n ![](/images/smart-contracts/integrations/wallets/wallets-6.webp){: .browser-extension}\n\n4. Go to the **Networks & Tokens** section.\n\n ![](/images/smart-contracts/integrations/wallets/wallets-7.webp)\n\n5. Click the **Manage networks** button.\n\n ![](/images/smart-contracts/integrations/wallets/wallets-8.webp)\n\n6. Click the **+ Add network** button.\n\n ![](/images/smart-contracts/integrations/wallets/wallets-9.webp)\n\n7. Fill in the form with the required parameters and click the **Add network** button.\n\n ![](/images/smart-contracts/integrations/wallets/wallets-10.webp)\n\n8. After that, you can switch to the Polkadot Hub TestNet by clicking on the network icon and selecting **Polkadot Hub TestNet**.\n\n ![](/images/smart-contracts/integrations/wallets/wallets-11.webp)\n\nAfter selecting the network, Talisman will automatically configure the necessary RPC URL and chain ID for you. You can now use Talisman to interact with the Polkadot Hub TestNet."} {"page_id": "smart-contracts-integrations-wallets", "page_title": "Wallets for Polkadot Hub", "index": 5, "depth": 2, "title": "Conclusion", "anchor": "conclusion", "start_char": 6716, "end_char": 7340, "estimated_token_count": 100, "token_estimator": "heuristic-v1", "text": "## Conclusion\n\nChoosing the right wallet for Polkadot Hub interactions depends on your specific requirements and familiarity with different interfaces. MetaMask provides a familiar entry point for developers with Ethereum experience, while Talisman offers deeper integration with Polkadot's unique features and native support for both EVM and Substrate accounts. By properly configuring your wallet connection, you gain access to the full spectrum of Polkadot Hub's capabilities.\n\n!!!info\n Remember to always verify network parameters when connecting to ensure a secure and reliable connection to the Polkadot ecosystem."} -{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 183, "end_char": 709, "estimated_token_count": 105, "token_estimator": "heuristic-v1", "text": "## Introduction\n\n[Ethers.js](https://docs.ethers.org/v6/){target=\\_blank} is a lightweight library that enables interaction with Ethereum Virtual Machine (EVM)-compatible blockchains through JavaScript. Ethers is widely used as a toolkit to establish connections and read and write blockchain data. This article demonstrates using Ethers.js to interact and deploy smart contracts to Polkadot Hub.\n\nThis guide is intended for developers who are familiar with JavaScript and want to interact with Polkadot Hub using Ethers.js."} -{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 1, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 709, "end_char": 1065, "estimated_token_count": 110, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore getting started, ensure you have the following installed:\n\n- **Node.js**: v22.13.1 or later, check the [Node.js installation guide](https://nodejs.org/en/download/current/){target=\\_blank}.\n- **npm**: v6.13.4 or later (comes bundled with Node.js).\n- **Solidity**: This guide uses Solidity `^0.8.9` for smart contract development."} -{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 2, "depth": 2, "title": "Project Structure", "anchor": "project-structure", "start_char": 1065, "end_char": 1577, "estimated_token_count": 144, "token_estimator": "heuristic-v1", "text": "## Project Structure\n\nThis project organizes contracts, scripts, and compiled artifacts for easy development and deployment.\n\n```text title=\"Ethers.js Polkadot Hub\"\nethers-project\n├── contracts\n│ ├── Storage.sol\n├── scripts\n│ ├── connectToProvider.js\n│ ├── fetchLastBlock.js\n│ ├── compile.js\n│ ├── deploy.js\n│ ├── checkStorage.js\n├── abis\n│ ├── Storage.json\n├── artifacts\n│ ├── Storage.polkavm\n├── contract-address.json\n├── node_modules/\n├── package.json\n├── package-lock.json\n└── README.md\n```"} -{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 3, "depth": 2, "title": "Set Up the Project", "anchor": "set-up-the-project", "start_char": 1577, "end_char": 1798, "estimated_token_count": 50, "token_estimator": "heuristic-v1", "text": "## Set Up the Project\n\nTo start working with Ethers.js, create a new folder and initialize your project by running the following commands in your terminal:\n\n```bash\nmkdir ethers-project\ncd ethers-project\nnpm init -y\n```"} -{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 4, "depth": 2, "title": "Install Dependencies", "anchor": "install-dependencies", "start_char": 1798, "end_char": 1922, "estimated_token_count": 28, "token_estimator": "heuristic-v1", "text": "## Install Dependencies\n\nNext, run the following command to install the Ethers.js library:\n\n```bash\nnpm install ethers\n```"} -{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 5, "depth": 2, "title": "Set Up the Ethers.js Provider", "anchor": "set-up-the-ethersjs-provider", "start_char": 1922, "end_char": 4510, "estimated_token_count": 574, "token_estimator": "heuristic-v1", "text": "## Set Up the Ethers.js Provider\n\nA [`Provider`](https://docs.ethers.org/v6/api/providers/#Provider){target=\\_blank} is an abstraction of a connection to the Ethereum network, allowing you to query blockchain data and send transactions. It serves as a bridge between your application and the blockchain.\n\nTo interact with Polkadot Hub, you must set up an Ethers.js provider. This provider connects to a blockchain node, allowing you to query blockchain data and interact with smart contracts. In the root of your project, create a file named `connectToProvider.js` and add the following code:\n\n```js title=\"scripts/connectToProvider.js\"\nconst { JsonRpcProvider } = require('ethers');\n\nconst createProvider = (rpcUrl, chainId, chainName) => {\n const provider = new JsonRpcProvider(rpcUrl, {\n chainId: chainId,\n name: chainName,\n });\n\n return provider;\n};\n\nconst PROVIDER_RPC = {\n rpc: 'INSERT_RPC_URL',\n chainId: 'INSERT_CHAIN_ID',\n name: 'INSERT_CHAIN_NAME',\n};\n\ncreateProvider(PROVIDER_RPC.rpc, PROVIDER_RPC.chainId, PROVIDER_RPC.name);\n\n```\n\n!!! note\n Replace `INSERT_RPC_URL`, `INSERT_CHAIN_ID`, and `INSERT_CHAIN_NAME` with the appropriate values. For example, to connect to Polkadot Hub TestNet's Ethereum RPC instance, you can use the following parameters:\n\n ```js\n const PROVIDER_RPC = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io',\n chainId: 420420422,\n name: 'polkadot-hub-testnet'\n };\n ```\n\nTo connect to the provider, execute:\n\n```bash\nnode connectToProvider\n```\n\nWith the provider set up, you can start querying the blockchain. For instance, to fetch the latest block number:\n\n??? code \"Fetch Last Block code\"\n\n ```js title=\"scripts/fetchLastBlock.js\"\n const { JsonRpcProvider } = require('ethers');\n\n const createProvider = (rpcUrl, chainId, chainName) => {\n const provider = new JsonRpcProvider(rpcUrl, {\n chainId: chainId,\n name: chainName,\n });\n\n return provider;\n };\n\n const PROVIDER_RPC = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io',\n chainId: 420420422,\n name: 'polkadot-hub-testnet',\n };\n\n const main = async () => {\n try {\n const provider = createProvider(\n PROVIDER_RPC.rpc,\n PROVIDER_RPC.chainId,\n PROVIDER_RPC.name,\n );\n const latestBlock = await provider.getBlockNumber();\n console.log(`Latest block: ${latestBlock}`);\n } catch (error) {\n console.error('Error connecting to Polkadot Hub TestNet: ' + error.message);\n }\n };\n\n main();\n\n ```"} -{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 6, "depth": 2, "title": "Compile Contracts", "anchor": "compile-contracts", "start_char": 4510, "end_char": 5230, "estimated_token_count": 154, "token_estimator": "heuristic-v1", "text": "## Compile Contracts\n\n!!! note \"Contracts Code Blob Size Disclaimer\"\n The maximum contract code blob size on Polkadot Hub networks is _100 kilobytes_, significantly larger than Ethereum’s EVM limit of 24 kilobytes.\n\n For detailed comparisons and migration guidelines, see the [EVM vs. PolkaVM](/polkadot-protocol/smart-contract-basics/evm-vs-polkavm/#current-memory-limits){target=\\_blank} documentation page.\n\nThe `revive` compiler transforms Solidity smart contracts into [PolkaVM](/smart-contracts/overview/#native-smart-contracts){target=\\_blank} bytecode for deployment on Polkadot Hub. Revive's Ethereum RPC interface allows you to use familiar tools like Ethers.js and MetaMask to interact with contracts."} -{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 7, "depth": 3, "title": "Install the Revive Library", "anchor": "install-the-revive-library", "start_char": 5230, "end_char": 5590, "estimated_token_count": 100, "token_estimator": "heuristic-v1", "text": "### Install the Revive Library\n\nThe [`@parity/resolc`](https://www.npmjs.com/package/@parity/resolc){target=\\_blank} library will compile your Solidity code for deployment on Polkadot Hub. Run the following command in your terminal to install the library:\n\n```bash\nnpm install --save-dev @parity/resolc \n```\n\nThis guide uses `@parity/resolc` version `0.2.0`."} -{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 8, "depth": 3, "title": "Sample Storage Smart Contract", "anchor": "sample-storage-smart-contract", "start_char": 5590, "end_char": 6415, "estimated_token_count": 171, "token_estimator": "heuristic-v1", "text": "### Sample Storage Smart Contract\n\nThis example demonstrates compiling a `Storage.sol` Solidity contract for deployment to Polkadot Hub. The contract's functionality stores a number and permits users to update it with a new value.\n\n```solidity title=\"contracts/Storage.sol\"\n//SPDX-License-Identifier: MIT\n\n// Solidity files have to start with this pragma.\n// It will be used by the Solidity compiler to validate its version.\npragma solidity ^0.8.9;\n\ncontract Storage {\n // Public state variable to store a number\n uint256 public storedNumber;\n\n /**\n * Updates the stored number.\n *\n * The `public` modifier allows anyone to call this function.\n *\n * @param _newNumber - The new value to store.\n */\n function setNumber(uint256 _newNumber) public {\n storedNumber = _newNumber;\n }\n}\n```"} -{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 9, "depth": 3, "title": "Compile the Smart Contract", "anchor": "compile-the-smart-contract", "start_char": 6415, "end_char": 8904, "estimated_token_count": 567, "token_estimator": "heuristic-v1", "text": "### Compile the Smart Contract\n\nTo compile this contract, use the following script:\n\n```js title=\"scripts/compile.js\"\nconst { compile } = require('@parity/resolc');\nconst { readFileSync, writeFileSync } = require('fs');\nconst { basename, join } = require('path');\n\nconst compileContract = async (solidityFilePath, outputDir) => {\n try {\n // Read the Solidity file\n const source = readFileSync(solidityFilePath, 'utf8');\n\n // Construct the input object for the compiler\n const input = {\n [basename(solidityFilePath)]: { content: source },\n };\n\n console.log(`Compiling contract: ${basename(solidityFilePath)}...`);\n\n // Compile the contract\n const out = await compile(input);\n\n for (const contracts of Object.values(out.contracts)) {\n for (const [name, contract] of Object.entries(contracts)) {\n console.log(`Compiled contract: ${name}`);\n\n // Write the ABI\n const abiPath = join(outputDir, `${name}.json`);\n writeFileSync(abiPath, JSON.stringify(contract.abi, null, 2));\n console.log(`ABI saved to ${abiPath}`);\n\n // Write the bytecode\n const bytecodePath = join(outputDir, `${name}.polkavm`);\n writeFileSync(\n bytecodePath,\n Buffer.from(contract.evm.bytecode.object, 'hex'),\n );\n console.log(`Bytecode saved to ${bytecodePath}`);\n }\n }\n } catch (error) {\n console.error('Error compiling contracts:', error);\n }\n};\n\nconst solidityFilePath = join(__dirname, '../contracts/Storage.sol');\nconst outputDir = join(__dirname, '../contracts');\n\ncompileContract(solidityFilePath, outputDir);\n\n```\n\n!!! note \n The script above is tailored to the `Storage.sol` contract. It can be adjusted for other contracts by changing the file name or modifying the ABI and bytecode paths.\n\nThe ABI (Application Binary Interface) is a JSON representation of your contract's functions, events, and their parameters. It serves as the interface between your JavaScript code and the deployed smart contract, allowing your application to know how to format function calls and interpret returned data.\n\nExecute the script above by running:\n\n```bash\nnode compile\n```\n\nAfter executing the script, the Solidity contract will be compiled into the required PolkaVM bytecode format. The ABI and bytecode will be saved into files with `.json` and `.polkavm` extensions, respectively. You can now proceed with deploying the contract to Polkadot Hub, as outlined in the next section."} -{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 10, "depth": 2, "title": "Deploy the Compiled Contract", "anchor": "deploy-the-compiled-contract", "start_char": 8904, "end_char": 16591, "estimated_token_count": 1604, "token_estimator": "heuristic-v1", "text": "## Deploy the Compiled Contract\n\nTo deploy your compiled contract to Polkadot Hub, you'll need a wallet with a private key to sign the deployment transaction.\n\nYou can create a `deploy.js` script in the root of your project to achieve this. The deployment script can be divided into key components:\n\n1. Set up the required imports and utilities:\n\n ```js title=\"scripts/deploy.js\"\n // Deploy an EVM-compatible smart contract using ethers.js\n const { writeFileSync, existsSync, readFileSync } = require('fs');\n const { join } = require('path');\n const { ethers, JsonRpcProvider } = require('ethers');\n\n const codegenDir = join(__dirname);\n ```\n\n2. Create a provider to connect to Polkadot Hub:\n\n ```js title=\"scripts/deploy.js\"\n\n // Creates an Ethereum provider with specified RPC URL and chain details\n const createProvider = (rpcUrl, chainId, chainName) => {\n const provider = new JsonRpcProvider(rpcUrl, {\n chainId: chainId,\n name: chainName,\n });\n return provider;\n };\n ```\n \n3. Set up functions to read contract artifacts:\n\n ```js title=\"scripts/deploy.js\"\n // Reads and parses the ABI file for a given contract\n const getAbi = (contractName) => {\n try {\n return JSON.parse(\n readFileSync(join(codegenDir, `${contractName}.json`), 'utf8'),\n );\n } catch (error) {\n console.error(\n `Could not find ABI for contract ${contractName}:`,\n error.message,\n );\n throw error;\n }\n };\n\n // Reads the compiled bytecode for a given contract\n const getByteCode = (contractName) => {\n try {\n const bytecodePath = join(\n codegenDir,\n '../contracts',\n `${contractName}.polkavm`,\n );\n return `0x${readFileSync(bytecodePath).toString('hex')}`;\n } catch (error) {\n console.error(\n `Could not find bytecode for contract ${contractName}:`,\n error.message,\n );\n throw error;\n }\n };\n ```\n\n4. Create the main deployment function:\n\n ```js title=\"scripts/deploy.js\"\n\n const deployContract = async (contractName, mnemonic, providerConfig) => {\n console.log(`Deploying ${contractName}...`);\n\n try {\n // Step 1: Set up provider and wallet\n const provider = createProvider(\n providerConfig.rpc,\n providerConfig.chainId,\n providerConfig.name,\n );\n const walletMnemonic = ethers.Wallet.fromPhrase(mnemonic);\n const wallet = walletMnemonic.connect(provider);\n\n // Step 2: Create and deploy the contract\n const factory = new ethers.ContractFactory(\n getAbi(contractName),\n getByteCode(contractName),\n wallet,\n );\n const contract = await factory.deploy();\n await contract.waitForDeployment();\n\n // Step 3: Save deployment information\n const address = await contract.getAddress();\n console.log(`Contract ${contractName} deployed at: ${address}`);\n\n const addressesFile = join(codegenDir, 'contract-address.json');\n const addresses = existsSync(addressesFile)\n ? JSON.parse(readFileSync(addressesFile, 'utf8'))\n : {};\n addresses[contractName] = address;\n writeFileSync(addressesFile, JSON.stringify(addresses, null, 2), 'utf8');\n } catch (error) {\n console.error(`Failed to deploy contract ${contractName}:`, error);\n }\n };\n ```\n\n5. Configure and execute the deployment:\n\n ```js title=\"scripts/deploy.js\"\n const providerConfig = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io',\n chainId: 420420422,\n name: 'polkadot-hub-testnet',\n };\n\n const mnemonic = 'INSERT_MNEMONIC';\n\n deployContract('Storage', mnemonic, providerConfig);\n ```\n\n !!! note\n A mnemonic (seed phrase) is a series of words that can generate multiple private keys and their corresponding addresses. It's used here to derive the wallet that will sign and pay for the deployment transaction. **Always keep your mnemonic secure and never share it publicly**.\n\n Ensure to replace the `INSERT_MNEMONIC` placeholder with your actual mnemonic.\n\n??? code \"View complete script\"\n\n ```js title=\"scripts/deploy.js\"\n // Deploy an EVM-compatible smart contract using ethers.js\n const { writeFileSync, existsSync, readFileSync } = require('fs');\n const { join } = require('path');\n const { ethers, JsonRpcProvider } = require('ethers');\n\n const codegenDir = join(__dirname);\n\n // Creates an Ethereum provider with specified RPC URL and chain details\n const createProvider = (rpcUrl, chainId, chainName) => {\n const provider = new JsonRpcProvider(rpcUrl, {\n chainId: chainId,\n name: chainName,\n });\n return provider;\n };\n\n // Reads and parses the ABI file for a given contract\n const getAbi = (contractName) => {\n try {\n return JSON.parse(\n readFileSync(join(codegenDir, `${contractName}.json`), 'utf8'),\n );\n } catch (error) {\n console.error(\n `Could not find ABI for contract ${contractName}:`,\n error.message,\n );\n throw error;\n }\n };\n\n // Reads the compiled bytecode for a given contract\n const getByteCode = (contractName) => {\n try {\n const bytecodePath = join(\n codegenDir,\n '../contracts',\n `${contractName}.polkavm`,\n );\n return `0x${readFileSync(bytecodePath).toString('hex')}`;\n } catch (error) {\n console.error(\n `Could not find bytecode for contract ${contractName}:`,\n error.message,\n );\n throw error;\n }\n };\n\n const deployContract = async (contractName, mnemonic, providerConfig) => {\n console.log(`Deploying ${contractName}...`);\n\n try {\n // Step 1: Set up provider and wallet\n const provider = createProvider(\n providerConfig.rpc,\n providerConfig.chainId,\n providerConfig.name,\n );\n const walletMnemonic = ethers.Wallet.fromPhrase(mnemonic);\n const wallet = walletMnemonic.connect(provider);\n\n // Step 2: Create and deploy the contract\n const factory = new ethers.ContractFactory(\n getAbi(contractName),\n getByteCode(contractName),\n wallet,\n );\n const contract = await factory.deploy();\n await contract.waitForDeployment();\n\n // Step 3: Save deployment information\n const address = await contract.getAddress();\n console.log(`Contract ${contractName} deployed at: ${address}`);\n\n const addressesFile = join(codegenDir, 'contract-address.json');\n const addresses = existsSync(addressesFile)\n ? JSON.parse(readFileSync(addressesFile, 'utf8'))\n : {};\n addresses[contractName] = address;\n writeFileSync(addressesFile, JSON.stringify(addresses, null, 2), 'utf8');\n } catch (error) {\n console.error(`Failed to deploy contract ${contractName}:`, error);\n }\n };\n\n const providerConfig = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io',\n chainId: 420420422,\n name: 'polkadot-hub-testnet',\n };\n\n const mnemonic = 'INSERT_MNEMONIC';\n\n deployContract('Storage', mnemonic, providerConfig);\n\n ```\n\nTo run the script, execute the following command:\n\n```bash\nnode deploy\n```\n\nAfter running this script, your contract will be deployed to Polkadot Hub, and its address will be saved in `contract-address.json` within your project directory. You can use this address for future contract interactions."} -{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 11, "depth": 2, "title": "Interact with the Contract", "anchor": "interact-with-the-contract", "start_char": 16591, "end_char": 19852, "estimated_token_count": 712, "token_estimator": "heuristic-v1", "text": "## Interact with the Contract\n\nOnce the contract is deployed, you can interact with it by calling its functions. For example, to set a number, read it and then modify that number by its double, you can create a file named `checkStorage.js` in the root of your project and add the following code:\n\n```js title=\"scripts/checkStorage.js\"\nconst { ethers } = require('ethers');\nconst { readFileSync } = require('fs');\nconst { join } = require('path');\n\nconst createProvider = (providerConfig) => {\n return new ethers.JsonRpcProvider(providerConfig.rpc, {\n chainId: providerConfig.chainId,\n name: providerConfig.name,\n });\n};\n\nconst createWallet = (mnemonic, provider) => {\n return ethers.Wallet.fromPhrase(mnemonic).connect(provider);\n};\n\nconst loadContractAbi = (contractName, directory = __dirname) => {\n const contractPath = join(directory, `${contractName}.json`);\n const contractJson = JSON.parse(readFileSync(contractPath, 'utf8'));\n return contractJson.abi || contractJson; // Depending on JSON structure\n};\n\nconst createContract = (contractAddress, abi, wallet) => {\n return new ethers.Contract(contractAddress, abi, wallet);\n};\n\nconst interactWithStorageContract = async (\n contractName,\n contractAddress,\n mnemonic,\n providerConfig,\n numberToSet,\n) => {\n try {\n console.log(`Setting new number in Storage contract: ${numberToSet}`);\n\n // Create provider and wallet\n const provider = createProvider(providerConfig);\n const wallet = createWallet(mnemonic, provider);\n\n // Load the contract ABI and create the contract instance\n const abi = loadContractAbi(contractName);\n const contract = createContract(contractAddress, abi, wallet);\n\n // Send a transaction to set the stored number\n const tx1 = await contract.setNumber(numberToSet);\n await tx1.wait(); // Wait for the transaction to be mined\n console.log(`Number successfully set to ${numberToSet}`);\n\n // Retrieve the updated number\n const storedNumber = await contract.storedNumber();\n console.log(`Retrieved stored number:`, storedNumber.toString());\n\n // Send a transaction to set the stored number\n const tx2 = await contract.setNumber(numberToSet * 2);\n await tx2.wait(); // Wait for the transaction to be mined\n console.log(`Number successfully set to ${numberToSet * 2}`);\n\n // Retrieve the updated number\n const updatedNumber = await contract.storedNumber();\n console.log(`Retrieved stored number:`, updatedNumber.toString());\n } catch (error) {\n console.error('Error interacting with Storage contract:', error.message);\n }\n};\n\nconst providerConfig = {\n name: 'asset-hub-smart-contracts',\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io',\n chainId: 420420422,\n};\n\nconst mnemonic = 'INSERT_MNEMONIC';\nconst contractName = 'Storage';\nconst contractAddress = 'INSERT_CONTRACT_ADDRESS';\nconst newNumber = 42;\n\ninteractWithStorageContract(\n contractName,\n contractAddress,\n mnemonic,\n providerConfig,\n newNumber,\n);\n\n```\n\nEnsure you replace the `INSERT_MNEMONIC`, `INSERT_CONTRACT_ADDRESS`, and `INSERT_ADDRESS_TO_CHECK` placeholders with actual values. Also, ensure the contract ABI file (`Storage.json`) is correctly referenced.\n\nTo interact with the contract, run:\n\n```bash\nnode checkStorage\n```"} -{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 12, "depth": 2, "title": "Where to Go Next", "anchor": "where-to-go-next", "start_char": 19852, "end_char": 20457, "estimated_token_count": 155, "token_estimator": "heuristic-v1", "text": "## Where to Go Next\n\nNow that you have the foundational knowledge to use Ethers.js with Polkadot Hub, you can:\n\n- **Dive into Ethers.js utilities**: Discover additional Ethers.js features, such as wallet management, signing messages, etc.\n- **Implement batch transactions**: Use Ethers.js to execute batch transactions for efficient multi-step contract interactions.\n- **Build scalable applications**: Combine Ethers.js with frameworks like [`Next.js`](https://nextjs.org/docs){target=\\_blank} or [`Node.js`](https://nodejs.org/en){target=\\_blank} to create full-stack decentralized applications (dApps)."} +{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 13, "end_char": 539, "estimated_token_count": 105, "token_estimator": "heuristic-v1", "text": "## Introduction\n\n[Ethers.js](https://docs.ethers.org/v6/){target=\\_blank} is a lightweight library that enables interaction with Ethereum Virtual Machine (EVM)-compatible blockchains through JavaScript. Ethers is widely used as a toolkit to establish connections and read and write blockchain data. This article demonstrates using Ethers.js to interact and deploy smart contracts to Polkadot Hub.\n\nThis guide is intended for developers who are familiar with JavaScript and want to interact with Polkadot Hub using Ethers.js."} +{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 1, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 539, "end_char": 895, "estimated_token_count": 110, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore getting started, ensure you have the following installed:\n\n- **Node.js**: v22.13.1 or later, check the [Node.js installation guide](https://nodejs.org/en/download/current/){target=\\_blank}.\n- **npm**: v6.13.4 or later (comes bundled with Node.js).\n- **Solidity**: This guide uses Solidity `^0.8.9` for smart contract development."} +{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 2, "depth": 2, "title": "Project Structure", "anchor": "project-structure", "start_char": 895, "end_char": 1403, "estimated_token_count": 144, "token_estimator": "heuristic-v1", "text": "## Project Structure\n\nThis project organizes contracts, scripts, and compiled artifacts for easy development and deployment.\n\n```text title=\"Ethers.js Polkadot Hub\"\nethers-project\n├── contracts\n│ ├── Storage.sol\n├── scripts\n│ ├── connectToProvider.js\n│ ├── fetchLastBlock.js\n│ ├── compile.js\n│ ├── deploy.js\n│ ├── checkStorage.js\n├── abis\n│ ├── Storage.json\n├── artifacts\n│ ├── Storage.bin\n├── contract-address.json\n├── node_modules/\n├── package.json\n├── package-lock.json\n└── README.md\n```"} +{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 3, "depth": 2, "title": "Set Up the Project", "anchor": "set-up-the-project", "start_char": 1403, "end_char": 1624, "estimated_token_count": 50, "token_estimator": "heuristic-v1", "text": "## Set Up the Project\n\nTo start working with Ethers.js, create a new folder and initialize your project by running the following commands in your terminal:\n\n```bash\nmkdir ethers-project\ncd ethers-project\nnpm init -y\n```"} +{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 4, "depth": 2, "title": "Install Dependencies", "anchor": "install-dependencies", "start_char": 1624, "end_char": 2083, "estimated_token_count": 122, "token_estimator": "heuristic-v1", "text": "## Install Dependencies\n\nNext, run the following command to install the Ethers.js library:\n\n```bash\nnpm install ethers\n```\n\nAdd the Solidity compiler so you can generate standard EVM bytecode:\n\n```bash\nnpm install --save-dev solc\n```\n\nThis guide uses `solc` version `0.8.33`.\n\n!!! tip\n The sample scripts use ECMAScript modules. Add `\"type\": \"module\"` to your `package.json` (or rename the files to `.mjs`) so that `node` can run the `import` statements."} +{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 5, "depth": 2, "title": "Set Up the Ethers.js Provider", "anchor": "set-up-the-ethersjs-provider", "start_char": 2083, "end_char": 4682, "estimated_token_count": 578, "token_estimator": "heuristic-v1", "text": "## Set Up the Ethers.js Provider\n\nA [`Provider`](https://docs.ethers.org/v6/api/providers/#Provider){target=\\_blank} is an abstraction of a connection to the Ethereum network, allowing you to query blockchain data and send transactions. It serves as a bridge between your application and the blockchain.\n\nTo interact with Polkadot Hub, you must set up an Ethers.js provider. This provider connects to a blockchain node, allowing you to query blockchain data and interact with smart contracts. In the root of your project, create a file named `connectToProvider.js` and add the following code:\n\n```js title=\"scripts/connectToProvider.js\"\nconst { JsonRpcProvider } = require('ethers');\n\nconst createProvider = (rpcUrl, chainId, chainName) => {\n const provider = new JsonRpcProvider(rpcUrl, {\n chainId: chainId,\n name: chainName,\n });\n\n return provider;\n};\n\nconst PROVIDER_RPC = {\n rpc: 'INSERT_RPC_URL',\n chainId: 'INSERT_CHAIN_ID',\n name: 'INSERT_CHAIN_NAME',\n};\n\ncreateProvider(PROVIDER_RPC.rpc, PROVIDER_RPC.chainId, PROVIDER_RPC.name);\n\n```\n\n!!! note\n Replace `INSERT_RPC_URL`, `INSERT_CHAIN_ID`, and `INSERT_CHAIN_NAME` with the appropriate values. For example, to connect to Polkadot Hub TestNet's Ethereum RPC instance, you can use the following parameters:\n\n ```js\n const PROVIDER_RPC = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io',\n chainId: 420420422,\n name: 'polkadot-hub-testnet'\n };\n ```\n\nTo connect to the provider, execute:\n\n```bash\nnode scripts/connectToProvider.js\n```\n\nWith the provider set up, you can start querying the blockchain. For instance, to fetch the latest block number:\n\n??? code \"Fetch Last Block code\"\n\n ```js title=\"scripts/fetchLastBlock.js\"\n const { JsonRpcProvider } = require('ethers');\n\n const createProvider = (rpcUrl, chainId, chainName) => {\n const provider = new JsonRpcProvider(rpcUrl, {\n chainId: chainId,\n name: chainName,\n });\n\n return provider;\n };\n\n const PROVIDER_RPC = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io',\n chainId: 420420422,\n name: 'polkadot-hub-testnet',\n };\n\n const main = async () => {\n try {\n const provider = createProvider(\n PROVIDER_RPC.rpc,\n PROVIDER_RPC.chainId,\n PROVIDER_RPC.name,\n );\n const latestBlock = await provider.getBlockNumber();\n console.log(`Latest block: ${latestBlock}`);\n } catch (error) {\n console.error('Error connecting to Polkadot Hub TestNet: ' + error.message);\n }\n };\n\n main();\n\n ```"} +{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 6, "depth": 2, "title": "Compile Contracts", "anchor": "compile-contracts", "start_char": 4682, "end_char": 5011, "estimated_token_count": 74, "token_estimator": "heuristic-v1", "text": "## Compile Contracts\n\nPolkadot Hub exposes an Ethereum JSON-RPC endpoint, so you can compile Solidity contracts to familiar EVM bytecode with the upstream [`solc`](https://www.npmjs.com/package/solc){target=\\_blank} compiler. The resulting artifacts work with any EVM-compatible toolchain and can be deployed through Ethers.js."} +{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 7, "depth": 3, "title": "Sample Storage Smart Contract", "anchor": "sample-storage-smart-contract", "start_char": 5011, "end_char": 5836, "estimated_token_count": 171, "token_estimator": "heuristic-v1", "text": "### Sample Storage Smart Contract\n\nThis example demonstrates compiling a `Storage.sol` Solidity contract for deployment to Polkadot Hub. The contract's functionality stores a number and permits users to update it with a new value.\n\n```solidity title=\"contracts/Storage.sol\"\n//SPDX-License-Identifier: MIT\n\n// Solidity files have to start with this pragma.\n// It will be used by the Solidity compiler to validate its version.\npragma solidity ^0.8.9;\n\ncontract Storage {\n // Public state variable to store a number\n uint256 public storedNumber;\n\n /**\n * Updates the stored number.\n *\n * The `public` modifier allows anyone to call this function.\n *\n * @param _newNumber - The new value to store.\n */\n function setNumber(uint256 _newNumber) public {\n storedNumber = _newNumber;\n }\n}\n```"} +{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 8, "depth": 3, "title": "Compile the Smart Contract", "anchor": "compile-the-smart-contract", "start_char": 5836, "end_char": 9393, "estimated_token_count": 810, "token_estimator": "heuristic-v1", "text": "### Compile the Smart Contract\n\nTo compile this contract, use the following script:\n\n```js title=\"scripts/compile.js\"\nconst solc = require('solc');\nconst { readFileSync, writeFileSync, mkdirSync, existsSync } = require('fs');\nconst { basename, join } = require('path');\n\nconst ensureDir = (dirPath) => {\n if (!existsSync(dirPath)) {\n mkdirSync(dirPath, { recursive: true });\n }\n};\n\nconst compileContract = (solidityFilePath, abiDir, artifactsDir) => {\n try {\n // Read the Solidity file\n const source = readFileSync(solidityFilePath, 'utf8');\n const fileName = basename(solidityFilePath);\n \n // Construct the input object for the Solidity compiler\n const input = {\n language: 'Solidity',\n sources: {\n [fileName]: {\n content: source,\n },\n },\n settings: {\n outputSelection: {\n '*': {\n '*': ['abi', 'evm.bytecode'],\n },\n },\n },\n };\n \n console.log(`Compiling contract: ${fileName}...`);\n \n // Compile the contract\n const output = JSON.parse(solc.compile(JSON.stringify(input)));\n \n // Check for errors\n if (output.errors) {\n const errors = output.errors.filter(error => error.severity === 'error');\n if (errors.length > 0) {\n console.error('Compilation errors:');\n errors.forEach(err => console.error(err.formattedMessage));\n return;\n }\n // Show warnings\n const warnings = output.errors.filter(error => error.severity === 'warning');\n warnings.forEach(warn => console.warn(warn.formattedMessage));\n }\n \n // Ensure output directories exist\n ensureDir(abiDir);\n ensureDir(artifactsDir);\n\n // Process compiled contracts\n for (const [sourceFile, contracts] of Object.entries(output.contracts)) {\n for (const [contractName, contract] of Object.entries(contracts)) {\n console.log(`Compiled contract: ${contractName}`);\n \n // Write the ABI\n const abiPath = join(abiDir, `${contractName}.json`);\n writeFileSync(abiPath, JSON.stringify(contract.abi, null, 2));\n console.log(`ABI saved to ${abiPath}`);\n \n // Write the bytecode\n const bytecodePath = join(artifactsDir, `${contractName}.bin`);\n writeFileSync(bytecodePath, contract.evm.bytecode.object);\n console.log(`Bytecode saved to ${bytecodePath}`);\n }\n }\n } catch (error) {\n console.error('Error compiling contracts:', error);\n }\n};\n\nconst solidityFilePath = join(__dirname, '../contracts/Storage.sol');\nconst abiDir = join(__dirname, '../abis');\nconst artifactsDir = join(__dirname, '../artifacts');\n\ncompileContract(solidityFilePath, abiDir, artifactsDir);\n```\n\n!!! note \n The script above is tailored to the `Storage.sol` contract. It can be adjusted for other contracts by changing the file name or modifying the ABI and bytecode paths.\n\nThe ABI (Application Binary Interface) is a JSON representation of your contract's functions, events, and their parameters. It serves as the interface between your JavaScript code and the deployed smart contract, allowing your application to know how to format function calls and interpret returned data.\n\nExecute the script above by running:\n\n```bash\nnode scripts/compile.js\n```\n\nAfter executing the script, the Solidity contract is compiled into standard EVM bytecode. The ABI and bytecode are saved into files with `.json` and `.bin` extensions, respectively. You can now proceed with deploying the contract to Polkadot Hub, as outlined in the next section."} +{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 9, "depth": 2, "title": "Deploy the Compiled Contract", "anchor": "deploy-the-compiled-contract", "start_char": 9393, "end_char": 16977, "estimated_token_count": 1599, "token_estimator": "heuristic-v1", "text": "## Deploy the Compiled Contract\n\nTo deploy your compiled contract to Polkadot Hub, you'll need a wallet with a private key to sign the deployment transaction.\n\nYou can create a `deploy.js` script in the root of your project to achieve this. The deployment script can be divided into key components:\n\n1. Set up the required imports and utilities:\n\n ```js title=\"scripts/deploy.js\"\n const { writeFileSync, existsSync, readFileSync } = require('fs');\n const { join } = require('path');\n const { ethers, JsonRpcProvider } = require('ethers');\n\n ```\n\n2. Create a provider to connect to Polkadot Hub:\n\n ```js title=\"scripts/deploy.js\"\n\n // Creates a provider with specified RPC URL and chain details\n const createProvider = (rpcUrl, chainId, chainName) => {\n const provider = new JsonRpcProvider(rpcUrl, {\n chainId: chainId,\n name: chainName,\n });\n return provider;\n };\n ```\n \n3. Set up functions to read contract artifacts:\n\n ```js title=\"scripts/deploy.js\"\n // Reads and parses the ABI file for a given contract\n const getAbi = (contractName) => {\n try {\n const abiPath = join(artifactsDir, `${contractName}.json`);\n return JSON.parse(readFileSync(abiPath, 'utf8'));\n } catch (error) {\n console.error(\n `Could not find ABI for contract ${contractName}:`,\n error.message,\n );\n throw error;\n }\n };\n\n // Reads the compiled bytecode for a given contract\n const getByteCode = (contractName) => {\n try {\n const bytecodePath = join(artifactsDir, `${contractName}.bin`);\n const bytecode = readFileSync(bytecodePath, 'utf8').trim();\n // Add 0x prefix if not present\n return bytecode.startsWith('0x') ? bytecode : `0x${bytecode}`;\n } catch (error) {\n console.error(\n `Could not find bytecode for contract ${contractName}:`,\n error.message,\n );\n throw error;\n }\n };\n\n ```\n\n4. Create the main deployment function:\n\n ```js title=\"scripts/deploy.js\"\n const deployContract = async (contractName, mnemonic, providerConfig) => {\n console.log(`Deploying ${contractName}...`);\n try {\n // Step 1: Set up provider and wallet\n const provider = createProvider(\n providerConfig.rpc,\n providerConfig.chainId,\n providerConfig.name,\n );\n const walletMnemonic = ethers.Wallet.fromPhrase(mnemonic);\n const wallet = walletMnemonic.connect(provider);\n\n // Step 2: Create and deploy the contract\n const factory = new ethers.ContractFactory(\n getAbi(contractName),\n getByteCode(contractName),\n wallet,\n );\n const contract = await factory.deploy();\n await contract.waitForDeployment();\n\n // Step 3: Save deployment information\n const address = await contract.getAddress();\n console.log(`Contract ${contractName} deployed at: ${address}`);\n\n const addressesFile = join(scriptsDir, 'contract-address.json');\n const addresses = existsSync(addressesFile)\n ? JSON.parse(readFileSync(addressesFile, 'utf8'))\n : {};\n\n addresses[contractName] = address;\n writeFileSync(addressesFile, JSON.stringify(addresses, null, 2), 'utf8');\n } catch (error) {\n console.error(`Failed to deploy contract ${contractName}:`, error);\n }\n };\n ```\n\n5. Configure and execute the deployment:\n\n ```js title=\"scripts/deploy.js\"\n \n ```\n\n !!! note\n A mnemonic (seed phrase) is a series of words that can generate multiple private keys and their corresponding addresses. It's used here to derive the wallet that will sign and pay for the deployment transaction. **Always keep your mnemonic secure and never share it publicly**.\n\n Ensure to replace the `INSERT_MNEMONIC` placeholder with your actual mnemonic.\n\n??? code \"View complete script\"\n\n ```js title=\"scripts/deploy.js\"\n const { writeFileSync, existsSync, readFileSync } = require('fs');\n const { join } = require('path');\n const { ethers, JsonRpcProvider } = require('ethers');\n\n const scriptsDir = __dirname;\n const artifactsDir = join(__dirname, '../contracts');\n\n // Creates a provider with specified RPC URL and chain details\n const createProvider = (rpcUrl, chainId, chainName) => {\n const provider = new JsonRpcProvider(rpcUrl, {\n chainId: chainId,\n name: chainName,\n });\n return provider;\n };\n\n // Reads and parses the ABI file for a given contract\n const getAbi = (contractName) => {\n try {\n const abiPath = join(artifactsDir, `${contractName}.json`);\n return JSON.parse(readFileSync(abiPath, 'utf8'));\n } catch (error) {\n console.error(\n `Could not find ABI for contract ${contractName}:`,\n error.message,\n );\n throw error;\n }\n };\n\n // Reads the compiled bytecode for a given contract\n const getByteCode = (contractName) => {\n try {\n const bytecodePath = join(artifactsDir, `${contractName}.bin`);\n const bytecode = readFileSync(bytecodePath, 'utf8').trim();\n // Add 0x prefix if not present\n return bytecode.startsWith('0x') ? bytecode : `0x${bytecode}`;\n } catch (error) {\n console.error(\n `Could not find bytecode for contract ${contractName}:`,\n error.message,\n );\n throw error;\n }\n };\n\n const deployContract = async (contractName, mnemonic, providerConfig) => {\n console.log(`Deploying ${contractName}...`);\n try {\n // Step 1: Set up provider and wallet\n const provider = createProvider(\n providerConfig.rpc,\n providerConfig.chainId,\n providerConfig.name,\n );\n const walletMnemonic = ethers.Wallet.fromPhrase(mnemonic);\n const wallet = walletMnemonic.connect(provider);\n\n // Step 2: Create and deploy the contract\n const factory = new ethers.ContractFactory(\n getAbi(contractName),\n getByteCode(contractName),\n wallet,\n );\n const contract = await factory.deploy();\n await contract.waitForDeployment();\n\n // Step 3: Save deployment information\n const address = await contract.getAddress();\n console.log(`Contract ${contractName} deployed at: ${address}`);\n\n const addressesFile = join(scriptsDir, 'contract-address.json');\n const addresses = existsSync(addressesFile)\n ? JSON.parse(readFileSync(addressesFile, 'utf8'))\n : {};\n\n addresses[contractName] = address;\n writeFileSync(addressesFile, JSON.stringify(addresses, null, 2), 'utf8');\n } catch (error) {\n console.error(`Failed to deploy contract ${contractName}:`, error);\n }\n };\n\n const providerConfig = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', #TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready\n chainId: 420420422,\n name: 'polkadot-hub-testnet',\n };\n\n const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon';\n\n deployContract('Storage', mnemonic, providerConfig);\n ```\n\nTo run the script, execute the following command:\n\n```bash\nnode scripts/deploy.js\n```\n\nAfter running this script, your contract will be deployed to Polkadot Hub, and its address will be saved in `contract-address.json` within your project directory. You can use this address for future contract interactions."} +{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 10, "depth": 2, "title": "Interact with the Contract", "anchor": "interact-with-the-contract", "start_char": 16977, "end_char": 20528, "estimated_token_count": 769, "token_estimator": "heuristic-v1", "text": "## Interact with the Contract\n\nOnce the contract is deployed, you can interact with it by calling its functions. For example, to set a number, read it and then modify that number by its double, you can create a file named `checkStorage.js` in the root of your project and add the following code:\n\n```js title=\"scripts/checkStorage.js\"\nconst { ethers } = require('ethers');\nconst { readFileSync } = require('fs');\nconst { join } = require('path');\n\nconst artifactsDir = join(__dirname, '../contracts');\n\nconst createProvider = (providerConfig) => {\n return new ethers.JsonRpcProvider(providerConfig.rpc, {\n chainId: providerConfig.chainId,\n name: providerConfig.name,\n });\n};\n\nconst createWallet = (mnemonic, provider) => {\n return ethers.Wallet.fromPhrase(mnemonic).connect(provider);\n};\n\nconst loadContractAbi = (contractName, directory = artifactsDir) => {\n const contractPath = join(directory, `${contractName}.json`);\n const contractJson = JSON.parse(readFileSync(contractPath, 'utf8'));\n return contractJson.abi || contractJson; // Depending on JSON structure\n};\n\nconst createContract = (contractAddress, abi, wallet) => {\n return new ethers.Contract(contractAddress, abi, wallet);\n};\n\nconst interactWithStorageContract = async (\n contractName,\n contractAddress,\n mnemonic,\n providerConfig,\n numberToSet,\n) => {\n try {\n console.log(`Setting new number in Storage contract: ${numberToSet}`);\n\n // Create provider and wallet\n const provider = createProvider(providerConfig);\n const wallet = createWallet(mnemonic, provider);\n\n // Load the contract ABI and create the contract instance\n const abi = loadContractAbi(contractName);\n const contract = createContract(contractAddress, abi, wallet);\n\n // Send a transaction to set the stored number\n const tx1 = await contract.setNumber(numberToSet);\n await tx1.wait(); // Wait for the transaction to be mined\n console.log(`Number successfully set to ${numberToSet}`);\n\n // Retrieve the updated number\n const storedNumber = await contract.storedNumber();\n console.log(`Retrieved stored number:`, storedNumber.toString());\n\n // Send a transaction to set the stored number\n const tx2 = await contract.setNumber(numberToSet * 2);\n await tx2.wait(); // Wait for the transaction to be mined\n console.log(`Number successfully set to ${numberToSet * 2}`);\n\n // Retrieve the updated number\n const updatedNumber = await contract.storedNumber();\n console.log(`Retrieved stored number:`, updatedNumber.toString());\n } catch (error) {\n console.error('Error interacting with Storage contract:', error.message);\n }\n};\n\nconst providerConfig = {\n name: 'asset-hub-smart-contracts',\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io',\n chainId: 420420422,\n};\n\nconst mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon';\nconst contractName = 'Storage';\nconst contractAddress = '0x83e43892a98f924706E9DB7917244897dC8b8126';\nconst newNumber = 42;\n\ninteractWithStorageContract(\n contractName,\n contractAddress,\n mnemonic,\n providerConfig,\n newNumber,\n);\n```\n\nEnsure you replace the `INSERT_MNEMONIC`, `INSERT_CONTRACT_ADDRESS`, and `INSERT_ADDRESS_TO_CHECK` placeholders with actual values. Also, ensure the contract ABI file (`Storage.json`) is correctly referenced. The script prints the balance for `ADDRESS_TO_CHECK` before it writes and doubles the stored value, so pick any account you want to monitor.\n\nTo interact with the contract, run:\n\n```bash\nnode scripts/checkStorage.js\n```"} +{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 11, "depth": 2, "title": "Where to Go Next", "anchor": "where-to-go-next", "start_char": 20528, "end_char": 21133, "estimated_token_count": 155, "token_estimator": "heuristic-v1", "text": "## Where to Go Next\n\nNow that you have the foundational knowledge to use Ethers.js with Polkadot Hub, you can:\n\n- **Dive into Ethers.js utilities**: Discover additional Ethers.js features, such as wallet management, signing messages, etc.\n- **Implement batch transactions**: Use Ethers.js to execute batch transactions for efficient multi-step contract interactions.\n- **Build scalable applications**: Combine Ethers.js with frameworks like [`Next.js`](https://nextjs.org/docs){target=\\_blank} or [`Node.js`](https://nodejs.org/en){target=\\_blank} to create full-stack decentralized applications (dApps)."} {"page_id": "smart-contracts-libraries-viem", "page_title": "viem for Polkadot Hub Smart Contracts", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 178, "end_char": 455, "estimated_token_count": 56, "token_estimator": "heuristic-v1", "text": "## Introduction\n\n[viem](https://viem.sh/){target=\\_blank} is a lightweight TypeScript library designed for interacting with Ethereum-compatible blockchains. This comprehensive guide will walk you through using viem to interact with and deploy smart contracts to Polkadot Hub."} {"page_id": "smart-contracts-libraries-viem", "page_title": "viem for Polkadot Hub Smart Contracts", "index": 1, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 455, "end_char": 811, "estimated_token_count": 110, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore getting started, ensure you have the following installed:\n\n- **Node.js**: v22.13.1 or later, check the [Node.js installation guide](https://nodejs.org/en/download/current/){target=\\_blank}.\n- **npm**: v6.13.4 or later (comes bundled with Node.js).\n- **Solidity**: This guide uses Solidity `^0.8.9` for smart contract development."} {"page_id": "smart-contracts-libraries-viem", "page_title": "viem for Polkadot Hub Smart Contracts", "index": 2, "depth": 2, "title": "Project Structure", "anchor": "project-structure", "start_char": 811, "end_char": 1231, "estimated_token_count": 119, "token_estimator": "heuristic-v1", "text": "## Project Structure\n\nThis project organizes contracts, scripts, and compiled artifacts for easy development and deployment.\n\n```text\nviem-project/\n├── package.json\n├── tsconfig.json\n├── src/\n│ ├── chainConfig.ts\n│ ├── createClient.ts\n│ ├── createWallet.ts\n│ ├── compile.ts\n│ ├── deploy.ts\n│ └── interact.ts\n├── contracts/\n│ └── Storage.sol\n└── artifacts/\n ├── Storage.json\n └── Storage.polkavm\n```"} diff --git a/llms.txt b/llms.txt index 1b820afd6..d7102baaa 100644 --- a/llms.txt +++ b/llms.txt @@ -6,7 +6,7 @@ This directory lists URLs for raw Markdown pages that complement the rendered pages on the documentation site. Use these Markdown files to retain semantic context when prompting models while avoiding passing HTML elements. ## Metadata -- Documentation pages: 146 +- Documentation pages: 147 - Categories: 13 ## Docs @@ -246,6 +246,7 @@ Docs: Uncategorized - [smart-contracts-integrations-indexers](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-integrations-indexers.md): No description available. - [smart-contracts-integrations-oracles](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-integrations-oracles.md): No description available. - [Advanced Functionalities via Precompiles](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-precompiles.md): Explores how Polkadot integrates precompiles to run essential functions natively, improving the speed and efficiency of smart contracts on the Hub. +- [text-smart-contracts-code-size](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/text-smart-contracts-code-size.md): No description available. Docs: dApp - [Zero to Hero Smart Contract DApp](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-cookbook-dapps-zero-to-hero.md): Learn how to build a decentralized application on Polkadot Hub using Viem and Next.js by creating a simple dApp that interacts with a smart contract. From c94b9ace6656ac5782803b3c31ba03d80b32f59a Mon Sep 17 00:00:00 2001 From: nhussein11 Date: Mon, 17 Nov 2025 10:08:03 -0300 Subject: [PATCH 3/7] Update checkStorage.js to use placeholders for mnemonic and contract address; revise documentation to reflect these changes and remove unnecessary placeholder instructions. --- .../code/smart-contracts/libraries/ethers-js/checkStorage.js | 4 ++-- smart-contracts/libraries/ethers-js.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.snippets/code/smart-contracts/libraries/ethers-js/checkStorage.js b/.snippets/code/smart-contracts/libraries/ethers-js/checkStorage.js index 216bfd83a..8febb14e5 100644 --- a/.snippets/code/smart-contracts/libraries/ethers-js/checkStorage.js +++ b/.snippets/code/smart-contracts/libraries/ethers-js/checkStorage.js @@ -71,9 +71,9 @@ const providerConfig = { chainId: 420420422, }; -const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon'; +const mnemonic = 'INSERT_MNEMONIC' const contractName = 'Storage'; -const contractAddress = '0x83e43892a98f924706E9DB7917244897dC8b8126'; +const contractAddress = 'INSERT_CONTRACT_ADDRESS' const newNumber = 42; interactWithStorageContract( diff --git a/smart-contracts/libraries/ethers-js.md b/smart-contracts/libraries/ethers-js.md index 9d4871414..abdbfab4d 100644 --- a/smart-contracts/libraries/ethers-js.md +++ b/smart-contracts/libraries/ethers-js.md @@ -175,7 +175,7 @@ You can create a `deploy.js` script in the root of your project to achieve this. 5. Configure and execute the deployment: ```js title="scripts/deploy.js" - --8<-- 'code/smart-contracts/libraries/ethers-js/deploy.js4:92' + --8<-- 'code/smart-contracts/libraries/ethers-js/deploy.js:84:92' ``` !!! note @@ -205,7 +205,7 @@ Once the contract is deployed, you can interact with it by calling its functions --8<-- 'code/smart-contracts/libraries/ethers-js/checkStorage.js' ``` -Ensure you replace the `INSERT_MNEMONIC`, `INSERT_CONTRACT_ADDRESS`, and `INSERT_ADDRESS_TO_CHECK` placeholders with actual values. Also, ensure the contract ABI file (`Storage.json`) is correctly referenced. The script prints the balance for `ADDRESS_TO_CHECK` before it writes and doubles the stored value, so pick any account you want to monitor. +Ensure you replace the `INSERT_MNEMONIC` and `INSERT_CONTRACT_ADDRESS` placeholders with actual values. Also, ensure the contract ABI file (`Storage.json`) is correctly referenced. The script prints the balance for `ADDRESS_TO_CHECK` before it writes and doubles the stored value, so pick any account you want to monitor. To interact with the contract, run: From 24009167b16a17ac7ee7f048dd7ff4f24c4f9ad8 Mon Sep 17 00:00:00 2001 From: nhussein11 Date: Mon, 17 Nov 2025 18:21:30 -0300 Subject: [PATCH 4/7] fix: removing code size --- .ai/categories/smart-contracts.md | 18 ++++++---- .ai/categories/tooling.md | 18 ++++++---- .../smart-contracts-libraries-ethers-js.md | 16 ++++++--- .../smart-contracts-libraries-web3-js.md | 2 -- .ai/pages/text-smart-contracts-code-size.md | 6 ---- .ai/site-index.json | 36 +++++-------------- llms-full.jsonl | 26 +++++++------- llms.txt | 3 +- smart-contracts/libraries/web3-js.md | 2 -- text/smart-contracts/code-size.md | 2 -- 10 files changed, 58 insertions(+), 71 deletions(-) delete mode 100644 .ai/pages/text-smart-contracts-code-size.md delete mode 100644 text/smart-contracts/code-size.md diff --git a/.ai/categories/smart-contracts.md b/.ai/categories/smart-contracts.md index 0b9e7d40a..9cef3b31b 100644 --- a/.ai/categories/smart-contracts.md +++ b/.ai/categories/smart-contracts.md @@ -3468,7 +3468,15 @@ You can create a `deploy.js` script in the root of your project to achieve this. 5. Configure and execute the deployment: ```js title="scripts/deploy.js" - + const providerConfig = { + rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', #TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready + chainId: 420420422, + name: 'polkadot-hub-testnet', + }; + + const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon'; + + deployContract('Storage', mnemonic, providerConfig); ``` !!! note @@ -3659,9 +3667,9 @@ const providerConfig = { chainId: 420420422, }; -const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon'; +const mnemonic = 'INSERT_MNEMONIC' const contractName = 'Storage'; -const contractAddress = '0x83e43892a98f924706E9DB7917244897dC8b8126'; +const contractAddress = 'INSERT_CONTRACT_ADDRESS' const newNumber = 42; interactWithStorageContract( @@ -3673,7 +3681,7 @@ interactWithStorageContract( ); ``` -Ensure you replace the `INSERT_MNEMONIC`, `INSERT_CONTRACT_ADDRESS`, and `INSERT_ADDRESS_TO_CHECK` placeholders with actual values. Also, ensure the contract ABI file (`Storage.json`) is correctly referenced. The script prints the balance for `ADDRESS_TO_CHECK` before it writes and doubles the stored value, so pick any account you want to monitor. +Ensure you replace the `INSERT_MNEMONIC` and `INSERT_CONTRACT_ADDRESS` placeholders with actual values. Also, ensure the contract ABI file (`Storage.json`) is correctly referenced. The script prints the balance for `ADDRESS_TO_CHECK` before it writes and doubles the stored value, so pick any account you want to monitor. To interact with the contract, run: @@ -10760,8 +10768,6 @@ Page Title: Web3.js # Web3.js -!!! smartcontract "PolkaVM Preview Release" - PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. !!! warning Web3.js has been [sunset](https://blog.chainsafe.io/web3-js-sunset/){target=\_blank}. You can find guides on using [Ethers.js](/smart-contracts/libraries/ethers-js/){target=\_blank} and [viem](/smart-contracts/libraries/viem/){target=\_blank} in the Libraries section. diff --git a/.ai/categories/tooling.md b/.ai/categories/tooling.md index 5f743028f..a4914ac5b 100644 --- a/.ai/categories/tooling.md +++ b/.ai/categories/tooling.md @@ -2766,7 +2766,15 @@ You can create a `deploy.js` script in the root of your project to achieve this. 5. Configure and execute the deployment: ```js title="scripts/deploy.js" - + const providerConfig = { + rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', #TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready + chainId: 420420422, + name: 'polkadot-hub-testnet', + }; + + const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon'; + + deployContract('Storage', mnemonic, providerConfig); ``` !!! note @@ -2957,9 +2965,9 @@ const providerConfig = { chainId: 420420422, }; -const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon'; +const mnemonic = 'INSERT_MNEMONIC' const contractName = 'Storage'; -const contractAddress = '0x83e43892a98f924706E9DB7917244897dC8b8126'; +const contractAddress = 'INSERT_CONTRACT_ADDRESS' const newNumber = 42; interactWithStorageContract( @@ -2971,7 +2979,7 @@ interactWithStorageContract( ); ``` -Ensure you replace the `INSERT_MNEMONIC`, `INSERT_CONTRACT_ADDRESS`, and `INSERT_ADDRESS_TO_CHECK` placeholders with actual values. Also, ensure the contract ABI file (`Storage.json`) is correctly referenced. The script prints the balance for `ADDRESS_TO_CHECK` before it writes and doubles the stored value, so pick any account you want to monitor. +Ensure you replace the `INSERT_MNEMONIC` and `INSERT_CONTRACT_ADDRESS` placeholders with actual values. Also, ensure the contract ABI file (`Storage.json`) is correctly referenced. The script prints the balance for `ADDRESS_TO_CHECK` before it writes and doubles the stored value, so pick any account you want to monitor. To interact with the contract, run: @@ -12855,8 +12863,6 @@ Page Title: Web3.js # Web3.js -!!! smartcontract "PolkaVM Preview Release" - PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. !!! warning Web3.js has been [sunset](https://blog.chainsafe.io/web3-js-sunset/){target=\_blank}. You can find guides on using [Ethers.js](/smart-contracts/libraries/ethers-js/){target=\_blank} and [viem](/smart-contracts/libraries/viem/){target=\_blank} in the Libraries section. diff --git a/.ai/pages/smart-contracts-libraries-ethers-js.md b/.ai/pages/smart-contracts-libraries-ethers-js.md index b09d29c2c..7fd2ab8fb 100644 --- a/.ai/pages/smart-contracts-libraries-ethers-js.md +++ b/.ai/pages/smart-contracts-libraries-ethers-js.md @@ -401,7 +401,15 @@ You can create a `deploy.js` script in the root of your project to achieve this. 5. Configure and execute the deployment: ```js title="scripts/deploy.js" - + const providerConfig = { + rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', #TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready + chainId: 420420422, + name: 'polkadot-hub-testnet', + }; + + const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon'; + + deployContract('Storage', mnemonic, providerConfig); ``` !!! note @@ -592,9 +600,9 @@ const providerConfig = { chainId: 420420422, }; -const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon'; +const mnemonic = 'INSERT_MNEMONIC' const contractName = 'Storage'; -const contractAddress = '0x83e43892a98f924706E9DB7917244897dC8b8126'; +const contractAddress = 'INSERT_CONTRACT_ADDRESS' const newNumber = 42; interactWithStorageContract( @@ -606,7 +614,7 @@ interactWithStorageContract( ); ``` -Ensure you replace the `INSERT_MNEMONIC`, `INSERT_CONTRACT_ADDRESS`, and `INSERT_ADDRESS_TO_CHECK` placeholders with actual values. Also, ensure the contract ABI file (`Storage.json`) is correctly referenced. The script prints the balance for `ADDRESS_TO_CHECK` before it writes and doubles the stored value, so pick any account you want to monitor. +Ensure you replace the `INSERT_MNEMONIC` and `INSERT_CONTRACT_ADDRESS` placeholders with actual values. Also, ensure the contract ABI file (`Storage.json`) is correctly referenced. The script prints the balance for `ADDRESS_TO_CHECK` before it writes and doubles the stored value, so pick any account you want to monitor. To interact with the contract, run: diff --git a/.ai/pages/smart-contracts-libraries-web3-js.md b/.ai/pages/smart-contracts-libraries-web3-js.md index 095b6ea5c..03b6f0add 100644 --- a/.ai/pages/smart-contracts-libraries-web3-js.md +++ b/.ai/pages/smart-contracts-libraries-web3-js.md @@ -7,8 +7,6 @@ url: https://docs.polkadot.com/smart-contracts/libraries/web3-js/ # Web3.js -!!! smartcontract "PolkaVM Preview Release" - PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. !!! warning Web3.js has been [sunset](https://blog.chainsafe.io/web3-js-sunset/){target=\_blank}. You can find guides on using [Ethers.js](/smart-contracts/libraries/ethers-js/){target=\_blank} and [viem](/smart-contracts/libraries/viem/){target=\_blank} in the Libraries section. diff --git a/.ai/pages/text-smart-contracts-code-size.md b/.ai/pages/text-smart-contracts-code-size.md deleted file mode 100644 index 191ee473a..000000000 --- a/.ai/pages/text-smart-contracts-code-size.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -url: https://docs.polkadot.com/text/smart-contracts/code-size/ ---- - -!!! info "Mind the contract size" - Polkadot Hub enforces Ethereum's 24 KiB contract-size limit (EIP-170) for EVM deployments. Keep contracts modular, share logic through libraries, and make use of compiler optimizations so your bytecode stays within the limit. diff --git a/.ai/site-index.json b/.ai/site-index.json index b75b63f4c..b2ccc9abe 100644 --- a/.ai/site-index.json +++ b/.ai/site-index.json @@ -8541,12 +8541,12 @@ } ], "stats": { - "chars": 21133, - "words": 2401, + "chars": 21413, + "words": 2435, "headings": 12, - "estimated_token_count_total": 4687 + "estimated_token_count_total": 4762 }, - "hash": "sha256:ea39f6aab99e80c378fbf7c48030d274e13c340e23465d40d4cfb33c9f0d0f2f", + "hash": "sha256:121e52bd405e70bde9288d65557266fbaa0dbca290bdfebc67de8105d9672785", "token_estimator": "heuristic-v1" }, { @@ -8723,7 +8723,7 @@ ], "raw_md_url": "https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-libraries-web3-js.md", "html_url": "https://docs.polkadot.com/smart-contracts/libraries/web3-js/", - "preview": "!!! smartcontract \"PolkaVM Preview Release\" PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. !!! warning Web3.js has been [sunset](https://blog.chainsafe.io/web3-js-sunset/){target=\\_blank}. You can find guides on using [Ethers.js](/smart-contracts/libraries/ethers-js/){target=\\_blank} and [viem](/smart-contracts/libraries/viem/){target=\\_blank} in the Libraries section.", + "preview": "!!! warning Web3.js has been [sunset](https://blog.chainsafe.io/web3-js-sunset/){target=\\_blank}. You can find guides on using [Ethers.js](/smart-contracts/libraries/ethers-js/){target=\\_blank} and [viem](/smart-contracts/libraries/viem/){target=\\_blank} in the Libraries section.", "outline": [ { "depth": 2, @@ -8777,12 +8777,12 @@ } ], "stats": { - "chars": 13266, - "words": 1579, + "chars": 13096, + "words": 1558, "headings": 10, "estimated_token_count_total": 3035 }, - "hash": "sha256:f0d36333d0d3afff7f6374a61d0f6d1fb878c9ef4c4e4c24447745661dbe59d0", + "hash": "sha256:0aafc5ad18ee58314c81b5bbe98aa80bddfd9d1820eeaf674607d69819702a2b", "token_estimator": "heuristic-v1" }, { @@ -9051,25 +9051,5 @@ }, "hash": "sha256:a40e3f34f70db22bfe39e40d68dc5a53a726ce47cb73b602d8605355c61ffd22", "token_estimator": "heuristic-v1" - }, - { - "id": "text-smart-contracts-code-size", - "title": "text-smart-contracts-code-size", - "slug": "text-smart-contracts-code-size", - "categories": [ - "Uncategorized" - ], - "raw_md_url": "https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/text-smart-contracts-code-size.md", - "html_url": "https://docs.polkadot.com/text/smart-contracts/code-size/", - "preview": "!!! info \"Mind the contract size\" Polkadot Hub enforces Ethereum's 24 KiB contract-size limit (EIP-170) for EVM deployments. Keep contracts modular, share logic through libraries, and make use of compiler optimizations so your bytecode stays within the limit.", - "outline": [], - "stats": { - "chars": 264, - "words": 40, - "headings": 0, - "estimated_token_count_total": 0 - }, - "hash": "sha256:e6c2ffab1e1d9d06f6e209f37e1c829abd6be41fa7c5350d7dcc858745d4e011", - "token_estimator": "heuristic-v1" } ] \ No newline at end of file diff --git a/llms-full.jsonl b/llms-full.jsonl index 8fb554bcc..6d2024005 100644 --- a/llms-full.jsonl +++ b/llms-full.jsonl @@ -1118,9 +1118,9 @@ {"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 6, "depth": 2, "title": "Compile Contracts", "anchor": "compile-contracts", "start_char": 4682, "end_char": 5011, "estimated_token_count": 74, "token_estimator": "heuristic-v1", "text": "## Compile Contracts\n\nPolkadot Hub exposes an Ethereum JSON-RPC endpoint, so you can compile Solidity contracts to familiar EVM bytecode with the upstream [`solc`](https://www.npmjs.com/package/solc){target=\\_blank} compiler. The resulting artifacts work with any EVM-compatible toolchain and can be deployed through Ethers.js."} {"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 7, "depth": 3, "title": "Sample Storage Smart Contract", "anchor": "sample-storage-smart-contract", "start_char": 5011, "end_char": 5836, "estimated_token_count": 171, "token_estimator": "heuristic-v1", "text": "### Sample Storage Smart Contract\n\nThis example demonstrates compiling a `Storage.sol` Solidity contract for deployment to Polkadot Hub. The contract's functionality stores a number and permits users to update it with a new value.\n\n```solidity title=\"contracts/Storage.sol\"\n//SPDX-License-Identifier: MIT\n\n// Solidity files have to start with this pragma.\n// It will be used by the Solidity compiler to validate its version.\npragma solidity ^0.8.9;\n\ncontract Storage {\n // Public state variable to store a number\n uint256 public storedNumber;\n\n /**\n * Updates the stored number.\n *\n * The `public` modifier allows anyone to call this function.\n *\n * @param _newNumber - The new value to store.\n */\n function setNumber(uint256 _newNumber) public {\n storedNumber = _newNumber;\n }\n}\n```"} {"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 8, "depth": 3, "title": "Compile the Smart Contract", "anchor": "compile-the-smart-contract", "start_char": 5836, "end_char": 9393, "estimated_token_count": 810, "token_estimator": "heuristic-v1", "text": "### Compile the Smart Contract\n\nTo compile this contract, use the following script:\n\n```js title=\"scripts/compile.js\"\nconst solc = require('solc');\nconst { readFileSync, writeFileSync, mkdirSync, existsSync } = require('fs');\nconst { basename, join } = require('path');\n\nconst ensureDir = (dirPath) => {\n if (!existsSync(dirPath)) {\n mkdirSync(dirPath, { recursive: true });\n }\n};\n\nconst compileContract = (solidityFilePath, abiDir, artifactsDir) => {\n try {\n // Read the Solidity file\n const source = readFileSync(solidityFilePath, 'utf8');\n const fileName = basename(solidityFilePath);\n \n // Construct the input object for the Solidity compiler\n const input = {\n language: 'Solidity',\n sources: {\n [fileName]: {\n content: source,\n },\n },\n settings: {\n outputSelection: {\n '*': {\n '*': ['abi', 'evm.bytecode'],\n },\n },\n },\n };\n \n console.log(`Compiling contract: ${fileName}...`);\n \n // Compile the contract\n const output = JSON.parse(solc.compile(JSON.stringify(input)));\n \n // Check for errors\n if (output.errors) {\n const errors = output.errors.filter(error => error.severity === 'error');\n if (errors.length > 0) {\n console.error('Compilation errors:');\n errors.forEach(err => console.error(err.formattedMessage));\n return;\n }\n // Show warnings\n const warnings = output.errors.filter(error => error.severity === 'warning');\n warnings.forEach(warn => console.warn(warn.formattedMessage));\n }\n \n // Ensure output directories exist\n ensureDir(abiDir);\n ensureDir(artifactsDir);\n\n // Process compiled contracts\n for (const [sourceFile, contracts] of Object.entries(output.contracts)) {\n for (const [contractName, contract] of Object.entries(contracts)) {\n console.log(`Compiled contract: ${contractName}`);\n \n // Write the ABI\n const abiPath = join(abiDir, `${contractName}.json`);\n writeFileSync(abiPath, JSON.stringify(contract.abi, null, 2));\n console.log(`ABI saved to ${abiPath}`);\n \n // Write the bytecode\n const bytecodePath = join(artifactsDir, `${contractName}.bin`);\n writeFileSync(bytecodePath, contract.evm.bytecode.object);\n console.log(`Bytecode saved to ${bytecodePath}`);\n }\n }\n } catch (error) {\n console.error('Error compiling contracts:', error);\n }\n};\n\nconst solidityFilePath = join(__dirname, '../contracts/Storage.sol');\nconst abiDir = join(__dirname, '../abis');\nconst artifactsDir = join(__dirname, '../artifacts');\n\ncompileContract(solidityFilePath, abiDir, artifactsDir);\n```\n\n!!! note \n The script above is tailored to the `Storage.sol` contract. It can be adjusted for other contracts by changing the file name or modifying the ABI and bytecode paths.\n\nThe ABI (Application Binary Interface) is a JSON representation of your contract's functions, events, and their parameters. It serves as the interface between your JavaScript code and the deployed smart contract, allowing your application to know how to format function calls and interpret returned data.\n\nExecute the script above by running:\n\n```bash\nnode scripts/compile.js\n```\n\nAfter executing the script, the Solidity contract is compiled into standard EVM bytecode. The ABI and bytecode are saved into files with `.json` and `.bin` extensions, respectively. You can now proceed with deploying the contract to Polkadot Hub, as outlined in the next section."} -{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 9, "depth": 2, "title": "Deploy the Compiled Contract", "anchor": "deploy-the-compiled-contract", "start_char": 9393, "end_char": 16977, "estimated_token_count": 1599, "token_estimator": "heuristic-v1", "text": "## Deploy the Compiled Contract\n\nTo deploy your compiled contract to Polkadot Hub, you'll need a wallet with a private key to sign the deployment transaction.\n\nYou can create a `deploy.js` script in the root of your project to achieve this. The deployment script can be divided into key components:\n\n1. Set up the required imports and utilities:\n\n ```js title=\"scripts/deploy.js\"\n const { writeFileSync, existsSync, readFileSync } = require('fs');\n const { join } = require('path');\n const { ethers, JsonRpcProvider } = require('ethers');\n\n ```\n\n2. Create a provider to connect to Polkadot Hub:\n\n ```js title=\"scripts/deploy.js\"\n\n // Creates a provider with specified RPC URL and chain details\n const createProvider = (rpcUrl, chainId, chainName) => {\n const provider = new JsonRpcProvider(rpcUrl, {\n chainId: chainId,\n name: chainName,\n });\n return provider;\n };\n ```\n \n3. Set up functions to read contract artifacts:\n\n ```js title=\"scripts/deploy.js\"\n // Reads and parses the ABI file for a given contract\n const getAbi = (contractName) => {\n try {\n const abiPath = join(artifactsDir, `${contractName}.json`);\n return JSON.parse(readFileSync(abiPath, 'utf8'));\n } catch (error) {\n console.error(\n `Could not find ABI for contract ${contractName}:`,\n error.message,\n );\n throw error;\n }\n };\n\n // Reads the compiled bytecode for a given contract\n const getByteCode = (contractName) => {\n try {\n const bytecodePath = join(artifactsDir, `${contractName}.bin`);\n const bytecode = readFileSync(bytecodePath, 'utf8').trim();\n // Add 0x prefix if not present\n return bytecode.startsWith('0x') ? bytecode : `0x${bytecode}`;\n } catch (error) {\n console.error(\n `Could not find bytecode for contract ${contractName}:`,\n error.message,\n );\n throw error;\n }\n };\n\n ```\n\n4. Create the main deployment function:\n\n ```js title=\"scripts/deploy.js\"\n const deployContract = async (contractName, mnemonic, providerConfig) => {\n console.log(`Deploying ${contractName}...`);\n try {\n // Step 1: Set up provider and wallet\n const provider = createProvider(\n providerConfig.rpc,\n providerConfig.chainId,\n providerConfig.name,\n );\n const walletMnemonic = ethers.Wallet.fromPhrase(mnemonic);\n const wallet = walletMnemonic.connect(provider);\n\n // Step 2: Create and deploy the contract\n const factory = new ethers.ContractFactory(\n getAbi(contractName),\n getByteCode(contractName),\n wallet,\n );\n const contract = await factory.deploy();\n await contract.waitForDeployment();\n\n // Step 3: Save deployment information\n const address = await contract.getAddress();\n console.log(`Contract ${contractName} deployed at: ${address}`);\n\n const addressesFile = join(scriptsDir, 'contract-address.json');\n const addresses = existsSync(addressesFile)\n ? JSON.parse(readFileSync(addressesFile, 'utf8'))\n : {};\n\n addresses[contractName] = address;\n writeFileSync(addressesFile, JSON.stringify(addresses, null, 2), 'utf8');\n } catch (error) {\n console.error(`Failed to deploy contract ${contractName}:`, error);\n }\n };\n ```\n\n5. Configure and execute the deployment:\n\n ```js title=\"scripts/deploy.js\"\n \n ```\n\n !!! note\n A mnemonic (seed phrase) is a series of words that can generate multiple private keys and their corresponding addresses. It's used here to derive the wallet that will sign and pay for the deployment transaction. **Always keep your mnemonic secure and never share it publicly**.\n\n Ensure to replace the `INSERT_MNEMONIC` placeholder with your actual mnemonic.\n\n??? code \"View complete script\"\n\n ```js title=\"scripts/deploy.js\"\n const { writeFileSync, existsSync, readFileSync } = require('fs');\n const { join } = require('path');\n const { ethers, JsonRpcProvider } = require('ethers');\n\n const scriptsDir = __dirname;\n const artifactsDir = join(__dirname, '../contracts');\n\n // Creates a provider with specified RPC URL and chain details\n const createProvider = (rpcUrl, chainId, chainName) => {\n const provider = new JsonRpcProvider(rpcUrl, {\n chainId: chainId,\n name: chainName,\n });\n return provider;\n };\n\n // Reads and parses the ABI file for a given contract\n const getAbi = (contractName) => {\n try {\n const abiPath = join(artifactsDir, `${contractName}.json`);\n return JSON.parse(readFileSync(abiPath, 'utf8'));\n } catch (error) {\n console.error(\n `Could not find ABI for contract ${contractName}:`,\n error.message,\n );\n throw error;\n }\n };\n\n // Reads the compiled bytecode for a given contract\n const getByteCode = (contractName) => {\n try {\n const bytecodePath = join(artifactsDir, `${contractName}.bin`);\n const bytecode = readFileSync(bytecodePath, 'utf8').trim();\n // Add 0x prefix if not present\n return bytecode.startsWith('0x') ? bytecode : `0x${bytecode}`;\n } catch (error) {\n console.error(\n `Could not find bytecode for contract ${contractName}:`,\n error.message,\n );\n throw error;\n }\n };\n\n const deployContract = async (contractName, mnemonic, providerConfig) => {\n console.log(`Deploying ${contractName}...`);\n try {\n // Step 1: Set up provider and wallet\n const provider = createProvider(\n providerConfig.rpc,\n providerConfig.chainId,\n providerConfig.name,\n );\n const walletMnemonic = ethers.Wallet.fromPhrase(mnemonic);\n const wallet = walletMnemonic.connect(provider);\n\n // Step 2: Create and deploy the contract\n const factory = new ethers.ContractFactory(\n getAbi(contractName),\n getByteCode(contractName),\n wallet,\n );\n const contract = await factory.deploy();\n await contract.waitForDeployment();\n\n // Step 3: Save deployment information\n const address = await contract.getAddress();\n console.log(`Contract ${contractName} deployed at: ${address}`);\n\n const addressesFile = join(scriptsDir, 'contract-address.json');\n const addresses = existsSync(addressesFile)\n ? JSON.parse(readFileSync(addressesFile, 'utf8'))\n : {};\n\n addresses[contractName] = address;\n writeFileSync(addressesFile, JSON.stringify(addresses, null, 2), 'utf8');\n } catch (error) {\n console.error(`Failed to deploy contract ${contractName}:`, error);\n }\n };\n\n const providerConfig = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', #TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready\n chainId: 420420422,\n name: 'polkadot-hub-testnet',\n };\n\n const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon';\n\n deployContract('Storage', mnemonic, providerConfig);\n ```\n\nTo run the script, execute the following command:\n\n```bash\nnode scripts/deploy.js\n```\n\nAfter running this script, your contract will be deployed to Polkadot Hub, and its address will be saved in `contract-address.json` within your project directory. You can use this address for future contract interactions."} -{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 10, "depth": 2, "title": "Interact with the Contract", "anchor": "interact-with-the-contract", "start_char": 16977, "end_char": 20528, "estimated_token_count": 769, "token_estimator": "heuristic-v1", "text": "## Interact with the Contract\n\nOnce the contract is deployed, you can interact with it by calling its functions. For example, to set a number, read it and then modify that number by its double, you can create a file named `checkStorage.js` in the root of your project and add the following code:\n\n```js title=\"scripts/checkStorage.js\"\nconst { ethers } = require('ethers');\nconst { readFileSync } = require('fs');\nconst { join } = require('path');\n\nconst artifactsDir = join(__dirname, '../contracts');\n\nconst createProvider = (providerConfig) => {\n return new ethers.JsonRpcProvider(providerConfig.rpc, {\n chainId: providerConfig.chainId,\n name: providerConfig.name,\n });\n};\n\nconst createWallet = (mnemonic, provider) => {\n return ethers.Wallet.fromPhrase(mnemonic).connect(provider);\n};\n\nconst loadContractAbi = (contractName, directory = artifactsDir) => {\n const contractPath = join(directory, `${contractName}.json`);\n const contractJson = JSON.parse(readFileSync(contractPath, 'utf8'));\n return contractJson.abi || contractJson; // Depending on JSON structure\n};\n\nconst createContract = (contractAddress, abi, wallet) => {\n return new ethers.Contract(contractAddress, abi, wallet);\n};\n\nconst interactWithStorageContract = async (\n contractName,\n contractAddress,\n mnemonic,\n providerConfig,\n numberToSet,\n) => {\n try {\n console.log(`Setting new number in Storage contract: ${numberToSet}`);\n\n // Create provider and wallet\n const provider = createProvider(providerConfig);\n const wallet = createWallet(mnemonic, provider);\n\n // Load the contract ABI and create the contract instance\n const abi = loadContractAbi(contractName);\n const contract = createContract(contractAddress, abi, wallet);\n\n // Send a transaction to set the stored number\n const tx1 = await contract.setNumber(numberToSet);\n await tx1.wait(); // Wait for the transaction to be mined\n console.log(`Number successfully set to ${numberToSet}`);\n\n // Retrieve the updated number\n const storedNumber = await contract.storedNumber();\n console.log(`Retrieved stored number:`, storedNumber.toString());\n\n // Send a transaction to set the stored number\n const tx2 = await contract.setNumber(numberToSet * 2);\n await tx2.wait(); // Wait for the transaction to be mined\n console.log(`Number successfully set to ${numberToSet * 2}`);\n\n // Retrieve the updated number\n const updatedNumber = await contract.storedNumber();\n console.log(`Retrieved stored number:`, updatedNumber.toString());\n } catch (error) {\n console.error('Error interacting with Storage contract:', error.message);\n }\n};\n\nconst providerConfig = {\n name: 'asset-hub-smart-contracts',\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io',\n chainId: 420420422,\n};\n\nconst mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon';\nconst contractName = 'Storage';\nconst contractAddress = '0x83e43892a98f924706E9DB7917244897dC8b8126';\nconst newNumber = 42;\n\ninteractWithStorageContract(\n contractName,\n contractAddress,\n mnemonic,\n providerConfig,\n newNumber,\n);\n```\n\nEnsure you replace the `INSERT_MNEMONIC`, `INSERT_CONTRACT_ADDRESS`, and `INSERT_ADDRESS_TO_CHECK` placeholders with actual values. Also, ensure the contract ABI file (`Storage.json`) is correctly referenced. The script prints the balance for `ADDRESS_TO_CHECK` before it writes and doubles the stored value, so pick any account you want to monitor.\n\nTo interact with the contract, run:\n\n```bash\nnode scripts/checkStorage.js\n```"} -{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 11, "depth": 2, "title": "Where to Go Next", "anchor": "where-to-go-next", "start_char": 20528, "end_char": 21133, "estimated_token_count": 155, "token_estimator": "heuristic-v1", "text": "## Where to Go Next\n\nNow that you have the foundational knowledge to use Ethers.js with Polkadot Hub, you can:\n\n- **Dive into Ethers.js utilities**: Discover additional Ethers.js features, such as wallet management, signing messages, etc.\n- **Implement batch transactions**: Use Ethers.js to execute batch transactions for efficient multi-step contract interactions.\n- **Build scalable applications**: Combine Ethers.js with frameworks like [`Next.js`](https://nextjs.org/docs){target=\\_blank} or [`Node.js`](https://nodejs.org/en){target=\\_blank} to create full-stack decentralized applications (dApps)."} +{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 9, "depth": 2, "title": "Deploy the Compiled Contract", "anchor": "deploy-the-compiled-contract", "start_char": 9393, "end_char": 17368, "estimated_token_count": 1692, "token_estimator": "heuristic-v1", "text": "## Deploy the Compiled Contract\n\nTo deploy your compiled contract to Polkadot Hub, you'll need a wallet with a private key to sign the deployment transaction.\n\nYou can create a `deploy.js` script in the root of your project to achieve this. The deployment script can be divided into key components:\n\n1. Set up the required imports and utilities:\n\n ```js title=\"scripts/deploy.js\"\n const { writeFileSync, existsSync, readFileSync } = require('fs');\n const { join } = require('path');\n const { ethers, JsonRpcProvider } = require('ethers');\n\n ```\n\n2. Create a provider to connect to Polkadot Hub:\n\n ```js title=\"scripts/deploy.js\"\n\n // Creates a provider with specified RPC URL and chain details\n const createProvider = (rpcUrl, chainId, chainName) => {\n const provider = new JsonRpcProvider(rpcUrl, {\n chainId: chainId,\n name: chainName,\n });\n return provider;\n };\n ```\n \n3. Set up functions to read contract artifacts:\n\n ```js title=\"scripts/deploy.js\"\n // Reads and parses the ABI file for a given contract\n const getAbi = (contractName) => {\n try {\n const abiPath = join(artifactsDir, `${contractName}.json`);\n return JSON.parse(readFileSync(abiPath, 'utf8'));\n } catch (error) {\n console.error(\n `Could not find ABI for contract ${contractName}:`,\n error.message,\n );\n throw error;\n }\n };\n\n // Reads the compiled bytecode for a given contract\n const getByteCode = (contractName) => {\n try {\n const bytecodePath = join(artifactsDir, `${contractName}.bin`);\n const bytecode = readFileSync(bytecodePath, 'utf8').trim();\n // Add 0x prefix if not present\n return bytecode.startsWith('0x') ? bytecode : `0x${bytecode}`;\n } catch (error) {\n console.error(\n `Could not find bytecode for contract ${contractName}:`,\n error.message,\n );\n throw error;\n }\n };\n\n ```\n\n4. Create the main deployment function:\n\n ```js title=\"scripts/deploy.js\"\n const deployContract = async (contractName, mnemonic, providerConfig) => {\n console.log(`Deploying ${contractName}...`);\n try {\n // Step 1: Set up provider and wallet\n const provider = createProvider(\n providerConfig.rpc,\n providerConfig.chainId,\n providerConfig.name,\n );\n const walletMnemonic = ethers.Wallet.fromPhrase(mnemonic);\n const wallet = walletMnemonic.connect(provider);\n\n // Step 2: Create and deploy the contract\n const factory = new ethers.ContractFactory(\n getAbi(contractName),\n getByteCode(contractName),\n wallet,\n );\n const contract = await factory.deploy();\n await contract.waitForDeployment();\n\n // Step 3: Save deployment information\n const address = await contract.getAddress();\n console.log(`Contract ${contractName} deployed at: ${address}`);\n\n const addressesFile = join(scriptsDir, 'contract-address.json');\n const addresses = existsSync(addressesFile)\n ? JSON.parse(readFileSync(addressesFile, 'utf8'))\n : {};\n\n addresses[contractName] = address;\n writeFileSync(addressesFile, JSON.stringify(addresses, null, 2), 'utf8');\n } catch (error) {\n console.error(`Failed to deploy contract ${contractName}:`, error);\n }\n };\n ```\n\n5. Configure and execute the deployment:\n\n ```js title=\"scripts/deploy.js\"\n const providerConfig = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', #TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready\n chainId: 420420422,\n name: 'polkadot-hub-testnet',\n };\n\n const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon';\n\n deployContract('Storage', mnemonic, providerConfig);\n ```\n\n !!! note\n A mnemonic (seed phrase) is a series of words that can generate multiple private keys and their corresponding addresses. It's used here to derive the wallet that will sign and pay for the deployment transaction. **Always keep your mnemonic secure and never share it publicly**.\n\n Ensure to replace the `INSERT_MNEMONIC` placeholder with your actual mnemonic.\n\n??? code \"View complete script\"\n\n ```js title=\"scripts/deploy.js\"\n const { writeFileSync, existsSync, readFileSync } = require('fs');\n const { join } = require('path');\n const { ethers, JsonRpcProvider } = require('ethers');\n\n const scriptsDir = __dirname;\n const artifactsDir = join(__dirname, '../contracts');\n\n // Creates a provider with specified RPC URL and chain details\n const createProvider = (rpcUrl, chainId, chainName) => {\n const provider = new JsonRpcProvider(rpcUrl, {\n chainId: chainId,\n name: chainName,\n });\n return provider;\n };\n\n // Reads and parses the ABI file for a given contract\n const getAbi = (contractName) => {\n try {\n const abiPath = join(artifactsDir, `${contractName}.json`);\n return JSON.parse(readFileSync(abiPath, 'utf8'));\n } catch (error) {\n console.error(\n `Could not find ABI for contract ${contractName}:`,\n error.message,\n );\n throw error;\n }\n };\n\n // Reads the compiled bytecode for a given contract\n const getByteCode = (contractName) => {\n try {\n const bytecodePath = join(artifactsDir, `${contractName}.bin`);\n const bytecode = readFileSync(bytecodePath, 'utf8').trim();\n // Add 0x prefix if not present\n return bytecode.startsWith('0x') ? bytecode : `0x${bytecode}`;\n } catch (error) {\n console.error(\n `Could not find bytecode for contract ${contractName}:`,\n error.message,\n );\n throw error;\n }\n };\n\n const deployContract = async (contractName, mnemonic, providerConfig) => {\n console.log(`Deploying ${contractName}...`);\n try {\n // Step 1: Set up provider and wallet\n const provider = createProvider(\n providerConfig.rpc,\n providerConfig.chainId,\n providerConfig.name,\n );\n const walletMnemonic = ethers.Wallet.fromPhrase(mnemonic);\n const wallet = walletMnemonic.connect(provider);\n\n // Step 2: Create and deploy the contract\n const factory = new ethers.ContractFactory(\n getAbi(contractName),\n getByteCode(contractName),\n wallet,\n );\n const contract = await factory.deploy();\n await contract.waitForDeployment();\n\n // Step 3: Save deployment information\n const address = await contract.getAddress();\n console.log(`Contract ${contractName} deployed at: ${address}`);\n\n const addressesFile = join(scriptsDir, 'contract-address.json');\n const addresses = existsSync(addressesFile)\n ? JSON.parse(readFileSync(addressesFile, 'utf8'))\n : {};\n\n addresses[contractName] = address;\n writeFileSync(addressesFile, JSON.stringify(addresses, null, 2), 'utf8');\n } catch (error) {\n console.error(`Failed to deploy contract ${contractName}:`, error);\n }\n };\n\n const providerConfig = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', #TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready\n chainId: 420420422,\n name: 'polkadot-hub-testnet',\n };\n\n const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon';\n\n deployContract('Storage', mnemonic, providerConfig);\n ```\n\nTo run the script, execute the following command:\n\n```bash\nnode scripts/deploy.js\n```\n\nAfter running this script, your contract will be deployed to Polkadot Hub, and its address will be saved in `contract-address.json` within your project directory. You can use this address for future contract interactions."} +{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 10, "depth": 2, "title": "Interact with the Contract", "anchor": "interact-with-the-contract", "start_char": 17368, "end_char": 20808, "estimated_token_count": 751, "token_estimator": "heuristic-v1", "text": "## Interact with the Contract\n\nOnce the contract is deployed, you can interact with it by calling its functions. For example, to set a number, read it and then modify that number by its double, you can create a file named `checkStorage.js` in the root of your project and add the following code:\n\n```js title=\"scripts/checkStorage.js\"\nconst { ethers } = require('ethers');\nconst { readFileSync } = require('fs');\nconst { join } = require('path');\n\nconst artifactsDir = join(__dirname, '../contracts');\n\nconst createProvider = (providerConfig) => {\n return new ethers.JsonRpcProvider(providerConfig.rpc, {\n chainId: providerConfig.chainId,\n name: providerConfig.name,\n });\n};\n\nconst createWallet = (mnemonic, provider) => {\n return ethers.Wallet.fromPhrase(mnemonic).connect(provider);\n};\n\nconst loadContractAbi = (contractName, directory = artifactsDir) => {\n const contractPath = join(directory, `${contractName}.json`);\n const contractJson = JSON.parse(readFileSync(contractPath, 'utf8'));\n return contractJson.abi || contractJson; // Depending on JSON structure\n};\n\nconst createContract = (contractAddress, abi, wallet) => {\n return new ethers.Contract(contractAddress, abi, wallet);\n};\n\nconst interactWithStorageContract = async (\n contractName,\n contractAddress,\n mnemonic,\n providerConfig,\n numberToSet,\n) => {\n try {\n console.log(`Setting new number in Storage contract: ${numberToSet}`);\n\n // Create provider and wallet\n const provider = createProvider(providerConfig);\n const wallet = createWallet(mnemonic, provider);\n\n // Load the contract ABI and create the contract instance\n const abi = loadContractAbi(contractName);\n const contract = createContract(contractAddress, abi, wallet);\n\n // Send a transaction to set the stored number\n const tx1 = await contract.setNumber(numberToSet);\n await tx1.wait(); // Wait for the transaction to be mined\n console.log(`Number successfully set to ${numberToSet}`);\n\n // Retrieve the updated number\n const storedNumber = await contract.storedNumber();\n console.log(`Retrieved stored number:`, storedNumber.toString());\n\n // Send a transaction to set the stored number\n const tx2 = await contract.setNumber(numberToSet * 2);\n await tx2.wait(); // Wait for the transaction to be mined\n console.log(`Number successfully set to ${numberToSet * 2}`);\n\n // Retrieve the updated number\n const updatedNumber = await contract.storedNumber();\n console.log(`Retrieved stored number:`, updatedNumber.toString());\n } catch (error) {\n console.error('Error interacting with Storage contract:', error.message);\n }\n};\n\nconst providerConfig = {\n name: 'asset-hub-smart-contracts',\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io',\n chainId: 420420422,\n};\n\nconst mnemonic = 'INSERT_MNEMONIC'\nconst contractName = 'Storage';\nconst contractAddress = 'INSERT_CONTRACT_ADDRESS'\nconst newNumber = 42;\n\ninteractWithStorageContract(\n contractName,\n contractAddress,\n mnemonic,\n providerConfig,\n newNumber,\n);\n```\n\nEnsure you replace the `INSERT_MNEMONIC` and `INSERT_CONTRACT_ADDRESS` placeholders with actual values. Also, ensure the contract ABI file (`Storage.json`) is correctly referenced. The script prints the balance for `ADDRESS_TO_CHECK` before it writes and doubles the stored value, so pick any account you want to monitor.\n\nTo interact with the contract, run:\n\n```bash\nnode scripts/checkStorage.js\n```"} +{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 11, "depth": 2, "title": "Where to Go Next", "anchor": "where-to-go-next", "start_char": 20808, "end_char": 21413, "estimated_token_count": 155, "token_estimator": "heuristic-v1", "text": "## Where to Go Next\n\nNow that you have the foundational knowledge to use Ethers.js with Polkadot Hub, you can:\n\n- **Dive into Ethers.js utilities**: Discover additional Ethers.js features, such as wallet management, signing messages, etc.\n- **Implement batch transactions**: Use Ethers.js to execute batch transactions for efficient multi-step contract interactions.\n- **Build scalable applications**: Combine Ethers.js with frameworks like [`Next.js`](https://nextjs.org/docs){target=\\_blank} or [`Node.js`](https://nodejs.org/en){target=\\_blank} to create full-stack decentralized applications (dApps)."} {"page_id": "smart-contracts-libraries-viem", "page_title": "viem for Polkadot Hub Smart Contracts", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 178, "end_char": 455, "estimated_token_count": 56, "token_estimator": "heuristic-v1", "text": "## Introduction\n\n[viem](https://viem.sh/){target=\\_blank} is a lightweight TypeScript library designed for interacting with Ethereum-compatible blockchains. This comprehensive guide will walk you through using viem to interact with and deploy smart contracts to Polkadot Hub."} {"page_id": "smart-contracts-libraries-viem", "page_title": "viem for Polkadot Hub Smart Contracts", "index": 1, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 455, "end_char": 811, "estimated_token_count": 110, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore getting started, ensure you have the following installed:\n\n- **Node.js**: v22.13.1 or later, check the [Node.js installation guide](https://nodejs.org/en/download/current/){target=\\_blank}.\n- **npm**: v6.13.4 or later (comes bundled with Node.js).\n- **Solidity**: This guide uses Solidity `^0.8.9` for smart contract development."} {"page_id": "smart-contracts-libraries-viem", "page_title": "viem for Polkadot Hub Smart Contracts", "index": 2, "depth": 2, "title": "Project Structure", "anchor": "project-structure", "start_char": 811, "end_char": 1231, "estimated_token_count": 119, "token_estimator": "heuristic-v1", "text": "## Project Structure\n\nThis project organizes contracts, scripts, and compiled artifacts for easy development and deployment.\n\n```text\nviem-project/\n├── package.json\n├── tsconfig.json\n├── src/\n│ ├── chainConfig.ts\n│ ├── createClient.ts\n│ ├── createWallet.ts\n│ ├── compile.ts\n│ ├── deploy.ts\n│ └── interact.ts\n├── contracts/\n│ └── Storage.sol\n└── artifacts/\n ├── Storage.json\n └── Storage.polkavm\n```"} @@ -1145,16 +1145,16 @@ {"page_id": "smart-contracts-libraries-wagmi", "page_title": "Wagmi for Polkadot Hub Smart Contracts", "index": 7, "depth": 2, "title": "Interact with Deployed Contract", "anchor": "interact-with-deployed-contract", "start_char": 6700, "end_char": 11209, "estimated_token_count": 989, "token_estimator": "heuristic-v1", "text": "## Interact with Deployed Contract\n\nThis guide uses a simple Storage contract already deployed to the Polkadot Hub TestNet (`0x58053f0e8ede1a47a1af53e43368cd04ddcaf66f`). The code of that contract is:\n\n??? code \"Storage.sol\"\n\n ```solidity title=\"Storage.sol\"\n //SPDX-License-Identifier: MIT\n\n // Solidity files have to start with this pragma.\n // It will be used by the Solidity compiler to validate its version.\n pragma solidity ^0.8.9;\n\n contract Storage {\n // Public state variable to store a number\n uint256 public storedNumber;\n\n /**\n * Updates the stored number.\n *\n * The `public` modifier allows anyone to call this function.\n *\n * @param _newNumber - The new value to store.\n */\n function setNumber(uint256 _newNumber) public {\n storedNumber = _newNumber;\n }\n }\n ```\n\nCreate a component to interact with your deployed contract. Create a file named `app/components/StorageContract.tsx`:\n\n```typescript title=\"app/components/StorageContract.tsx\"\n\"use client\";\n\nimport { useState } from \"react\";\nimport {\n useReadContract,\n useWriteContract,\n useWaitForTransactionReceipt,\n} from \"wagmi\";\n\nconst CONTRACT_ADDRESS =\n \"0xabBd46Ef74b88E8B1CDa49BeFb5057710443Fd29\" as `0x${string}`;\n\nexport function StorageContract() {\n const [number, setNumber] = useState(\"42\");\n\n // Contract ABI (should match your compiled contract)\n const abi = [\n {\n inputs: [],\n name: \"storedNumber\",\n outputs: [{ internalType: \"uint256\", name: \"\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [\n { internalType: \"uint256\", name: \"_newNumber\", type: \"uint256\" },\n ],\n name: \"setNumber\",\n outputs: [],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n ];\n\n // Read the current stored number\n const { data: storedNumber, refetch } = useReadContract({\n address: CONTRACT_ADDRESS,\n abi,\n functionName: \"storedNumber\",\n });\n\n // Write to the contract\n const { writeContract, data: hash, error, isPending } = useWriteContract();\n\n // Wait for transaction to be mined\n const { isLoading: isConfirming, isSuccess: isConfirmed } =\n useWaitForTransactionReceipt({\n hash,\n });\n\n const handleSetNumber = () => {\n writeContract({\n address: CONTRACT_ADDRESS,\n abi,\n functionName: \"setNumber\",\n args: [BigInt(number)],\n });\n };\n\n return (\n
\n

Storage Contract Interaction

\n
\n

Contract Address: {CONTRACT_ADDRESS}

\n

Current Stored Number: {storedNumber?.toString() || \"Loading...\"}

\n
\n\n
\n setNumber(e.target.value)}\n disabled={isPending || isConfirming}\n />\n \n
\n\n {error &&
Error: {error.message}
}\n\n {isConfirmed && (\n
\n Successfully updated!{\" \"}\n \n
\n )}\n
\n );\n}\n\n```\n\nThis component demonstrates how to interact with a smart contract using Wagmi's hooks:\n\n- **[`useReadContract`](https://wagmi.sh/react/api/hooks/useReadContract#useReadContract){target=\\_blank}**: Calls a read-only function on your smart contract to retrieve data without modifying the blockchain state.\n- **[`useWriteContract`](https://wagmi.sh/react/api/hooks/useWriteContract#useWriteContract){target=\\_blank}**: Calls a state-modifying function on your smart contract, which requires a transaction to be signed and sent.\n- **[`useWaitForTransactionReceipt`](https://wagmi.sh/react/api/hooks/useWaitForTransactionReceipt#useWaitForTransactionReceipt){target=\\_blank}**: Tracks the status of a transaction after it's been submitted, allowing you to know when it's been confirmed.\n\nThe component also includes proper state handling to:\n\n- Show the current value stored in the contract.\n- Allow users to input a new value.\n- Display transaction status (pending, confirming, or completed).\n- Handle errors.\n- Provide feedback when a transaction is successful."} {"page_id": "smart-contracts-libraries-wagmi", "page_title": "Wagmi for Polkadot Hub Smart Contracts", "index": 8, "depth": 2, "title": "Integrate Components", "anchor": "integrate-components", "start_char": 11209, "end_char": 11961, "estimated_token_count": 183, "token_estimator": "heuristic-v1", "text": "## Integrate Components\n\nUpdate your main page to combine all the components. Create or update the file `src/app/page.tsx`:\n\n```typescript title=\"src/app/page.tsx\"\n\"use client\";\n\nimport { BlockchainInfo } from \"./components/BlockchainInfo\";\nimport { ConnectWallet } from \"./components/ConnectWallet\";\nimport { StorageContract } from \"./components/StorageContract\";\nimport { useAccount } from \"wagmi\";\n\nexport default function Home() {\n const { isConnected } = useAccount();\n\n return (\n
\n

Wagmi - Polkadot Hub Smart Contracts

\n \n {isConnected ? : Connect your wallet}\n {isConnected ? : Connect your wallet}\n
\n );\n}\n\n```"} {"page_id": "smart-contracts-libraries-wagmi", "page_title": "Wagmi for Polkadot Hub Smart Contracts", "index": 9, "depth": 2, "title": "Where to Go Next", "anchor": "where-to-go-next", "start_char": 11961, "end_char": 13604, "estimated_token_count": 512, "token_estimator": "heuristic-v1", "text": "## Where to Go Next\n\nNow that you have the foundational knowledge to use Wagmi with Polkadot Hub, consider exploring:\n\n
\n\n- External __Advanced Wagmi__\n\n ---\n\n Explore Wagmi's advanced features:\n\n
    \n
  • [:octicons-arrow-right-24: Watch Contract Events](https://wagmi.sh/core/api/actions/watchContractEvent#eventname){target=\\_blank}
  • \n
  • [:octicons-arrow-right-24: Different Transports](https://wagmi.sh/react/api/transports){target=\\_blank}
  • \n
  • [:octicons-arrow-right-24: Actions](https://wagmi.sh/react/api/actions){target=\\_blank}
  • \n
\n\n- External __Wallet Integration__\n\n ---\n\n Connect your dApp with popular wallet providers:\n\n
    \n
  • [:octicons-arrow-right-24: MetaMask](https://wagmi.sh/core/api/connectors/metaMask){target=\\_blank}
  • \n
  • [:octicons-arrow-right-24: WalletConnect](https://wagmi.sh/core/api/connectors/walletConnect){target=\\_blank}
  • \n
  • [:octicons-arrow-right-24: Coinbase Wallet](https://wagmi.sh/core/api/connectors/coinbaseWallet){target=\\_blank}
  • \n
\n\n- External __Testing & Development__\n\n ---\n\n Enhance your development workflow:\n\n
    \n
  • [:octicons-arrow-right-24: Test Suite](https://wagmi.sh/dev/contributing#_6-running-the-test-suite){target=\\_blank}
  • \n
  • [:octicons-arrow-right-24: Dev Playground](https://wagmi.sh/dev/contributing#_5-running-the-dev-playgrounds){target=\\_blank}
  • \n
\n
"} -{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 468, "end_char": 1027, "estimated_token_count": 102, "token_estimator": "heuristic-v1", "text": "## Introduction\n\nInteracting with blockchains typically requires an interface between your application and the network. [Web3.js](https://web3js.readthedocs.io/){target=\\_blank} offers this interface through a comprehensive collection of libraries, facilitating seamless interaction with the nodes using HTTP or WebSocket protocols. This guide illustrates how to utilize Web3.js specifically for interactions with Polkadot Hub.\n\nThis guide is intended for developers who are familiar with JavaScript and want to interact with the Polkadot Hub using Web3.js."} -{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 1, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 1027, "end_char": 1383, "estimated_token_count": 110, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore getting started, ensure you have the following installed:\n\n- **Node.js**: v22.13.1 or later, check the [Node.js installation guide](https://nodejs.org/en/download/current/){target=\\_blank}.\n- **npm**: v6.13.4 or later (comes bundled with Node.js).\n- **Solidity**: This guide uses Solidity `^0.8.9` for smart contract development."} -{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 2, "depth": 2, "title": "Project Structure", "anchor": "project-structure", "start_char": 1383, "end_char": 1868, "estimated_token_count": 136, "token_estimator": "heuristic-v1", "text": "## Project Structure\n\nThis project organizes contracts, scripts, and compiled artifacts for easy development and deployment.\n\n```text title=\"Web3.js Polkadot Hub\"\nweb3js-project\n├── contracts\n│ ├── Storage.sol\n├── scripts\n│ ├── connectToProvider.js\n│ ├── fetchLastBlock.js\n│ ├── compile.js\n│ ├── deploy.js\n│ ├── updateStorage.js\n├── abis\n│ ├── Storage.json\n├── artifacts\n│ ├── Storage.polkavm\n├── node_modules/\n├── package.json\n├── package-lock.json\n└── README.md\n```"} -{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 3, "depth": 2, "title": "Set Up the Project", "anchor": "set-up-the-project", "start_char": 1868, "end_char": 1984, "estimated_token_count": 31, "token_estimator": "heuristic-v1", "text": "## Set Up the Project\n\nTo start working with Web3.js, begin by initializing your project:\n\n```bash\nnpm init -y\n```"} -{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 4, "depth": 2, "title": "Install Dependencies", "anchor": "install-dependencies", "start_char": 1984, "end_char": 2117, "estimated_token_count": 38, "token_estimator": "heuristic-v1", "text": "## Install Dependencies\n\nNext, install the Web3.js library:\n\n```bash\nnpm install web3\n```\n\nThis guide uses `web3` version `4.16.0`."} -{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 5, "depth": 2, "title": "Set Up the Web3 Provider", "anchor": "set-up-the-web3-provider", "start_char": 2117, "end_char": 3950, "estimated_token_count": 425, "token_estimator": "heuristic-v1", "text": "## Set Up the Web3 Provider\n\nThe provider configuration is the foundation of any Web3.js application. The following example establishes a connection to Polkadot Hub. To use the example script, replace `INSERT_RPC_URL`, `INSERT_CHAIN_ID`, and `INSERT_CHAIN_NAME` with the appropriate values. The provider connection script should look something like this:\n\n```javascript title=\"scripts/connectToProvider.js\"\nconst { Web3 } = require('web3');\n\nconst createProvider = (rpcUrl) => {\n const web3 = new Web3(rpcUrl);\n return web3;\n};\n\nconst PROVIDER_RPC = {\n rpc: 'INSERT_RPC_URL',\n chainId: 'INSERT_CHAIN_ID',\n name: 'INSERT_CHAIN_NAME',\n};\n\ncreateProvider(PROVIDER_RPC.rpc);\n\n```\n\nFor example, for the Polkadot Hub TestNet, use these specific connection parameters:\n\n```js\nconst PROVIDER_RPC = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io',\n chainId: 420420422,\n name: 'polkadot-hub-testnet'\n};\n```\n\nWith the Web3 provider set up, you can start querying the blockchain.\n\nFor instance, to fetch the latest block number of the chain, you can use the following code snippet:\n\n???+ code \"View complete script\"\n\n ```javascript title=\"scripts/fetchLastBlock.js\"\n const { Web3 } = require('web3');\n\n const createProvider = (rpcUrl) => {\n const web3 = new Web3(rpcUrl);\n return web3;\n };\n\n const PROVIDER_RPC = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io',\n chainId: 420420422,\n name: 'polkadot-hub-testnet',\n };\n\n const main = async () => {\n try {\n const web3 = createProvider(PROVIDER_RPC.rpc);\n const latestBlock = await web3.eth.getBlockNumber();\n console.log('Last block: ' + latestBlock);\n } catch (error) {\n console.error('Error connecting to Polkadot Hub TestNet: ' + error.message);\n }\n };\n\n main();\n\n ```"} -{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 6, "depth": 2, "title": "Compile Contracts", "anchor": "compile-contracts", "start_char": 3950, "end_char": 7431, "estimated_token_count": 840, "token_estimator": "heuristic-v1", "text": "## Compile Contracts\n\n!!! note \"Contracts Code Blob Size Disclaimer\"\n The maximum contract code blob size on Polkadot Hub networks is _100 kilobytes_, significantly larger than Ethereum’s EVM limit of 24 kilobytes.\n\n For detailed comparisons and migration guidelines, see the [EVM vs. PolkaVM](/polkadot-protocol/smart-contract-basics/evm-vs-polkavm/#current-memory-limits){target=\\_blank} documentation page.\n\nPolkadot Hub requires contracts to be compiled to [PolkaVM](/smart-contracts/for-eth-devs/dual-vm-stack/){target=\\_blank} bytecode. This is achieved using the [`revive`](https://github.com/paritytech/revive/tree/v0.2.0/js/resolc){target=\\_blank} compiler. Install the [`@parity/resolc`](https://github.com/paritytech/revive){target=\\_blank} library as a development dependency:\n\n```bash\nnpm install --save-dev @parity/resolc\n```\n\nThis guide uses `@parity/resolc` version `0.2.0`.\n\nHere's a simple storage contract that you can use to follow the process:\n\n```solidity title=\"contracts/Storage.sol\"\n//SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\ncontract Storage {\n // Public state variable to store a number\n uint256 public storedNumber;\n\n /**\n * Updates the stored number.\n *\n * The `public` modifier allows anyone to call this function.\n *\n * @param _newNumber - The new value to store.\n */\n function setNumber(uint256 _newNumber) public {\n storedNumber = _newNumber;\n }\n}\n```\n\nWith that, you can now create a `compile.js` snippet that transforms your solidity code into PolkaVM bytecode:\n\n```javascript title=\"scripts/compile.js\"\nconst { compile } = require('@parity/resolc');\nconst { readFileSync, writeFileSync } = require('fs');\nconst { basename, join } = require('path');\n\nconst compileContract = async (solidityFilePath, outputDir) => {\n try {\n // Read the Solidity file\n const source = readFileSync(solidityFilePath, 'utf8');\n\n // Construct the input object for the compiler\n const input = {\n [basename(solidityFilePath)]: { content: source },\n };\n\n console.log(`Compiling contract: ${basename(solidityFilePath)}...`);\n\n // Compile the contract\n const out = await compile(input);\n\n for (const contracts of Object.values(out.contracts)) {\n for (const [name, contract] of Object.entries(contracts)) {\n console.log(`Compiled contract: ${name}`);\n\n // Write the ABI\n const abiPath = join(outputDir, `${name}.json`);\n writeFileSync(abiPath, JSON.stringify(contract.abi, null, 2));\n console.log(`ABI saved to ${abiPath}`);\n\n // Write the bytecode\n const bytecodePath = join(outputDir, `${name}.polkavm`);\n writeFileSync(\n bytecodePath,\n Buffer.from(contract.evm.bytecode.object, 'hex'),\n );\n console.log(`Bytecode saved to ${bytecodePath}`);\n }\n }\n } catch (error) {\n console.error('Error compiling contracts:', error);\n }\n};\n\nconst solidityFilePath = './Storage.sol';\nconst outputDir = '.';\n\ncompileContract(solidityFilePath, outputDir);\n\n```\n\nTo compile your contract, simply run the following command:\n\n```bash\nnode compile\n```\n\nAfter compilation, you'll have two key files: an ABI (`.json`) file, which provides a JSON interface describing the contract's functions and how to interact with it, and a bytecode (`.polkavm`) file, which contains the low-level machine code executable on PolkaVM that represents the compiled smart contract ready for blockchain deployment."} -{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 7, "depth": 2, "title": "Contract Deployment", "anchor": "contract-deployment", "start_char": 7431, "end_char": 10374, "estimated_token_count": 674, "token_estimator": "heuristic-v1", "text": "## Contract Deployment\n\nTo deploy your compiled contract to Polkadot Hub using Web3.js, you'll need an account with a private key to sign the deployment transaction. The deployment process is exactly the same as for any Ethereum-compatible chain, involving creating a contract instance, estimating gas, and sending a deployment transaction. Here's how to deploy the contract, ensure replacing the `INSERT_RPC_URL`, `INSERT_PRIVATE_KEY`, and `INSERT_CONTRACT_NAME` with the appropriate values:\n\n```javascript title=\"scripts/deploy.js\"\nimport { readFileSync } from 'fs';\nimport { Web3 } from 'web3';\n\nconst getAbi = (contractName) => {\n try {\n return JSON.parse(readFileSync(`${contractName}.json`), 'utf8');\n } catch (error) {\n console.error(\n `❌ Could not find ABI for contract ${contractName}:`,\n error.message\n );\n throw error;\n }\n};\n\nconst getByteCode = (contractName) => {\n try {\n return `0x${readFileSync(`${contractName}.polkavm`).toString('hex')}`;\n } catch (error) {\n console.error(\n `❌ Could not find bytecode for contract ${contractName}:`,\n error.message\n );\n throw error;\n }\n};\n\nexport const deploy = async (config) => {\n try {\n // Initialize Web3 with RPC URL\n const web3 = new Web3(config.rpcUrl);\n\n // Prepare account\n const account = web3.eth.accounts.privateKeyToAccount(config.privateKey);\n web3.eth.accounts.wallet.add(account);\n\n // Load abi\n const abi = getAbi('Storage');\n\n // Create contract instance\n const contract = new web3.eth.Contract(abi);\n\n // Prepare deployment\n const deployTransaction = contract.deploy({\n data: getByteCode('Storage'),\n arguments: [], // Add constructor arguments if needed\n });\n\n // Estimate gas\n const gasEstimate = await deployTransaction.estimateGas({\n from: account.address,\n });\n\n // Get current gas price\n const gasPrice = await web3.eth.getGasPrice();\n\n // Send deployment transaction\n const deployedContract = await deployTransaction.send({\n from: account.address,\n gas: gasEstimate,\n gasPrice: gasPrice,\n });\n\n // Log and return contract details\n console.log(`Contract deployed at: ${deployedContract.options.address}`);\n return deployedContract;\n } catch (error) {\n console.error('Deployment failed:', error);\n throw error;\n }\n};\n\n// Example usage\nconst deploymentConfig = {\n rpcUrl: 'INSERT_RPC_URL',\n privateKey: 'INSERT_PRIVATE_KEY',\n contractName: 'INSERT_CONTRACT_NAME',\n};\n\ndeploy(deploymentConfig)\n .then((contract) => console.log('Deployment successful'))\n .catch((error) => console.error('Deployment error'));\n\n```\n\nFor further details on private key exportation, refer to the article [How to export an account's private key](https://support.metamask.io/configure/accounts/how-to-export-an-accounts-private-key/){target=\\_blank}.\n\nTo deploy your contract, run the following command:\n\n```bash\nnode deploy\n```"} -{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 8, "depth": 2, "title": "Interact with the Contract", "anchor": "interact-with-the-contract", "start_char": 10374, "end_char": 12757, "estimated_token_count": 548, "token_estimator": "heuristic-v1", "text": "## Interact with the Contract\n\nOnce deployed, you can interact with your contract using Web3.js methods. Here's how to set a number and read it back, ensure replacing `INSERT_RPC_URL`, `INSERT_PRIVATE_KEY`, and `INSERT_CONTRACT_ADDRESS` with the appropriate values:\n\n```javascript title=\"scripts/updateStorage.js\"\nimport { readFileSync } from 'fs';\nimport { Web3 } from 'web3';\n\nconst getAbi = (contractName) => {\n try {\n return JSON.parse(readFileSync(`${contractName}.json`), 'utf8');\n } catch (error) {\n console.error(\n `❌ Could not find ABI for contract ${contractName}:`,\n error.message\n );\n throw error;\n }\n};\n\nconst updateStorage = async (config) => {\n try {\n // Initialize Web3 with RPC URL\n const web3 = new Web3(config.rpcUrl);\n\n // Prepare account\n const account = web3.eth.accounts.privateKeyToAccount(config.privateKey);\n web3.eth.accounts.wallet.add(account);\n\n // Load abi\n const abi = getAbi('Storage');\n\n // Create contract instance\n const contract = new web3.eth.Contract(abi, config.contractAddress);\n\n // Get initial value\n const initialValue = await contract.methods.storedNumber().call();\n console.log('Current stored value:', initialValue);\n\n // Prepare transaction\n const updateTransaction = contract.methods.setNumber(1);\n\n // Estimate gas\n const gasEstimate = await updateTransaction.estimateGas({\n from: account.address,\n });\n\n // Get current gas price\n const gasPrice = await web3.eth.getGasPrice();\n\n // Send update transaction\n const receipt = await updateTransaction.send({\n from: account.address,\n gas: gasEstimate,\n gasPrice: gasPrice,\n });\n\n // Log transaction details\n console.log(`Transaction hash: ${receipt.transactionHash}`);\n\n // Get updated value\n const newValue = await contract.methods.storedNumber().call();\n console.log('New stored value:', newValue);\n\n return receipt;\n } catch (error) {\n console.error('Update failed:', error);\n throw error;\n }\n};\n\n// Example usage\nconst config = {\n rpcUrl: 'INSERT_RPC_URL',\n privateKey: 'INSERT_PRIVATE_KEY',\n contractAddress: 'INSERT_CONTRACT_ADDRESS',\n};\n\nupdateStorage(config)\n .then((receipt) => console.log('Update successful'))\n .catch((error) => console.error('Update error'));\n\n```\n\nTo execute the logic above, run:\n\n```bash\nnode updateStorage\n```"} -{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 9, "depth": 2, "title": "Where to Go Next", "anchor": "where-to-go-next", "start_char": 12757, "end_char": 13266, "estimated_token_count": 131, "token_estimator": "heuristic-v1", "text": "## Where to Go Next\n\nNow that you’ve learned how to use Web3.js with Polkadot Hub, explore more advanced topics:\n\n- **Utilize Web3.js utilities**: Learn about additional [Web3.js](https://docs.web3js.org/){target=\\_blank} features such as signing transactions, managing wallets, and subscribing to events.\n- **Build full-stack dApps**: [integrate Web3.js](https://docs.web3js.org/guides/dapps/intermediate-dapp){target=\\_blank} with different libraries and frameworks to build decentralized web applications."} +{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 298, "end_char": 857, "estimated_token_count": 102, "token_estimator": "heuristic-v1", "text": "## Introduction\n\nInteracting with blockchains typically requires an interface between your application and the network. [Web3.js](https://web3js.readthedocs.io/){target=\\_blank} offers this interface through a comprehensive collection of libraries, facilitating seamless interaction with the nodes using HTTP or WebSocket protocols. This guide illustrates how to utilize Web3.js specifically for interactions with Polkadot Hub.\n\nThis guide is intended for developers who are familiar with JavaScript and want to interact with the Polkadot Hub using Web3.js."} +{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 1, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 857, "end_char": 1213, "estimated_token_count": 110, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore getting started, ensure you have the following installed:\n\n- **Node.js**: v22.13.1 or later, check the [Node.js installation guide](https://nodejs.org/en/download/current/){target=\\_blank}.\n- **npm**: v6.13.4 or later (comes bundled with Node.js).\n- **Solidity**: This guide uses Solidity `^0.8.9` for smart contract development."} +{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 2, "depth": 2, "title": "Project Structure", "anchor": "project-structure", "start_char": 1213, "end_char": 1698, "estimated_token_count": 136, "token_estimator": "heuristic-v1", "text": "## Project Structure\n\nThis project organizes contracts, scripts, and compiled artifacts for easy development and deployment.\n\n```text title=\"Web3.js Polkadot Hub\"\nweb3js-project\n├── contracts\n│ ├── Storage.sol\n├── scripts\n│ ├── connectToProvider.js\n│ ├── fetchLastBlock.js\n│ ├── compile.js\n│ ├── deploy.js\n│ ├── updateStorage.js\n├── abis\n│ ├── Storage.json\n├── artifacts\n│ ├── Storage.polkavm\n├── node_modules/\n├── package.json\n├── package-lock.json\n└── README.md\n```"} +{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 3, "depth": 2, "title": "Set Up the Project", "anchor": "set-up-the-project", "start_char": 1698, "end_char": 1814, "estimated_token_count": 31, "token_estimator": "heuristic-v1", "text": "## Set Up the Project\n\nTo start working with Web3.js, begin by initializing your project:\n\n```bash\nnpm init -y\n```"} +{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 4, "depth": 2, "title": "Install Dependencies", "anchor": "install-dependencies", "start_char": 1814, "end_char": 1947, "estimated_token_count": 38, "token_estimator": "heuristic-v1", "text": "## Install Dependencies\n\nNext, install the Web3.js library:\n\n```bash\nnpm install web3\n```\n\nThis guide uses `web3` version `4.16.0`."} +{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 5, "depth": 2, "title": "Set Up the Web3 Provider", "anchor": "set-up-the-web3-provider", "start_char": 1947, "end_char": 3780, "estimated_token_count": 425, "token_estimator": "heuristic-v1", "text": "## Set Up the Web3 Provider\n\nThe provider configuration is the foundation of any Web3.js application. The following example establishes a connection to Polkadot Hub. To use the example script, replace `INSERT_RPC_URL`, `INSERT_CHAIN_ID`, and `INSERT_CHAIN_NAME` with the appropriate values. The provider connection script should look something like this:\n\n```javascript title=\"scripts/connectToProvider.js\"\nconst { Web3 } = require('web3');\n\nconst createProvider = (rpcUrl) => {\n const web3 = new Web3(rpcUrl);\n return web3;\n};\n\nconst PROVIDER_RPC = {\n rpc: 'INSERT_RPC_URL',\n chainId: 'INSERT_CHAIN_ID',\n name: 'INSERT_CHAIN_NAME',\n};\n\ncreateProvider(PROVIDER_RPC.rpc);\n\n```\n\nFor example, for the Polkadot Hub TestNet, use these specific connection parameters:\n\n```js\nconst PROVIDER_RPC = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io',\n chainId: 420420422,\n name: 'polkadot-hub-testnet'\n};\n```\n\nWith the Web3 provider set up, you can start querying the blockchain.\n\nFor instance, to fetch the latest block number of the chain, you can use the following code snippet:\n\n???+ code \"View complete script\"\n\n ```javascript title=\"scripts/fetchLastBlock.js\"\n const { Web3 } = require('web3');\n\n const createProvider = (rpcUrl) => {\n const web3 = new Web3(rpcUrl);\n return web3;\n };\n\n const PROVIDER_RPC = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io',\n chainId: 420420422,\n name: 'polkadot-hub-testnet',\n };\n\n const main = async () => {\n try {\n const web3 = createProvider(PROVIDER_RPC.rpc);\n const latestBlock = await web3.eth.getBlockNumber();\n console.log('Last block: ' + latestBlock);\n } catch (error) {\n console.error('Error connecting to Polkadot Hub TestNet: ' + error.message);\n }\n };\n\n main();\n\n ```"} +{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 6, "depth": 2, "title": "Compile Contracts", "anchor": "compile-contracts", "start_char": 3780, "end_char": 7261, "estimated_token_count": 840, "token_estimator": "heuristic-v1", "text": "## Compile Contracts\n\n!!! note \"Contracts Code Blob Size Disclaimer\"\n The maximum contract code blob size on Polkadot Hub networks is _100 kilobytes_, significantly larger than Ethereum’s EVM limit of 24 kilobytes.\n\n For detailed comparisons and migration guidelines, see the [EVM vs. PolkaVM](/polkadot-protocol/smart-contract-basics/evm-vs-polkavm/#current-memory-limits){target=\\_blank} documentation page.\n\nPolkadot Hub requires contracts to be compiled to [PolkaVM](/smart-contracts/for-eth-devs/dual-vm-stack/){target=\\_blank} bytecode. This is achieved using the [`revive`](https://github.com/paritytech/revive/tree/v0.2.0/js/resolc){target=\\_blank} compiler. Install the [`@parity/resolc`](https://github.com/paritytech/revive){target=\\_blank} library as a development dependency:\n\n```bash\nnpm install --save-dev @parity/resolc\n```\n\nThis guide uses `@parity/resolc` version `0.2.0`.\n\nHere's a simple storage contract that you can use to follow the process:\n\n```solidity title=\"contracts/Storage.sol\"\n//SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\ncontract Storage {\n // Public state variable to store a number\n uint256 public storedNumber;\n\n /**\n * Updates the stored number.\n *\n * The `public` modifier allows anyone to call this function.\n *\n * @param _newNumber - The new value to store.\n */\n function setNumber(uint256 _newNumber) public {\n storedNumber = _newNumber;\n }\n}\n```\n\nWith that, you can now create a `compile.js` snippet that transforms your solidity code into PolkaVM bytecode:\n\n```javascript title=\"scripts/compile.js\"\nconst { compile } = require('@parity/resolc');\nconst { readFileSync, writeFileSync } = require('fs');\nconst { basename, join } = require('path');\n\nconst compileContract = async (solidityFilePath, outputDir) => {\n try {\n // Read the Solidity file\n const source = readFileSync(solidityFilePath, 'utf8');\n\n // Construct the input object for the compiler\n const input = {\n [basename(solidityFilePath)]: { content: source },\n };\n\n console.log(`Compiling contract: ${basename(solidityFilePath)}...`);\n\n // Compile the contract\n const out = await compile(input);\n\n for (const contracts of Object.values(out.contracts)) {\n for (const [name, contract] of Object.entries(contracts)) {\n console.log(`Compiled contract: ${name}`);\n\n // Write the ABI\n const abiPath = join(outputDir, `${name}.json`);\n writeFileSync(abiPath, JSON.stringify(contract.abi, null, 2));\n console.log(`ABI saved to ${abiPath}`);\n\n // Write the bytecode\n const bytecodePath = join(outputDir, `${name}.polkavm`);\n writeFileSync(\n bytecodePath,\n Buffer.from(contract.evm.bytecode.object, 'hex'),\n );\n console.log(`Bytecode saved to ${bytecodePath}`);\n }\n }\n } catch (error) {\n console.error('Error compiling contracts:', error);\n }\n};\n\nconst solidityFilePath = './Storage.sol';\nconst outputDir = '.';\n\ncompileContract(solidityFilePath, outputDir);\n\n```\n\nTo compile your contract, simply run the following command:\n\n```bash\nnode compile\n```\n\nAfter compilation, you'll have two key files: an ABI (`.json`) file, which provides a JSON interface describing the contract's functions and how to interact with it, and a bytecode (`.polkavm`) file, which contains the low-level machine code executable on PolkaVM that represents the compiled smart contract ready for blockchain deployment."} +{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 7, "depth": 2, "title": "Contract Deployment", "anchor": "contract-deployment", "start_char": 7261, "end_char": 10204, "estimated_token_count": 674, "token_estimator": "heuristic-v1", "text": "## Contract Deployment\n\nTo deploy your compiled contract to Polkadot Hub using Web3.js, you'll need an account with a private key to sign the deployment transaction. The deployment process is exactly the same as for any Ethereum-compatible chain, involving creating a contract instance, estimating gas, and sending a deployment transaction. Here's how to deploy the contract, ensure replacing the `INSERT_RPC_URL`, `INSERT_PRIVATE_KEY`, and `INSERT_CONTRACT_NAME` with the appropriate values:\n\n```javascript title=\"scripts/deploy.js\"\nimport { readFileSync } from 'fs';\nimport { Web3 } from 'web3';\n\nconst getAbi = (contractName) => {\n try {\n return JSON.parse(readFileSync(`${contractName}.json`), 'utf8');\n } catch (error) {\n console.error(\n `❌ Could not find ABI for contract ${contractName}:`,\n error.message\n );\n throw error;\n }\n};\n\nconst getByteCode = (contractName) => {\n try {\n return `0x${readFileSync(`${contractName}.polkavm`).toString('hex')}`;\n } catch (error) {\n console.error(\n `❌ Could not find bytecode for contract ${contractName}:`,\n error.message\n );\n throw error;\n }\n};\n\nexport const deploy = async (config) => {\n try {\n // Initialize Web3 with RPC URL\n const web3 = new Web3(config.rpcUrl);\n\n // Prepare account\n const account = web3.eth.accounts.privateKeyToAccount(config.privateKey);\n web3.eth.accounts.wallet.add(account);\n\n // Load abi\n const abi = getAbi('Storage');\n\n // Create contract instance\n const contract = new web3.eth.Contract(abi);\n\n // Prepare deployment\n const deployTransaction = contract.deploy({\n data: getByteCode('Storage'),\n arguments: [], // Add constructor arguments if needed\n });\n\n // Estimate gas\n const gasEstimate = await deployTransaction.estimateGas({\n from: account.address,\n });\n\n // Get current gas price\n const gasPrice = await web3.eth.getGasPrice();\n\n // Send deployment transaction\n const deployedContract = await deployTransaction.send({\n from: account.address,\n gas: gasEstimate,\n gasPrice: gasPrice,\n });\n\n // Log and return contract details\n console.log(`Contract deployed at: ${deployedContract.options.address}`);\n return deployedContract;\n } catch (error) {\n console.error('Deployment failed:', error);\n throw error;\n }\n};\n\n// Example usage\nconst deploymentConfig = {\n rpcUrl: 'INSERT_RPC_URL',\n privateKey: 'INSERT_PRIVATE_KEY',\n contractName: 'INSERT_CONTRACT_NAME',\n};\n\ndeploy(deploymentConfig)\n .then((contract) => console.log('Deployment successful'))\n .catch((error) => console.error('Deployment error'));\n\n```\n\nFor further details on private key exportation, refer to the article [How to export an account's private key](https://support.metamask.io/configure/accounts/how-to-export-an-accounts-private-key/){target=\\_blank}.\n\nTo deploy your contract, run the following command:\n\n```bash\nnode deploy\n```"} +{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 8, "depth": 2, "title": "Interact with the Contract", "anchor": "interact-with-the-contract", "start_char": 10204, "end_char": 12587, "estimated_token_count": 548, "token_estimator": "heuristic-v1", "text": "## Interact with the Contract\n\nOnce deployed, you can interact with your contract using Web3.js methods. Here's how to set a number and read it back, ensure replacing `INSERT_RPC_URL`, `INSERT_PRIVATE_KEY`, and `INSERT_CONTRACT_ADDRESS` with the appropriate values:\n\n```javascript title=\"scripts/updateStorage.js\"\nimport { readFileSync } from 'fs';\nimport { Web3 } from 'web3';\n\nconst getAbi = (contractName) => {\n try {\n return JSON.parse(readFileSync(`${contractName}.json`), 'utf8');\n } catch (error) {\n console.error(\n `❌ Could not find ABI for contract ${contractName}:`,\n error.message\n );\n throw error;\n }\n};\n\nconst updateStorage = async (config) => {\n try {\n // Initialize Web3 with RPC URL\n const web3 = new Web3(config.rpcUrl);\n\n // Prepare account\n const account = web3.eth.accounts.privateKeyToAccount(config.privateKey);\n web3.eth.accounts.wallet.add(account);\n\n // Load abi\n const abi = getAbi('Storage');\n\n // Create contract instance\n const contract = new web3.eth.Contract(abi, config.contractAddress);\n\n // Get initial value\n const initialValue = await contract.methods.storedNumber().call();\n console.log('Current stored value:', initialValue);\n\n // Prepare transaction\n const updateTransaction = contract.methods.setNumber(1);\n\n // Estimate gas\n const gasEstimate = await updateTransaction.estimateGas({\n from: account.address,\n });\n\n // Get current gas price\n const gasPrice = await web3.eth.getGasPrice();\n\n // Send update transaction\n const receipt = await updateTransaction.send({\n from: account.address,\n gas: gasEstimate,\n gasPrice: gasPrice,\n });\n\n // Log transaction details\n console.log(`Transaction hash: ${receipt.transactionHash}`);\n\n // Get updated value\n const newValue = await contract.methods.storedNumber().call();\n console.log('New stored value:', newValue);\n\n return receipt;\n } catch (error) {\n console.error('Update failed:', error);\n throw error;\n }\n};\n\n// Example usage\nconst config = {\n rpcUrl: 'INSERT_RPC_URL',\n privateKey: 'INSERT_PRIVATE_KEY',\n contractAddress: 'INSERT_CONTRACT_ADDRESS',\n};\n\nupdateStorage(config)\n .then((receipt) => console.log('Update successful'))\n .catch((error) => console.error('Update error'));\n\n```\n\nTo execute the logic above, run:\n\n```bash\nnode updateStorage\n```"} +{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 9, "depth": 2, "title": "Where to Go Next", "anchor": "where-to-go-next", "start_char": 12587, "end_char": 13096, "estimated_token_count": 131, "token_estimator": "heuristic-v1", "text": "## Where to Go Next\n\nNow that you’ve learned how to use Web3.js with Polkadot Hub, explore more advanced topics:\n\n- **Utilize Web3.js utilities**: Learn about additional [Web3.js](https://docs.web3js.org/){target=\\_blank} features such as signing transactions, managing wallets, and subscribing to events.\n- **Build full-stack dApps**: [integrate Web3.js](https://docs.web3js.org/guides/dapps/intermediate-dapp){target=\\_blank} with different libraries and frameworks to build decentralized web applications."} {"page_id": "smart-contracts-libraries-web3-py", "page_title": "Web3.py", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 181, "end_char": 605, "estimated_token_count": 83, "token_estimator": "heuristic-v1", "text": "## Introduction\n\nInteracting with blockchains typically requires an interface between your application and the network. [Web3.py](https://web3py.readthedocs.io/en/stable/index.html){target=\\_blank} offers this interface through a collection of libraries, facilitating seamless interaction with the nodes using HTTP or WebSocket protocols. \n\nThis guide illustrates how to utilize Web3.py for interactions with Polkadot Hub."} {"page_id": "smart-contracts-libraries-web3-py", "page_title": "Web3.py", "index": 1, "depth": 2, "title": "Set Up the Project", "anchor": "set-up-the-project", "start_char": 605, "end_char": 986, "estimated_token_count": 88, "token_estimator": "heuristic-v1", "text": "## Set Up the Project\n\n1. To start working with Web3.py, begin by initializing your project:\n\n ```bash\n mkdir web3py-project\n cd web3py-project\n ```\n\n2. Create and activate a virtual environment for your project:\n\n ```bash\n python -m venv venv\n source venv/bin/activate\n ```\n\n3. Next, install the Web3.py library:\n\n ```bash\n pip install web3\n ```"} {"page_id": "smart-contracts-libraries-web3-py", "page_title": "Web3.py", "index": 2, "depth": 2, "title": "Set Up the Web3 Provider", "anchor": "set-up-the-web3-provider", "start_char": 986, "end_char": 3080, "estimated_token_count": 423, "token_estimator": "heuristic-v1", "text": "## Set Up the Web3 Provider\n\nThe [provider](https://web3py.readthedocs.io/en/stable/providers.html){target=\\_blank} configuration is the foundation of any Web3.py application. The following example establishes a connection to Polkadot Hub. Follow these steps to use the provider configuration:\n\n1. Replace `INSERT_RPC_URL` with the appropriate value. For instance, to connect to Polkadot Hub TestNet, use the following parameter:\n\n ```python\n PROVIDER_RPC = 'https://testnet-passet-hub-eth-rpc.polkadot.io'\n ```\n\n The provider connection script should look something like this:\n\n ```python title=\"connect_to_provider.py\"\n from web3 import Web3\n\n def create_provider(rpc_url):\n web3 = Web3(Web3.HTTPProvider(rpc_url))\n return web3\n\n PROVIDER_RPC = 'INSERT_RPC_URL'\n\n create_provider(PROVIDER_RPC)\n ```\n\n1. With the Web3 provider set up, start querying the blockchain. For instance, you can use the following code snippet to fetch the latest block number of the chain:\n\n ```python title=\"fetch_last_block.py\"\n def main():\n try:\n web3 = create_provider(PROVIDER_RPC)\n latest_block = web3.eth.block_number\n print('Last block: ' + str(latest_block))\n except Exception as error:\n print('Error connecting to Polkadot Hub TestNet: ' + str(error))\n\n if __name__ == \"__main__\":\n main()\n ```\n\n ??? code \"View complete script\"\n\n ```python title=\"fetch_last_block.py\"\n from web3 import Web3\n\n def create_provider(rpc_url):\n web3 = Web3(Web3.HTTPProvider(rpc_url))\n return web3\n\n PROVIDER_RPC = 'https://testnet-passet-hub-eth-rpc.polkadot.io'\n\n def main():\n try:\n web3 = create_provider(PROVIDER_RPC)\n latest_block = web3.eth.block_number\n print('Last block: ' + str(latest_block))\n except Exception as error:\n print('Error connecting to Polkadot Hub TestNet: ' + str(error))\n\n if __name__ == \"__main__\":\n main()\n ```"} diff --git a/llms.txt b/llms.txt index d7102baaa..1b820afd6 100644 --- a/llms.txt +++ b/llms.txt @@ -6,7 +6,7 @@ This directory lists URLs for raw Markdown pages that complement the rendered pages on the documentation site. Use these Markdown files to retain semantic context when prompting models while avoiding passing HTML elements. ## Metadata -- Documentation pages: 147 +- Documentation pages: 146 - Categories: 13 ## Docs @@ -246,7 +246,6 @@ Docs: Uncategorized - [smart-contracts-integrations-indexers](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-integrations-indexers.md): No description available. - [smart-contracts-integrations-oracles](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-integrations-oracles.md): No description available. - [Advanced Functionalities via Precompiles](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-precompiles.md): Explores how Polkadot integrates precompiles to run essential functions natively, improving the speed and efficiency of smart contracts on the Hub. -- [text-smart-contracts-code-size](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/text-smart-contracts-code-size.md): No description available. Docs: dApp - [Zero to Hero Smart Contract DApp](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-cookbook-dapps-zero-to-hero.md): Learn how to build a decentralized application on Polkadot Hub using Viem and Next.js by creating a simple dApp that interacts with a smart contract. diff --git a/smart-contracts/libraries/web3-js.md b/smart-contracts/libraries/web3-js.md index 8c4545aa4..1bd2e9302 100644 --- a/smart-contracts/libraries/web3-js.md +++ b/smart-contracts/libraries/web3-js.md @@ -6,8 +6,6 @@ categories: Smart Contracts, Tooling # Web3.js ---8<-- 'text/smart-contracts/polkaVM-warning.md' - !!! warning Web3.js has been [sunset](https://blog.chainsafe.io/web3-js-sunset/){target=\_blank}. You can find guides on using [Ethers.js](/smart-contracts/libraries/ethers-js/){target=\_blank} and [viem](/smart-contracts/libraries/viem/){target=\_blank} in the Libraries section. diff --git a/text/smart-contracts/code-size.md b/text/smart-contracts/code-size.md deleted file mode 100644 index b004a7594..000000000 --- a/text/smart-contracts/code-size.md +++ /dev/null @@ -1,2 +0,0 @@ -!!! info "Mind the contract size" - Polkadot Hub enforces Ethereum's 24 KiB contract-size limit (EIP-170) for EVM deployments. Keep contracts modular, share logic through libraries, and make use of compiler optimizations so your bytecode stays within the limit. From 926bdd5a26c3a554fab8a927e6d97e0edcb7226d Mon Sep 17 00:00:00 2001 From: nhussein11 Date: Mon, 17 Nov 2025 18:25:15 -0300 Subject: [PATCH 5/7] fix: rollback web3-js unintended change for this pr --- .ai/categories/smart-contracts.md | 2 ++ .ai/categories/tooling.md | 2 ++ .../smart-contracts-libraries-web3-js.md | 2 ++ .ai/site-index.json | 8 ++++---- llms-full.jsonl | 20 +++++++++---------- smart-contracts/libraries/web3-js.md | 2 ++ 6 files changed, 22 insertions(+), 14 deletions(-) diff --git a/.ai/categories/smart-contracts.md b/.ai/categories/smart-contracts.md index 9cef3b31b..c6fbd51ec 100644 --- a/.ai/categories/smart-contracts.md +++ b/.ai/categories/smart-contracts.md @@ -10768,6 +10768,8 @@ Page Title: Web3.js # Web3.js +!!! smartcontract "PolkaVM Preview Release" + PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. !!! warning Web3.js has been [sunset](https://blog.chainsafe.io/web3-js-sunset/){target=\_blank}. You can find guides on using [Ethers.js](/smart-contracts/libraries/ethers-js/){target=\_blank} and [viem](/smart-contracts/libraries/viem/){target=\_blank} in the Libraries section. diff --git a/.ai/categories/tooling.md b/.ai/categories/tooling.md index a4914ac5b..0c1678e58 100644 --- a/.ai/categories/tooling.md +++ b/.ai/categories/tooling.md @@ -12863,6 +12863,8 @@ Page Title: Web3.js # Web3.js +!!! smartcontract "PolkaVM Preview Release" + PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. !!! warning Web3.js has been [sunset](https://blog.chainsafe.io/web3-js-sunset/){target=\_blank}. You can find guides on using [Ethers.js](/smart-contracts/libraries/ethers-js/){target=\_blank} and [viem](/smart-contracts/libraries/viem/){target=\_blank} in the Libraries section. diff --git a/.ai/pages/smart-contracts-libraries-web3-js.md b/.ai/pages/smart-contracts-libraries-web3-js.md index 03b6f0add..095b6ea5c 100644 --- a/.ai/pages/smart-contracts-libraries-web3-js.md +++ b/.ai/pages/smart-contracts-libraries-web3-js.md @@ -7,6 +7,8 @@ url: https://docs.polkadot.com/smart-contracts/libraries/web3-js/ # Web3.js +!!! smartcontract "PolkaVM Preview Release" + PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. !!! warning Web3.js has been [sunset](https://blog.chainsafe.io/web3-js-sunset/){target=\_blank}. You can find guides on using [Ethers.js](/smart-contracts/libraries/ethers-js/){target=\_blank} and [viem](/smart-contracts/libraries/viem/){target=\_blank} in the Libraries section. diff --git a/.ai/site-index.json b/.ai/site-index.json index b2ccc9abe..c5791cfe6 100644 --- a/.ai/site-index.json +++ b/.ai/site-index.json @@ -8723,7 +8723,7 @@ ], "raw_md_url": "https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-libraries-web3-js.md", "html_url": "https://docs.polkadot.com/smart-contracts/libraries/web3-js/", - "preview": "!!! warning Web3.js has been [sunset](https://blog.chainsafe.io/web3-js-sunset/){target=\\_blank}. You can find guides on using [Ethers.js](/smart-contracts/libraries/ethers-js/){target=\\_blank} and [viem](/smart-contracts/libraries/viem/){target=\\_blank} in the Libraries section.", + "preview": "!!! smartcontract \"PolkaVM Preview Release\" PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. !!! warning Web3.js has been [sunset](https://blog.chainsafe.io/web3-js-sunset/){target=\\_blank}. You can find guides on using [Ethers.js](/smart-contracts/libraries/ethers-js/){target=\\_blank} and [viem](/smart-contracts/libraries/viem/){target=\\_blank} in the Libraries section.", "outline": [ { "depth": 2, @@ -8777,12 +8777,12 @@ } ], "stats": { - "chars": 13096, - "words": 1558, + "chars": 13266, + "words": 1579, "headings": 10, "estimated_token_count_total": 3035 }, - "hash": "sha256:0aafc5ad18ee58314c81b5bbe98aa80bddfd9d1820eeaf674607d69819702a2b", + "hash": "sha256:f0d36333d0d3afff7f6374a61d0f6d1fb878c9ef4c4e4c24447745661dbe59d0", "token_estimator": "heuristic-v1" }, { diff --git a/llms-full.jsonl b/llms-full.jsonl index 6d2024005..25a0578e0 100644 --- a/llms-full.jsonl +++ b/llms-full.jsonl @@ -1145,16 +1145,16 @@ {"page_id": "smart-contracts-libraries-wagmi", "page_title": "Wagmi for Polkadot Hub Smart Contracts", "index": 7, "depth": 2, "title": "Interact with Deployed Contract", "anchor": "interact-with-deployed-contract", "start_char": 6700, "end_char": 11209, "estimated_token_count": 989, "token_estimator": "heuristic-v1", "text": "## Interact with Deployed Contract\n\nThis guide uses a simple Storage contract already deployed to the Polkadot Hub TestNet (`0x58053f0e8ede1a47a1af53e43368cd04ddcaf66f`). The code of that contract is:\n\n??? code \"Storage.sol\"\n\n ```solidity title=\"Storage.sol\"\n //SPDX-License-Identifier: MIT\n\n // Solidity files have to start with this pragma.\n // It will be used by the Solidity compiler to validate its version.\n pragma solidity ^0.8.9;\n\n contract Storage {\n // Public state variable to store a number\n uint256 public storedNumber;\n\n /**\n * Updates the stored number.\n *\n * The `public` modifier allows anyone to call this function.\n *\n * @param _newNumber - The new value to store.\n */\n function setNumber(uint256 _newNumber) public {\n storedNumber = _newNumber;\n }\n }\n ```\n\nCreate a component to interact with your deployed contract. Create a file named `app/components/StorageContract.tsx`:\n\n```typescript title=\"app/components/StorageContract.tsx\"\n\"use client\";\n\nimport { useState } from \"react\";\nimport {\n useReadContract,\n useWriteContract,\n useWaitForTransactionReceipt,\n} from \"wagmi\";\n\nconst CONTRACT_ADDRESS =\n \"0xabBd46Ef74b88E8B1CDa49BeFb5057710443Fd29\" as `0x${string}`;\n\nexport function StorageContract() {\n const [number, setNumber] = useState(\"42\");\n\n // Contract ABI (should match your compiled contract)\n const abi = [\n {\n inputs: [],\n name: \"storedNumber\",\n outputs: [{ internalType: \"uint256\", name: \"\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [\n { internalType: \"uint256\", name: \"_newNumber\", type: \"uint256\" },\n ],\n name: \"setNumber\",\n outputs: [],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n ];\n\n // Read the current stored number\n const { data: storedNumber, refetch } = useReadContract({\n address: CONTRACT_ADDRESS,\n abi,\n functionName: \"storedNumber\",\n });\n\n // Write to the contract\n const { writeContract, data: hash, error, isPending } = useWriteContract();\n\n // Wait for transaction to be mined\n const { isLoading: isConfirming, isSuccess: isConfirmed } =\n useWaitForTransactionReceipt({\n hash,\n });\n\n const handleSetNumber = () => {\n writeContract({\n address: CONTRACT_ADDRESS,\n abi,\n functionName: \"setNumber\",\n args: [BigInt(number)],\n });\n };\n\n return (\n
\n

Storage Contract Interaction

\n
\n

Contract Address: {CONTRACT_ADDRESS}

\n

Current Stored Number: {storedNumber?.toString() || \"Loading...\"}

\n
\n\n
\n setNumber(e.target.value)}\n disabled={isPending || isConfirming}\n />\n \n
\n\n {error &&
Error: {error.message}
}\n\n {isConfirmed && (\n
\n Successfully updated!{\" \"}\n \n
\n )}\n
\n );\n}\n\n```\n\nThis component demonstrates how to interact with a smart contract using Wagmi's hooks:\n\n- **[`useReadContract`](https://wagmi.sh/react/api/hooks/useReadContract#useReadContract){target=\\_blank}**: Calls a read-only function on your smart contract to retrieve data without modifying the blockchain state.\n- **[`useWriteContract`](https://wagmi.sh/react/api/hooks/useWriteContract#useWriteContract){target=\\_blank}**: Calls a state-modifying function on your smart contract, which requires a transaction to be signed and sent.\n- **[`useWaitForTransactionReceipt`](https://wagmi.sh/react/api/hooks/useWaitForTransactionReceipt#useWaitForTransactionReceipt){target=\\_blank}**: Tracks the status of a transaction after it's been submitted, allowing you to know when it's been confirmed.\n\nThe component also includes proper state handling to:\n\n- Show the current value stored in the contract.\n- Allow users to input a new value.\n- Display transaction status (pending, confirming, or completed).\n- Handle errors.\n- Provide feedback when a transaction is successful."} {"page_id": "smart-contracts-libraries-wagmi", "page_title": "Wagmi for Polkadot Hub Smart Contracts", "index": 8, "depth": 2, "title": "Integrate Components", "anchor": "integrate-components", "start_char": 11209, "end_char": 11961, "estimated_token_count": 183, "token_estimator": "heuristic-v1", "text": "## Integrate Components\n\nUpdate your main page to combine all the components. Create or update the file `src/app/page.tsx`:\n\n```typescript title=\"src/app/page.tsx\"\n\"use client\";\n\nimport { BlockchainInfo } from \"./components/BlockchainInfo\";\nimport { ConnectWallet } from \"./components/ConnectWallet\";\nimport { StorageContract } from \"./components/StorageContract\";\nimport { useAccount } from \"wagmi\";\n\nexport default function Home() {\n const { isConnected } = useAccount();\n\n return (\n
\n

Wagmi - Polkadot Hub Smart Contracts

\n \n {isConnected ? : Connect your wallet}\n {isConnected ? : Connect your wallet}\n
\n );\n}\n\n```"} {"page_id": "smart-contracts-libraries-wagmi", "page_title": "Wagmi for Polkadot Hub Smart Contracts", "index": 9, "depth": 2, "title": "Where to Go Next", "anchor": "where-to-go-next", "start_char": 11961, "end_char": 13604, "estimated_token_count": 512, "token_estimator": "heuristic-v1", "text": "## Where to Go Next\n\nNow that you have the foundational knowledge to use Wagmi with Polkadot Hub, consider exploring:\n\n
\n\n- External __Advanced Wagmi__\n\n ---\n\n Explore Wagmi's advanced features:\n\n
    \n
  • [:octicons-arrow-right-24: Watch Contract Events](https://wagmi.sh/core/api/actions/watchContractEvent#eventname){target=\\_blank}
  • \n
  • [:octicons-arrow-right-24: Different Transports](https://wagmi.sh/react/api/transports){target=\\_blank}
  • \n
  • [:octicons-arrow-right-24: Actions](https://wagmi.sh/react/api/actions){target=\\_blank}
  • \n
\n\n- External __Wallet Integration__\n\n ---\n\n Connect your dApp with popular wallet providers:\n\n
    \n
  • [:octicons-arrow-right-24: MetaMask](https://wagmi.sh/core/api/connectors/metaMask){target=\\_blank}
  • \n
  • [:octicons-arrow-right-24: WalletConnect](https://wagmi.sh/core/api/connectors/walletConnect){target=\\_blank}
  • \n
  • [:octicons-arrow-right-24: Coinbase Wallet](https://wagmi.sh/core/api/connectors/coinbaseWallet){target=\\_blank}
  • \n
\n\n- External __Testing & Development__\n\n ---\n\n Enhance your development workflow:\n\n
    \n
  • [:octicons-arrow-right-24: Test Suite](https://wagmi.sh/dev/contributing#_6-running-the-test-suite){target=\\_blank}
  • \n
  • [:octicons-arrow-right-24: Dev Playground](https://wagmi.sh/dev/contributing#_5-running-the-dev-playgrounds){target=\\_blank}
  • \n
\n
"} -{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 298, "end_char": 857, "estimated_token_count": 102, "token_estimator": "heuristic-v1", "text": "## Introduction\n\nInteracting with blockchains typically requires an interface between your application and the network. [Web3.js](https://web3js.readthedocs.io/){target=\\_blank} offers this interface through a comprehensive collection of libraries, facilitating seamless interaction with the nodes using HTTP or WebSocket protocols. This guide illustrates how to utilize Web3.js specifically for interactions with Polkadot Hub.\n\nThis guide is intended for developers who are familiar with JavaScript and want to interact with the Polkadot Hub using Web3.js."} -{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 1, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 857, "end_char": 1213, "estimated_token_count": 110, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore getting started, ensure you have the following installed:\n\n- **Node.js**: v22.13.1 or later, check the [Node.js installation guide](https://nodejs.org/en/download/current/){target=\\_blank}.\n- **npm**: v6.13.4 or later (comes bundled with Node.js).\n- **Solidity**: This guide uses Solidity `^0.8.9` for smart contract development."} -{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 2, "depth": 2, "title": "Project Structure", "anchor": "project-structure", "start_char": 1213, "end_char": 1698, "estimated_token_count": 136, "token_estimator": "heuristic-v1", "text": "## Project Structure\n\nThis project organizes contracts, scripts, and compiled artifacts for easy development and deployment.\n\n```text title=\"Web3.js Polkadot Hub\"\nweb3js-project\n├── contracts\n│ ├── Storage.sol\n├── scripts\n│ ├── connectToProvider.js\n│ ├── fetchLastBlock.js\n│ ├── compile.js\n│ ├── deploy.js\n│ ├── updateStorage.js\n├── abis\n│ ├── Storage.json\n├── artifacts\n│ ├── Storage.polkavm\n├── node_modules/\n├── package.json\n├── package-lock.json\n└── README.md\n```"} -{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 3, "depth": 2, "title": "Set Up the Project", "anchor": "set-up-the-project", "start_char": 1698, "end_char": 1814, "estimated_token_count": 31, "token_estimator": "heuristic-v1", "text": "## Set Up the Project\n\nTo start working with Web3.js, begin by initializing your project:\n\n```bash\nnpm init -y\n```"} -{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 4, "depth": 2, "title": "Install Dependencies", "anchor": "install-dependencies", "start_char": 1814, "end_char": 1947, "estimated_token_count": 38, "token_estimator": "heuristic-v1", "text": "## Install Dependencies\n\nNext, install the Web3.js library:\n\n```bash\nnpm install web3\n```\n\nThis guide uses `web3` version `4.16.0`."} -{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 5, "depth": 2, "title": "Set Up the Web3 Provider", "anchor": "set-up-the-web3-provider", "start_char": 1947, "end_char": 3780, "estimated_token_count": 425, "token_estimator": "heuristic-v1", "text": "## Set Up the Web3 Provider\n\nThe provider configuration is the foundation of any Web3.js application. The following example establishes a connection to Polkadot Hub. To use the example script, replace `INSERT_RPC_URL`, `INSERT_CHAIN_ID`, and `INSERT_CHAIN_NAME` with the appropriate values. The provider connection script should look something like this:\n\n```javascript title=\"scripts/connectToProvider.js\"\nconst { Web3 } = require('web3');\n\nconst createProvider = (rpcUrl) => {\n const web3 = new Web3(rpcUrl);\n return web3;\n};\n\nconst PROVIDER_RPC = {\n rpc: 'INSERT_RPC_URL',\n chainId: 'INSERT_CHAIN_ID',\n name: 'INSERT_CHAIN_NAME',\n};\n\ncreateProvider(PROVIDER_RPC.rpc);\n\n```\n\nFor example, for the Polkadot Hub TestNet, use these specific connection parameters:\n\n```js\nconst PROVIDER_RPC = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io',\n chainId: 420420422,\n name: 'polkadot-hub-testnet'\n};\n```\n\nWith the Web3 provider set up, you can start querying the blockchain.\n\nFor instance, to fetch the latest block number of the chain, you can use the following code snippet:\n\n???+ code \"View complete script\"\n\n ```javascript title=\"scripts/fetchLastBlock.js\"\n const { Web3 } = require('web3');\n\n const createProvider = (rpcUrl) => {\n const web3 = new Web3(rpcUrl);\n return web3;\n };\n\n const PROVIDER_RPC = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io',\n chainId: 420420422,\n name: 'polkadot-hub-testnet',\n };\n\n const main = async () => {\n try {\n const web3 = createProvider(PROVIDER_RPC.rpc);\n const latestBlock = await web3.eth.getBlockNumber();\n console.log('Last block: ' + latestBlock);\n } catch (error) {\n console.error('Error connecting to Polkadot Hub TestNet: ' + error.message);\n }\n };\n\n main();\n\n ```"} -{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 6, "depth": 2, "title": "Compile Contracts", "anchor": "compile-contracts", "start_char": 3780, "end_char": 7261, "estimated_token_count": 840, "token_estimator": "heuristic-v1", "text": "## Compile Contracts\n\n!!! note \"Contracts Code Blob Size Disclaimer\"\n The maximum contract code blob size on Polkadot Hub networks is _100 kilobytes_, significantly larger than Ethereum’s EVM limit of 24 kilobytes.\n\n For detailed comparisons and migration guidelines, see the [EVM vs. PolkaVM](/polkadot-protocol/smart-contract-basics/evm-vs-polkavm/#current-memory-limits){target=\\_blank} documentation page.\n\nPolkadot Hub requires contracts to be compiled to [PolkaVM](/smart-contracts/for-eth-devs/dual-vm-stack/){target=\\_blank} bytecode. This is achieved using the [`revive`](https://github.com/paritytech/revive/tree/v0.2.0/js/resolc){target=\\_blank} compiler. Install the [`@parity/resolc`](https://github.com/paritytech/revive){target=\\_blank} library as a development dependency:\n\n```bash\nnpm install --save-dev @parity/resolc\n```\n\nThis guide uses `@parity/resolc` version `0.2.0`.\n\nHere's a simple storage contract that you can use to follow the process:\n\n```solidity title=\"contracts/Storage.sol\"\n//SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\ncontract Storage {\n // Public state variable to store a number\n uint256 public storedNumber;\n\n /**\n * Updates the stored number.\n *\n * The `public` modifier allows anyone to call this function.\n *\n * @param _newNumber - The new value to store.\n */\n function setNumber(uint256 _newNumber) public {\n storedNumber = _newNumber;\n }\n}\n```\n\nWith that, you can now create a `compile.js` snippet that transforms your solidity code into PolkaVM bytecode:\n\n```javascript title=\"scripts/compile.js\"\nconst { compile } = require('@parity/resolc');\nconst { readFileSync, writeFileSync } = require('fs');\nconst { basename, join } = require('path');\n\nconst compileContract = async (solidityFilePath, outputDir) => {\n try {\n // Read the Solidity file\n const source = readFileSync(solidityFilePath, 'utf8');\n\n // Construct the input object for the compiler\n const input = {\n [basename(solidityFilePath)]: { content: source },\n };\n\n console.log(`Compiling contract: ${basename(solidityFilePath)}...`);\n\n // Compile the contract\n const out = await compile(input);\n\n for (const contracts of Object.values(out.contracts)) {\n for (const [name, contract] of Object.entries(contracts)) {\n console.log(`Compiled contract: ${name}`);\n\n // Write the ABI\n const abiPath = join(outputDir, `${name}.json`);\n writeFileSync(abiPath, JSON.stringify(contract.abi, null, 2));\n console.log(`ABI saved to ${abiPath}`);\n\n // Write the bytecode\n const bytecodePath = join(outputDir, `${name}.polkavm`);\n writeFileSync(\n bytecodePath,\n Buffer.from(contract.evm.bytecode.object, 'hex'),\n );\n console.log(`Bytecode saved to ${bytecodePath}`);\n }\n }\n } catch (error) {\n console.error('Error compiling contracts:', error);\n }\n};\n\nconst solidityFilePath = './Storage.sol';\nconst outputDir = '.';\n\ncompileContract(solidityFilePath, outputDir);\n\n```\n\nTo compile your contract, simply run the following command:\n\n```bash\nnode compile\n```\n\nAfter compilation, you'll have two key files: an ABI (`.json`) file, which provides a JSON interface describing the contract's functions and how to interact with it, and a bytecode (`.polkavm`) file, which contains the low-level machine code executable on PolkaVM that represents the compiled smart contract ready for blockchain deployment."} -{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 7, "depth": 2, "title": "Contract Deployment", "anchor": "contract-deployment", "start_char": 7261, "end_char": 10204, "estimated_token_count": 674, "token_estimator": "heuristic-v1", "text": "## Contract Deployment\n\nTo deploy your compiled contract to Polkadot Hub using Web3.js, you'll need an account with a private key to sign the deployment transaction. The deployment process is exactly the same as for any Ethereum-compatible chain, involving creating a contract instance, estimating gas, and sending a deployment transaction. Here's how to deploy the contract, ensure replacing the `INSERT_RPC_URL`, `INSERT_PRIVATE_KEY`, and `INSERT_CONTRACT_NAME` with the appropriate values:\n\n```javascript title=\"scripts/deploy.js\"\nimport { readFileSync } from 'fs';\nimport { Web3 } from 'web3';\n\nconst getAbi = (contractName) => {\n try {\n return JSON.parse(readFileSync(`${contractName}.json`), 'utf8');\n } catch (error) {\n console.error(\n `❌ Could not find ABI for contract ${contractName}:`,\n error.message\n );\n throw error;\n }\n};\n\nconst getByteCode = (contractName) => {\n try {\n return `0x${readFileSync(`${contractName}.polkavm`).toString('hex')}`;\n } catch (error) {\n console.error(\n `❌ Could not find bytecode for contract ${contractName}:`,\n error.message\n );\n throw error;\n }\n};\n\nexport const deploy = async (config) => {\n try {\n // Initialize Web3 with RPC URL\n const web3 = new Web3(config.rpcUrl);\n\n // Prepare account\n const account = web3.eth.accounts.privateKeyToAccount(config.privateKey);\n web3.eth.accounts.wallet.add(account);\n\n // Load abi\n const abi = getAbi('Storage');\n\n // Create contract instance\n const contract = new web3.eth.Contract(abi);\n\n // Prepare deployment\n const deployTransaction = contract.deploy({\n data: getByteCode('Storage'),\n arguments: [], // Add constructor arguments if needed\n });\n\n // Estimate gas\n const gasEstimate = await deployTransaction.estimateGas({\n from: account.address,\n });\n\n // Get current gas price\n const gasPrice = await web3.eth.getGasPrice();\n\n // Send deployment transaction\n const deployedContract = await deployTransaction.send({\n from: account.address,\n gas: gasEstimate,\n gasPrice: gasPrice,\n });\n\n // Log and return contract details\n console.log(`Contract deployed at: ${deployedContract.options.address}`);\n return deployedContract;\n } catch (error) {\n console.error('Deployment failed:', error);\n throw error;\n }\n};\n\n// Example usage\nconst deploymentConfig = {\n rpcUrl: 'INSERT_RPC_URL',\n privateKey: 'INSERT_PRIVATE_KEY',\n contractName: 'INSERT_CONTRACT_NAME',\n};\n\ndeploy(deploymentConfig)\n .then((contract) => console.log('Deployment successful'))\n .catch((error) => console.error('Deployment error'));\n\n```\n\nFor further details on private key exportation, refer to the article [How to export an account's private key](https://support.metamask.io/configure/accounts/how-to-export-an-accounts-private-key/){target=\\_blank}.\n\nTo deploy your contract, run the following command:\n\n```bash\nnode deploy\n```"} -{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 8, "depth": 2, "title": "Interact with the Contract", "anchor": "interact-with-the-contract", "start_char": 10204, "end_char": 12587, "estimated_token_count": 548, "token_estimator": "heuristic-v1", "text": "## Interact with the Contract\n\nOnce deployed, you can interact with your contract using Web3.js methods. Here's how to set a number and read it back, ensure replacing `INSERT_RPC_URL`, `INSERT_PRIVATE_KEY`, and `INSERT_CONTRACT_ADDRESS` with the appropriate values:\n\n```javascript title=\"scripts/updateStorage.js\"\nimport { readFileSync } from 'fs';\nimport { Web3 } from 'web3';\n\nconst getAbi = (contractName) => {\n try {\n return JSON.parse(readFileSync(`${contractName}.json`), 'utf8');\n } catch (error) {\n console.error(\n `❌ Could not find ABI for contract ${contractName}:`,\n error.message\n );\n throw error;\n }\n};\n\nconst updateStorage = async (config) => {\n try {\n // Initialize Web3 with RPC URL\n const web3 = new Web3(config.rpcUrl);\n\n // Prepare account\n const account = web3.eth.accounts.privateKeyToAccount(config.privateKey);\n web3.eth.accounts.wallet.add(account);\n\n // Load abi\n const abi = getAbi('Storage');\n\n // Create contract instance\n const contract = new web3.eth.Contract(abi, config.contractAddress);\n\n // Get initial value\n const initialValue = await contract.methods.storedNumber().call();\n console.log('Current stored value:', initialValue);\n\n // Prepare transaction\n const updateTransaction = contract.methods.setNumber(1);\n\n // Estimate gas\n const gasEstimate = await updateTransaction.estimateGas({\n from: account.address,\n });\n\n // Get current gas price\n const gasPrice = await web3.eth.getGasPrice();\n\n // Send update transaction\n const receipt = await updateTransaction.send({\n from: account.address,\n gas: gasEstimate,\n gasPrice: gasPrice,\n });\n\n // Log transaction details\n console.log(`Transaction hash: ${receipt.transactionHash}`);\n\n // Get updated value\n const newValue = await contract.methods.storedNumber().call();\n console.log('New stored value:', newValue);\n\n return receipt;\n } catch (error) {\n console.error('Update failed:', error);\n throw error;\n }\n};\n\n// Example usage\nconst config = {\n rpcUrl: 'INSERT_RPC_URL',\n privateKey: 'INSERT_PRIVATE_KEY',\n contractAddress: 'INSERT_CONTRACT_ADDRESS',\n};\n\nupdateStorage(config)\n .then((receipt) => console.log('Update successful'))\n .catch((error) => console.error('Update error'));\n\n```\n\nTo execute the logic above, run:\n\n```bash\nnode updateStorage\n```"} -{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 9, "depth": 2, "title": "Where to Go Next", "anchor": "where-to-go-next", "start_char": 12587, "end_char": 13096, "estimated_token_count": 131, "token_estimator": "heuristic-v1", "text": "## Where to Go Next\n\nNow that you’ve learned how to use Web3.js with Polkadot Hub, explore more advanced topics:\n\n- **Utilize Web3.js utilities**: Learn about additional [Web3.js](https://docs.web3js.org/){target=\\_blank} features such as signing transactions, managing wallets, and subscribing to events.\n- **Build full-stack dApps**: [integrate Web3.js](https://docs.web3js.org/guides/dapps/intermediate-dapp){target=\\_blank} with different libraries and frameworks to build decentralized web applications."} +{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 468, "end_char": 1027, "estimated_token_count": 102, "token_estimator": "heuristic-v1", "text": "## Introduction\n\nInteracting with blockchains typically requires an interface between your application and the network. [Web3.js](https://web3js.readthedocs.io/){target=\\_blank} offers this interface through a comprehensive collection of libraries, facilitating seamless interaction with the nodes using HTTP or WebSocket protocols. This guide illustrates how to utilize Web3.js specifically for interactions with Polkadot Hub.\n\nThis guide is intended for developers who are familiar with JavaScript and want to interact with the Polkadot Hub using Web3.js."} +{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 1, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 1027, "end_char": 1383, "estimated_token_count": 110, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore getting started, ensure you have the following installed:\n\n- **Node.js**: v22.13.1 or later, check the [Node.js installation guide](https://nodejs.org/en/download/current/){target=\\_blank}.\n- **npm**: v6.13.4 or later (comes bundled with Node.js).\n- **Solidity**: This guide uses Solidity `^0.8.9` for smart contract development."} +{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 2, "depth": 2, "title": "Project Structure", "anchor": "project-structure", "start_char": 1383, "end_char": 1868, "estimated_token_count": 136, "token_estimator": "heuristic-v1", "text": "## Project Structure\n\nThis project organizes contracts, scripts, and compiled artifacts for easy development and deployment.\n\n```text title=\"Web3.js Polkadot Hub\"\nweb3js-project\n├── contracts\n│ ├── Storage.sol\n├── scripts\n│ ├── connectToProvider.js\n│ ├── fetchLastBlock.js\n│ ├── compile.js\n│ ├── deploy.js\n│ ├── updateStorage.js\n├── abis\n│ ├── Storage.json\n├── artifacts\n│ ├── Storage.polkavm\n├── node_modules/\n├── package.json\n├── package-lock.json\n└── README.md\n```"} +{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 3, "depth": 2, "title": "Set Up the Project", "anchor": "set-up-the-project", "start_char": 1868, "end_char": 1984, "estimated_token_count": 31, "token_estimator": "heuristic-v1", "text": "## Set Up the Project\n\nTo start working with Web3.js, begin by initializing your project:\n\n```bash\nnpm init -y\n```"} +{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 4, "depth": 2, "title": "Install Dependencies", "anchor": "install-dependencies", "start_char": 1984, "end_char": 2117, "estimated_token_count": 38, "token_estimator": "heuristic-v1", "text": "## Install Dependencies\n\nNext, install the Web3.js library:\n\n```bash\nnpm install web3\n```\n\nThis guide uses `web3` version `4.16.0`."} +{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 5, "depth": 2, "title": "Set Up the Web3 Provider", "anchor": "set-up-the-web3-provider", "start_char": 2117, "end_char": 3950, "estimated_token_count": 425, "token_estimator": "heuristic-v1", "text": "## Set Up the Web3 Provider\n\nThe provider configuration is the foundation of any Web3.js application. The following example establishes a connection to Polkadot Hub. To use the example script, replace `INSERT_RPC_URL`, `INSERT_CHAIN_ID`, and `INSERT_CHAIN_NAME` with the appropriate values. The provider connection script should look something like this:\n\n```javascript title=\"scripts/connectToProvider.js\"\nconst { Web3 } = require('web3');\n\nconst createProvider = (rpcUrl) => {\n const web3 = new Web3(rpcUrl);\n return web3;\n};\n\nconst PROVIDER_RPC = {\n rpc: 'INSERT_RPC_URL',\n chainId: 'INSERT_CHAIN_ID',\n name: 'INSERT_CHAIN_NAME',\n};\n\ncreateProvider(PROVIDER_RPC.rpc);\n\n```\n\nFor example, for the Polkadot Hub TestNet, use these specific connection parameters:\n\n```js\nconst PROVIDER_RPC = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io',\n chainId: 420420422,\n name: 'polkadot-hub-testnet'\n};\n```\n\nWith the Web3 provider set up, you can start querying the blockchain.\n\nFor instance, to fetch the latest block number of the chain, you can use the following code snippet:\n\n???+ code \"View complete script\"\n\n ```javascript title=\"scripts/fetchLastBlock.js\"\n const { Web3 } = require('web3');\n\n const createProvider = (rpcUrl) => {\n const web3 = new Web3(rpcUrl);\n return web3;\n };\n\n const PROVIDER_RPC = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io',\n chainId: 420420422,\n name: 'polkadot-hub-testnet',\n };\n\n const main = async () => {\n try {\n const web3 = createProvider(PROVIDER_RPC.rpc);\n const latestBlock = await web3.eth.getBlockNumber();\n console.log('Last block: ' + latestBlock);\n } catch (error) {\n console.error('Error connecting to Polkadot Hub TestNet: ' + error.message);\n }\n };\n\n main();\n\n ```"} +{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 6, "depth": 2, "title": "Compile Contracts", "anchor": "compile-contracts", "start_char": 3950, "end_char": 7431, "estimated_token_count": 840, "token_estimator": "heuristic-v1", "text": "## Compile Contracts\n\n!!! note \"Contracts Code Blob Size Disclaimer\"\n The maximum contract code blob size on Polkadot Hub networks is _100 kilobytes_, significantly larger than Ethereum’s EVM limit of 24 kilobytes.\n\n For detailed comparisons and migration guidelines, see the [EVM vs. PolkaVM](/polkadot-protocol/smart-contract-basics/evm-vs-polkavm/#current-memory-limits){target=\\_blank} documentation page.\n\nPolkadot Hub requires contracts to be compiled to [PolkaVM](/smart-contracts/for-eth-devs/dual-vm-stack/){target=\\_blank} bytecode. This is achieved using the [`revive`](https://github.com/paritytech/revive/tree/v0.2.0/js/resolc){target=\\_blank} compiler. Install the [`@parity/resolc`](https://github.com/paritytech/revive){target=\\_blank} library as a development dependency:\n\n```bash\nnpm install --save-dev @parity/resolc\n```\n\nThis guide uses `@parity/resolc` version `0.2.0`.\n\nHere's a simple storage contract that you can use to follow the process:\n\n```solidity title=\"contracts/Storage.sol\"\n//SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\ncontract Storage {\n // Public state variable to store a number\n uint256 public storedNumber;\n\n /**\n * Updates the stored number.\n *\n * The `public` modifier allows anyone to call this function.\n *\n * @param _newNumber - The new value to store.\n */\n function setNumber(uint256 _newNumber) public {\n storedNumber = _newNumber;\n }\n}\n```\n\nWith that, you can now create a `compile.js` snippet that transforms your solidity code into PolkaVM bytecode:\n\n```javascript title=\"scripts/compile.js\"\nconst { compile } = require('@parity/resolc');\nconst { readFileSync, writeFileSync } = require('fs');\nconst { basename, join } = require('path');\n\nconst compileContract = async (solidityFilePath, outputDir) => {\n try {\n // Read the Solidity file\n const source = readFileSync(solidityFilePath, 'utf8');\n\n // Construct the input object for the compiler\n const input = {\n [basename(solidityFilePath)]: { content: source },\n };\n\n console.log(`Compiling contract: ${basename(solidityFilePath)}...`);\n\n // Compile the contract\n const out = await compile(input);\n\n for (const contracts of Object.values(out.contracts)) {\n for (const [name, contract] of Object.entries(contracts)) {\n console.log(`Compiled contract: ${name}`);\n\n // Write the ABI\n const abiPath = join(outputDir, `${name}.json`);\n writeFileSync(abiPath, JSON.stringify(contract.abi, null, 2));\n console.log(`ABI saved to ${abiPath}`);\n\n // Write the bytecode\n const bytecodePath = join(outputDir, `${name}.polkavm`);\n writeFileSync(\n bytecodePath,\n Buffer.from(contract.evm.bytecode.object, 'hex'),\n );\n console.log(`Bytecode saved to ${bytecodePath}`);\n }\n }\n } catch (error) {\n console.error('Error compiling contracts:', error);\n }\n};\n\nconst solidityFilePath = './Storage.sol';\nconst outputDir = '.';\n\ncompileContract(solidityFilePath, outputDir);\n\n```\n\nTo compile your contract, simply run the following command:\n\n```bash\nnode compile\n```\n\nAfter compilation, you'll have two key files: an ABI (`.json`) file, which provides a JSON interface describing the contract's functions and how to interact with it, and a bytecode (`.polkavm`) file, which contains the low-level machine code executable on PolkaVM that represents the compiled smart contract ready for blockchain deployment."} +{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 7, "depth": 2, "title": "Contract Deployment", "anchor": "contract-deployment", "start_char": 7431, "end_char": 10374, "estimated_token_count": 674, "token_estimator": "heuristic-v1", "text": "## Contract Deployment\n\nTo deploy your compiled contract to Polkadot Hub using Web3.js, you'll need an account with a private key to sign the deployment transaction. The deployment process is exactly the same as for any Ethereum-compatible chain, involving creating a contract instance, estimating gas, and sending a deployment transaction. Here's how to deploy the contract, ensure replacing the `INSERT_RPC_URL`, `INSERT_PRIVATE_KEY`, and `INSERT_CONTRACT_NAME` with the appropriate values:\n\n```javascript title=\"scripts/deploy.js\"\nimport { readFileSync } from 'fs';\nimport { Web3 } from 'web3';\n\nconst getAbi = (contractName) => {\n try {\n return JSON.parse(readFileSync(`${contractName}.json`), 'utf8');\n } catch (error) {\n console.error(\n `❌ Could not find ABI for contract ${contractName}:`,\n error.message\n );\n throw error;\n }\n};\n\nconst getByteCode = (contractName) => {\n try {\n return `0x${readFileSync(`${contractName}.polkavm`).toString('hex')}`;\n } catch (error) {\n console.error(\n `❌ Could not find bytecode for contract ${contractName}:`,\n error.message\n );\n throw error;\n }\n};\n\nexport const deploy = async (config) => {\n try {\n // Initialize Web3 with RPC URL\n const web3 = new Web3(config.rpcUrl);\n\n // Prepare account\n const account = web3.eth.accounts.privateKeyToAccount(config.privateKey);\n web3.eth.accounts.wallet.add(account);\n\n // Load abi\n const abi = getAbi('Storage');\n\n // Create contract instance\n const contract = new web3.eth.Contract(abi);\n\n // Prepare deployment\n const deployTransaction = contract.deploy({\n data: getByteCode('Storage'),\n arguments: [], // Add constructor arguments if needed\n });\n\n // Estimate gas\n const gasEstimate = await deployTransaction.estimateGas({\n from: account.address,\n });\n\n // Get current gas price\n const gasPrice = await web3.eth.getGasPrice();\n\n // Send deployment transaction\n const deployedContract = await deployTransaction.send({\n from: account.address,\n gas: gasEstimate,\n gasPrice: gasPrice,\n });\n\n // Log and return contract details\n console.log(`Contract deployed at: ${deployedContract.options.address}`);\n return deployedContract;\n } catch (error) {\n console.error('Deployment failed:', error);\n throw error;\n }\n};\n\n// Example usage\nconst deploymentConfig = {\n rpcUrl: 'INSERT_RPC_URL',\n privateKey: 'INSERT_PRIVATE_KEY',\n contractName: 'INSERT_CONTRACT_NAME',\n};\n\ndeploy(deploymentConfig)\n .then((contract) => console.log('Deployment successful'))\n .catch((error) => console.error('Deployment error'));\n\n```\n\nFor further details on private key exportation, refer to the article [How to export an account's private key](https://support.metamask.io/configure/accounts/how-to-export-an-accounts-private-key/){target=\\_blank}.\n\nTo deploy your contract, run the following command:\n\n```bash\nnode deploy\n```"} +{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 8, "depth": 2, "title": "Interact with the Contract", "anchor": "interact-with-the-contract", "start_char": 10374, "end_char": 12757, "estimated_token_count": 548, "token_estimator": "heuristic-v1", "text": "## Interact with the Contract\n\nOnce deployed, you can interact with your contract using Web3.js methods. Here's how to set a number and read it back, ensure replacing `INSERT_RPC_URL`, `INSERT_PRIVATE_KEY`, and `INSERT_CONTRACT_ADDRESS` with the appropriate values:\n\n```javascript title=\"scripts/updateStorage.js\"\nimport { readFileSync } from 'fs';\nimport { Web3 } from 'web3';\n\nconst getAbi = (contractName) => {\n try {\n return JSON.parse(readFileSync(`${contractName}.json`), 'utf8');\n } catch (error) {\n console.error(\n `❌ Could not find ABI for contract ${contractName}:`,\n error.message\n );\n throw error;\n }\n};\n\nconst updateStorage = async (config) => {\n try {\n // Initialize Web3 with RPC URL\n const web3 = new Web3(config.rpcUrl);\n\n // Prepare account\n const account = web3.eth.accounts.privateKeyToAccount(config.privateKey);\n web3.eth.accounts.wallet.add(account);\n\n // Load abi\n const abi = getAbi('Storage');\n\n // Create contract instance\n const contract = new web3.eth.Contract(abi, config.contractAddress);\n\n // Get initial value\n const initialValue = await contract.methods.storedNumber().call();\n console.log('Current stored value:', initialValue);\n\n // Prepare transaction\n const updateTransaction = contract.methods.setNumber(1);\n\n // Estimate gas\n const gasEstimate = await updateTransaction.estimateGas({\n from: account.address,\n });\n\n // Get current gas price\n const gasPrice = await web3.eth.getGasPrice();\n\n // Send update transaction\n const receipt = await updateTransaction.send({\n from: account.address,\n gas: gasEstimate,\n gasPrice: gasPrice,\n });\n\n // Log transaction details\n console.log(`Transaction hash: ${receipt.transactionHash}`);\n\n // Get updated value\n const newValue = await contract.methods.storedNumber().call();\n console.log('New stored value:', newValue);\n\n return receipt;\n } catch (error) {\n console.error('Update failed:', error);\n throw error;\n }\n};\n\n// Example usage\nconst config = {\n rpcUrl: 'INSERT_RPC_URL',\n privateKey: 'INSERT_PRIVATE_KEY',\n contractAddress: 'INSERT_CONTRACT_ADDRESS',\n};\n\nupdateStorage(config)\n .then((receipt) => console.log('Update successful'))\n .catch((error) => console.error('Update error'));\n\n```\n\nTo execute the logic above, run:\n\n```bash\nnode updateStorage\n```"} +{"page_id": "smart-contracts-libraries-web3-js", "page_title": "Web3.js", "index": 9, "depth": 2, "title": "Where to Go Next", "anchor": "where-to-go-next", "start_char": 12757, "end_char": 13266, "estimated_token_count": 131, "token_estimator": "heuristic-v1", "text": "## Where to Go Next\n\nNow that you’ve learned how to use Web3.js with Polkadot Hub, explore more advanced topics:\n\n- **Utilize Web3.js utilities**: Learn about additional [Web3.js](https://docs.web3js.org/){target=\\_blank} features such as signing transactions, managing wallets, and subscribing to events.\n- **Build full-stack dApps**: [integrate Web3.js](https://docs.web3js.org/guides/dapps/intermediate-dapp){target=\\_blank} with different libraries and frameworks to build decentralized web applications."} {"page_id": "smart-contracts-libraries-web3-py", "page_title": "Web3.py", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 181, "end_char": 605, "estimated_token_count": 83, "token_estimator": "heuristic-v1", "text": "## Introduction\n\nInteracting with blockchains typically requires an interface between your application and the network. [Web3.py](https://web3py.readthedocs.io/en/stable/index.html){target=\\_blank} offers this interface through a collection of libraries, facilitating seamless interaction with the nodes using HTTP or WebSocket protocols. \n\nThis guide illustrates how to utilize Web3.py for interactions with Polkadot Hub."} {"page_id": "smart-contracts-libraries-web3-py", "page_title": "Web3.py", "index": 1, "depth": 2, "title": "Set Up the Project", "anchor": "set-up-the-project", "start_char": 605, "end_char": 986, "estimated_token_count": 88, "token_estimator": "heuristic-v1", "text": "## Set Up the Project\n\n1. To start working with Web3.py, begin by initializing your project:\n\n ```bash\n mkdir web3py-project\n cd web3py-project\n ```\n\n2. Create and activate a virtual environment for your project:\n\n ```bash\n python -m venv venv\n source venv/bin/activate\n ```\n\n3. Next, install the Web3.py library:\n\n ```bash\n pip install web3\n ```"} {"page_id": "smart-contracts-libraries-web3-py", "page_title": "Web3.py", "index": 2, "depth": 2, "title": "Set Up the Web3 Provider", "anchor": "set-up-the-web3-provider", "start_char": 986, "end_char": 3080, "estimated_token_count": 423, "token_estimator": "heuristic-v1", "text": "## Set Up the Web3 Provider\n\nThe [provider](https://web3py.readthedocs.io/en/stable/providers.html){target=\\_blank} configuration is the foundation of any Web3.py application. The following example establishes a connection to Polkadot Hub. Follow these steps to use the provider configuration:\n\n1. Replace `INSERT_RPC_URL` with the appropriate value. For instance, to connect to Polkadot Hub TestNet, use the following parameter:\n\n ```python\n PROVIDER_RPC = 'https://testnet-passet-hub-eth-rpc.polkadot.io'\n ```\n\n The provider connection script should look something like this:\n\n ```python title=\"connect_to_provider.py\"\n from web3 import Web3\n\n def create_provider(rpc_url):\n web3 = Web3(Web3.HTTPProvider(rpc_url))\n return web3\n\n PROVIDER_RPC = 'INSERT_RPC_URL'\n\n create_provider(PROVIDER_RPC)\n ```\n\n1. With the Web3 provider set up, start querying the blockchain. For instance, you can use the following code snippet to fetch the latest block number of the chain:\n\n ```python title=\"fetch_last_block.py\"\n def main():\n try:\n web3 = create_provider(PROVIDER_RPC)\n latest_block = web3.eth.block_number\n print('Last block: ' + str(latest_block))\n except Exception as error:\n print('Error connecting to Polkadot Hub TestNet: ' + str(error))\n\n if __name__ == \"__main__\":\n main()\n ```\n\n ??? code \"View complete script\"\n\n ```python title=\"fetch_last_block.py\"\n from web3 import Web3\n\n def create_provider(rpc_url):\n web3 = Web3(Web3.HTTPProvider(rpc_url))\n return web3\n\n PROVIDER_RPC = 'https://testnet-passet-hub-eth-rpc.polkadot.io'\n\n def main():\n try:\n web3 = create_provider(PROVIDER_RPC)\n latest_block = web3.eth.block_number\n print('Last block: ' + str(latest_block))\n except Exception as error:\n print('Error connecting to Polkadot Hub TestNet: ' + str(error))\n\n if __name__ == \"__main__\":\n main()\n ```"} diff --git a/smart-contracts/libraries/web3-js.md b/smart-contracts/libraries/web3-js.md index 1bd2e9302..8c4545aa4 100644 --- a/smart-contracts/libraries/web3-js.md +++ b/smart-contracts/libraries/web3-js.md @@ -6,6 +6,8 @@ categories: Smart Contracts, Tooling # Web3.js +--8<-- 'text/smart-contracts/polkaVM-warning.md' + !!! warning Web3.js has been [sunset](https://blog.chainsafe.io/web3-js-sunset/){target=\_blank}. You can find guides on using [Ethers.js](/smart-contracts/libraries/ethers-js/){target=\_blank} and [viem](/smart-contracts/libraries/viem/){target=\_blank} in the Libraries section. From 75bb055a12fce05d57ba49cc40c831e80cb790c4 Mon Sep 17 00:00:00 2001 From: DAWN KELLY Date: Thu, 20 Nov 2025 15:03:14 -0500 Subject: [PATCH 6/7] updated title on code block --- smart-contracts/libraries/ethers-js.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smart-contracts/libraries/ethers-js.md b/smart-contracts/libraries/ethers-js.md index abdbfab4d..374e5f915 100644 --- a/smart-contracts/libraries/ethers-js.md +++ b/smart-contracts/libraries/ethers-js.md @@ -103,7 +103,7 @@ node scripts/connectToProvider.js With the provider set up, you can start querying the blockchain. For instance, to fetch the latest block number: -??? code "Fetch Last Block code" +??? code "fetchLastBlock.js code" ```js title="scripts/fetchLastBlock.js" --8<-- 'code/smart-contracts/libraries/ethers-js/fetchLastBlock.js' From 98e46fed88312e5ab7097480a206a292a3ec8924 Mon Sep 17 00:00:00 2001 From: DAWN KELLY Date: Thu, 20 Nov 2025 15:10:42 -0500 Subject: [PATCH 7/7] apply review feedback, fresh llms --- .ai/categories/smart-contracts.md | 10 +++++----- .ai/categories/tooling.md | 10 +++++----- .ai/pages/smart-contracts-libraries-ethers-js.md | 10 +++++----- .ai/site-index.json | 8 ++++---- .../smart-contracts/libraries/ethers-js/deploy.js | 4 ++-- llms-full.jsonl | 14 +++++++------- 6 files changed, 28 insertions(+), 28 deletions(-) diff --git a/.ai/categories/smart-contracts.md b/.ai/categories/smart-contracts.md index c6fbd51ec..450b5d6f2 100644 --- a/.ai/categories/smart-contracts.md +++ b/.ai/categories/smart-contracts.md @@ -3189,7 +3189,7 @@ node scripts/connectToProvider.js With the provider set up, you can start querying the blockchain. For instance, to fetch the latest block number: -??? code "Fetch Last Block code" +??? code "fetchLastBlock.js code" ```js title="scripts/fetchLastBlock.js" const { JsonRpcProvider } = require('ethers'); @@ -3469,12 +3469,12 @@ You can create a `deploy.js` script in the root of your project to achieve this. ```js title="scripts/deploy.js" const providerConfig = { - rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', #TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready + rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', //TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready chainId: 420420422, name: 'polkadot-hub-testnet', }; - const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon'; + const mnemonic = 'INSERT_MNEMONIC'; deployContract('Storage', mnemonic, providerConfig); ``` @@ -3571,12 +3571,12 @@ You can create a `deploy.js` script in the root of your project to achieve this. }; const providerConfig = { - rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', #TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready + rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', //TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready chainId: 420420422, name: 'polkadot-hub-testnet', }; - const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon'; + const mnemonic = 'INSERT_MNEMONIC'; deployContract('Storage', mnemonic, providerConfig); ``` diff --git a/.ai/categories/tooling.md b/.ai/categories/tooling.md index 0c1678e58..d3dd8e4ea 100644 --- a/.ai/categories/tooling.md +++ b/.ai/categories/tooling.md @@ -2487,7 +2487,7 @@ node scripts/connectToProvider.js With the provider set up, you can start querying the blockchain. For instance, to fetch the latest block number: -??? code "Fetch Last Block code" +??? code "fetchLastBlock.js code" ```js title="scripts/fetchLastBlock.js" const { JsonRpcProvider } = require('ethers'); @@ -2767,12 +2767,12 @@ You can create a `deploy.js` script in the root of your project to achieve this. ```js title="scripts/deploy.js" const providerConfig = { - rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', #TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready + rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', //TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready chainId: 420420422, name: 'polkadot-hub-testnet', }; - const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon'; + const mnemonic = 'INSERT_MNEMONIC'; deployContract('Storage', mnemonic, providerConfig); ``` @@ -2869,12 +2869,12 @@ You can create a `deploy.js` script in the root of your project to achieve this. }; const providerConfig = { - rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', #TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready + rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', //TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready chainId: 420420422, name: 'polkadot-hub-testnet', }; - const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon'; + const mnemonic = 'INSERT_MNEMONIC'; deployContract('Storage', mnemonic, providerConfig); ``` diff --git a/.ai/pages/smart-contracts-libraries-ethers-js.md b/.ai/pages/smart-contracts-libraries-ethers-js.md index 7fd2ab8fb..a12b531a0 100644 --- a/.ai/pages/smart-contracts-libraries-ethers-js.md +++ b/.ai/pages/smart-contracts-libraries-ethers-js.md @@ -122,7 +122,7 @@ node scripts/connectToProvider.js With the provider set up, you can start querying the blockchain. For instance, to fetch the latest block number: -??? code "Fetch Last Block code" +??? code "fetchLastBlock.js code" ```js title="scripts/fetchLastBlock.js" const { JsonRpcProvider } = require('ethers'); @@ -402,12 +402,12 @@ You can create a `deploy.js` script in the root of your project to achieve this. ```js title="scripts/deploy.js" const providerConfig = { - rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', #TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready + rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', //TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready chainId: 420420422, name: 'polkadot-hub-testnet', }; - const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon'; + const mnemonic = 'INSERT_MNEMONIC'; deployContract('Storage', mnemonic, providerConfig); ``` @@ -504,12 +504,12 @@ You can create a `deploy.js` script in the root of your project to achieve this. }; const providerConfig = { - rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', #TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready + rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', //TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready chainId: 420420422, name: 'polkadot-hub-testnet', }; - const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon'; + const mnemonic = 'INSERT_MNEMONIC'; deployContract('Storage', mnemonic, providerConfig); ``` diff --git a/.ai/site-index.json b/.ai/site-index.json index c5791cfe6..cae61f0cc 100644 --- a/.ai/site-index.json +++ b/.ai/site-index.json @@ -8541,12 +8541,12 @@ } ], "stats": { - "chars": 21413, - "words": 2435, + "chars": 21292, + "words": 2412, "headings": 12, - "estimated_token_count_total": 4762 + "estimated_token_count_total": 4742 }, - "hash": "sha256:121e52bd405e70bde9288d65557266fbaa0dbca290bdfebc67de8105d9672785", + "hash": "sha256:3493aaeec569be8d72f418c9b1abeeed64ff3bbcc316b42a33dad5f172c4e841", "token_estimator": "heuristic-v1" }, { diff --git a/.snippets/code/smart-contracts/libraries/ethers-js/deploy.js b/.snippets/code/smart-contracts/libraries/ethers-js/deploy.js index c2bc56b59..c753c714a 100644 --- a/.snippets/code/smart-contracts/libraries/ethers-js/deploy.js +++ b/.snippets/code/smart-contracts/libraries/ethers-js/deploy.js @@ -82,11 +82,11 @@ const deployContract = async (contractName, mnemonic, providerConfig) => { }; const providerConfig = { - rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', #TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready + rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', //TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready chainId: 420420422, name: 'polkadot-hub-testnet', }; -const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon'; +const mnemonic = 'INSERT_MNEMONIC'; deployContract('Storage', mnemonic, providerConfig); \ No newline at end of file diff --git a/llms-full.jsonl b/llms-full.jsonl index 25a0578e0..3837a8fd8 100644 --- a/llms-full.jsonl +++ b/llms-full.jsonl @@ -1114,13 +1114,13 @@ {"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 2, "depth": 2, "title": "Project Structure", "anchor": "project-structure", "start_char": 895, "end_char": 1403, "estimated_token_count": 144, "token_estimator": "heuristic-v1", "text": "## Project Structure\n\nThis project organizes contracts, scripts, and compiled artifacts for easy development and deployment.\n\n```text title=\"Ethers.js Polkadot Hub\"\nethers-project\n├── contracts\n│ ├── Storage.sol\n├── scripts\n│ ├── connectToProvider.js\n│ ├── fetchLastBlock.js\n│ ├── compile.js\n│ ├── deploy.js\n│ ├── checkStorage.js\n├── abis\n│ ├── Storage.json\n├── artifacts\n│ ├── Storage.bin\n├── contract-address.json\n├── node_modules/\n├── package.json\n├── package-lock.json\n└── README.md\n```"} {"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 3, "depth": 2, "title": "Set Up the Project", "anchor": "set-up-the-project", "start_char": 1403, "end_char": 1624, "estimated_token_count": 50, "token_estimator": "heuristic-v1", "text": "## Set Up the Project\n\nTo start working with Ethers.js, create a new folder and initialize your project by running the following commands in your terminal:\n\n```bash\nmkdir ethers-project\ncd ethers-project\nnpm init -y\n```"} {"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 4, "depth": 2, "title": "Install Dependencies", "anchor": "install-dependencies", "start_char": 1624, "end_char": 2083, "estimated_token_count": 122, "token_estimator": "heuristic-v1", "text": "## Install Dependencies\n\nNext, run the following command to install the Ethers.js library:\n\n```bash\nnpm install ethers\n```\n\nAdd the Solidity compiler so you can generate standard EVM bytecode:\n\n```bash\nnpm install --save-dev solc\n```\n\nThis guide uses `solc` version `0.8.33`.\n\n!!! tip\n The sample scripts use ECMAScript modules. Add `\"type\": \"module\"` to your `package.json` (or rename the files to `.mjs`) so that `node` can run the `import` statements."} -{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 5, "depth": 2, "title": "Set Up the Ethers.js Provider", "anchor": "set-up-the-ethersjs-provider", "start_char": 2083, "end_char": 4682, "estimated_token_count": 578, "token_estimator": "heuristic-v1", "text": "## Set Up the Ethers.js Provider\n\nA [`Provider`](https://docs.ethers.org/v6/api/providers/#Provider){target=\\_blank} is an abstraction of a connection to the Ethereum network, allowing you to query blockchain data and send transactions. It serves as a bridge between your application and the blockchain.\n\nTo interact with Polkadot Hub, you must set up an Ethers.js provider. This provider connects to a blockchain node, allowing you to query blockchain data and interact with smart contracts. In the root of your project, create a file named `connectToProvider.js` and add the following code:\n\n```js title=\"scripts/connectToProvider.js\"\nconst { JsonRpcProvider } = require('ethers');\n\nconst createProvider = (rpcUrl, chainId, chainName) => {\n const provider = new JsonRpcProvider(rpcUrl, {\n chainId: chainId,\n name: chainName,\n });\n\n return provider;\n};\n\nconst PROVIDER_RPC = {\n rpc: 'INSERT_RPC_URL',\n chainId: 'INSERT_CHAIN_ID',\n name: 'INSERT_CHAIN_NAME',\n};\n\ncreateProvider(PROVIDER_RPC.rpc, PROVIDER_RPC.chainId, PROVIDER_RPC.name);\n\n```\n\n!!! note\n Replace `INSERT_RPC_URL`, `INSERT_CHAIN_ID`, and `INSERT_CHAIN_NAME` with the appropriate values. For example, to connect to Polkadot Hub TestNet's Ethereum RPC instance, you can use the following parameters:\n\n ```js\n const PROVIDER_RPC = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io',\n chainId: 420420422,\n name: 'polkadot-hub-testnet'\n };\n ```\n\nTo connect to the provider, execute:\n\n```bash\nnode scripts/connectToProvider.js\n```\n\nWith the provider set up, you can start querying the blockchain. For instance, to fetch the latest block number:\n\n??? code \"Fetch Last Block code\"\n\n ```js title=\"scripts/fetchLastBlock.js\"\n const { JsonRpcProvider } = require('ethers');\n\n const createProvider = (rpcUrl, chainId, chainName) => {\n const provider = new JsonRpcProvider(rpcUrl, {\n chainId: chainId,\n name: chainName,\n });\n\n return provider;\n };\n\n const PROVIDER_RPC = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io',\n chainId: 420420422,\n name: 'polkadot-hub-testnet',\n };\n\n const main = async () => {\n try {\n const provider = createProvider(\n PROVIDER_RPC.rpc,\n PROVIDER_RPC.chainId,\n PROVIDER_RPC.name,\n );\n const latestBlock = await provider.getBlockNumber();\n console.log(`Latest block: ${latestBlock}`);\n } catch (error) {\n console.error('Error connecting to Polkadot Hub TestNet: ' + error.message);\n }\n };\n\n main();\n\n ```"} -{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 6, "depth": 2, "title": "Compile Contracts", "anchor": "compile-contracts", "start_char": 4682, "end_char": 5011, "estimated_token_count": 74, "token_estimator": "heuristic-v1", "text": "## Compile Contracts\n\nPolkadot Hub exposes an Ethereum JSON-RPC endpoint, so you can compile Solidity contracts to familiar EVM bytecode with the upstream [`solc`](https://www.npmjs.com/package/solc){target=\\_blank} compiler. The resulting artifacts work with any EVM-compatible toolchain and can be deployed through Ethers.js."} -{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 7, "depth": 3, "title": "Sample Storage Smart Contract", "anchor": "sample-storage-smart-contract", "start_char": 5011, "end_char": 5836, "estimated_token_count": 171, "token_estimator": "heuristic-v1", "text": "### Sample Storage Smart Contract\n\nThis example demonstrates compiling a `Storage.sol` Solidity contract for deployment to Polkadot Hub. The contract's functionality stores a number and permits users to update it with a new value.\n\n```solidity title=\"contracts/Storage.sol\"\n//SPDX-License-Identifier: MIT\n\n// Solidity files have to start with this pragma.\n// It will be used by the Solidity compiler to validate its version.\npragma solidity ^0.8.9;\n\ncontract Storage {\n // Public state variable to store a number\n uint256 public storedNumber;\n\n /**\n * Updates the stored number.\n *\n * The `public` modifier allows anyone to call this function.\n *\n * @param _newNumber - The new value to store.\n */\n function setNumber(uint256 _newNumber) public {\n storedNumber = _newNumber;\n }\n}\n```"} -{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 8, "depth": 3, "title": "Compile the Smart Contract", "anchor": "compile-the-smart-contract", "start_char": 5836, "end_char": 9393, "estimated_token_count": 810, "token_estimator": "heuristic-v1", "text": "### Compile the Smart Contract\n\nTo compile this contract, use the following script:\n\n```js title=\"scripts/compile.js\"\nconst solc = require('solc');\nconst { readFileSync, writeFileSync, mkdirSync, existsSync } = require('fs');\nconst { basename, join } = require('path');\n\nconst ensureDir = (dirPath) => {\n if (!existsSync(dirPath)) {\n mkdirSync(dirPath, { recursive: true });\n }\n};\n\nconst compileContract = (solidityFilePath, abiDir, artifactsDir) => {\n try {\n // Read the Solidity file\n const source = readFileSync(solidityFilePath, 'utf8');\n const fileName = basename(solidityFilePath);\n \n // Construct the input object for the Solidity compiler\n const input = {\n language: 'Solidity',\n sources: {\n [fileName]: {\n content: source,\n },\n },\n settings: {\n outputSelection: {\n '*': {\n '*': ['abi', 'evm.bytecode'],\n },\n },\n },\n };\n \n console.log(`Compiling contract: ${fileName}...`);\n \n // Compile the contract\n const output = JSON.parse(solc.compile(JSON.stringify(input)));\n \n // Check for errors\n if (output.errors) {\n const errors = output.errors.filter(error => error.severity === 'error');\n if (errors.length > 0) {\n console.error('Compilation errors:');\n errors.forEach(err => console.error(err.formattedMessage));\n return;\n }\n // Show warnings\n const warnings = output.errors.filter(error => error.severity === 'warning');\n warnings.forEach(warn => console.warn(warn.formattedMessage));\n }\n \n // Ensure output directories exist\n ensureDir(abiDir);\n ensureDir(artifactsDir);\n\n // Process compiled contracts\n for (const [sourceFile, contracts] of Object.entries(output.contracts)) {\n for (const [contractName, contract] of Object.entries(contracts)) {\n console.log(`Compiled contract: ${contractName}`);\n \n // Write the ABI\n const abiPath = join(abiDir, `${contractName}.json`);\n writeFileSync(abiPath, JSON.stringify(contract.abi, null, 2));\n console.log(`ABI saved to ${abiPath}`);\n \n // Write the bytecode\n const bytecodePath = join(artifactsDir, `${contractName}.bin`);\n writeFileSync(bytecodePath, contract.evm.bytecode.object);\n console.log(`Bytecode saved to ${bytecodePath}`);\n }\n }\n } catch (error) {\n console.error('Error compiling contracts:', error);\n }\n};\n\nconst solidityFilePath = join(__dirname, '../contracts/Storage.sol');\nconst abiDir = join(__dirname, '../abis');\nconst artifactsDir = join(__dirname, '../artifacts');\n\ncompileContract(solidityFilePath, abiDir, artifactsDir);\n```\n\n!!! note \n The script above is tailored to the `Storage.sol` contract. It can be adjusted for other contracts by changing the file name or modifying the ABI and bytecode paths.\n\nThe ABI (Application Binary Interface) is a JSON representation of your contract's functions, events, and their parameters. It serves as the interface between your JavaScript code and the deployed smart contract, allowing your application to know how to format function calls and interpret returned data.\n\nExecute the script above by running:\n\n```bash\nnode scripts/compile.js\n```\n\nAfter executing the script, the Solidity contract is compiled into standard EVM bytecode. The ABI and bytecode are saved into files with `.json` and `.bin` extensions, respectively. You can now proceed with deploying the contract to Polkadot Hub, as outlined in the next section."} -{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 9, "depth": 2, "title": "Deploy the Compiled Contract", "anchor": "deploy-the-compiled-contract", "start_char": 9393, "end_char": 17368, "estimated_token_count": 1692, "token_estimator": "heuristic-v1", "text": "## Deploy the Compiled Contract\n\nTo deploy your compiled contract to Polkadot Hub, you'll need a wallet with a private key to sign the deployment transaction.\n\nYou can create a `deploy.js` script in the root of your project to achieve this. The deployment script can be divided into key components:\n\n1. Set up the required imports and utilities:\n\n ```js title=\"scripts/deploy.js\"\n const { writeFileSync, existsSync, readFileSync } = require('fs');\n const { join } = require('path');\n const { ethers, JsonRpcProvider } = require('ethers');\n\n ```\n\n2. Create a provider to connect to Polkadot Hub:\n\n ```js title=\"scripts/deploy.js\"\n\n // Creates a provider with specified RPC URL and chain details\n const createProvider = (rpcUrl, chainId, chainName) => {\n const provider = new JsonRpcProvider(rpcUrl, {\n chainId: chainId,\n name: chainName,\n });\n return provider;\n };\n ```\n \n3. Set up functions to read contract artifacts:\n\n ```js title=\"scripts/deploy.js\"\n // Reads and parses the ABI file for a given contract\n const getAbi = (contractName) => {\n try {\n const abiPath = join(artifactsDir, `${contractName}.json`);\n return JSON.parse(readFileSync(abiPath, 'utf8'));\n } catch (error) {\n console.error(\n `Could not find ABI for contract ${contractName}:`,\n error.message,\n );\n throw error;\n }\n };\n\n // Reads the compiled bytecode for a given contract\n const getByteCode = (contractName) => {\n try {\n const bytecodePath = join(artifactsDir, `${contractName}.bin`);\n const bytecode = readFileSync(bytecodePath, 'utf8').trim();\n // Add 0x prefix if not present\n return bytecode.startsWith('0x') ? bytecode : `0x${bytecode}`;\n } catch (error) {\n console.error(\n `Could not find bytecode for contract ${contractName}:`,\n error.message,\n );\n throw error;\n }\n };\n\n ```\n\n4. Create the main deployment function:\n\n ```js title=\"scripts/deploy.js\"\n const deployContract = async (contractName, mnemonic, providerConfig) => {\n console.log(`Deploying ${contractName}...`);\n try {\n // Step 1: Set up provider and wallet\n const provider = createProvider(\n providerConfig.rpc,\n providerConfig.chainId,\n providerConfig.name,\n );\n const walletMnemonic = ethers.Wallet.fromPhrase(mnemonic);\n const wallet = walletMnemonic.connect(provider);\n\n // Step 2: Create and deploy the contract\n const factory = new ethers.ContractFactory(\n getAbi(contractName),\n getByteCode(contractName),\n wallet,\n );\n const contract = await factory.deploy();\n await contract.waitForDeployment();\n\n // Step 3: Save deployment information\n const address = await contract.getAddress();\n console.log(`Contract ${contractName} deployed at: ${address}`);\n\n const addressesFile = join(scriptsDir, 'contract-address.json');\n const addresses = existsSync(addressesFile)\n ? JSON.parse(readFileSync(addressesFile, 'utf8'))\n : {};\n\n addresses[contractName] = address;\n writeFileSync(addressesFile, JSON.stringify(addresses, null, 2), 'utf8');\n } catch (error) {\n console.error(`Failed to deploy contract ${contractName}:`, error);\n }\n };\n ```\n\n5. Configure and execute the deployment:\n\n ```js title=\"scripts/deploy.js\"\n const providerConfig = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', #TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready\n chainId: 420420422,\n name: 'polkadot-hub-testnet',\n };\n\n const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon';\n\n deployContract('Storage', mnemonic, providerConfig);\n ```\n\n !!! note\n A mnemonic (seed phrase) is a series of words that can generate multiple private keys and their corresponding addresses. It's used here to derive the wallet that will sign and pay for the deployment transaction. **Always keep your mnemonic secure and never share it publicly**.\n\n Ensure to replace the `INSERT_MNEMONIC` placeholder with your actual mnemonic.\n\n??? code \"View complete script\"\n\n ```js title=\"scripts/deploy.js\"\n const { writeFileSync, existsSync, readFileSync } = require('fs');\n const { join } = require('path');\n const { ethers, JsonRpcProvider } = require('ethers');\n\n const scriptsDir = __dirname;\n const artifactsDir = join(__dirname, '../contracts');\n\n // Creates a provider with specified RPC URL and chain details\n const createProvider = (rpcUrl, chainId, chainName) => {\n const provider = new JsonRpcProvider(rpcUrl, {\n chainId: chainId,\n name: chainName,\n });\n return provider;\n };\n\n // Reads and parses the ABI file for a given contract\n const getAbi = (contractName) => {\n try {\n const abiPath = join(artifactsDir, `${contractName}.json`);\n return JSON.parse(readFileSync(abiPath, 'utf8'));\n } catch (error) {\n console.error(\n `Could not find ABI for contract ${contractName}:`,\n error.message,\n );\n throw error;\n }\n };\n\n // Reads the compiled bytecode for a given contract\n const getByteCode = (contractName) => {\n try {\n const bytecodePath = join(artifactsDir, `${contractName}.bin`);\n const bytecode = readFileSync(bytecodePath, 'utf8').trim();\n // Add 0x prefix if not present\n return bytecode.startsWith('0x') ? bytecode : `0x${bytecode}`;\n } catch (error) {\n console.error(\n `Could not find bytecode for contract ${contractName}:`,\n error.message,\n );\n throw error;\n }\n };\n\n const deployContract = async (contractName, mnemonic, providerConfig) => {\n console.log(`Deploying ${contractName}...`);\n try {\n // Step 1: Set up provider and wallet\n const provider = createProvider(\n providerConfig.rpc,\n providerConfig.chainId,\n providerConfig.name,\n );\n const walletMnemonic = ethers.Wallet.fromPhrase(mnemonic);\n const wallet = walletMnemonic.connect(provider);\n\n // Step 2: Create and deploy the contract\n const factory = new ethers.ContractFactory(\n getAbi(contractName),\n getByteCode(contractName),\n wallet,\n );\n const contract = await factory.deploy();\n await contract.waitForDeployment();\n\n // Step 3: Save deployment information\n const address = await contract.getAddress();\n console.log(`Contract ${contractName} deployed at: ${address}`);\n\n const addressesFile = join(scriptsDir, 'contract-address.json');\n const addresses = existsSync(addressesFile)\n ? JSON.parse(readFileSync(addressesFile, 'utf8'))\n : {};\n\n addresses[contractName] = address;\n writeFileSync(addressesFile, JSON.stringify(addresses, null, 2), 'utf8');\n } catch (error) {\n console.error(`Failed to deploy contract ${contractName}:`, error);\n }\n };\n\n const providerConfig = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', #TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready\n chainId: 420420422,\n name: 'polkadot-hub-testnet',\n };\n\n const mnemonic = 'evoke moment pluck misery cheese boy era fresh useful frame resemble cinnamon';\n\n deployContract('Storage', mnemonic, providerConfig);\n ```\n\nTo run the script, execute the following command:\n\n```bash\nnode scripts/deploy.js\n```\n\nAfter running this script, your contract will be deployed to Polkadot Hub, and its address will be saved in `contract-address.json` within your project directory. You can use this address for future contract interactions."} -{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 10, "depth": 2, "title": "Interact with the Contract", "anchor": "interact-with-the-contract", "start_char": 17368, "end_char": 20808, "estimated_token_count": 751, "token_estimator": "heuristic-v1", "text": "## Interact with the Contract\n\nOnce the contract is deployed, you can interact with it by calling its functions. For example, to set a number, read it and then modify that number by its double, you can create a file named `checkStorage.js` in the root of your project and add the following code:\n\n```js title=\"scripts/checkStorage.js\"\nconst { ethers } = require('ethers');\nconst { readFileSync } = require('fs');\nconst { join } = require('path');\n\nconst artifactsDir = join(__dirname, '../contracts');\n\nconst createProvider = (providerConfig) => {\n return new ethers.JsonRpcProvider(providerConfig.rpc, {\n chainId: providerConfig.chainId,\n name: providerConfig.name,\n });\n};\n\nconst createWallet = (mnemonic, provider) => {\n return ethers.Wallet.fromPhrase(mnemonic).connect(provider);\n};\n\nconst loadContractAbi = (contractName, directory = artifactsDir) => {\n const contractPath = join(directory, `${contractName}.json`);\n const contractJson = JSON.parse(readFileSync(contractPath, 'utf8'));\n return contractJson.abi || contractJson; // Depending on JSON structure\n};\n\nconst createContract = (contractAddress, abi, wallet) => {\n return new ethers.Contract(contractAddress, abi, wallet);\n};\n\nconst interactWithStorageContract = async (\n contractName,\n contractAddress,\n mnemonic,\n providerConfig,\n numberToSet,\n) => {\n try {\n console.log(`Setting new number in Storage contract: ${numberToSet}`);\n\n // Create provider and wallet\n const provider = createProvider(providerConfig);\n const wallet = createWallet(mnemonic, provider);\n\n // Load the contract ABI and create the contract instance\n const abi = loadContractAbi(contractName);\n const contract = createContract(contractAddress, abi, wallet);\n\n // Send a transaction to set the stored number\n const tx1 = await contract.setNumber(numberToSet);\n await tx1.wait(); // Wait for the transaction to be mined\n console.log(`Number successfully set to ${numberToSet}`);\n\n // Retrieve the updated number\n const storedNumber = await contract.storedNumber();\n console.log(`Retrieved stored number:`, storedNumber.toString());\n\n // Send a transaction to set the stored number\n const tx2 = await contract.setNumber(numberToSet * 2);\n await tx2.wait(); // Wait for the transaction to be mined\n console.log(`Number successfully set to ${numberToSet * 2}`);\n\n // Retrieve the updated number\n const updatedNumber = await contract.storedNumber();\n console.log(`Retrieved stored number:`, updatedNumber.toString());\n } catch (error) {\n console.error('Error interacting with Storage contract:', error.message);\n }\n};\n\nconst providerConfig = {\n name: 'asset-hub-smart-contracts',\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io',\n chainId: 420420422,\n};\n\nconst mnemonic = 'INSERT_MNEMONIC'\nconst contractName = 'Storage';\nconst contractAddress = 'INSERT_CONTRACT_ADDRESS'\nconst newNumber = 42;\n\ninteractWithStorageContract(\n contractName,\n contractAddress,\n mnemonic,\n providerConfig,\n newNumber,\n);\n```\n\nEnsure you replace the `INSERT_MNEMONIC` and `INSERT_CONTRACT_ADDRESS` placeholders with actual values. Also, ensure the contract ABI file (`Storage.json`) is correctly referenced. The script prints the balance for `ADDRESS_TO_CHECK` before it writes and doubles the stored value, so pick any account you want to monitor.\n\nTo interact with the contract, run:\n\n```bash\nnode scripts/checkStorage.js\n```"} -{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 11, "depth": 2, "title": "Where to Go Next", "anchor": "where-to-go-next", "start_char": 20808, "end_char": 21413, "estimated_token_count": 155, "token_estimator": "heuristic-v1", "text": "## Where to Go Next\n\nNow that you have the foundational knowledge to use Ethers.js with Polkadot Hub, you can:\n\n- **Dive into Ethers.js utilities**: Discover additional Ethers.js features, such as wallet management, signing messages, etc.\n- **Implement batch transactions**: Use Ethers.js to execute batch transactions for efficient multi-step contract interactions.\n- **Build scalable applications**: Combine Ethers.js with frameworks like [`Next.js`](https://nextjs.org/docs){target=\\_blank} or [`Node.js`](https://nodejs.org/en){target=\\_blank} to create full-stack decentralized applications (dApps)."} +{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 5, "depth": 2, "title": "Set Up the Ethers.js Provider", "anchor": "set-up-the-ethersjs-provider", "start_char": 2083, "end_char": 4683, "estimated_token_count": 578, "token_estimator": "heuristic-v1", "text": "## Set Up the Ethers.js Provider\n\nA [`Provider`](https://docs.ethers.org/v6/api/providers/#Provider){target=\\_blank} is an abstraction of a connection to the Ethereum network, allowing you to query blockchain data and send transactions. It serves as a bridge between your application and the blockchain.\n\nTo interact with Polkadot Hub, you must set up an Ethers.js provider. This provider connects to a blockchain node, allowing you to query blockchain data and interact with smart contracts. In the root of your project, create a file named `connectToProvider.js` and add the following code:\n\n```js title=\"scripts/connectToProvider.js\"\nconst { JsonRpcProvider } = require('ethers');\n\nconst createProvider = (rpcUrl, chainId, chainName) => {\n const provider = new JsonRpcProvider(rpcUrl, {\n chainId: chainId,\n name: chainName,\n });\n\n return provider;\n};\n\nconst PROVIDER_RPC = {\n rpc: 'INSERT_RPC_URL',\n chainId: 'INSERT_CHAIN_ID',\n name: 'INSERT_CHAIN_NAME',\n};\n\ncreateProvider(PROVIDER_RPC.rpc, PROVIDER_RPC.chainId, PROVIDER_RPC.name);\n\n```\n\n!!! note\n Replace `INSERT_RPC_URL`, `INSERT_CHAIN_ID`, and `INSERT_CHAIN_NAME` with the appropriate values. For example, to connect to Polkadot Hub TestNet's Ethereum RPC instance, you can use the following parameters:\n\n ```js\n const PROVIDER_RPC = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io',\n chainId: 420420422,\n name: 'polkadot-hub-testnet'\n };\n ```\n\nTo connect to the provider, execute:\n\n```bash\nnode scripts/connectToProvider.js\n```\n\nWith the provider set up, you can start querying the blockchain. For instance, to fetch the latest block number:\n\n??? code \"fetchLastBlock.js code\"\n\n ```js title=\"scripts/fetchLastBlock.js\"\n const { JsonRpcProvider } = require('ethers');\n\n const createProvider = (rpcUrl, chainId, chainName) => {\n const provider = new JsonRpcProvider(rpcUrl, {\n chainId: chainId,\n name: chainName,\n });\n\n return provider;\n };\n\n const PROVIDER_RPC = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io',\n chainId: 420420422,\n name: 'polkadot-hub-testnet',\n };\n\n const main = async () => {\n try {\n const provider = createProvider(\n PROVIDER_RPC.rpc,\n PROVIDER_RPC.chainId,\n PROVIDER_RPC.name,\n );\n const latestBlock = await provider.getBlockNumber();\n console.log(`Latest block: ${latestBlock}`);\n } catch (error) {\n console.error('Error connecting to Polkadot Hub TestNet: ' + error.message);\n }\n };\n\n main();\n\n ```"} +{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 6, "depth": 2, "title": "Compile Contracts", "anchor": "compile-contracts", "start_char": 4683, "end_char": 5012, "estimated_token_count": 74, "token_estimator": "heuristic-v1", "text": "## Compile Contracts\n\nPolkadot Hub exposes an Ethereum JSON-RPC endpoint, so you can compile Solidity contracts to familiar EVM bytecode with the upstream [`solc`](https://www.npmjs.com/package/solc){target=\\_blank} compiler. The resulting artifacts work with any EVM-compatible toolchain and can be deployed through Ethers.js."} +{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 7, "depth": 3, "title": "Sample Storage Smart Contract", "anchor": "sample-storage-smart-contract", "start_char": 5012, "end_char": 5837, "estimated_token_count": 171, "token_estimator": "heuristic-v1", "text": "### Sample Storage Smart Contract\n\nThis example demonstrates compiling a `Storage.sol` Solidity contract for deployment to Polkadot Hub. The contract's functionality stores a number and permits users to update it with a new value.\n\n```solidity title=\"contracts/Storage.sol\"\n//SPDX-License-Identifier: MIT\n\n// Solidity files have to start with this pragma.\n// It will be used by the Solidity compiler to validate its version.\npragma solidity ^0.8.9;\n\ncontract Storage {\n // Public state variable to store a number\n uint256 public storedNumber;\n\n /**\n * Updates the stored number.\n *\n * The `public` modifier allows anyone to call this function.\n *\n * @param _newNumber - The new value to store.\n */\n function setNumber(uint256 _newNumber) public {\n storedNumber = _newNumber;\n }\n}\n```"} +{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 8, "depth": 3, "title": "Compile the Smart Contract", "anchor": "compile-the-smart-contract", "start_char": 5837, "end_char": 9394, "estimated_token_count": 810, "token_estimator": "heuristic-v1", "text": "### Compile the Smart Contract\n\nTo compile this contract, use the following script:\n\n```js title=\"scripts/compile.js\"\nconst solc = require('solc');\nconst { readFileSync, writeFileSync, mkdirSync, existsSync } = require('fs');\nconst { basename, join } = require('path');\n\nconst ensureDir = (dirPath) => {\n if (!existsSync(dirPath)) {\n mkdirSync(dirPath, { recursive: true });\n }\n};\n\nconst compileContract = (solidityFilePath, abiDir, artifactsDir) => {\n try {\n // Read the Solidity file\n const source = readFileSync(solidityFilePath, 'utf8');\n const fileName = basename(solidityFilePath);\n \n // Construct the input object for the Solidity compiler\n const input = {\n language: 'Solidity',\n sources: {\n [fileName]: {\n content: source,\n },\n },\n settings: {\n outputSelection: {\n '*': {\n '*': ['abi', 'evm.bytecode'],\n },\n },\n },\n };\n \n console.log(`Compiling contract: ${fileName}...`);\n \n // Compile the contract\n const output = JSON.parse(solc.compile(JSON.stringify(input)));\n \n // Check for errors\n if (output.errors) {\n const errors = output.errors.filter(error => error.severity === 'error');\n if (errors.length > 0) {\n console.error('Compilation errors:');\n errors.forEach(err => console.error(err.formattedMessage));\n return;\n }\n // Show warnings\n const warnings = output.errors.filter(error => error.severity === 'warning');\n warnings.forEach(warn => console.warn(warn.formattedMessage));\n }\n \n // Ensure output directories exist\n ensureDir(abiDir);\n ensureDir(artifactsDir);\n\n // Process compiled contracts\n for (const [sourceFile, contracts] of Object.entries(output.contracts)) {\n for (const [contractName, contract] of Object.entries(contracts)) {\n console.log(`Compiled contract: ${contractName}`);\n \n // Write the ABI\n const abiPath = join(abiDir, `${contractName}.json`);\n writeFileSync(abiPath, JSON.stringify(contract.abi, null, 2));\n console.log(`ABI saved to ${abiPath}`);\n \n // Write the bytecode\n const bytecodePath = join(artifactsDir, `${contractName}.bin`);\n writeFileSync(bytecodePath, contract.evm.bytecode.object);\n console.log(`Bytecode saved to ${bytecodePath}`);\n }\n }\n } catch (error) {\n console.error('Error compiling contracts:', error);\n }\n};\n\nconst solidityFilePath = join(__dirname, '../contracts/Storage.sol');\nconst abiDir = join(__dirname, '../abis');\nconst artifactsDir = join(__dirname, '../artifacts');\n\ncompileContract(solidityFilePath, abiDir, artifactsDir);\n```\n\n!!! note \n The script above is tailored to the `Storage.sol` contract. It can be adjusted for other contracts by changing the file name or modifying the ABI and bytecode paths.\n\nThe ABI (Application Binary Interface) is a JSON representation of your contract's functions, events, and their parameters. It serves as the interface between your JavaScript code and the deployed smart contract, allowing your application to know how to format function calls and interpret returned data.\n\nExecute the script above by running:\n\n```bash\nnode scripts/compile.js\n```\n\nAfter executing the script, the Solidity contract is compiled into standard EVM bytecode. The ABI and bytecode are saved into files with `.json` and `.bin` extensions, respectively. You can now proceed with deploying the contract to Polkadot Hub, as outlined in the next section."} +{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 9, "depth": 2, "title": "Deploy the Compiled Contract", "anchor": "deploy-the-compiled-contract", "start_char": 9394, "end_char": 17247, "estimated_token_count": 1672, "token_estimator": "heuristic-v1", "text": "## Deploy the Compiled Contract\n\nTo deploy your compiled contract to Polkadot Hub, you'll need a wallet with a private key to sign the deployment transaction.\n\nYou can create a `deploy.js` script in the root of your project to achieve this. The deployment script can be divided into key components:\n\n1. Set up the required imports and utilities:\n\n ```js title=\"scripts/deploy.js\"\n const { writeFileSync, existsSync, readFileSync } = require('fs');\n const { join } = require('path');\n const { ethers, JsonRpcProvider } = require('ethers');\n\n ```\n\n2. Create a provider to connect to Polkadot Hub:\n\n ```js title=\"scripts/deploy.js\"\n\n // Creates a provider with specified RPC URL and chain details\n const createProvider = (rpcUrl, chainId, chainName) => {\n const provider = new JsonRpcProvider(rpcUrl, {\n chainId: chainId,\n name: chainName,\n });\n return provider;\n };\n ```\n \n3. Set up functions to read contract artifacts:\n\n ```js title=\"scripts/deploy.js\"\n // Reads and parses the ABI file for a given contract\n const getAbi = (contractName) => {\n try {\n const abiPath = join(artifactsDir, `${contractName}.json`);\n return JSON.parse(readFileSync(abiPath, 'utf8'));\n } catch (error) {\n console.error(\n `Could not find ABI for contract ${contractName}:`,\n error.message,\n );\n throw error;\n }\n };\n\n // Reads the compiled bytecode for a given contract\n const getByteCode = (contractName) => {\n try {\n const bytecodePath = join(artifactsDir, `${contractName}.bin`);\n const bytecode = readFileSync(bytecodePath, 'utf8').trim();\n // Add 0x prefix if not present\n return bytecode.startsWith('0x') ? bytecode : `0x${bytecode}`;\n } catch (error) {\n console.error(\n `Could not find bytecode for contract ${contractName}:`,\n error.message,\n );\n throw error;\n }\n };\n\n ```\n\n4. Create the main deployment function:\n\n ```js title=\"scripts/deploy.js\"\n const deployContract = async (contractName, mnemonic, providerConfig) => {\n console.log(`Deploying ${contractName}...`);\n try {\n // Step 1: Set up provider and wallet\n const provider = createProvider(\n providerConfig.rpc,\n providerConfig.chainId,\n providerConfig.name,\n );\n const walletMnemonic = ethers.Wallet.fromPhrase(mnemonic);\n const wallet = walletMnemonic.connect(provider);\n\n // Step 2: Create and deploy the contract\n const factory = new ethers.ContractFactory(\n getAbi(contractName),\n getByteCode(contractName),\n wallet,\n );\n const contract = await factory.deploy();\n await contract.waitForDeployment();\n\n // Step 3: Save deployment information\n const address = await contract.getAddress();\n console.log(`Contract ${contractName} deployed at: ${address}`);\n\n const addressesFile = join(scriptsDir, 'contract-address.json');\n const addresses = existsSync(addressesFile)\n ? JSON.parse(readFileSync(addressesFile, 'utf8'))\n : {};\n\n addresses[contractName] = address;\n writeFileSync(addressesFile, JSON.stringify(addresses, null, 2), 'utf8');\n } catch (error) {\n console.error(`Failed to deploy contract ${contractName}:`, error);\n }\n };\n ```\n\n5. Configure and execute the deployment:\n\n ```js title=\"scripts/deploy.js\"\n const providerConfig = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', //TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready\n chainId: 420420422,\n name: 'polkadot-hub-testnet',\n };\n\n const mnemonic = 'INSERT_MNEMONIC';\n\n deployContract('Storage', mnemonic, providerConfig);\n ```\n\n !!! note\n A mnemonic (seed phrase) is a series of words that can generate multiple private keys and their corresponding addresses. It's used here to derive the wallet that will sign and pay for the deployment transaction. **Always keep your mnemonic secure and never share it publicly**.\n\n Ensure to replace the `INSERT_MNEMONIC` placeholder with your actual mnemonic.\n\n??? code \"View complete script\"\n\n ```js title=\"scripts/deploy.js\"\n const { writeFileSync, existsSync, readFileSync } = require('fs');\n const { join } = require('path');\n const { ethers, JsonRpcProvider } = require('ethers');\n\n const scriptsDir = __dirname;\n const artifactsDir = join(__dirname, '../contracts');\n\n // Creates a provider with specified RPC URL and chain details\n const createProvider = (rpcUrl, chainId, chainName) => {\n const provider = new JsonRpcProvider(rpcUrl, {\n chainId: chainId,\n name: chainName,\n });\n return provider;\n };\n\n // Reads and parses the ABI file for a given contract\n const getAbi = (contractName) => {\n try {\n const abiPath = join(artifactsDir, `${contractName}.json`);\n return JSON.parse(readFileSync(abiPath, 'utf8'));\n } catch (error) {\n console.error(\n `Could not find ABI for contract ${contractName}:`,\n error.message,\n );\n throw error;\n }\n };\n\n // Reads the compiled bytecode for a given contract\n const getByteCode = (contractName) => {\n try {\n const bytecodePath = join(artifactsDir, `${contractName}.bin`);\n const bytecode = readFileSync(bytecodePath, 'utf8').trim();\n // Add 0x prefix if not present\n return bytecode.startsWith('0x') ? bytecode : `0x${bytecode}`;\n } catch (error) {\n console.error(\n `Could not find bytecode for contract ${contractName}:`,\n error.message,\n );\n throw error;\n }\n };\n\n const deployContract = async (contractName, mnemonic, providerConfig) => {\n console.log(`Deploying ${contractName}...`);\n try {\n // Step 1: Set up provider and wallet\n const provider = createProvider(\n providerConfig.rpc,\n providerConfig.chainId,\n providerConfig.name,\n );\n const walletMnemonic = ethers.Wallet.fromPhrase(mnemonic);\n const wallet = walletMnemonic.connect(provider);\n\n // Step 2: Create and deploy the contract\n const factory = new ethers.ContractFactory(\n getAbi(contractName),\n getByteCode(contractName),\n wallet,\n );\n const contract = await factory.deploy();\n await contract.waitForDeployment();\n\n // Step 3: Save deployment information\n const address = await contract.getAddress();\n console.log(`Contract ${contractName} deployed at: ${address}`);\n\n const addressesFile = join(scriptsDir, 'contract-address.json');\n const addresses = existsSync(addressesFile)\n ? JSON.parse(readFileSync(addressesFile, 'utf8'))\n : {};\n\n addresses[contractName] = address;\n writeFileSync(addressesFile, JSON.stringify(addresses, null, 2), 'utf8');\n } catch (error) {\n console.error(`Failed to deploy contract ${contractName}:`, error);\n }\n };\n\n const providerConfig = {\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', //TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready\n chainId: 420420422,\n name: 'polkadot-hub-testnet',\n };\n\n const mnemonic = 'INSERT_MNEMONIC';\n\n deployContract('Storage', mnemonic, providerConfig);\n ```\n\nTo run the script, execute the following command:\n\n```bash\nnode scripts/deploy.js\n```\n\nAfter running this script, your contract will be deployed to Polkadot Hub, and its address will be saved in `contract-address.json` within your project directory. You can use this address for future contract interactions."} +{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 10, "depth": 2, "title": "Interact with the Contract", "anchor": "interact-with-the-contract", "start_char": 17247, "end_char": 20687, "estimated_token_count": 751, "token_estimator": "heuristic-v1", "text": "## Interact with the Contract\n\nOnce the contract is deployed, you can interact with it by calling its functions. For example, to set a number, read it and then modify that number by its double, you can create a file named `checkStorage.js` in the root of your project and add the following code:\n\n```js title=\"scripts/checkStorage.js\"\nconst { ethers } = require('ethers');\nconst { readFileSync } = require('fs');\nconst { join } = require('path');\n\nconst artifactsDir = join(__dirname, '../contracts');\n\nconst createProvider = (providerConfig) => {\n return new ethers.JsonRpcProvider(providerConfig.rpc, {\n chainId: providerConfig.chainId,\n name: providerConfig.name,\n });\n};\n\nconst createWallet = (mnemonic, provider) => {\n return ethers.Wallet.fromPhrase(mnemonic).connect(provider);\n};\n\nconst loadContractAbi = (contractName, directory = artifactsDir) => {\n const contractPath = join(directory, `${contractName}.json`);\n const contractJson = JSON.parse(readFileSync(contractPath, 'utf8'));\n return contractJson.abi || contractJson; // Depending on JSON structure\n};\n\nconst createContract = (contractAddress, abi, wallet) => {\n return new ethers.Contract(contractAddress, abi, wallet);\n};\n\nconst interactWithStorageContract = async (\n contractName,\n contractAddress,\n mnemonic,\n providerConfig,\n numberToSet,\n) => {\n try {\n console.log(`Setting new number in Storage contract: ${numberToSet}`);\n\n // Create provider and wallet\n const provider = createProvider(providerConfig);\n const wallet = createWallet(mnemonic, provider);\n\n // Load the contract ABI and create the contract instance\n const abi = loadContractAbi(contractName);\n const contract = createContract(contractAddress, abi, wallet);\n\n // Send a transaction to set the stored number\n const tx1 = await contract.setNumber(numberToSet);\n await tx1.wait(); // Wait for the transaction to be mined\n console.log(`Number successfully set to ${numberToSet}`);\n\n // Retrieve the updated number\n const storedNumber = await contract.storedNumber();\n console.log(`Retrieved stored number:`, storedNumber.toString());\n\n // Send a transaction to set the stored number\n const tx2 = await contract.setNumber(numberToSet * 2);\n await tx2.wait(); // Wait for the transaction to be mined\n console.log(`Number successfully set to ${numberToSet * 2}`);\n\n // Retrieve the updated number\n const updatedNumber = await contract.storedNumber();\n console.log(`Retrieved stored number:`, updatedNumber.toString());\n } catch (error) {\n console.error('Error interacting with Storage contract:', error.message);\n }\n};\n\nconst providerConfig = {\n name: 'asset-hub-smart-contracts',\n rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io',\n chainId: 420420422,\n};\n\nconst mnemonic = 'INSERT_MNEMONIC'\nconst contractName = 'Storage';\nconst contractAddress = 'INSERT_CONTRACT_ADDRESS'\nconst newNumber = 42;\n\ninteractWithStorageContract(\n contractName,\n contractAddress,\n mnemonic,\n providerConfig,\n newNumber,\n);\n```\n\nEnsure you replace the `INSERT_MNEMONIC` and `INSERT_CONTRACT_ADDRESS` placeholders with actual values. Also, ensure the contract ABI file (`Storage.json`) is correctly referenced. The script prints the balance for `ADDRESS_TO_CHECK` before it writes and doubles the stored value, so pick any account you want to monitor.\n\nTo interact with the contract, run:\n\n```bash\nnode scripts/checkStorage.js\n```"} +{"page_id": "smart-contracts-libraries-ethers-js", "page_title": "Deploy Contracts to Polkadot Hub with Ethers.js", "index": 11, "depth": 2, "title": "Where to Go Next", "anchor": "where-to-go-next", "start_char": 20687, "end_char": 21292, "estimated_token_count": 155, "token_estimator": "heuristic-v1", "text": "## Where to Go Next\n\nNow that you have the foundational knowledge to use Ethers.js with Polkadot Hub, you can:\n\n- **Dive into Ethers.js utilities**: Discover additional Ethers.js features, such as wallet management, signing messages, etc.\n- **Implement batch transactions**: Use Ethers.js to execute batch transactions for efficient multi-step contract interactions.\n- **Build scalable applications**: Combine Ethers.js with frameworks like [`Next.js`](https://nextjs.org/docs){target=\\_blank} or [`Node.js`](https://nodejs.org/en){target=\\_blank} to create full-stack decentralized applications (dApps)."} {"page_id": "smart-contracts-libraries-viem", "page_title": "viem for Polkadot Hub Smart Contracts", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 178, "end_char": 455, "estimated_token_count": 56, "token_estimator": "heuristic-v1", "text": "## Introduction\n\n[viem](https://viem.sh/){target=\\_blank} is a lightweight TypeScript library designed for interacting with Ethereum-compatible blockchains. This comprehensive guide will walk you through using viem to interact with and deploy smart contracts to Polkadot Hub."} {"page_id": "smart-contracts-libraries-viem", "page_title": "viem for Polkadot Hub Smart Contracts", "index": 1, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 455, "end_char": 811, "estimated_token_count": 110, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore getting started, ensure you have the following installed:\n\n- **Node.js**: v22.13.1 or later, check the [Node.js installation guide](https://nodejs.org/en/download/current/){target=\\_blank}.\n- **npm**: v6.13.4 or later (comes bundled with Node.js).\n- **Solidity**: This guide uses Solidity `^0.8.9` for smart contract development."} {"page_id": "smart-contracts-libraries-viem", "page_title": "viem for Polkadot Hub Smart Contracts", "index": 2, "depth": 2, "title": "Project Structure", "anchor": "project-structure", "start_char": 811, "end_char": 1231, "estimated_token_count": 119, "token_estimator": "heuristic-v1", "text": "## Project Structure\n\nThis project organizes contracts, scripts, and compiled artifacts for easy development and deployment.\n\n```text\nviem-project/\n├── package.json\n├── tsconfig.json\n├── src/\n│ ├── chainConfig.ts\n│ ├── createClient.ts\n│ ├── createWallet.ts\n│ ├── compile.ts\n│ ├── deploy.ts\n│ └── interact.ts\n├── contracts/\n│ └── Storage.sol\n└── artifacts/\n ├── Storage.json\n └── Storage.polkavm\n```"}